
简介本资源是一套面向自动驾驶初学者与计算机视觉从业者的车道线语义分割实战方案基于Unet网络架构实现端到端建模解决真实场景下车道线精准识别与像素级定位问题。资源包共2000个文件含1859张PNG格式标注图像、133张JPG原始图像、5个核心Python训练/推理脚本、2个配置说明文本及1份详细README文档整体压缩后大小为489.46MB数据预处理、训练、评估全流程均已封装小白按目录摆放数据即可启动训练。已有654人学习下载项目采用自建高质量车道线数据集2类别约3200张样本仅训练30个epoch即达全局准确率0.995、Dice系数0.91代码支持Adam/SGD/RMSProp多优化器切换、BCE损失函数、余弦退火等学习率策略并自动保存最优权重、生成loss/dice曲线、预处理可视化图及完整训练日志便于结果复现与性能调优。1. 项目概述从车道线分割到自动驾驶感知的基石在自动驾驶技术栈里感知模块是车辆的“眼睛”而车道线检测则是这双眼睛最基础、最核心的视觉任务之一。它不仅仅是画几条线那么简单而是车辆理解道路结构、保持安全行驶轨迹、实现车道保持辅助LKA和自适应巡航ACC等高级功能的前提。传统的基于图像处理的方法如霍夫变换、边缘检测在光照变化、遮挡、道路磨损等复杂场景下鲁棒性很差。深度学习特别是语义分割网络为这个问题提供了全新的解决方案。Unet作为Unet架构的增强版本以其密集跳跃连接和深度监督的特性在医学图像分割领域大放异彩后也被证明非常适合处理车道线分割这类需要精细边缘和上下文信息的任务。这个项目就是一次将Unet模型应用于自动驾驶车道线分割的完整实战演练。我会带你从零开始理解背后的原理准备好数据集一步步完成模型训练、评估并最终得到可以直接用于推理的模型和代码。无论你是刚入门计算机视觉的学生还是希望将算法落地的工程师这篇详尽的记录都能给你提供一条清晰的路径和一堆可以“抄作业”的代码。2. 核心思路与方案选型为什么是Unet在动手之前我们必须想清楚面对车道线分割为什么选择Unet而不是其他更流行的模型比如DeepLabv3、PSPNet或者原始的Unet这个选择背后是问题特性与模型特性的深度匹配。2.1 车道线分割的任务特性分析车道线分割本质上是一个二类或多类语义分割问题但其具有几个鲜明特点细长结构与类别不平衡车道线在图像中通常呈现为细长的、连续的曲线或直线像素占比极低通常不到5%。这导致了严重的类别不平衡背景像素远多于前景车道线像素。强空间先验与上下文依赖车道线并非随机出现它们遵循道路的透视规律彼此之间大致平行且与车辆行驶方向相关。局部的遮挡如前方车辆或磨损需要模型依靠全局上下文信息进行推断和补全。需要高分辨率细节为了进行精准的车道保持分割出的车道线边缘需要尽可能清晰、连续这就要求模型在编码下采样过程中丢失的细节信息能在解码上采样过程中有效地恢复。实时性要求自动驾驶系统对感知模块的推理速度有严格要求通常需要在几十毫秒内完成一帧图像的处理。2.2 Unet的架构优势原始的Unet通过经典的“U型”编码器-解码器结构和跳跃连接已经在生物医学图像分割中证明了其有效性。Unet在此基础上做了关键改进其架构思想完美契合了上述车道线分割的需求密集跳跃连接与嵌套结构Unet在编码器和解码器之间建立了密集的、多层次的跳跃连接。这不仅仅是连接编码器和解码器的对应层而是通过一系列卷积层将不同尺度的特征图在解码路径上重新融合。这种设计带来了两个核心好处缓解梯度消失促进梯度流动更密集的连接使得浅层特征包含更多细节和边缘信息能更直接地影响深层特征的生成这对于恢复车道线的精细边缘至关重要。多尺度特征融合模型能够同时利用从粗到细多个尺度的特征信息。深层特征把握全局上下文“这是一条高速公路”浅层特征提供局部细节“这里有一条白色虚线”融合后模型对局部遮挡和模糊的车道线有更强的推断能力。深度监督Unet在每一个解码子网络上都添加了一个辅助的1x1卷积层和Sigmoid激活函数用于产生该尺度下的分割图。在训练时这些不同尺度的输出都会计算损失。这样做的好处是缓解梯度消失损失信号可以直接作用于较浅的层加速训练收敛。模型正则化迫使中间层也学习到有意义的特征表示提升了模型的泛化能力。可选的剪枝与加速在推理阶段我们可以根据对速度和精度的权衡选择性地使用某个较浅层的输出从而实现模型加速这为满足自动驾驶的实时性要求提供了灵活性。针对类别不平衡的优化友好Unet的架构使其能够很好地与各种针对类别不平衡设计的损失函数如Dice Loss, Focal Loss, Lovász-Softmax Loss结合。我们可以轻松地在不同深度的监督头上应用这些损失从多个层面督促模型关注难以分割的车道线像素。相比之下DeepLabv3虽然通过ASPP模块获得了强大的多尺度上下文感知能力但在恢复非常精细的边缘方面有时不如具有密集跳跃连接的Unet。而原始Unet的单一跳跃连接在特征融合的丰富性上又稍逊一筹。因此对于车道线分割这个对边缘精度和上下文都有要求的任务Unet是一个在精度和效率上取得了很好平衡的选择。注意模型选择没有银弹。Unet在公开车道线数据集上表现优异但实际部署时仍需结合具体硬件平台如GPU、NPU进行模型量化、剪枝或转换为TensorRT/MNN等推理引擎格式。本项目侧重于算法流程的完整实现为后续的工程化优化打下坚实基础。3. 数据集准备与预处理模型的“粮食”巧妇难为无米之炊高质量的数据集是模型成功的基石。自动驾驶领域有几个知名的车道线分割数据集如TuSimple, CULane, BDD100K, ApolloScape以及你提到的Aeroscapes。我们需要根据数据集的规模、标注质量、场景多样性来选择。3.1 数据集选择与介绍对于入门和实战TuSimple数据集是一个非常好的起点。它规模适中标注精准场景相对简单主要是高速公路便于快速验证算法流程。内容包含在良好天气条件下美国高速公路上拍摄的640x720分辨率视频帧。标注它提供的是车道线的点集标注每个车道线由一系列点的横纵坐标表示而不是像素级的语义分割图。因此我们需要一个额外的步骤将这些点连接成线并“画”到一张空白图上生成对应的二值化分割标签图车道线为白色255背景为黑色0。挑战场景相对单一缺乏恶劣天气、夜间、复杂城市道路的情况。如果你的目标是训练一个更鲁棒的模型CULane数据集是更具挑战性的选择。内容包含了多种场景城市、乡村、高速公路、隧道、夜间、雨天等下的164K张图像分辨率达1640x590。标注直接提供了像素级的二值分割图省去了从点集生成标签的步骤但数据量更大下载和处理需要更多时间和存储空间。Aeroscapes数据集则是一个航空影像分割数据集虽然名字相关但主要用于空中视角的场景理解与车载视角差异较大一般不作为车道线分割的首选。本项目将以TuSimple数据集为例演示从原始数据到训练可用的图像-标签对的完整处理流程。掌握了这个方法你可以轻松迁移到CULane或其他数据集。3.2 数据预处理全流程详解拿到TuSimple数据集的压缩包后我们按以下步骤处理解压与结构梳理通常你会得到train_set.zip,test_set.zip和一个label_data_xxxx.json文件。解压后组织成如下目录结构tusimple_data/ ├── train/ │ ├── clips/ # 训练视频片段文件夹 │ └── label_data_0531.json # 训练标注文件 ├── test/ │ ├── clips/ # 测试视频片段文件夹 │ └── test_label.json # 测试标注文件通常不含真实标签 ├── train_images/ # (待生成) 提取出的训练图片 ├── train_masks/ # (待生成) 生成的训练标签图 ├── val_images/ # (待生成) 验证集图片 └── val_masks/ # (待生成) 验证集标签图从JSON标注生成分割掩码这是最关键的一步。TuSimple的JSON文件里每一行对应一张图片包含了图片路径和每个车道线的点坐标列表。我们需要写一个脚本完成以下工作读取坐标解析JSON获取每张图中每条车道线的点列表[[x1,y1], [x2,y2], ...]。坐标转换与连线注意标注的y坐标是沿着车道线的纵向位置从近到远x坐标是对应的横向位置。我们需要将其映射到图像像素坐标上。然后使用cv2.polylines或cv2.line函数将这些点依次连接绘制到一张全黑的图像上。处理车道线类别TuSimple有最多5条车道线当前车道和相邻车道。在简单的二分类任务中我们可以将所有车道线都视为同一类别前景。如果需要区分左、右车道线等可以为不同索引的车道线赋予不同的灰度值。保存掩码将绘制好的二值图0和255保存为PNG格式与原始图片同名存放在train_masks文件夹。# 示例代码片段从JSON点集生成掩码图 import json import cv2 import os import numpy as np def generate_mask_from_json(json_path, image_base_dir, mask_output_dir): with open(json_path, r) as f: lines f.readlines() for line in lines: data json.loads(line) raw_file data[raw_file] # 图片相对路径如 clips/0531/1492626007222176976_0/20.jpg lanes data[lanes] # 车道线点列表 h_samples data[h_samples] # 统一的y坐标采样点 # 1. 读取原始图片仅用于获取尺寸也可用固定尺寸 img_path os.path.join(image_base_dir, raw_file) # 注意这里也可以不读图片因为TuSimple图片尺寸固定为640x720 height, width 720, 1280 # TuSimple实际是1280x720但标注区域是ROI # 2. 创建空白掩码图 mask np.zeros((height, width), dtypenp.uint8) # 3. 遍历每条车道线 for lane in lanes: points [] for y, x in zip(h_samples, lane): if x -2: # TuSimple用-2表示该点无效 continue # x, y 已经是像素坐标 points.append([x, y]) if len(points) 2: continue # 点太少无法画线 points np.array(points, dtypenp.int32).reshape((-1, 1, 2)) # 用白色(255)绘制线线宽可以设为4-8像素以模拟车道线的宽度 cv2.polylines(mask, [points], isClosedFalse, color255, thickness6) # 4. 保存掩码图 # 确保输出目录存在 mask_filename os.path.basename(raw_file).replace(.jpg, .png) mask_subdir os.path.dirname(raw_file) # 保持原目录结构 output_subdir os.path.join(mask_output_dir, mask_subdir) os.makedirs(output_subdir, exist_okTrue) output_path os.path.join(output_subdir, mask_filename) cv2.imwrite(output_path, mask) print(fGenerated: {output_path})数据集划分不要把所有数据都用于训练通常按照8:1:1或7:2:1的比例随机划分训练集、验证集和测试集。验证集用于在训练过程中监控模型在未见数据上的表现防止过拟合测试集用于最终评估模型性能。可以使用sklearn.model_selection的train_test_split函数进行两次划分。数据增强这是提升模型泛化能力、防止过拟合的必备手段。对于车道线分割有效的增强包括几何变换随机水平翻转对车道线检测非常有效因为道路场景通常左右对称、小角度的随机旋转模拟车辆轻微偏航、随机缩放和裁剪模拟不同距离。颜色空间变换随机调整亮度、对比度、饱和度模拟不同天气和光照条件。添加随机高斯噪声模拟传感器噪声。模拟遮挡随机在图像上放置一些黑色或模糊的矩形块模拟被车辆、树木等临时遮挡的情况。重要提示必须对图像和掩码进行完全相同的变换否则标签就对不齐了。可以使用Albumentations或imgaug这样的专业增强库它们支持对图像和掩码进行同步变换。# 使用Albumentations定义增强管道示例 import albumentations as A train_transform A.Compose([ A.HorizontalFlip(p0.5), # 50%概率水平翻转 A.RandomBrightnessContrast(p0.2), # 随机亮度对比度 A.HueSaturationValue(p0.2), # 随机色相饱和度 A.RandomGamma(p0.2), # 随机Gamma变换 A.Blur(blur_limit3, p0.1), # 轻微模糊 A.CLAHE(p0.1), # 限制对比度自适应直方图均衡化 A.RandomSnow(p0.1), # 模拟雪天可选 A.ShiftScaleRotate(shift_limit0.0625, scale_limit0.1, rotate_limit5, p0.3), # 轻微平移缩放旋转 A.CoarseDropout(max_holes8, max_height20, max_width20, fill_value0, p0.2), # 模拟随机遮挡 ]) # 使用时 augmented train_transform(imageimage, maskmask) aug_image, aug_mask augmented[image], augmented[mask]构建数据加载器使用PyTorch的Dataset和DataLoader类来高效地加载和批处理数据。在Dataset的__getitem__方法中完成图像的读取、增强、归一化如将像素值从[0,255]缩放到[0,1]或使用ImageNet的均值和标准差以及转换为Tensor的操作。4. Unet模型构建与训练策略有了数据接下来我们搭建Unet模型并设计一套针对车道线分割的训练策略。4.1 Unet的PyTorch实现详解Unet的架构图看起来复杂但将其分解为模块后用PyTorch实现是非常清晰的。核心在于嵌套的、密集的跳跃连接。我们通常以预训练的ResNet、VGG或EfficientNet作为编码器Backbone取其不同阶段的特征图。import torch import torch.nn as nn import torch.nn.functional as F from torchvision import models class ConvBlock(nn.Module): 一个简单的卷积块Conv2d - BatchNorm - ReLU重复两次 def __init__(self, in_channels, out_channels): super().__init__() self.conv nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size3, padding1), nn.BatchNorm2d(out_channels), nn.ReLU(inplaceTrue), nn.Conv2d(out_channels, out_channels, kernel_size3, padding1), nn.BatchNorm2d(out_channels), nn.ReLU(inplaceTrue) ) def forward(self, x): return self.conv(x) class UpConv(nn.Module): 上采样模块通常使用转置卷积或双线性插值卷积 def __init__(self, in_channels, out_channels): super().__init__() self.up nn.ConvTranspose2d(in_channels, out_channels, kernel_size2, stride2) # 或者使用self.up nn.Upsample(scale_factor2, modebilinear, align_cornersTrue) # self.conv ConvBlock(in_channels, out_channels) # 注意通道数处理 def forward(self, x): return self.up(x) class UNetPlusPlus(nn.Module): def __init__(self, backboneresnet34, num_classes1, pretrainedTrue): super().__init__() # 1. 加载预训练编码器并获取中间层输出 if backbone resnet34: base_model models.resnet34(pretrainedpretrained) encoder_channels [64, 64, 128, 256, 512] # 对应ResNet的layer0,1,2,3,4输出通道 # 我们需要截取ResNet的前向传播获取中间特征 # 这里简化处理实际需要重写forward_features函数 self.encoder base_model # ... 具体实现需要根据backbone调整获取各阶段特征图 ... # 2. 定义解码路径的通道数通常与编码器对称或减半 decoder_channels [256, 128, 64, 32] # 3. 构建Unet的密集连接结构 # X^{i,j} 表示第i层编码器特征与第j层解码器特征的融合节点 # 需要大量定义 ConvBlock 和 UpConv 模块并按照论文图示连接 # 此处省略冗长的结构定义代码核心是创建多个 nn.ModuleList 来存储各节点 self.nodes nn.ModuleDict() # 存储所有X^{i,j} # ... 初始化所有节点模块 ... # 4. 深度监督头每个解码层输出一个分割图 self.supervision_heads nn.ModuleList([ nn.Conv2d(ch, num_classes, kernel_size1) for ch in decoder_channels ]) # 5. 最终输出层融合所有深度监督结果或仅用最深层的 self.final_conv nn.Conv2d(decoder_channels[0], num_classes, kernel_size1) def forward(self, x): # 1. 编码器前向获取各层特征 e0, e1, e2, e3, e4 encoder_features self._encode(x) # 2. 解码器前向按照Unet的密集连接规则计算每个节点 # 规则X^{i,j} Conv( Concat( [ Up(X^{i1, j}), X^{i, j-1}, ... (所有左侧和上方节点) ] ) ) # 需要仔细实现多层循环 decoder_outputs [] # ... 实现复杂的节点计算逻辑 ... # 3. 计算每个深度监督头的输出 supervision_outputs [] for i, head in enumerate(self.supervision_heads): sup_out head(decoder_outputs[i]) # decoder_outputs[i] 对应第i个解码层输出 sup_out F.interpolate(sup_out, scale_factor2**i, modebilinear, align_cornersTrue) # 上采样到原图大小 supervision_outputs.append(sup_out) # 4. 最终输出可以取最深层的监督头输出或者将它们融合 final_output self.final_conv(decoder_outputs[0]) final_output F.interpolate(final_output, scale_factor16, modebilinear, align_cornersTrue) # 上采样到输入尺寸 if self.training: # 训练时返回所有监督头的输出和最终输出用于计算多尺度损失 return supervision_outputs [final_output] else: # 推理时只返回最终输出 return final_output实操心得自己从零实现Unet是一个很好的学习过程但为了快速实验和保证正确性我强烈推荐使用成熟的语义分割库如Segmentation Models Pytorch (SMP)。它提供了丰富的预训练主干网络和包括Unet在内的多种分割架构只需几行代码即可构建模型并且完全兼容PyTorch生态。import segmentation_models_pytorch as smp model smp.UnetPlusPlus( encoder_nameresnet34, # 选择编码器 encoder_weightsimagenet, # 使用ImageNet预训练权重 in_channels3, # 输入通道数 classes1, # 输出类别数二分类为1 activationsigmoid # 二分类输出用sigmoid )4.2 损失函数与优化器应对类别不平衡车道线分割中背景像素负样本远多于车道线像素正样本直接使用标准的交叉熵损失BCE Loss会导致模型倾向于预测背景忽略车道线。Dice Loss / F1 Loss基于Dice系数对正负样本不平衡不敏感直接优化分割区域的重叠度。非常适合二分类分割任务。class DiceLoss(nn.Module): def __init__(self, smooth1e-6): super().__init__() self.smooth smooth def forward(self, pred, target): pred pred.view(-1) target target.view(-1) intersection (pred * target).sum() dice (2. * intersection self.smooth) / (pred.sum() target.sum() self.smooth) return 1 - diceFocal Loss在标准交叉熵损失的基础上为难以分类的样本通常是正样本即车道线分配更大的权重让模型更关注难例。# SMP库中已集成 loss smp.losses.FocalLoss(modebinary)组合损失实践中常常将多种损失函数结合取长补短。例如Total Loss BCE Loss Dice Loss。BCE Loss保证梯度稳定Dice Loss直接优化分割目标。优化器选择Adam或AdamW优化器是深度学习中的默认选择它们自适应调整学习率收敛速度快。对于Unet这类模型AdamWAdam with decoupled weight decay通常表现更好能带来更好的泛化性能。import torch.optim as optim optimizer optim.AdamW(model.parameters(), lr1e-4, weight_decay1e-4)学习率调度使用学习率热身Warmup和余弦退火Cosine Annealing策略可以显著提升训练稳定性和最终精度。torch.optim.lr_scheduler.CosineAnnealingWarmRestarts或OneCycleLR都是不错的选择。4.3 训练循环与评估指标训练循环是标准的PyTorch流程但需要注意以下几点混合精度训练使用torch.cuda.amp进行自动混合精度训练可以大幅减少GPU显存占用并可能加快训练速度对于大图像分割任务尤其有用。梯度累积如果由于图像分辨率高导致批量大小Batch Size只能设得很小可以使用梯度累积来模拟大批量训练的效果稳定优化过程。模型保存不仅要保存验证集上性能最好的模型best_model.pth也要定期保存检查点checkpoint_epoch_{}.pth防止训练意外中断。评估指标不能只看损失函数下降。对于分割任务常用的评估指标有交并比IoU, Intersection over Union预测区域与真实区域交集与并集的比值。这是分割任务的核心指标。Dice系数与Dice Loss对应值越接近1越好。准确率Accuracy由于类别极不平衡这个指标参考价值不大可能很高但模型什么都没学到。精确率Precision与召回率Recall可以绘制P-R曲线或计算平均精度AP。对于车道线高召回率可能比高精确率更重要宁可多检不能漏检。特定于车道线的指标如TuSimple官方使用的准确率基于车道点预测和假阳性/假阴性率。但作为像素级分割我们主要关注IoU和Dice。在训练过程中要在验证集上计算这些指标并以此作为选择最佳模型的依据。5. 模型推理、可视化与结果分析训练完成后我们得到了一个.pth文件。接下来就是加载模型对新的图片进行推理并分析结果。5.1 推理脚本编写推理脚本需要完成以下步骤加载模型结构和权重。定义与训练时相同的数据预处理流程归一化等但通常不需要数据增强。读取输入图像进行预处理转换为Tensor。将Tensor送入模型得到预测输出。对输出进行后处理对于二分类通常对sigmoid输出设定一个阈值如0.5大于阈值的像素视为车道线。将二值化的预测图与原始图像叠加进行可视化。import cv2 import torch import numpy as np from model import UNetPlusPlus # 导入你的模型定义 from torchvision import transforms def inference_single_image(model_path, image_path, devicecuda): # 1. 加载模型 model UNetPlusPlus(num_classes1).to(device) checkpoint torch.load(model_path, map_locationdevice) model.load_state_dict(checkpoint[model_state_dict]) model.eval() # 切换到评估模式 # 2. 预处理 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), # ImageNet标准归一化 ]) original_image cv2.imread(image_path) image_rgb cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) input_tensor transform(image_rgb).unsqueeze(0).to(device) # 增加batch维度 # 3. 推理 with torch.no_grad(): output model(input_tensor) if isinstance(output, list): # 如果训练时返回了多尺度输出取最后一个最终输出 output output[-1] prob_map torch.sigmoid(output).squeeze().cpu().numpy() # 得到概率图 # 4. 后处理二值化 threshold 0.5 binary_mask (prob_map threshold).astype(np.uint8) * 255 # 5. 可视化将预测的红色车道线叠加到原图上 # 创建一个红色的彩色掩码 color_mask np.zeros_like(original_image) color_mask[binary_mask 255] [0, 0, 255] # 红色 (BGR格式) # 将彩色掩码与原图混合 overlayed_image cv2.addWeighted(original_image, 0.7, color_mask, 0.3, 0) # 6. 保存或显示结果 cv2.imwrite(prediction_result.jpg, overlayed_image) # 也可以并排显示原图、概率热力图、二值掩码和叠加图 return overlayed_image, binary_mask, prob_map5.2 结果分析与常见问题排查运行推理脚本后你会得到一系列可视化结果。如何判断模型的好坏定性分析肉眼观察清晰连续好的分割结果车道线应该是清晰、连续、光滑的曲线没有明显的断裂或毛刺。抗干扰能力强在阴影、路面颜色变化、轻微反光的地方车道线仍然能被正确识别不会被误判为背景。处理遮挡当前方有车辆遮挡部分车道线时模型能否根据上下文进行合理的推测和补全这需要模型有较强的全局感知能力。边缘准确分割出的车道线宽度应与真实情况基本吻合没有过度膨胀或收缩。定量分析指标计算在保留的测试集上计算整体的平均IoUmIoU和平均Dice系数。可以按不同场景晴天、阴影、弯道等分别计算以发现模型的薄弱环节。常见问题与调优方向问题车道线断裂、不连续。可能原因1模型感受野不够大无法建立长距离的依赖关系。解决方案使用更深的主干网络如ResNet101或在Unet中尝试使用空洞卷积Dilated Convolution来扩大感受野。可能原因2损失函数对连续性约束不够。解决方案在损失函数中加入基于形态学如连通域的惩罚项或者尝试使用条件随机场CRF作为后处理但会降低速度。问题误检较多将路面裂缝、阴影识别为车道线。可能原因模型过拟合了训练集中的某些噪声模式或数据增强不够充分。解决方案增加更丰富的数据增强特别是颜色扰动和模拟遮挡在损失函数中增加Focal Loss的权重让模型更关注“真正的”车道线像素难负样本。问题推理速度慢无法满足实时性。可能原因模型参数量过大或输入图像分辨率过高。解决方案模型轻量化更换更轻量的主干网络如MobileNetV3, EfficientNet-B0。使用Unet的剪枝特性在推理时不使用所有的解码层和深度监督头而是选择一个较浅的输出层如X^{0,2}这可以显著减少计算量但可能会损失一些精度。降低输入分辨率将输入图像下采样如从1280x720降到640x360再进行预测然后上采样回原图大小。这是一个精度和速度的权衡。模型量化与加速使用PyTorch的量化功能或将模型转换为TensorRT、ONNX Runtime等推理引擎进行加速。问题训练损失震荡或不下降。可能原因1学习率设置过高。解决方案使用学习率热身和余弦退火调度器并从更小的学习率如3e-5开始尝试。可能原因2数据预处理或增强中存在错误导致图像和标签不对齐。解决方案可视化检查一批次训练数据确保增强后的图像和掩码是完全对应的。可能原因3类别极度不平衡损失被背景主导。解决方案调整损失函数中正负样本的权重或采用Dice Loss、Lovász Loss等对类别不平衡不敏感的损失。6. 项目总结与扩展思考完成整个项目后你手上应该有一套完整的代码包括数据预处理脚本、模型定义、训练循环、推理脚本和训练好的模型权重。这个过程不仅让你掌握了Unet的原理和实现更让你体验了一个完整的深度学习项目 pipeline从数据准备、模型搭建、训练调优到部署测试。我个人在实际操作中的体会是数据质量决定了模型性能的上限而模型结构和训练策略决定了你能多接近这个上限。在车道线分割任务上花在数据清洗、增强和构建更鲁棒的评测集上的时间往往比调参带来的收益更大。例如手动检查并修正一些标注错误的样本或者合成一些极端天气下的数据对模型泛化能力的提升是立竿见影的。这个项目后续还可以从以下几个方向进行扩展和深化多类别分割不仅仅是区分车道线和背景可以进一步区分左车道线、右车道线、双黄线、虚实线等这需要有多类别的标注数据并将模型的输出通道数改为类别数使用nn.CrossEntropyLoss或DiceLoss的多类别版本。实例分割如果同一个类别有多个实例如多条同类型的车道线语义分割无法区分它们。可以尝试结合实例分割的方法如Mask R-CNN或基于嵌入向量的方法如Embedding Branch为每条车道线分配唯一的ID。3D车道线检测将2D图像中的车道线提升到3D空间这需要结合相机的内外参数或者使用单目深度估计网络这对于自动驾驶的路径规划至关重要。视频序列处理利用车道线在视频帧间的时序连续性可以引入循环神经网络RNN或3D卷积或者使用光流信息来稳定检测结果减少单帧预测的抖动。模型轻量化与部署探索知识蒸馏、网络剪枝、量化等技术将训练好的大模型压缩成小模型并部署到嵌入式设备如Jetson Nano, NX或移动端实现真正的实时推理。车道线分割是自动驾驶感知领域一个经典且不断演进的问题。通过这个基于Unet的实战项目你不仅获得了一个可用的工具更重要的是建立起了一套解决计算机视觉分割问题的完整方法论。接下来你可以用这套方法去挑战更复杂的场景、更精细的标注或者尝试将其应用到其他领域的分割任务中去。本文还有配套的精品资源点击获取