十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv3三类别车辆检测实战:数据集处理、模型训练与调优指南

YOLOv3三类别车辆检测实战:数据集处理、模型训练与调优指南 简介面向自动驾驶、智能交通与安防监控等场景的车辆检测专用数据集明确划分car、bus、truck三个类别共5380个文件压缩包整体约603.55MB。其中包含1793张jpg原图配套1794个txt标注与1793个xml标注txt格式直接记录边界框坐标与类别解析简洁xml遵循PASCAL VOC标准提供更多物体元数据两种格式均可直接用于YOLOv3等目标检测模型的训练与调试。已有1011人学习下载图片内容覆盖多角度、不同光照和车流密度适合在开发早期快速验证模型结构、调整anchor尺寸、评估不同标签格式对训练效果的影响。利用这份数据可以训练出能够区分轿车、公交车和卡车的检测器支撑真实环境中的车型识别、车流统计、违章抓拍及自动驾驶感知等工程任务。1. 这个三类别车辆检测数据集到底能解决什么任务很多人拿到YOLOv3车辆检测数据集-三类别.rar时会下意识把它当成“交通目标检测”的数据集直接用。但实际上三类别意味着它不是单纯回答“这里有没有车”而是要区分轿车、公交车、卡车这三类交通工具输出带类别标签的预测框。这对车流统计、公交专用道占道识别、停车场空位管理和辅助驾驶感知都有实际意义。YOLOv3 在中等尺寸目标检测上训练快、部署成本低至今仍是很多传统视觉方案的默认起点。阅读这篇文章的人要么是在做智能交通或安防项目要么是初学者想拿一份清晰的数据集跑通 YOLOv3 全流程。无论哪种先理解这份数据集的三类别标签再把它干净地接入 darknet是后面所有调参的前提。2. 上车前先拆开数据集的目录结构和三类别标注格式2.1 rar 解包后最常见的目录长这样把 rar 解压后你看到的目录几乎都是“图片 标签 文件列表”的组合。我一般会先执行tree -L 2看一层结构避免上来就盲目改配置mkdir -p yolov3_vehicle_data unrar x YOLOv3车辆检测数据集-三类别.rar yolov3_vehicle_data/ tree -L 2 yolov3_vehicle_data/一种非常常见的组织方式是 images 和 labels 分开再配三个.txt文件作为图片路径清单yolov3_vehicle_data/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt ├── train.txt ├── val.txt └── test.txt注意train.txt里每一行是图片的完整路径或相对路径darknet 在训练时会根据路径自动把尾部的.jpg替换成.txt去对应的 labels 目录里找标签。正因为有这个约定images 和 labels 目录的层级必须保持一致。如果你解压后看到的是JPEGImages和Annotations说明数据集是更古典的 VOC 结构需要先把标注转成 YOLO 的 txt 格式否则没法喂给 darknet。2.2 三类别标签怎么定义每一行就是一个目标YOLOv3 原生的标签是纯文本一行表示一个目标格式为class_id x_center y_center width height前四项都归一化到 0.01.0。一个三类别数据的 label 文件通常长这样0 0.543598 0.432516 0.185119 0.326406 1 0.731155 0.649632 0.097158 0.231854 2 0.408712 0.287531 0.058441 0.132870上面三行分别对应classes.txt里的某个顺序常见定义是0car, 1bus, 2truck。转换成坐标时先算出标注框的中心点再分别除以图宽w和图高h框宽高也同理。如果你拿到的标注是 VOC 的xmin/ymin/xmax/ymax绝对像素转换脚本可以这样写import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, out_file, classes): tree ET.parse(xml_file) w int(tree.findtext(./size/width)) h int(tree.findtext(./size/height)) lines [] for obj in tree.findall(./object): name obj.findtext(name) xmin int(obj.findtext(bndbox/xmin)) ymin int(obj.findtext(bndbox/ymin)) xmax int(obj.findtext(bndbox/xmax)) ymax int(obj.findtext(bndbox/ymax)) x ((xmin xmax) / 2) / w y ((ymin ymax) / 2) / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{classes.index(name)} {x:.6f} {y:.6f} {bw:.6f} {bh:.6f}) open(out_file, w).write(\n.join(lines))这段代码的核心是classes.index(name)它把类别字符串映射成数字 id顺序必须和后面的classes.txt完全一致。很多人在转换时只改坐标、不改 id训练出来的模型就会把 bus 当成 truck。数据集的图片尺寸比较杂的话还要在转换前确认 XML 里的width和height是原始图片尺寸而不是某次缩放之后的值。2.3 把图片和标签切成训练集、验证集的脚本如果 rar 包里的train.txt和val.txt对你来说不够干净或者你想重新划分常见做法是用一个短脚本自己切。90% 图片进训练集10% 进验证集随机种子固定以保证每次划分结果一致import os import random img_dir images/train img_files [os.path.join(img_dir, f) for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] random.seed(0) random.shuffle(img_files) split int(len(img_files) * 0.9) with open(train.txt, w) as f: f.write(\n.join(img_files[:split]) \n) with open(val.txt, w) as f: f.write(\n.join(img_files[split:]) \n)脚本本身不复制任何文件只是生成路径清单。darknet 读取train.txt后会沿着图片路径把images/train/0001.jpg变成labels/train/0001.txt。所以这里的关键不是随机划分本身而是图片和 label 的文件名必须严格同名只差扩展名。划分完成后随便取一张图片确认它对应的 txt 文件里至少有行为好空 label 文件过多会让训练时出现大量背景样本。2.4 检查三类别的样本均衡防止 car 一家独大训练开始前花一分钟统计训练集里三个类别的框数量能避免后面踩大坑。这个统计可以基于 labels 目录直接做import os from collections import Counter counts Counter() for label_file in os.listdir(labels/train): with open(os.path.join(labels/train, label_file)) as f: for line in f: cls_id int(line.split()[0]) counts[cls_id] 1 print(counts)统计结果可能接近下面这张表类别框数示例占比car864282.1%bus10449.9%truck8428.0%表格只是演示但这类长尾分布在三类别车辆检测数据里非常典型。car 样本多训练时每个 batch 里几乎都能见到bus 和 truck 样本少模型容易把注意力全放在“如何区分前景和背景”上而忽略了对稀有类别内部造型差异的学习。看到超过 8:1 的比例就应该在训练前做一次过采样或数据增强而不是指望 loss 自己平衡。3. 用 YOLOv3 把三类别车辆检测数据跑起来3.1 先写三个配置文件names、data、cfg进入训练前需要准备三类文件。第一个是类别名文件vehicle.names内容就是三行car bus truck第二个是数据集描述文件vehicle.data它告诉 darknet 去哪里读训练列表和验证列表classes 3 train /absolute/path/to/train.txt valid /absolute/path/to/val.txt names /absolute/path/to/vehicle.names backup backup/backup目录用来保存训练过程中生成的 weights 文件一定要提前建好否则保存权重时会报路径错误。第三个是网络配置文件这里直接基于官方yolov3.cfg修改。YOLOv3 有 3 个不同尺度的 yolo 层每层前面的卷积核个数是3 * (5 classes)classes 为 3 时就是 24。用 sed 可以把三处 255 和 classes80 一次性改掉sed -i s/^filters255/filters24/ cfg/yolov3.cfg sed -i s/^classes80/classes3/ cfg/yolov3.cfg两行命令分别处理卷积核数和类别数。filters24这个数不能乱填它由检测头的输出需求决定3 表示每个网格有 3 个 anchor5 表示 x、y、w、h 和 objectness 置信度再加 classes 个类别概率。改漏任何一处训练时都会看到维度不对的报错。3.2 预训练权重迁移学习比从零训练划算官方darknet53.conv.74是一个只有 74 个卷积层的预训练权重不含检测头。选择它而不是yolov3.weights的原因很直接你的类别数已经从 80 改为 3yolo 层前面的卷积层形状已经变化直接加载完整权重会报尺寸不匹配。而darknet53.conv.74恰好覆盖主干网络部分检测头可以重新随机初始化。下载后放到项目目录不必改名字。训练时它会作为-i之外的第一个可选参数传入。如果数据集本身有几万张图你甚至可以从零开始训练但通常徒增三到五倍的收敛时间效果未必更好。迁移学习还能让 loss 在前期下降得很快。3.3 训练命令与三个必看参数训练命令在 darknet 根目录下执行./darknet detector train cfg/vehicle.data cfg/yolov3.cfg darknet53.conv.74 -map | tee train.log| tee train.log是为了把训练日志同时输出到屏幕和文件里方便后面回看 loss 趋势。-map会让训练过程定期在验证集上计算 mAP并且在日志里打印出来没有这个参数你只能靠 loss 猜模型好坏。进入训练前需要检查yolov3.cfg里几个关键参数。表格里写的是三类别车辆检测场景下的推荐起点参数推荐值说明batch64一个迭代用 64 张图影响 BN 统计subdivisions16 或 32显卡显存不够时拆成更小的子 batchwidth / height416 或 608小目标多时用 608但显存和速度要权衡max_batches6000官方常见做法是 classes * 2000steps4800, 5400分别接近 max_batches 的 80% 和 90%learning_rate0.001微调阶段通常不用再动momentum0.9保持官方默认decay0.0005保持官方默认subdivisions是显存不足时最常用的调节项。batch64, subdivisions16意味着一次迭代内实际分成 16 个小批次前向每个小批次 4 张图。如果你看到 CUDA out of memory就翻倍加subdivisions但这也会等比例降低训练速度。提示训练速度很慢但显存占用并不高时可以适当减小subdivisions让并行度更高。3.4 训练日志如何判断三类别模型开始收敛darknet 训练时输出的日志里前面几项比 loss 数字本身更重要。一段走向收敛的日志通常长这样v3 (iou loss, Normalizer: (iou: 0.75, obj: 1.00)) Region Avg IOU: 0.82, Class: 0.83, Obj: 0.74, No Obj: 0.01, .5R: 0.92, .75R: 0.67, count: 4 4002: 1.120519, 1.120570 avg, 0.001000 rate, 3.512334 seconds, 32016 images这里的Region Avg IOU是当前 batch 里正样本框的平均 IoU高于 0.8 说明框已经基本贴上目标Class是类别置信度.5R是 IoU 阈值为 0.5 时的召回率。最后一行第一个数字是当前 loss紧跟着的avg是 loss 的滑动平均观察收敛主要看它。三类别数据在 6000 轮训完avg一般会降到 1.5 以下如果 2000 轮还在 3 以上先回去补查标签坐标是否归一化。4. 在三类别评测里找出薄弱环节4.1 用训练好的 weights 测试单张图片与视频训练完成后训练脚本保存一份backup/yolov3_final.weights。单张图片的检测命令是./darknet detector test cfg/vehicle.data cfg/yolov3.cfg \ backup/yolov3_final.weights data/test_001.jpg -thresh 0.25-thresh是置信度阈值只有超过这个值的目标才会被画出来。0.25 是官方常用值需要看漏检时降到 0.1需要看误检时调到 0.4是个快速判断模型状态的好办法。视频检测换成 demo 子命令./darknet detector demo cfg/vehicle.data cfg/yolov3.cfg \ backup/yolov3_final.weights data/test_video.mp4 -out_filename out.mp4demo 输出图片或视频时会在画面左上角打印当前 FPS。三类别模型如果每个目标都画出框且类别正确基本可以进入批量评测阶段。4.2 mAP 结果按三类别拆开看评估 mAP 的命令与测试类似但会用验证集中的所有图片计算平均精度./darknet detector map cfg/vehicle.data cfg/yolov3.cfg \ backup/yolov3_final.weights -thresh 0.25运行结束会打印每个类别的 AP 和整体 mAP输出形式类似class_id 0, name car, ap 91.45% class_id 1, name bus, ap 74.21% class_id 2, name truck, ap 81.30%只看总 mAP 会得到“效果不错”的结论但拆开后往往发现 bus 的 AP 明显更低。原因不外乎三类bus 样本少、bus 标注框内遮挡多、或者图片里 bus 和货车在侧面视角下过于接近。总 mAP 被占比最大的 car 拉高所以调参前先盯每个类别的 AP 差尤其是最低的那一类。4.3 车辆检测三类别最容易出现的误检在真实交通场景里三类别车辆检测常见的误判有规律可循。car 被检成 bus 或 truck多发生在车头正对镜头、尺寸被放大的情况下比如近距离的 SUV 或面包车轮廓和轻客很像。bus 与 truck 的混淆则集中在侧面视角箱式货车和公交车的矩形外观差异很小。远处小目标漏检也很普遍因为 416 输入分辨率下一辆 20 米外的轿车可能只有 8×8 像素。针对这些状态可以做一个针对性的调整表现象常见原因可尝试方案bus 和 truck 互相误判侧视轮廓接近增加侧视、斜视样本或提高输入分辨率到 608远处小目标漏检目标像素太少把 width/height 改成 608保留多尺度训练 random1重叠车辆只出一个框训练时重叠目标匹配不够调大ignore_thresh到 0.8 并重训夜间误检严重亮度、对比度不足检查数据里是否包含夜间样本否则补数据提示AP 的差距比总 mAP 更值得盯。car 的 AP 高不等于 bus 也能用。如果表格里某种现象占了主导就不要急着改网络结构先补对应场景的数据。模型在验证集上稳定后把最好的一个 weights 单独拷出来后面所有部署测试都基于它减少反复比对的成本。5. 部署前再收紧三类别输出的三个实用技巧5.1 样本不平衡时怎么给 bus 和 truck 提高话语权darknet 没有现成的命令行参数让某个类别在 loss 里加权最可靠的做法是过采样。常见操作是把labels/train里包含类别 1 或 2 的样本复制到另一个临时目录然后在train.txt里把它们的图片路径重复写几遍让每个 batch 里 bus 和 truck 出现得更频繁。为了不破坏原始结构可以用一个循环先统计各类别数量再按目标比例补充。补多少没有固定公式我一般把少数类样本数补到多数类的 60%80%补太多会重复学习同一批图导致过拟合。另一种做法是离线做亮度、翻转、裁剪增强生成更多 bus 和 truck 的变体缺点是占用磁盘空间。5.2 置信度阈值和 ignore_thresh 比改 NMS 更实用部署阶段调整置信度阈值是最容易上手的-thresh 0.4能明显减少对树影、护栏、路边停车的误检代价是轻度漏检-thresh 0.15则相反。如果车辆重叠时经常只出一个框应该回到训练参数ignore_thresh它控制训练中对重叠候选框的容忍程度。默认 0.7 偏保守改成 0.8 再重新训练sed -i s/ignore_thresh .7/ignore_thresh .8/ cfg/yolov3.cfg ./darknet detector train cfg/vehicle.data cfg/yolov3.cfg darknet53.conv.74 -map这里先把ignore_thresh调大让更多与真实框有明显重叠的 anchor 参与匹配模型就有机会学习“紧挨着的两辆车是不同目标”。改完一个参数只重训一次不要同时动learning_rate和width否则很难判断是谁起了作用。5.3 换 Tiny YOLOv3 或输入尺寸 608如果最终要跑到嵌入式设备上可以换个思路先把输入尺寸降到 416 并确认三类别 AP 下降幅度再考虑要不要换成yolov3-tiny.cfg。Tiny 的主干更浅只能加载配套的 tiny 预训练权重但处理和改造方式和标准版一致sed -i s/^filters255/filters24/ cfg/yolov3-tiny.cfg sed -i s/^classes80/classes3/ cfg/yolov3-tiny.cfgTiny 对 car 这类中小目标的影响最明显但对 bus 和 truck 这种大目标一般还能保住六成以上 AP。反过来如果项目用小目标检测为主就优先把width/height改成 608而不是换 Tiny。三类别车辆检测并不需要非常深的特征训练时多尝试“标准版 416 过采样”和“Tiny 416 更高分辨率”这两组组合能在实际视频流上对比哪个更适合你的硬件。本文还有配套的精品资源点击获取
返回列表