恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
YOLO多任务道路识别实战:从数据标注到模型部署全流程
首页
资讯中心
/
YOLO多任务道路识别实战:从数据标注到模型部署全流程
YOLO多任务道路识别实战:从数据标注到模型部署全流程
发布时间:2026/9/8 11:21:44
简介基于YOLO系列YOLOv5、YOLOv8、YOLOv11的多任务道路状况识别项目代码包面向计算机视觉初学者、目标检测研究者及智能交通应用开发者聚焦车辆、斑马线、交通标志、路灯等7类道路目标的识别与定位。压缩包共46个文件包含YAML模型配置文件定义数据集路径与模型参数、Python训练与推理脚本实现数据加载、模型训练和检测、jpg/png样例图像展示输入样本与检测结果以及txt标注信息文件提供类别与坐标数据整体仅115KB轻量精简便于快速下载和本地复现。目前已有104人学习使用。项目基于CULane数据集完整演示了从自定义数据标注、YAML配置编写、数据集划分到模型训练与结果评估的流程并附有道路识别效果示意图方便用户对照检查。代码结构清晰支持更换自有数据集进行迁移学习也可对比不同YOLO版本在多任务道路场景下的性能差异适合作为课程设计、毕业设计或智能交通课题的起步代码。 如果只让我挑一个今年最值得动手复现的计算机视觉项目我会选YOLO多任务道路识别。这个项目看起来只是把“检测分割姿态”塞进一个工程但真正做完一遍你会把目标检测、实例分割、数据标注、模型部署、前后端展示这一整条链路全部打通收益比单独跑一个COCO demo高太多。YOLO多任务道路识别要解决的事情很具体一张道路图片丢进去模型不光要告诉你哪里有车、有人、有骑行者还要把车道线、可行驶区域画出来顺便判断路面有没有坑洼、裂缝、积水。工程上最顺手的做法不是堆三个模型而是基于YOLO这一套框架做统一的多任务输出。对做毕设、竞赛、实际项目预研的人来说这个方向既有深度又有落地场景我非常推荐。1. 项目整体思路多任务组合怎么设计1.1 为什么用YOLO而不是拼三个模型很多人拿到道路识别需求第一反应是“检测一个模型分割一个模型姿态一个模型”三个独立跑。这个方案不是不行但问题很明显显存翻倍、推理延迟翻倍、后处理逻辑分散在三套代码里出了问题你都不知道该查哪一环。我更建议直接走YOLO的Unified框架。Ultralytics把detect、segment、pose、obb、classify五种任务都封装在同一套代码里共享backbone和neck只在不同head上做输出。这意味着你可以用同一份数据管线、同一种训练策略、同一套评估脚本去处理多个任务工程上省心太多。实测下来无论是yolov8还是yolo11API基本一致迁移成本很低。1.2 任务组合与数据来源规划我自己的项目拆成三个任务交通目标检测、车道线与可行驶区域分割、路面病害检测。它们的输出形态不同但都吃同一批道路图像。任务输出实现方式数据来源交通目标检测车辆、行人、骑行者、标志牌框YOLO detectBDD100K VisDrone2019车道线/可行驶区域像素级maskYOLO segmentBDD100K路面病害坑洼、裂缝、积水框/maskYOLO detect/segment自制小数据集 公开缺陷数据BDD100K是最值得用的公开数据集它自带车辆检测框、车道线、可行驶区域标注一份数据支撑两个训练任务。VisDrone2019则是无人机视角的交通目标数据能补充大量小目标样本。路面病害数据公开的少我一开始是手动标了两百多张够把流程跑通。1.3 共享Backbone的代价与对策多任务共享特征不是没有代价。检测任务需要判别性强的语义特征分割任务需要更多空间细节两者在同一个backbone里会互相“打架”。我实际训练时发现如果两个任务的loss往同一个权重上加很容易出现检测指标涨了、分割mask边缘变粗糙的情况。对策也不复杂在neck之后保持独立的head别在backbone里强行共享给不同head配上不同loss权重实在不对付就分开训练推理时再统一。先稳定落地再追求端到端多任务这是我反复强调的工程顺序。2. 环境搭建AMD RX 580能不能跑依赖版本怎么选2.1 AMD显卡的技术现实热词里好几个人问“AMD 580显卡能跑yolo吗”“需要安装CUDA吗”。这里直接说结论RX 580不支持CUDA它是AMD GCN架构只能走ROCm路线。问题是ROCm对RX 580这种老卡支持很有限装起来费劲装完跑YOLO也没比CPU快多少非常不划算。我的建议是分情况处理手头只有RX 580就老老实实用CPU跑yolov8n或yolov8s做推理验证训练丢给云GPU平台N卡优先3060以上都可以比较舒服地训练yolov8m实在没钱先用小模型把流程跑通再换大模型不要在环境上死磕。2.2 依赖版本与安装环境版本我固定用这套组合踩坑最少python3.10 torch2.1.2 torchvision0.16.2 ultralytics8.2.0 opencv-python4.8安装时要特别注意PyTorch和CUDA的配套关系。CUDA 11.8或12.1都能跑但如果你用的是NVIDIA驱动先nvidia-smi看一眼驱动版本再决定用哪个CUDA。安装命令里一定要指定index-url否则默认装CPU版训练慢到怀疑人生。2.3 先跑通最小验证正式训练前我用官方自带的coco8数据集先跑10个epoch验证环境是否通畅。这一步非常关键如果coco8能正常出训练曲线、能正常保存权重说明CUDA、PyTorch、Ultralytics三者没问题后面再怎么折腾都是数据和配置问题不会陷入“环境到底哪坏了”的泥潭。3. 数据集准备VisDrone2019转YOLO与标签组织3.1 VisDrone2019格式转换VisDrone2019是无人机视角的目标检测基准很多人下载完发现格式跟YOLO完全不同。它的标注每行是逗号分隔的bbox左上角x、左上角y、宽w、高h、score、truncation、occlusion、类别。转换时要过滤掉score为0的忽略目标类别索引还要减1因为VisDrone的类别从1开始且0是ignored。import os def visdrone_to_yolo(label_path, img_w, img_h, out_path): with open(label_path, r) as f: lines f.readlines() out_lines [] for line in lines: parts list(map(float, line.strip().split(,))) x, y, w, h, score, _, _, cls parts[:8] if score 0 or cls 0: continue x_center (x w / 2) / img_w y_center (y h / 2) / img_h w_norm w / img_w h_norm h / img_h out_lines.append( f{int(cls) - 1} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f} ) with open(out_path, w) as f: f.write(\n.join(out_lines))这段代码是我实际转换时用的目录结构按images和labels分开。转换完抽几张图可视化检查一遍确认框的位置没有偏移再进训练不然模型会在错坐标上学到一堆噪声。3.2 多任务标签目录怎么组织ultralytics的训练接口一次只接受一种任务类型所以多任务项目的标签最好按任务拆开目录避免混淆datasets/road/ ├── images/ │ ├── train/ │ └── val/ ├── labels_detect/ │ ├── train/ │ └── val/ ├── labels_segment/ │ ├── train/ │ └── val/ ├── road_detect.yaml └── road_segment.yaml检测标签是“类别 x_center y_center w h”的归一化坐标分割标签则是“类别 x1 y1 x2 y2 ... ”的多边形归一化点集。BDD100K原格式是JSON转YOLO分割格式时要先把多边形点取出来归一化注意BDD100K的一些标注是RLE编码的mask得先转polygon才能用。3.3 半自动标注与数据划分如果自己标注千万别一上来就用裸的labelImg硬标。我的做法是用X-AnyLabeling或CVAT搭半自动流程先用SAM或已有模型打底再人工修正边界效率能快好几倍。分割mask边缘粗糙的样本宁可直接删掉也不要留在训练集里拖后腿。数据划分还有一个大坑按视频帧抽的数据如果随机切分同一段视频的相似帧会同时出现在训练集和验证集导致验证指标虚高。我习惯按视频片段或采集时间段切分保证验证集真正“没见过”相近场景。4. 模型与配置文件yolov8m还是别的4.1 选择模型与初始权重模型选择我倾向于yolov8m或yolo11ms和n适合快速验证l和x在个人显卡上训起来吃力。如果同时做检测和分割直接下载yolov8m-seg.pt或yolo11m-seg.pt作为初始权重它能同时产出框和mask等于给分割任务一个更好的起点。姿态分支如果也想要就用yolov8m-pose.pt关键点坐标归一化和检测标签类似。不过我个人认为道路识别项目里姿态更多是“可选项”对行人和骑行者做姿态估计能辅助行为分析但前期可以不做保持简单。4.2 data.yaml与训练超参检测和分割各写一个yaml内容结构差不多关键是names和类别数量不能搞错# road_detect.yaml path: ./datasets/road train: images/train val: images/val names: 0: car 1: bus 2: truck 3: pedestrian 4: cyclist 5: motor 6: traffic_sign训练超参我固定的初始值是这样imgsz: 640 batch: 16 epochs: 100 patience: 50 optimizer: AdamW lr0: 0.001小目标多的时候imgz提到768或1280效果立竿见影但显存压力也上来了batch要跟着降。imgsz的调整是收益最明显的单点操作比花几天调loss权重见效快。4.3 损失函数理解与矩形切图的坑检测头用的是CIoUDFLBCE的组合分割头额外叠加BCEDice。这个组合在YOLO里是默认的你不用改代码但要理解Dice loss对mask边缘敏感这就是为什么标注粗糙会导致seg结果粗糙。热词里有人问“yolo切割只能切矩形图片吗”这里展开说模型输入本身就是矩形tile切图只能是矩形但切图不只是切图分割标注的polygon要在同一偏移下重新裁剪和坐标换算。我见过有人大图切patch之后只挪了图像没挪mask结果模型在完全没有mask的区域上乱学。正确的做法是滑窗切图的时候mask和图片用完全相同的偏移量处理回贴预测结果时再反向偏移回原图坐标这一步最容易出错。5. 训练实战命令、曲线与常见问题5.1 训练入口与多任务折衷训练用ultralytics的API一把梭from ultralytics import YOLO # 检测任务 det_model YOLO(yolov8m.pt) det_model.train( dataroad_detect.yaml, epochs100, imgsz640, batch16, projectroad_multi, namedetect, patience50, optimizerAdamW, lr00.001, ) # 分割任务 seg_model YOLO(yolov8m-seg.pt) seg_model.train( dataroad_segment.yaml, epochs100, imgsz640, batch12, projectroad_multi, namesegment, patience50, optimizerAdamW, lr00.001, )需要说清楚一件事ultralytics原生不支持一个模型同时训练检测分割姿态三个head多任务在工程上是“统一框架下分开训练推理时统一输出”。如果你追求的是一个真正的单模型多head可以去看YOLOP这类方案但调试成本会高很多。我自己的项目先走分开训练再融合有问题拆开查非常稳。5.2 训练过程怎么看训练时看几个关键指标train/loss、val_box_loss、val_seg_loss、mAP50、mAP50-95。正常现象是前10个epoch的seg loss收敛比det慢dfl_loss降得也慢这些不用慌。反而要警惕的是mAP50一直纹丝不动那大概率是数据或标注出了问题不是训练步数不够。早停patience我设50超过50个epoch验证集不改善就自动停。这样即使epochs设了100实际到七八十轮停了也很正常权重会保存最佳的一版。5.3 常见问题速查表现象可能原因处理方式训练OOMbatch过大、imgsz过高batch降到8或4开AMP自动混合精度loss出现nan学习率过大、标签有脏数据lr0降到0.0001检查标签坐标是否越界小目标漏检严重输入尺寸不够、下采样丢失细节SAHI切图或imgsz提到1280mask边缘粗糙分割标注本身粗糙、epochs不足优先修标注再考虑增加训练轮数验证集掉点明显数据划分泄露、过拟合按视频片段划分考虑冻结backbone前10层训练类别混淆厉害类别定义不清、样本不均衡合并相似类别或补充边界样本6. 推理、部署与展示6.1 单图与视频推理训练完拿到best.pt推理代码很简单from ultralytics import YOLO det_model YOLO(road_multi/detect/weights/best.pt) seg_model YOLO(road_multi/segment/weights/best.pt) res_det det_model.predict(test.jpg, conf0.4, iou0.5, saveTrue) res_seg seg_model.predict(test.jpg, conf0.4, iou0.5, retina_masksTrue, saveTrue)retina_masksTrue会输出更精细的mask代价是多一点计算量可视化更漂亮。conf和iou要按场景调道路场景遮挡多、小目标多conf可以放到0.25iou保持0.5太多误报就回0.4。6.2 导出ONNX/TensorRT与边缘设备部署环节导出格式很讲究# 导出ONNX yolo export modelroad_multi/detect/weights/best.pt formatonnx opset12 # 导出TensorRT engine yolo export modelroad_multi/detect/weights/best.pt formatengine device0 halfTrueTensorRT的engine和硬件绑定换了显卡型号或CUDA版本就得重新导出。边缘设备上华为Atlas走ATC转换ONNXK230则要转成kmodel核心思路都是ONNX - 专用格式 - target device推理。模型选型上边缘端我用yolov8n而不是mn模型约6M参数在边缘设备上能跑实时精度牺牲可接受。6.3 Flask Vue MySQL展示做展示层的时候我又补了个轻量Web方案Flask做后端Vue做前端MySQL存识别记录。核心接口很薄from flask import Flask, request, jsonify from PIL import Image from ultralytics import YOLO app Flask(__name__) model YOLO(road_multi/detect/weights/best.pt) app.route(/predict, methods[POST]) def predict(): file request.files[image] img Image.open(file.stream).convert(RGB) results model.predict(img, conf0.4) r results[0] return jsonify({ boxes: r.boxes.xyxy.tolist(), scores: r.boxes.conf.tolist(), classes: r.boxes.cls.tolist(), }) if __name__ __main__: app.run(host0.0.0.0, port5000)前端上传图片后端返回框坐标和类别前端再用canvas画框。整套流程不复杂但演示和验收时很有说服力。7. 复盘踩过的坑和我的实用心得7.1 多任务Loss权重失衡我先试过一个任务跑100轮再接着跑另一个任务效果很差前面的任务指标掉得厉害。后来改成两个任务独立训练推理阶段再统一输出稳定很多。如果你一定要端到端微调多任务给不同任务的loss配权重时先单独跑一遍每个任务记录loss量级然后按量级反比加权别凭感觉设。7.2 小目标别硬训VisDrone2019里小目标非常多imgsz640训出来的模型漏检严重。我实际用SAHI切图推理把大图切成512x512的重叠patch分别检测再融合结果mAP提升非常明显。代价是推理耗时增加但边缘设备可以靠开启半精度和更小的模型来平衡。7.3 数据“脏”的代价分割标注粗不粗糙直接决定mask边缘好不好看。我最初用半自动工具过了一遍懒得细修结果训练出来的车道线mask像锯齿。后来花两天把标注修了一遍指标直接涨了三个多点。数据质量永远是投入产出比最高的环节别省。7.4 部署环境不一致Docker是正解有一次在本地导出的engine拿到部署机上加载失败折腾半天发现是CUDA版本不一致。后来我直接用docker镜像固定环境比如nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu20.04训练、导出、部署同一套环境engine再也没出过兼容性问题。整个项目跑完一遍我最大的感受是多任务道路识别难的不是模型有多深而是数据怎么对齐、任务怎么取舍、环境怎么稳定。把ultralytics这套框架吃透配合清晰的数据组织方式即使是一个人的小项目也能做出接近工程落地的效果。最后再分享一个小技巧所有数据集文件命名统一用数字前缀或固定命名规则别用中文和特殊符号Linux环境下坑少很多。本文还有配套的精品资源点击获取