资讯详情

YOLOv3目标检测实战:行人自行车机动车识别与训练指南

📅 2026/9/28 11:54:48 | 华诺云谱 👁 阅读
YOLOv3目标检测实战:行人自行车机动车识别与训练指南
简介面向目标检测入门与课程实训的YOLOv3完整方案针对行人、自行车与机动车识别场景提供模型代码、实验报告与数据集说明适合高校学生、毕业设计或想快速上手PaddlePaddle实现YOLO的开发者。资源包共12个文件3个Python脚本承担模型训练、推理与检测结果处理7张PNG图展示精度曲线、mAP及检测效果另有说明文档与类别配置文件整体仅158KB便于下载。已有693人学习使用。资料从YOLO算法原理、网络结构讲到参数调整与模型优化并给出YOLO与YOLO-tiny对比、挑战集测试分析和mAP性能评估结合训练与推理脚本及报告目录读者可复现训练流程、理解调参思路也可参考实验报告结构完成自己的课程作业。1. 基于YOLOv3的目标检测神经网络与数据集先认清“识别”和“检测”的距离每个学期都会有一批人拿着同一个标题来问基于YOLOv3的目标检测神经网络和数据集识别行人、自行车与机动车。这不是冷门课题而是计算机视觉课程作业的标配。很多人卡在第一层认知上——识别和检测是两码事。识别只告诉你“这是一个人”检测要在画面里把那个人的框画出来顺便标出类别。YOLOv3做的就是后一件事它把目标检测建模成一个卷积神经网络的回归问题一张图里有多少行人、多少自行车、多少机动车一次性全部输出。这篇文章就是给卡在课程作业的人写的从YOLOv3的输出逻辑讲到数据集准备、训练参数和常见坑。不需要复现论文也不需要顶配显卡一台能跑CUDA的普通机器足够。2. 理解YOLOv3的工作原理在跑数据之前先看懂输出逻辑2.1 一张图如何变成一堆框YOLOv3的输入输出拆解很多新手一上来就复制训练命令结果改了参数也不知道为什么。我的建议是先花半小时把输入输出关系搞清楚。YOLOv3会把任意尺寸的输入图resize到固定大小默认是416×416。经过Darknet-53骨干网络提取特征后输出三个尺度的特征图。浅层特征图负责小目标比如远处行人深层特征图负责大目标比如近处的卡车。三层各有自己的网格划分比如13×13、26×26、52×52。在每一个网格里YOLOv3预设了3个不同形状的锚框每个锚框需要回归5个量4个坐标和1个物体置信度再加上类别概率。你的任务是三类目标因此每个网格最终输出 3×(413)24 个值。这个24就是后面改cfg时filters参数的由来。理解这一点很重要因为很多人后面把classes改成3却忘了把filters从255改成24训练直接报错。从数学上讲YOLOv3把定位和分类放在同一个回归任务里。网格负责回答“物体在哪一片区域”锚框负责回答“物体的形状接近哪种预设”类别概率负责回答“这是人、自行车还是机动车”。课程作业里不需要你手写这些前向计算但需要你能解释清楚这个流程。否则答辩时老师问一句“你的输出张量长什么样”你只能站在那里干瞪眼。2.2 锚框、IOU与NMS训练和预测时真正起作用的三个机制锚框是YOLOv3最核心的设计之一。YOLOv3在COCO数据集上聚类出9组预设尺寸按照由小到大分配到三个尺度层。模型不是直接预测目标的绝对宽高而是预测相对锚框的偏移量。这样做的好处是降低学习难度小型数据集只要在预设形状附近微调即可而不是从零学所有可能的物体形状。这也是YOLOv3能在少量数据上收敛的重要原因。IOU交并比用于训练时的正负样本匹配。每一个标注框会和同网格里的锚框计算重叠程度重叠高的锚框被当作正样本负责预测这个目标重叠很低的锚框则作为负样本强迫网络学会“这里没有物体”。课程作业里不需要手动干预这个匹配过程但标注框画得是否贴合会直接影响IOU计算进而影响哪些锚框被选中。标注框比物体大一圈看起来无所谓实际会让模型学到一堆错误的偏移量。NMS非极大值抑制是预测时的后处理。模型在三个尺度上会生成大量候选框同一个物体可能被多个网格同时检测到。NMS把这些候选框按置信度排序保留最高分框抑制掉和它重叠度高的其他框。如果训练结束后检测结果里一个物体上叠着五六个框多半是NMS阈值设得不合适这个在后文排查章节会展开。2.3 课程作业要不要上YOLOv3和Faster R-CNN、YOLOv8对比后的选择选型这件事课程作业和工业项目逻辑完全不同。工业项目追求精度和部署效率课程作业追求的是“在一个学期内跑通、能解释、出问题搜得到答案”。Faster R-CNN在精度上确实不输但两阶段结构对显存和训练时间都不友好而且实现版本杂乱新手很容易在环境配置上耗掉一半时间。YOLOv8系列虽然更好用但它带来的配置项比YOLOv3多一个数量级很多参数在课程作业里根本用不到反而增加理解负担。YOLOv3有一个其他版本替代不了的优势Darknet官方实现只有一套流程网上能搜到的踩坑记录几乎覆盖了所有会出错的地方。你遇到“loss不降”或者“mAP为0”大概率已经有人把原因写清楚了。课程作业要求的是把目标检测的整体链路讲明白YOLOv3的结构恰好是“骨干网络加深、多尺度预测、锚框机制”三件套展示出来的知识量足够撑起一份像样的实验报告。所以我的结论是这个标题下YOLOv3就是当前性价比最高的选择不需要纠结。3. 准备行人/自行车/机动车数据集从标注到划分的完整流程3.1 标注工具选型与最少操作LabelImg、VOC/YOLO两种格式的取舍数据集是这个课程作业的大头。找现成的COCO或者UA-DETRAC虽然省事但类别定义可能和你的作业要求对不上而且交作业时老师常会问“数据是你自己标还是下载的”。自己标一批图更稳妥也更能讲清楚每一类的边界。常用工具是LabelImg安装很直接pip install labelimg labelimg启动后先设置图片目录和保存目录。我一般把工程结构建在项目根目录下不要散落到别处data/ images/ img_001.jpg img_002.jpg labels/ img_001.txt img_002.txtLabelImg默认保存成Pascal VOC格式的XML文件但Darknet训练需要的是YOLO格式的txt。界面上方有一个按钮可以切换成YOLO模式保存后会直接生成同名txt。我建议课程作业直接用YOLO模式省掉一次VOC转YOLO的脚本。因为转换脚本一旦写错类别编号错位或者坐标归一化搞反你后面所有训练结果都是错的排查起来比多花十分钟标注痛苦得多。YOLO格式的每一行是类别编号 x_center y_center width height后四个值都是归一化比例范围在0到1之间。例如一行2 0.5 0.4 0.3 0.25表示类别2机动车中心点在图片的(50%, 40%)处宽高分别占整张图的30%和25%。这个格式只要记住一次就够了后面看训练日志和检测结果都用得上。注意类别名称不要用中文写在标注文件里。Darknet读取的是obj.names按行号对应的类别名txt第一列只写数字不要写“行人”两个字否则训练会得到一堆无法解析的样本。3.2 三类目标的标注规范行人、自行车与机动车的边界标注规范比很多人想象得更重要。同一个物体在不同人手里标出来可能差很多比如骑自行车的人到底算行人还是自行车我的建议是如果人坐在自行车上、自行车占画面主体整框标注为bicycle不再额外单独标一个人如果人推着自行车走人和车可以分两个框也可以只标人取决于你的场景定义。课程作业一般拍的是校园道路骑车人占多数统一按“整辆自行车含骑手”标成bicycle最稳定。行人框要从头部顶到脚底左右贴近身体边缘不要从人头顶上方留一大片天空。机动车包含轿车、SUV、卡车和公交车按车体外轮廓标注后视镜这种凸出部件可以忽略。最容易翻车的是把电动车或摩托车当作自行车或者把两辆并排停靠的车标成一个框。前一种会让bicycle类别内部形状分裂后一种会让模型学到一个框同时包含两个目标NMS阶段很难处理。数据量方面课程作业我一般建议每类至少150个实例三类合计500个左右。如果数据集里全是单目标图模型泛化会很差。尽量拍一些一个画面同时出现两类甚至三类的照片让模型学到“人和自行车可以共处一个画面”的上下文而不是只学单目标模板。标注完成后随机抽20张图用LabelImg的“下一张”快速翻一遍检查有没有漏标和框错位这一步花十分钟能省掉后面好几轮无效训练。3.3 一键划分训练集与验证集带类别统计的Python脚本标注完成后Darknet需要两个文本文件train.txt和valid.txt每行一张训练图片的绝对路径。同时我们要确认三类目标的样本分布是不是均衡。用下面这个脚本可以一次完成划分和统计import os import random from collections import Counter random.seed(42) img_dir, label_dir data/images, data/labels imgs [f for f in os.listdir(img_dir) if f.endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) train_ratio 0.9 split int(len(imgs) * train_ratio) train_imgs, valid_imgs imgs[:split], imgs[split:] with open(data/train.txt, w) as ft, open(data/valid.txt, w) as fv: for name in train_imgs: ft.write(os.path.join(os.path.abspath(img_dir), name) \n) for name in valid_imgs: fv.write(os.path.join(os.path.abspath(img_dir), name) \n) cnt Counter() for name in train_imgs: label_path os.path.join(label_dir, os.path.splitext(name)[0] .txt) if not os.path.exists(label_path): continue with open(label_path) as f: for line in f: cnt[int(line.split()[0])] 1 print(train images:, len(train_imgs), valid images:, len(valid_imgs)) for cls, num in sorted(cnt.items()): print(class, cls, instances:, num)这个脚本的关键点是os.path.abspath它把相对路径转成绝对路径写进train.txt。Darknet在读取训练列表时如果遇到相对路径会以它自己的工作目录为基准拼接很容易出现找不到图片的错误。随机种子固定成42保证每次划分结果一致这样你训练两个版本对比时可以排除“验证集内容不同”这个干扰因素。参数方面train_ratio0.9适合几百张的小数据集留10%大概几十张做验证足够。类别编号按obj.names里的顺序从0开始0对应person1对应bicycle2对应car。如果统计出来某类只有其他类的一半最好是回去补拍不要试图靠后续数据增强硬撑。3.4 小数据集增强配置Darknet在cfg里自带的数据增强参数在准备数据阶段最后一件要做的事是给训练配置数据增强。Darknet自带了一套基于cfg的数据增强不需要额外写Python代码去离线生成图片。在yolov3.cfg文件的顶部模型定义里就写着flip1 jitter0.3 saturation1.5 exposure1.5 hue0.1flip1表示允许训练时水平翻转能让数据量近似翻倍。对行人和自行车这类左右对称的目标来说非常安全。jitter0.3是输入图片的随机缩放和长宽比扰动让模型对透视变形不那么敏感不过数值过大会导致车看起来比例失真。saturation和exposure控制饱和度和曝光随机变化目的是让模型适应不同光照条件。课程作业里我一般不会去加大这些参数保持官方默认值就够了。如果训练集里傍晚场景特别少与其把exposure调大不如直接补拍几十张傍晚的图进数据集。数据增强只能增加颜色和几何变化补偿不了场景分布上的缺失。这一点在后面遇到“换场景就漏检”时还会再提到。4. 把YOLOv3训练跑起来从Darknet编译到自定义参数调整4.1 为什么用Darknet而不是PyTorch复现课程作业最稳的编译流程YOLOv3最原始的官方实现就是Darknet框架。PyTorch复现版很多但版本差异会造成训练命令、权重格式、配置文件写法都不完全一致。课程作业最怕的就是教程对不上代码所以我一般建议直接用Darknet因为它只有一套标准流程遇到问题搜到的答案基本都能复用。编译的第一步是拉取代码和修改Makefilegit clone https://github.com/pjreddie/darknet.git cd darknet vim Makefile打开Makefile后把这几行的值从0改成1GPU1 CUDNN1 OPENCV1然后保存退出执行make编译成功的标志是darknet目录下出现一个可执行文件darknet。如果机器没有NVIDIA显卡或者CUDA没有装好可以把GPU保持为0用CPU模式编译。CPU模式也能完成训练但速度会慢上好几倍一个小数据集在GPU上跑一晚上的训练量CPU可能要跑两三天。所以只要机器有显卡尽量把GPU打开。参数说明OPENCV1不是必须的但建议打开。它在检测时会自动保存输出图方便你在测试阶段直接看效果。如果编译时报错找不到opencv的头文件先把OPENCV设回0训练不受影响只是检测后不会自动生成图片需要手动用代码保存结果。4.2 四个训练配置文件obj.names、obj.data、train.txt与cfg改法从这一步开始所有操作都围绕四个文件展开。第一个是data/obj.names内容就是类别名一行一个person bicycle car第二个是data/obj.data它告诉Darknet训练数据从哪来、验证数据从哪来、类别数是多少classes 3 train data/train.txt valid data/valid.txt names data/obj.names backup backup/第三个是上一步生成的train.txt里面是每张训练图片的绝对路径。第四个是cfg文件。Darknet官方自带的是cfg/yolov3.cfg我们复制一份改成自己的cp cfg/yolov3.cfg cfg/yolo-obj.cfg mkdir backup然后开始修改yolo-obj.cfg。这一步是整篇作业最容易出错的地方。需要改的参数集中在文件顶部和三个[yolo]层里。顶部要改的分辨率和批大小batch64 subdivisions16 width416 height416三个[yolo]层分布在文件不同位置搜索[yolo]能找到把每个yolo层里的classes从80改成3classes 3同时每个[yolo]层前面紧挨着一个卷积层它的filters要改成24公式是3 × (classes 5)即3 × (3 5)。很多人在这一步只改了classes忘了改filters启动训练后直接报尺寸不匹配的错误。最后是训练轮数相关参数。YOLOv3的官方建议是每类训练2000轮三类就是6000轮。在cfg文件搜索max_batchesmax_batches6000 policysteps steps4800,5400steps表示学习率在4800轮和5400轮时分别下降一次比例是max_batches的80%和90%。这样做的好处是前期大学习率让模型快速逼近后期小学习率精调边框位置。如果显卡不行或者数据集很小可以把max_batches降成4500steps对应改成3600,4050但不要低于3000否则模型还没收敛就结束了。4.3 开始训练与续训命令、日志解读和三个最关键的观察指标训练前先下载YOLOv3在ImageNet上预训练好的骨干权重wget https://pjreddie.com/media/files/darknet53.conv.74使用预训练权重能让模型不再从零学习特征这是课程作业数据集小却仍能收敛的关键。训练命令如下./darknet detector train data/obj.data cfg/yolo-obj.cfg darknet53.conv.74 -map -dont_show-map表示每训练若干轮后在验证集上计算mAP日志里会周期打印出来。-dont_show表示不弹训练窗避免远程连接时界面卡死。如果一切正常屏幕上会不断刷新一行行训练日志重点关注三个值avg loss、iou avg和map。avg loss从2到3开始是正常的随着训练推进慢慢往下降最终可能到0.5甚至更低。如果loss不是缓慢下降而是卡在2以上震荡多半是配置有问题去排查filters和预训练权重。iou avg反映预测框和标注框的重合度稳定在0.7以上算正常如果一直很低回去检查标注框是否太随意。map是最直观的指标数字越大越好但小数据集下波动很正常不要看到某一次validate掉了10个点就着急。如果训练中途断掉续训一定不要重新用darknet53.conv.74而是用backup目录里保存的权重./darknet detector train data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_last.weights -map -dont_showbackup目录里会有定期保存的多个weights文件last文件是最近一轮的完整状态用它继续训练即可。很多新手在这里翻车中断后重新用预训练权重跑损失回到初始值白白浪费之前所有训练时间。提示如果训练报CUDA out of memory把cfg顶部的batch改成32subdivisions改成64width和height改成416。显存不足大多数情况下不是显卡太差而是batch和分辨率叠一起顶爆了显存。5. 踩坑记录YOLOv3训练与检测中排查最多的问题5.1 训练阶段的三种典型故障loss不降、显存溢出、续训退化训练阶段遇到的第一个典型故障是loss卡在2左右不动mAP始终保持0。现象是训练日志每一行的avg loss都在2.3到2.6之间来回震荡跑了几百轮也不往下走验证时mAP要么不显示要么一直是0。原因一般出在两个地方一是改cfg时只改了classes没改对应的filters二是训练时直接从随机初始化开始没有加载darknet53.conv.74。YOLOv3在小型数据集上从头训练几乎不可能收敛只有预训练骨干能提供足够好的底层特征。解决方法是先搜索cfg里所有[yolo]层确认每个yolo层前面的filters都是24然后重新用预训练权重开始训练不要相信“已经跑了100轮再补救”这种侥幸心理。第二个常见故障是训练启动后很快报CUDA out of memory。现象是make成功命令一执行前几秒还有日志输出然后整个进程被显存溢出中断。原因通常是batch64、subdivisions16、width608这组参数叠加后的显存峰值超过了显卡容量。解决方法是把width和height从608调回416再改batch32、subdivisions64。注意subdivisions的作用是把一个大batch拆成多个小份依次forward调大它能降低单次占用的显存峰值但也意味着训练实际速度变慢所以不要为了省显存无限调大。第三个故障是中断后续训loss反而比中断前更高像是从头开始训练。现象是你明明加载了backup里的权重损失却从2.5到3重新起步。原因不是模型坏了而是“加载错文件”。Darknet在训练命令里接受权重路径参数如果路径写成了darknet53.conv.74这个预训练文件自然会把之前学到的知识全部丢掉。解决方法是使用后文这一条命令务必确认路径指向backup/yolo-obj_last.weights而不是预训练文件。养成这个习惯后中途断训就只剩“等它继续跑”这一件事了。5.2 测试阶段的三类翻车重复框、小目标漏检、换场景失效训练完成后进入测试阶段第一类翻车是同一辆车被标出四五个框。现象是置信度都在0.3以下NMS似乎没有生效。原因一般是测试时没有显式设置置信度阈值模型会把大量低置信度候选框全部保留下来另外标注框如果互相重叠严重多个锚框会同时学习到同一个目标NMS压不掉这些重叠框。解决方法是给检测命令加-thresh 0.25或-thresh 0.3把低于这个置信度的框过滤掉。如果仍然出现大量重复回到标注阶段检查有没有把一张图上紧挨着的两个目标画成了一个框。第二类翻车是最典型的机动车检测正常行人几乎漏检自行车也偶尔丢。现象是远距离行人完全检测不到近距离行人也只有一半概率被召回。原因是行人属于小目标在416×416的训练分辨率下远行人可能只有十来个像素特征经过多次下采样后已经消失。解决思路有两步第一步把cfg里的width和height改成608给浅层特征图更多像素信息第二步是补拍一些行人离镜头近的照片让模型看到足够大的行人特征。注意这两步都会让训练变慢但行人检测本来就是三类目标里最吃分辨率的。第三类翻车是训练集里全是白天的校园场景换到傍晚或者阴天测试后漏检率飙升。现象是同一组权重白天照片表现不错导入几张傍晚照片后框变少很多。这其实不算模型坏了而是训练集分布覆盖不够。数据增强里的saturation和exposure虽然能模拟部分光照变化但无法弥补场景背景、色温、阴影分布上的差异。解决方法是把实际测试会遇到的天气和时间段各拍几十张补进数据集重新微调。课程作业里最经济的做法是先用现有模型预测这些新照片选出漏检部分再标注这些漏检图补训而不是全部重新标一遍。6. 验证模型与提升精度的技巧mAP、阈值与简单批量检测6.1 用mAP验证模型数字比肉眼更可信训练结束时backup目录里会有一批weights文件其中yolo-obj_final.weights是最后一轮的模型。用它跑一遍验证集就能得到量化指标./darknet detector map data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights命令结束后会打印mAP0.50、mAP0.75等数值。课程作业看mAP0.50就够这个值反映“框的大致位置对不对”mAP0.75如果明显偏低说明预测框和标注框的贴合度不够问题多半在标注阶段框画得不够紧而不是模型需要继续训。6.2 一个对自己友好的批量检测习惯单张图检测可以用下面的命令-ext_output会把目标的坐标和置信度逐行列出来mkdir -p predictions for img in test_images/*.jpg; do name$(basename $img) ./darknet detector test data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights $img -thresh 0.25 -ext_output 2/dev/null | tee predictions/$name.txt done这个循环会把每张测试图的检测日志存成一份txt方便你统计每一类检测到了多少个目标也方便交作业时附一份机器可读的检测结果。我自己做类似作业时会先把旧权重单独备份到一个固定目录每次调整数据集或参数后都保留一个版本再用上面这个批量命令过一遍固定测试图。效果好的版本留下翻车的版本也能回头排查是哪一次改动导致的。这套流程走下来课程作业就不再是“跑通一个模型”那么简单了你能说清楚mAP是多少、哪一类拖了后腿、标注规范里哪个约定影响最大。这些细节在答辩时比代码本身更有说服力。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑