ARTICLE DETAIL

资讯详情

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

YOLOv5目标检测:从网络架构到嵌入式部署的完整指南

YOLOv5目标检测:从网络架构到嵌入式部署的完整指南 1. 项目概述为什么YOLOv5依然是目标检测的“硬通货”如果你这两年稍微关注过计算机视觉尤其是目标检测领域那“YOLOv5”这个名字你一定不陌生。它可能不是你听说过的第一个YOLO版本但绝对是近年来在工业界和学术界被讨论、应用、魔改得最多的版本之一。从最初的争议到如今的广泛认可YOLOv5已经从一个“非官方”的PyTorch实现演变成了一个集成了数据增强、模型训练、模型导出、性能评估的完整目标检测工具箱。很多人第一次接触目标检测项目就是从下载YOLOv5的代码仓库、跑通官方的COCO数据集预训练模型开始的。那么YOLOv5到底强在哪里为什么在YOLOv7、v8甚至v9、v10相继推出的今天依然有大量开发者尤其是在嵌入式平台如你搜索词里的RV1106、RK3568上部署时首选或者绕不开YOLOv5核心原因在于它的工程化友好度和生态成熟度。它不仅仅是一个算法更是一套标准化的流程。从准备数据集的YOLO格式标注到使用超参数文件进行训练再到导出为ONNX、TensorRT等格式进行部署YOLOv5提供了一条清晰、可复现的路径。这对于需要快速验证想法、将算法落地到实际产品的工程师来说价值巨大。本文将带你深入YOLOv5网络的内部不仅会拆解其Backbone、Neck、Head的结构更会结合大量实际部署包括你关心的RV1106、RK3568等边缘设备和训练调参的经验告诉你每个模块设计的意图、训练中常见的“坑”比如训练map总是0以及如何根据你的需求比如训练单通道图像进行定制化修改。无论你是刚入门的新手还是正在为模型部署发愁的工程师都能从中找到可直接操作的干货。2. YOLOv5网络架构深度拆解YOLOv5的整体架构延续了YOLO系列的一贯思想“You Only Look Once”即单阶段检测。其网络可以清晰地分为三个部分Backbone骨干网络、Neck颈部和Head检测头。这种划分使得网络功能模块化便于理解和修改。2.1 BackboneCSPDarknet与Focus模块的演进YOLOv5的Backbone名为CSPDarknet它是YOLOv4中CSPNet与Darknet53思想的结合与优化。其核心目标是高效地提取图像的多尺度特征。CSP结构Cross Stage Partial Network是这里的精髓。简单来说它将特征图在通道维度上分成两部分一部分经过一个密集的卷积块通常是多个卷积层另一部分则直接通过一个捷径shortcut连接。最后再将两部分合并。这样做的最大好处是在保持甚至提升精度的同时大幅减少计算量和参数量并且减轻了梯度消失问题让网络更容易训练。你可以把它想象成一条主干道分出了一条辅路大部分车流走复杂的辅路去处理“难题”小部分车流直接走主干道保持“信息通畅”最后在出口汇合既高效又全面。在YOLOv5 v6.0版本之前网络入口使用了一个颇具争议的Focus模块。这个模块的操作很巧妙它将输入图像每个2x2的邻域像素取出来拼接成一个4倍通道数的特征图。例如一张640x640x3的图片经过Focus模块后会变成320x320x12的特征图然后再通过一个卷积层调整通道数。这相当于一种无参数的“空间到深度”的变换目的是在不丢失信息的情况下进行下采样并增加通道数为后续卷积提供更丰富的特征表示。不过由于某些硬件或推理框架对这种特殊的切片操作支持不佳在v6.0及之后的版本中Focus模块被一个标准的6x6卷积层stride2所替代实现了相同的下采样效果但兼容性更好。如果你在较老的代码或教程中看到Focus需要知道这个变化。Backbone中大量使用了C3模块在v5.0版本中是BottleneckCSP模块。一个C3模块由多个标准的卷积层和Bottleneck残差结构构成并应用了前文提到的CSP思想。它是构建深度网络的基础块负责在多个尺度上深化特征提取。2.2 NeckFPNPAN的强强联合Neck部分的任务是融合Backbone提取的不同层次的特征。低层特征分辨率高包含丰富的细节信息如边缘、纹理有利于检测小物体高层特征分辨率低但语义信息强有利于识别物体的类别和大致位置。YOLOv5的Neck采用了FPNFeature Pyramid Network与PANPath Aggregation Network结合的结构。FPN是自上而下的融合它将深层的高语义特征通过上采样与浅层的细节特征进行逐元素相加add或拼接concat从而将语义信息“传递”到浅层提升浅层特征的语义表达能力。PAN是自下而上的融合在FPN的基础上PAN再将融合后的浅层特征通过下采样与深层特征进行二次融合。这样深层特征也能获得更精确的定位信息。这种双向自上而下自下而上的特征金字塔结构使得网络在各个尺度上都能同时拥有强语义和精定位信息显著提升了模型对不同大小目标的检测能力尤其是改善了小目标的检测效果。在代码中这体现为一系列包含上采样、下采样和Concat操作的结构。2.3 Head解耦头与Anchor-Based机制YOLOv5的Head负责输出最终的检测结果。在v5.0-v5.3版本中它采用耦合头Coupled Head即同一个卷积层同时预测类别概率和边界框坐标。而从v6.0版本开始YOLOv5借鉴了YOLOX等工作的思想引入了解耦头Decoupled Head。解耦头将分类任务和回归任务分离开使用两个独立的并行分支来分别处理。这样做的好处是让两个任务互不干扰实践表明解耦头通常能带来精度的小幅提升并且更便于后续的模型部署和优化。Head的预测是基于Anchor锚框的。YOLOv5继承了YOLOv2以来的Anchor机制但有一个重要的改进自适应锚框计算。在训练开始前YOLOv5会对你提供的训练集标注框进行K-means聚类自动计算出9组针对3种不同尺度特征图最匹配你数据集的Anchor尺寸。你不再需要手动去COCO数据集上找一组Anchor然后硬套在自己的数据上这大大提升了模型在你特定数据集上的收敛速度和最终精度。运行训练脚本时看到的“AutoAnchor: Running kmeans for 9 anchors on 2135 points...”就是这个过程。Head最终会在三个不同尺度的特征图上进行预测例如80x80, 40x40, 20x20对应输入640x640分别负责检测小、中、大物体。每个预测位置会对应3个Anchor每个Anchor会输出一个预测结果向量通常包含边界框中心点偏移量tx, ty、宽高缩放量tw, th、该框包含物体的置信度objectness score、以及各个类别的条件概率。3. 从零开始YOLOv5环境配置与数据准备实战理论清晰之后动手实践才是关键。很多人在第一步——环境安装和数据准备上就会遇到各种问题导致“从入门到放弃”。这里我将结合最常见的坑给你一个清晰的路线图。3.1 安装步骤详解与避坑指南官方推荐使用Python3.8和PyTorch1.7。我的建议是为了稳定性尽量使用较新的、但非最新的版本组合例如Python 3.8/3.9 PyTorch 1.12/1.13。# 1. 克隆仓库建议使用国内镜像或指定分支master分支可能包含最新但不稳定的改动 git clone https://github.com/ultralytics/yolov5.git cd yolov5 # 2. 创建并激活虚拟环境强烈推荐避免包冲突 conda create -n yolov5 python3.9 conda activate yolov5 # 3. 安装PyTorch核心步骤最容易出错 # 先去PyTorch官网https://pytorch.org/get-started/locally/根据你的CUDA版本选择命令。 # 如果你没有NVIDIA GPU或CUDA就选择CPU版本。 # 例如对于CUDA 11.6 pip install torch1.12.1cu116 torchvision0.13.1cu116 torchaudio0.12.1 --extra-index-url https://download.pytorch.org/whl/cu116 # 4. 安装YOLOv5依赖 pip install -r requirements.txt注意requirements.txt里的opencv-python在某些系统上可能安装失败可以尝试pip install opencv-python-headless这是一个不包含GUI功能的轻量版本对于服务器部署更友好。另外如果遇到PyTorch安装慢或失败可以尝试使用清华、阿里云等镜像源。安装完成后强烈建议运行一下官方提供的快速验证脚本确保一切正常python detect.py --weights yolov5s.pt --source data/images/这个命令会下载最小的预训练模型yolov5s.pt并对data/images文件夹下的示例图片进行推理。如果能看到输出图片并在控制台看到检测结果说明安装成功。3.2 训练自己的数据集格式、脚本与技巧YOLOv5要求的数据标注格式是YOLO格式的.txt文件。每个图像对应一个同名的txt文件内容如下class_id x_center y_center width height所有坐标值都是归一化后的即相对于图像宽度和高度的比例范围在0到1之间。假设一张图片img001.jpg的尺寸是 640x480上面有一个标注框其左上角坐标为 (100, 120)宽高为 (200, 150)类别为“狗”假设class_id为 0。那么计算过程如下x_center (100 200/2) / 640 0.234375y_center (120 150/2) / 480 0.3125width 200 / 640 0.3125height 150 / 480 0.3125所以img001.txt的内容就是一行0 0.234375 0.3125 0.3125 0.3125数据集的目录结构应如下所示datasets/ ├── your_custom_dataset/ │ ├── images/ │ │ ├── train/ │ │ │ ├── img001.jpg │ │ │ └── ... │ │ └── val/ │ │ ├── img100.jpg │ │ └── ... │ └── labels/ │ ├── train/ │ │ ├── img001.txt │ │ └── ... │ └── val/ │ ├── img100.txt │ └── ...接下来你需要创建一个数据集配置文件例如your_dataset.yaml放在yolov5/data/目录下# 数据集路径可以是绝对路径也可以是相对于yolov5根目录的相对路径 path: ../datasets/your_custom_dataset # 训练集和验证集的图像目录相对于上面的path train: images/train val: images/val # 类别数量 nc: 2 # 例如猫和狗就是2类 # 类别名称列表 names: [cat, dog]现在你可以开始训练了。基础训练命令如下python train.py --img 640 --batch 16 --epochs 100 --data data/your_dataset.yaml --weights yolov5s.pt--img 640: 输入图像尺寸默认是正方形。你可以根据你的数据集和目标大小调整如--img 416。--batch 16: 批次大小。这个值受你的GPU显存限制。如果出现“CUDA out of memory”错误就减小--batch或者尝试使用--batch-size更细粒度控制。--epochs 100: 训练轮数。--data: 指向你刚创建的数据集配置文件。--weights yolov5s.pt: 使用预训练权重进行迁移学习这能极大加速收敛并提升最终精度。yolov5s.pt是最小的模型还有yolov5m.pt,yolov5l.pt,yolov5x.pt模型容量和精度依次增加但速度变慢。4. 超参数解析与调优实战告别“map总是0”训练启动后最让人沮丧的莫过于看着损失曲线波动但最后的mAP平均精度始终是0。这往往是数据、参数或训练过程出了问题。我们来逐一排查。4.1 核心超参数详解YOLOv5的超参数定义在data/hyps/hyp.scratch-*.yaml从头训练和data/hyps/hyp.finetune.yaml微调等文件中。理解它们对调优至关重要。学习率lr0, lrf:lr0: 初始学习率。这是最重要的参数之一。太大容易震荡不收敛太小则收敛慢。对于微调通常从0.01或0.001开始尝试对于小数据集甚至可以从0.0001开始。lrf: 最终学习率因子。最终学习率 lr0 * lrf。它定义了学习率衰减的程度。lrf0.01意味着最终学习率是初始的1%。动量momentum与权重衰减weight_decay:momentum: 通常设为0.937帮助优化器加速收敛并冲出局部最小值一般不需改动。weight_decay: 正则化参数防止过拟合。默认0.0005。如果你的数据集很小可以适当增大如0.001如果数据集很大可以减小。数据增强相关:hsv_h,hsv_s,hsv_v: HSV颜色空间增强的幅度。随机调整图像的色调、饱和度和明度增加数据多样性。degrees,translate,scale,shear: 几何增强参数分别是旋转角度、平移比例、缩放比例和剪切比例。这些对于提升模型鲁棒性非常有效但对于一些方向敏感的场景如文字检测需要调小degrees和shear。mosaic: 马赛克增强开关。默认开启mosaic1.0。它会将四张图片拼成一张进行训练极大地丰富了背景和小物体上下文。如果你的数据集目标很大或者拼接后会导致目标变形严重可以考虑在训练后期关闭通过--cos-lr配合close_mosaic10参数表示最后10个epoch关闭mosaic。4.2 “训练map总是0”的排查清单当你的mAP为0时请按以下顺序检查检查数据标注这是最常见的原因。用可视化脚本检查你的标注框是否画对了。YOLOv5提供了utils/plots.py中的函数或者你可以直接运行python train.py --data your_dataset.yaml --weights yolov5s.pt --epochs 1 --batch-size 1训练一个epoch在runs/train/exp目录下会生成一个train_batch*.jpg文件里面显示了数据增强后、带标注框的图片。仔细看框的位置和类别对吗常见错误有坐标未归一化、类别ID超出范围比如你只有2类但标注了class_id2、标注文件与图片不对应等。检查数据集配置文件.yaml确保path、train、val路径正确无误。一个快速验证的方法是在Python中加载这个yaml文件并打印出找到的图片数量。路径错误会导致模型在“空数据”上训练。检查类别不平衡如果你的某个类别样本极少模型可能很难学会。查看labels文件夹下所有txt文件统计每个类别的出现次数。如果严重不平衡可以考虑使用类别权重class weights。YOLOv5默认是开启类别权重的通过--cls_pw参数默认值可能因版本而异它会根据类别频率自动调整损失函数中的分类权重。你也可以在训练命令中显式设置--cls_pw 1.0来尝试。降低学习率这是解决“损失下降但mAP为0”的常用手段。预训练模型是在大数据集上训练的其权重已经在一个较好的位置。用太大的学习率微调可能会“冲垮”这些已有知识。尝试将lr0从默认的0.01降到0.001甚至0.0001。关闭复杂的数据增强特别是mosaic和mixup。对于非常规尺寸目标或小数据集过于激进的数据增强可能会让模型“学懵”。在hyp.finetune.yaml中将mosaic设为0mixup设为0先让模型在“正常”的图片上学会基础特征。检查Anchor是否匹配虽然YOLOv5有自动计算Anchor的功能但如果你的目标尺寸非常特殊比如所有目标都是极细长的条状自动计算的Anchor可能仍然不理想。训练日志里会打印出计算出的Anchor和最佳可能召回率Best Possible Recall, BPR。如果BPR低于0.98说明Anchor匹配度不高。你可以考虑使用--noautoanchor参数禁用自动Anchor使用默认Anchor训练看看。自己运行K-means聚类算法生成更适合你数据集的Anchor尺寸然后修改模型配置文件.yaml中的anchors参数。从更小的模型开始如果使用yolov5x.pt不收敛可以尝试用yolov5s.pt。小模型参数少更容易优化虽然最终精度可能低点但至少能验证流程是否正确。5. 特殊场景与高级技巧单通道图像与嵌入式部署5.1 训练单通道灰度图像YOLOv5默认输入是3通道RGB图像。如果你的数据是灰度图直接输入会导致维度不匹配。你需要修改两个地方修改模型配置文件以yolov5s.yaml为例找到第一层卷积的定义# YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 ... ]初始的Conv层对应替换掉Focus的那个6x6卷积的输入通道数由args列表的第一个数字64前面的默认值3决定。你需要修改网络深度nc和宽度depth_multiple,width_multiple参数之后增加一个channels参数或者直接修改源码。更简单的方法是在数据加载时将灰度图复制成3通道。这不会损失信息因为卷积核会学习到三个通道的权重是相同的。这是最常用且省事的做法。在dataset.py的LoadImagesAndLabels类中图像读取后通常是cv2.imread如果是单通道可以img cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)。或者在你准备数据集时就提前将灰度图转换成3通道的“伪RGB”图。修改预训练权重加载逻辑可选如果你使用RGB预训练模型如yolov5s.pt来微调灰度任务第一层卷积核的维度不匹配预训练是3通道输入你现在是1通道。常见的处理方式是随机初始化第一层卷积核或者将预训练权重中3通道的均值作为新1通道的权重。但更推荐上述“灰度转伪RGB”的方法因为它无需修改模型结构能完全利用预训练知识。5.2 在嵌入式平台部署RK3568与RV1106实战要点将YOLOv5部署到RK3568瑞芯微或RV1106瑞星微这类边缘计算芯片上是当前的热门需求。核心流程是PyTorch训练 - ONNX导出 - 芯片厂商工具链转换如RKNN、RV工具链 - 板上推理。步骤一导出ONNX模型首先你需要一个训练好的.pt模型文件。使用YOLOv5自带的导出脚本python export.py --weights runs/train/exp/weights/best.pt --include onnx --img 640 --batch 1 --dynamic--include onnx: 指定导出为ONNX格式。--img 640: 指定输入尺寸必须与训练和部署时一致。--batch 1: 指定批次为1很多嵌入式推理框架只支持batch1。--dynamic: 导出动态尺寸的ONNX模型输入尺寸可以在一定范围内变化。如果确定是固定尺寸如640x640可以不加此参数性能可能更优。步骤二使用厂商工具链转换这是最易出错的环节因为不同芯片的NPU神经网络处理单元指令集和内存结构不同。对于RK3568使用RKNN Toolkit:安装RKNN Toolkit通常由厂商提供Python包。编写转换脚本加载ONNX模型进行量化INT8量化能极大提升速度并降低功耗但会轻微损失精度生成.rknn模型文件。关键点注意预处理和后处理。YOLOv5的输入需要归一化/255.0输出需要经过非极大值抑制NMS。你需要确认这个预处理是在模型内部即导出ONNX时已包含还是需要在推理代码中手动完成。通常为了部署简便我们希望在模型内部完成预处理减均值、除标准差。可以在export.py时通过--simplify和--opset版本尝试或者使用RKNN Toolkit提供的预处理参数配置。对于RV1106: 流程类似但使用的是RV1106配套的AI工具链如Rock-X SDK或厂商自定义的工具。需要特别注意模型简化RV1106算力和内存更有限。可能需要选择更小的模型如yolov5n或自定义的剪枝版yolov5s。输入尺寸可能不支持太大的输入如640x640需要尝试更小的尺寸如320x320, 416x416这需要重新训练或使用动态尺寸导出。算子支持确认工具链是否支持ONNX模型中的所有算子如Resize上采样、Slice等。不支持的需要在导出前修改网络结构或用支持的操作替换。部署通用技巧精度验证在PC上用ONNX Runtime加载导出的ONNX模型对同一张图片进行推理对比结果与PyTorch原始模型的结果是否一致允许微小误差。这是确保导出过程无误的关键一步。性能分析在板端部署后使用工具链提供的性能分析功能查看每一层的耗时。瓶颈可能出现在某些特定算子如大尺寸的卷积或数据搬运上。针对性地优化如调整网络结构、使用更高效的算子实现。内存优化嵌入式设备内存紧张。确保你的模型在量化后中间激活层的内存占用不会超出限制。有时需要降低输入分辨率或减少网络宽度/深度。6. 模型训练监控、评估与结果分析训练不是一蹴而就的你需要像看仪表盘一样监控整个过程并在结束后客观评估模型好坏。6.1 训练过程监控启动训练后YOLOv5会在终端打印日志并在runs/train/exp每次训练会新建一个如exp2,exp3的目录文件夹下生成一系列可视化文件最重要的有损失曲线loss.png包含box_loss,obj_loss,cls_loss。理想情况下它们应该平滑下降并最终趋于平缓。如果box_loss或cls_loss剧烈震荡或上升可能是学习率太大或数据有问题。如果obj_loss物体置信度损失一直很高可能是Anchor匹配度差或背景中有很多类似目标的干扰。评估指标曲线metrics.png主要看precision精确率和recall召回率曲线。我们希望两者都高。如果precision高但recall低说明模型很保守只检测它非常确信的目标漏检多反之则误检多。训练后期两者应达到一个平衡。混淆矩阵confusion_matrix.png查看类别间的误检情况。理想情况下对角线正确分类应该最亮。如果某些类别容易被混淆例如“猫”和“狗”说明这些类别在特征上比较接近可能需要更多数据或数据增强。6.2 模型评估与mAP解读训练结束后模型的最佳权重默认是best.pt基于mAP0.5:0.95指标和最后权重last.pt会保存在weights文件夹下。使用以下命令在验证集上评估模型python val.py --weights runs/train/exp/weights/best.pt --data data/your_dataset.yaml --img 640 --task val关键的输出指标是mAPmean Average PrecisionmAP0.5IoU交并比阈值为0.5时的平均精度。这是最常用的指标衡量模型在宽松阈值下的检测能力。mAP0.5:0.95IoU阈值从0.5到0.95步长0.05共10个阈值下mAP的平均值。这个指标更严格衡量模型定位的精确度。一份好的评估报告还会给出每个类别的APAverage Precision帮助你发现哪些类别是模型的短板。6.3 模型测试与推理优化得到满意的模型后就可以用它来预测新图片或视频了python detect.py --weights runs/train/exp/weights/best.pt --source your_image_or_video_path --conf 0.25 --iou 0.45--conf: 置信度阈值。高于此值的检测框才会被保留。根据你的应用场景调整需要高召回率宁可错杀不可放过就调低如0.1需要高精确率确保检测到的都是对的就调高如0.5。--iou: NMS用的IoU阈值。用于合并重叠的检测框。值越小合并越严格留下的框越少。对于部署你可能会关心推理速度FPS。使用--half参数可以启用FP16半精度推理在支持Tensor Core的GPU上能显著提升速度且精度损失很小。python detect.py --weights best.pt --source data/images --half7. 进阶话题与未来展望掌握了以上内容你已经可以解决YOLOv5项目中90%的问题。如果你想更进一步这里有一些方向模型轻量化与剪枝对于嵌入式部署模型大小和速度至关重要。可以探索知识蒸馏用一个大模型教师指导一个小模型学生训练让小模型获得接近大模型的性能。通道剪枝识别并剪掉网络中不重要的通道减少计算量和参数。有一些开源工具如torch-pruning可以尝试。使用更高效的网络结构将YOLOv5的Backbone替换为MobileNetV3、ShuffleNetV2等轻量级网络但这通常需要重新设计Neck和Head的通道数来匹配。自定义数据增强YOLOv5支持丰富的数据增强你还可以在dataset.py中自定义增强策略。例如对于遮挡严重的场景可以增加随机擦除Random Erasing对于光照变化的场景可以增加更复杂的颜色抖动。损失函数改进YOLOv5默认使用CIoU Loss。你可以尝试替换为更先进的损失函数如Alpha-IoU、SIoU等这些可能在你的特定数据集上有更好的边界框回归效果。这需要修改utils/loss.py文件。关注社区与后续版本Ultralytics团队一直在更新YOLOv5并推出了YOLOv8。YOLOv8在易用性、速度和精度上又有提升并且原生支持了实例分割、姿态估计等任务。虽然YOLOv5的生态和稳定性目前仍是巨大优势但了解v8的新特性如无Anchor机制、更简洁的架构对于技术选型很有帮助。不过对于许多已部署的项目和边缘设备由于其工具链和生态的成熟度YOLOv5在未来一段时间内仍将是主流选择之一。从我个人的多次部署经验来看YOLOv5的成功不在于它是最先进的算法而在于它提供了一个极其稳健、可复现、文档齐全的工程框架。它降低了目标检测的应用门槛让开发者能更专注于解决业务问题本身。当你吃透了它的网络结构、数据流和配置哲学再去学习或迁移到其他任何视觉模型都会感到事半功倍。
返回列表