为什么五年后还有人在用 YOLOv5?拆解这套工业检测的“老兵“架构

为什么五年后还有人在用 YOLOv5?拆解这套工业检测的“老兵“架构 Ai算法爱好者学习如果你去一家做视觉检测的公司仓库里逛一圈问他们产线上跑的是什么模型十有八九会听到一个名字YOLOv5。这玩意2020年出来到现在五六年了。后面v8、v10、11迭代了好几轮各种新结构、新损失函数层出不穷但不少工控机里大概率还是Ultralytics那套train.py在稳稳地跑。不是大家不想追新而是这套东西实在太皮实——改个yaml配置对好数据路径一行命令下去第二天就能拿到一个能用的权重。对于要交付的项目来说这种确定性比论文里高几个点的mAP更值钱。YOLOv5的真正价值可能不在于它提出了什么惊天动地的理论突破而在于它第一次把目标检测从实验室调参变成了一件工程上可落地的事。它用纯PyTorch重写把训练、验证、导出、推理串成了一条完整的流水线让写Python的工程师不用再对着C的Darknet Makefile发愁。这篇文章我想把YOLOv5的骨架拆开来看。从输入端的Mosaic增强到Backbone的CSPDarknet再到Neck的FPNPAN最后到Head的三个检测层把这些模块为什么这样设计怎么配合尽量讲清楚。官方文档https://docs.ultralytics.com/yolov5/官方实现仓库https://github.com/ultralytics/yolov5一、基础知识点1.1 网络架构YOLOv5采用了一种模块化的网络架构主要由三个部分组成Backbone主干网络作为特征提取的核心通常是在大规模数据集如ImageNet或COCO上预训练的卷积神经网络如ResNet-50或Darknet53。Neck颈部网络介于Backbone和Head之间用于整合不同层级的特征图以提升检测性能。Head头部网络位于模型的末端负责预测目标的类别和边界框位置目标检测模型的工作流程可概括为输入数据通过主干网络提取特征然后颈部网络进一步提炼特征最终由头部网络完成目标的类别和位置预测输出检测结果。 YOLOv5与Yolov3及Yolov4进行比较。主要的不同点1输入端 Mosaic数据增强v4中使用到了、自适应锚框计算、自适应图片缩放2骨干网络Backbone Focus结构CSP结构3颈部网络Neck FPNPAN结构4头部网络Head GIOU_Loss1.2 自定义锚框在 yolov3、v4 中是采用 kmean 和遗传算法对自定义数据集进行分析获得合适自定义数据集中对象边界框预测的预设锚点框。在 yolov5 中锚点框是基于训练数据自动学习的。Auto Learning Bounding Box Anchors具体代码实现可以参考 general.py 文件中的 check_anchors 函数。1.3 激活函数在 yolov5 中中间 / 隐藏层使用了 Leaky ReLU 激活函数最后的检测层使用了 Sigmoid 激活函数1.4 优化器在 yolov5 中提供了两个优化函数 Adam 和 SGD并预设了与之匹配的训练超参数默认是 SGD。1.5 损失函数yolo 系列的损失计算是基于 objectness score class probabilitybounding box regression score。yolov5 中使用 GIoU Loss 作为 bounding box 的损失yolov5 中使用 二进制交叉熵(BCE) 和 Logits 损失函数 计算类概率和目标得分的损失同时我们也可以使用 fl_gamma 参数来激活 focal loss 计算损失函数。二、创新点2.0 Mosaic数据增强Yolov5的输入端采用了和Yolov4一样的Mosaic数据增强的方式。随机缩放、随机裁剪、随机排布的方式进行拼接对于小目标的检测效果很不错。Yolov4中使用的Mosaic是参考2019年底提出的CutMix数据增强的方式但CutMix只使用了两张图片进行拼接而Mosaic数据增强则采用了4张图片随机缩放、随机裁剪、随机排布的方式进行拼接。Mosaic数据增强的主要步骤随机选择四张不同的图像作为输入分别对四张图片进行翻转对原始图片进行左右的翻转、缩放对原始图片进行大小的缩放、色域变化对原始图片的明亮度、饱和度、色调进行改变等操作。操作完成之后然后再将原始图片按照 第一张图片摆放在左上第二张图片摆放在左下第三张图片摆放在右下第四张图片摆放在右上四个方向位置摆好。根据每张图片的尺寸变换方式将映射关系对应到图片标签上。依据指定的横纵坐标对大图进行拼接。处理超过边界的检测框坐标。主要有几个优点增加数据多样性随机选取四张图像进行组合组合得到图像个数比原图个数要多。增强模型鲁棒性混合四张具有不同语义信息的图片可以让模型检测超出常规语境的目标。加强批归一化层Batch Normalization的效果。当模型设置 BN 操作后训练时会尽可能增大批样本总量BatchSize因为 BN 原理为计算每一个特征层的均值和方差如果批样本总量越大那么 BN 计算的均值和方差就越接近于整个数据集的均值和方差效果越好。Mosaic 数据增强算法有利于提升小目标检测性能。Mosaic 数据增强图像由四张原始图像拼接而成这样每张图像会有更大概率包含小目标。2.1 自适应锚框计算在YOLOv5中每次训练开始之前它都会根据你的数据集来自适应计算anchor锚框在 yolo v3 和 yolo v4 中是采用 kmean 和遗传学习算法对自定义数据集进行分析获得适合自定义数据集中对象边界框预测的预设锚定框。在 yolo v5 中锚定框是基于训练数据自动学习的。若觉得计算的锚框效果不佳可以将--noautoanchor参数设置True default值即可关闭。parser.add_argument(--noautoanchor, defaultTrue, actionstore_true, help 不自动调整anchor默认为False)在 YOLOv5 的配置文件model/*.yaml 中已经预设了一些针对 COCO数据集在 640 × 640 640×640 640×640图像大小下锚定框的尺寸anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 anchors参数共有三行每行6个数值且每一行代表应用不同的特征图 第一行是在最大的特征图上的锚框 80 x 80 80x80 80x80代表浅层的特征图P3包含较多的低层级信息适合用于检测小目标所以这一特征图所用的anchor尺度较小 第二行是在中间的特征图上的锚框 40 x 40 40x40 40x40特征图上就用介于这两个尺度之间的anchor用来检测中等大小的目标 第三行是在最小的特征图上的锚框 20 x 20 20x20 20x20代表深层的特征图包含更多高层级的信息如轮廓、结构等信息适合用于大目标的检测所以这一特征图所用的anchor尺度较大。自定义锚框锚框核查函数 /utils/autoanchor.py 文件中 YOLOv5 在开始训练前会计算数据集标注信息针对默认锚定框的最佳召回率如果最佳召回率大于或等于0.98则不需要重新计算锚定框使用默认锚框如果最佳召回率小于0.98则需要重新计算符合此数据集的锚框。def metric(k): # compute metric r wh[:, None] / k[None] x torch.min(r, 1 / r).min(2)[0] # ratio metric best x.max(1)[0] # best_x aat (x 1 / thr).float().sum(1).mean() # anchors above threshold bpr (best 1 / thr).float().mean() # best possible recall return bpr, aat stride m.stride.to(m.anchors.device).view(-1, 1, 1) # model strides anchors m.anchors.clone() * stride # current anchors bpr, aat metric(anchors.cpu().view(-1, 2))其中bprbest possible recall参数就是判断是否需要重新计算锚定框的依据是否小于 0.98 重新计算符合此数据集标注框的锚定框是利用 k均值聚类算法k-means clustering和遗传算法genetic algorithm实现的。自定义锚框计算过程读取训练集中所有图片的w、h以及检测框的w、h将读取的坐标修正为绝对坐标使用Kmeans算法对训练集中所有的检测框进行聚类得到k个anchors通过遗传算法对得到的anchors进行变异如果变异后效果好将其保留否则跳过将最终得到的最优anchors按照面积返回import utils.autoanchor as autoAC # 对数据集重新计算 anchors new_anchors autoAC.kmean_anchors(./data/mydata.yaml, 9, 640, 5.0, 1000, True) print(new_anchors)2.2 自适应图片缩放utils/datasets.py中def letterbox(img, new_shape(640, 640), color(114, 114, 114), autoTrue, scaleFillFalse, scaleupTrue): # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 shape img.shape[:2] # current shape [height, width] if isinstance(new_shape, int): new_shape (new_shape, new_shape) # Scale ratio (new / old) r min(new_shape[0] / shape[0], new_shape[1] / shape[1]) if not scaleup: # only scale down, do not scale up (for better test mAP) r min(r, 1.0) # Compute padding ratio r, r # width, height ratios new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding if auto: # minimum rectangle dw, dh np.mod(dw, 64), np.mod(dh, 64) # wh padding elif scaleFill: # stretch dw, dh 0.0, 0.0 new_unpad (new_shape[1], new_shape[0]) ratio new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios dw / 2 # divide padding into 2 sides dh / 2 if shape[::-1] ! new_unpad: # resize img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) # add border return img, ratio, (dw, dh)在常用的目标检测 算法中不同的图片长宽都不相同因此常用的方式是将原始图片统一缩放到一个标准尺寸再送入检测网络中。 第一步计算缩放比例原始缩放尺寸是416*416都除以原始图像的尺寸后可以得到0.52和0.69两个缩放系数选择小的缩放系数。第二步计算缩放后的尺寸原始图片的长宽都乘以最小的缩放系数0.52宽变成了416而高变成了312。第三步计算黑边填充数值将416-312104得到原本需要填充的高度。再采用numpy中np.mod取余数的方式得到8个像素再除以2即得到图片高度两端需要填充的数值。此外需要注意的是a.这里大白填充的是黑色即000而Yolov5中填充的是灰色即114,114,114都是一样的效果。b.训练时没有采用缩减黑边的方式还是采用传统填充的方式即缩放到416*416大小。只是在测试使用模型推理时才采用缩减黑边的方式提高目标检测推理的速度。c.为什么np.mod函数的后面用32因为Yolov5的网络经过5次下采样而2的5次方等于32。所以至少要去掉32的倍数再进行取余。三、BackboneYOLOv5的骨干网络Backbone是整个目标检测模型的基础负责从输入图像中提取有用的特征并不断缩小特征图。YOLOv5的Backbone采用了New CSP-Darknet53架构这是一种专门为目标检测任务优化的深度学习模型。New CSP-Darknet533.1 CSP结构YOLOv5的Backbone使用了Cross Stage Partial NetworkCSPNet结构这是一种减少计算量的技术。CSP通过在卷积层之间共享权重减少了模型的参数数量和计算量同时保持了特征提取的效率。CSPNet(Cross Stage Partial Network):跨阶段局部网络以缓解以前需要大量推理计算的问题。增强了CNN的学习能力能够在轻量化的同时保持准确性。降低计算瓶颈。降低内存成本。CSPNet通过将梯度的变化从头到尾地集成到特征图中在减少了计算量的同时可以保证准确率。 CSPNet和PRN都是一个思想将feature map拆成两个部分一部分进行卷积操作另一部分和上一部分卷积操作的结果进行concate。Darknet架构Darknet是一个为YOLO系列优化的深度学习框架它以速度快和资源消耗低而著称。Darknet53是Darknet系列中的一个变种拥有53层深度它通过堆叠多个卷积层和池化层来逐步提取图像的深层特征。CBS模块C3模块3由三个CBS模块和一个BottleNeck模块组成得名C3。在Backbone中C3是更为重要的提取特征的模块。其结构图如下SPPF模块SPP是空间金字塔池化采用 1 × 1 1×1 1×1 5 × 5 5×5 5×5 9 × 9 9×9 9×9 13 × 13 13×13 13×13的最大池化的方式进行多尺度融合。YOLOv5 6.0版本开始使用了在SPP基础上改进的SPPF3.2 Focus结构YOLOv5在Backbone的开始部分使用了Focus结构这是一种有效的特征融合技术。Focus结构通过将输入图像分割成小块然后分别提取特征最后再将这些特征合并从而提高了模型对小目标的检测能力。YOLOv5 6.0开始将Focus模块替换成了一个 6 ∗ 6 66 6∗6的卷积层。两者的计算量是等价的但使用 6 ∗ 6 66 6∗6的卷积会更加高效。3.3 高效的激活函数YOLOv5采用了Mish激活函数这是一种比传统的ReLU激活函数更加平滑的激活函数有助于在训练过程中提供更稳定的梯度流动。Mish激活函数是YOLOv5中的一个关键创新它在正区间的表现比传统的ReLU激活函数更为平滑这有助于梯度更有效地流动从而加快网络训练的收敛速度。Mish的设计避免了ReLU在负区间的梯度消失问题同时在正区间保持了类似ReLU的线性增长这对于提取深层次特征和提高模型的非线性表达能力至关重要。Mish是光滑的非单调激活函数可定义为・ς其中ς是一个激活函数和。3.4 多尺度特征融合YOLOv5的Backbone通过SPPFSpatial Pyramid Pooling with Feature map Fusion模块实现了多尺度的特征融合这使得模型能够同时检测不同大小的目标。SPP是空间金字塔池化采用 1 × 1 1×1 1×1 5 × 5 5×5 5×5 9 × 9 9×9 9×9 13 × 13 13×13 13×13的最大池化的方式进行多尺度融合。YOLOv5 6.0版本开始使用了在SPP基础上改进的SPPF。SPP是将三个并行的MaxPool2d和输入Concat到一起第一个MaxPool2d的kernel为 5 ∗ 5 55 5∗5第二个为 9 ∗ 9 99 9∗9第三个为 13 ∗ 13 1313 13∗13。用三个不同大小的kernel代表三个尺度。 5 ∗ 5 55 5∗5的kernel可以理解为比较大的尺度而 13 ∗ 13 13*13 13∗13就是比较小的尺度。这样就在图片的不同尺度下取到了最大的代表特征值并Concat融合。SPPF是将三个kernel为 5 ∗ 5 5*5 5∗5的MaxPool2d做串行计算。第一个MaxPool2d表示较大的尺度第二个MaxPool在第一个MaxPool2d的基础上进一步做池化那么产生的尺度将会进一步缩小第三个同理。通过这些设计YOLOv5的Backbone能够高效地从输入图像中提取丰富的特征为后续的检测任务提供了坚实的基础。这些特征随后会被传递到Neck和Head部分进行更精细的目标检测和定位。四、NeckNeck的作用就是从Backbone中获取相对于较浅的特征再与深层的语义特征Concat到一起。Yolov5现在的Neck和Yolov4中一样都采用FPNPAN的结构但在Yolov5刚出来时只使用了FPN结构后面才增加了PAN结构此外网络中其他部分也进行了调整。Yolov4的Neck结构中采用的都是普通的卷积操作。而Yolov5的Neck结构中采用借鉴CSPnet设计的CSP2结构加强网络特征融合的能力。 FPN 结构通过自顶向下进行上采样使得底层特征图包含更强的图像强语义信息FPN结构中通过Upsample上采样的方式向特征图中插值使特征图的尺寸变大以便于融合来自Backbone的特征图做特征的向上融合特征图不断变大PAN 结构自底向上进行下采样使顶层特征包含图像位置信息两个特征最后进行融合使不同尺寸的特征图都包含图像语义信息和图像特征信息保证了对不同尺寸的图片的准确预测。五、HeadHead层为Detect模块Detect模块的网络结构很简单仅由三个 1 ∗ 1 11 1∗1卷积构成对应三个检测特征层。上述经过FPN特征金字塔我们可以获得 20 ∗ 20 ∗ 512 2020512 20∗20∗512、 40 ∗ 40 ∗ 256 4040256 40∗40∗256、 80 ∗ 80 ∗ 128 8080*128 80∗80∗128三个加强特征然后我们利用这三个shape的特征层传入Yolo Head获得预测结果。对于每一个特征层我们可以获得利用一个 1 ∗ 1 1*1 1∗1卷积调整通道数最终的通道数和需要区分的种类个数相关每一个特征层上每一个特征点存在3个先验框。如果使用的是COCO训练集类则为 80 80 80种最后的维度应该为 255 3 ∗ 85 255 385 2553∗85三个特征层的shape为 20 ∗ 20 ∗ 255 2020255 20∗20∗255、 40 ∗ 40 ∗ 255 4040255 40∗40∗255、 80 ∗ 80 ∗ 255 8080*255 80∗80∗255最后的255可以拆分成 3 3 3个 85 85 85对应 3 3 3个先验框的 85 85 85个参数85可以拆分成 4 1 80 4180 4180。这里的3是指每个位置先验框锚框的数量前4个参数用于判断每一个特征点的回归参数回归参数调整后可以获得预测框第5个参数用于判断每一个特征点是否包含物体 最后80个参数用于判断每一个特征点所包含的物体种类。六、损失函数YOLOV5默认应该是使用的Clou,但它源码提供了Giou,Diou等函数可以在源码中调整YOLOv5采用了CIoUComplete Intersection over UnionLoss函数来优化边界框预测。CIoU Loss不仅考虑了预测框与真实框之间的重叠区域还考虑了两者中心点的距离、宽高比和对角线长度从而更全面地评估预测框与真实框之间的相似度。CIoU Loss的引入使得模型在训练过程中能够更精确地预测边界框尤其是在目标尺寸和形状上。其中Yolov5中采用其中的GIOU_Loss做Bounding box的损失函数先计算两个框的最小闭包 区域面积 (通俗理解同时包含了预测框和真实框的最小框的面积)再计算出IoU再计算闭包区域中不属于两个框的区域占闭包区域的比重最后用IoU减去这个比重得到GIoU。两个框的最小闭包区域面积 红色矩形面积 IoU 黄色框和蓝色框的交集 / 并集 闭包区域中不属于两个框的区域占闭包区域的比重 蓝色面积 / 红色矩阵面积 GIoU IoU - 比重def Giou(rec1,rec2): #分别是第一个矩形左右上下的坐标 x1,x2,y1,y2 rec1 x3,x4,y3,y4 rec2 iou Iou(rec1,rec2) area_C (max(x1,x2,x3,x4)-min(x1,x2,x3,x4))*(max(y1,y2,y3,y4)-min(y1,y2,y3,y4)) area_1 (x2-x1)*(y1-y2) area_2 (x4-x3)*(y3-y4) sum_area area_1 area_2 w1 x2 - x1 #第一个矩形的宽 w2 x4 - x3 #第二个矩形的宽 h1 y1 - y2 h2 y3 - y4 W min(x1,x2,x3,x4)w1w2-max(x1,x2,x3,x4) #交叉部分的宽 H min(y1,y2,y3,y4)h1h2-max(y1,y2,y3,y4) #交叉部分的高 Area W*H #交叉的面积 add_area sum_area - Area #两矩形并集的面积 end_area (area_C - add_area)/area_C #闭包区域中不属于两个框的区域占闭包区域的比重 giou iou - end_area return giou其中可使用的DIoUDIoU要比GIou更加符合目标框回归的机制将目标与anchor之间的距离重叠率以及尺度都考虑进去使得目标框回归变得更加稳定不会像IoU和GIoU一样出现训练过程中发散等问题。与GIoU loss类似DIoU lossL D I o U 1 − D I o U L_{DIoU} 1 - DIoUL DIoU1−DIoU在与目标框不重叠时仍然可以为边界框提供移动方向。 DIoU loss可以直接最小化两个目标框的距离因此比GIoU loss收敛快得多。 对于包含两个框在水平方向和垂直方向上这种情况DIoU损失可以使回归非常快而GIoU损失几乎退化为IoU损失。 DIoU还可以替换普通的IoU评价策略应用于NMS中使得NMS得到的结果更加合理和有效。def Diou(bboxes1, bboxes2): rows bboxes1.shape[0] cols bboxes2.shape[0] dious torch.zeros((rows, cols)) if rows * cols 0:# return dious exchange False if bboxes1.shape[0] bboxes2.shape[0]: bboxes1, bboxes2 bboxes2, bboxes1 dious torch.zeros((cols, rows)) exchange True # #xmin,ymin,xmax,ymax-[:,0],[:,1],[:,2],[:,3] w1 bboxes1[:, 2] - bboxes1[:, 0] h1 bboxes1[:, 3] - bboxes1[:, 1] w2 bboxes2[:, 2] - bboxes2[:, 0] h2 bboxes2[:, 3] - bboxes2[:, 1] area1 w1 * h1 area2 w2 * h2 center_x1 (bboxes1[:, 2] bboxes1[:, 0]) / 2 center_y1 (bboxes1[:, 3] bboxes1[:, 1]) / 2 center_x2 (bboxes2[:, 2] bboxes2[:, 0]) / 2 center_y2 (bboxes2[:, 3] bboxes2[:, 1]) / 2 inter_max_xy torch.min(bboxes1[:, 2:],bboxes2[:, 2:]) inter_min_xy torch.max(bboxes1[:, :2],bboxes2[:, :2]) out_max_xy torch.max(bboxes1[:, 2:],bboxes2[:, 2:]) out_min_xy torch.min(bboxes1[:, :2],bboxes2[:, :2]) inter torch.clamp((inter_max_xy - inter_min_xy), min0) inter_area inter[:, 0] * inter[:, 1] inter_diag (center_x2 - center_x1)**2 (center_y2 - center_y1)**2 outer torch.clamp((out_max_xy - out_min_xy), min0) outer_diag (outer[:, 0] ** 2) (outer[:, 1] ** 2) union area1area2-inter_area dious inter_area / union - (inter_diag) / outer_diag dious torch.clamp(dious,min-1.0,max 1.0) if exchange: dious dious.T return dious其中CIOU作者考虑到bbox回归三要素中的长宽比还没被考虑到计算中因此进一步在DIoU的基础上提出了CIoU。Yolov4中采用CIOU_Loss作为目标Bounding box的损失。 完整的 CIoU 损失函数定义其中 α \alphaα 是权重函数而 v vv 用来度量长宽比的相似性定义为def bbox_overlaps_ciou(bboxes1, bboxes2): rows bboxes1.shape[0] cols bboxes2.shape[0] cious torch.zeros((rows, cols)) if rows * cols 0: return cious exchange False if bboxes1.shape[0] bboxes2.shape[0]: bboxes1, bboxes2 bboxes2, bboxes1 cious torch.zeros((cols, rows)) exchange True w1 bboxes1[:, 2] - bboxes1[:, 0] h1 bboxes1[:, 3] - bboxes1[:, 1] w2 bboxes2[:, 2] - bboxes2[:, 0] h2 bboxes2[:, 3] - bboxes2[:, 1] area1 w1 * h1 area2 w2 * h2 center_x1 (bboxes1[:, 2] bboxes1[:, 0]) / 2 center_y1 (bboxes1[:, 3] bboxes1[:, 1]) / 2 center_x2 (bboxes2[:, 2] bboxes2[:, 0]) / 2 center_y2 (bboxes2[:, 3] bboxes2[:, 1]) / 2 inter_max_xy torch.min(bboxes1[:, 2:],bboxes2[:, 2:]) inter_min_xy torch.max(bboxes1[:, :2],bboxes2[:, :2]) out_max_xy torch.max(bboxes1[:, 2:],bboxes2[:, 2:]) out_min_xy torch.min(bboxes1[:, :2],bboxes2[:, :2]) inter torch.clamp((inter_max_xy - inter_min_xy), min0) inter_area inter[:, 0] * inter[:, 1] inter_diag (center_x2 - center_x1)**2 (center_y2 - center_y1)**2 outer torch.clamp((out_max_xy - out_min_xy), min0) outer_diag (outer[:, 0] ** 2) (outer[:, 1] ** 2) union area1area2-inter_area u (inter_diag) / outer_diag iou inter_area / union with torch.no_grad(): arctan torch.atan(w2 / h2) - torch.atan(w1 / h1) v (4 / (math.pi ** 2)) * torch.pow((torch.atan(w2 / h2) - torch.atan(w1 / h1)), 2) S 1 - iou alpha v / (S v) w_temp 2 * w1 ar (8 / (math.pi ** 2)) * arctan * ((w1 - w_temp) * h1) cious iou - (u alpha * ar) cious torch.clamp(cious,min-1.0,max 1.0) if exchange: cious cious.T return ciousnms非极大值抑制在目标检测的后处理过程中针对很多目标框的筛选通常需要nms操作。 因为CIOU_Loss中包含影响因子v涉及groudtruth的信息而测试推理时是没有groundtruth的。所以Yolov4在DIOU_Loss的基础上采用DIOU_nms的方式而Yolov5中采用加权nms的方式。 不同的nms会有不同的效果采用了DIOU_nms的方式在同样的参数情况下将nms中IOU修改成DIOU_nms。对于一些遮挡重叠的目标确实会有一些改进。 比如下面黄色箭头部分原本两个人重叠的部分在参数和普通的IOU_nms一致的情况下修改成DIOU_nms可以将两个目标检出。虽然大多数状态下效果差不多但在不增加计算成本的情况下有稍微的改进也是好的。七、 超参数详解7.1 hpy超参数文件位于data/hyps文件夹下# Hyperparameters for VOC finetuning # ython train.py --batch 64 --weights yolov5m.pt --data voc.yaml --img 512 --epochs 50 lr0: 0.01 # 学习率, SGD1E-2, Adam1E-3 lrf: 0.01 # 余弦退火超参数 momentum: 0.937 # 学习率动量 weight_decay: 0.0005 # 权重衰减系数 warmup_epochs: 3.0 # 预热学习epoch warmup_momentum: 0.8 # 预热学习率动量 warmup_bias_lr: 0.1 # 预热学习率 box: 0.05 # Bounding Box Regeression 损失的系数 cls: 0.5 # 分类损失的系数 cls_pw: 1.0 # 分类BCELoss中正样本的权重 obj: 1.0 # 有无物体损失的系数 obj_pw: 1.0 # 有无物体BCELoss中正样本的权重 iou_t: 0.20 # 标签与anchors的iou阈值 iou training threshold anchor_t: 4 # 标签的长h宽w/anchor的长h_a宽w_a阈值, 即h/h_a, w/w_a都要在(1/4, 4)之间anchor-multiple threshold # anchors: 3.63 # 下面是一些数据增强的系数, 包括颜色空间和图片空间 fl_gamma: 0.0 hsv_h: 0.015 # 色调 hsv_s: 0.7 # 饱和度 hsv_v: 0.4 # 明度 degrees: 0.0 #旋转角度 translate: 0.1 # 水平和垂直平移 scale: 0.5 # 缩放 shear: 0.0 # 剪切 perspective: 0.0 # 透视变换参数 flipud: 0.0 # 上下翻转 fliplr: 0.5 # 左右翻转 mosaic: 1.0 #进行mosaic的概率 mixup: 0.0 #进行mixup的概率, 在mosaic启用时才可启用 copy_paste: 0.0 # segment copy-paste (probability), 在mosaic启用时, 才可以启用7.2 AcnhorYOLOv5在yaml文件中预设好了输入图像为 640 ∗ 640 640*640 640∗640分辨率对应的anchor尺寸YOLOv5的anchor也是在大特征图上检测小目标在小特征图上检测大目标。三个特征图每个特征图上的格子有三种尺寸的anchor。# anchors anchors: - [10,13, 16,30, 33,23] # P3/8 检测小目标 1013是一组尺寸一共三组 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 检测大目标7.3 Backbone# YOLOv5s v6.0 backbone backbone: # YOLOv5 v6.0 backbone backbone: # from 第一列 输入来自哪一层 -1代表上一层 4代表第4层 # number 第二列 卷积核的数量 最终数量需要乘上width # module 第三列 模块名称 包括Conv Focus BottleneckCSP SPP # args 第四列 模块的参数 # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 卷积核的数量 128 * wedith 128*0.564 [-1, 3, C3, [128]], # 模块数量 3 * depth 3*0.331 [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], # 模块数量 6 * depth 6*0.332 [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], # # 模块数量 9 * depth 9*0.333 [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ]7.4 网络结构参数**backbone的前3个C3数量对应yolov5s.yaml的配置369分别除了3变为1/3后的123,和模型深度参数有关depth_multiple: 0.33** 层数第几层 from n params module arguments ch[-1] 数量 参数量 模块名称m 网络结构参数输入维度输出维度卷积核大小卷积步长 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] 2 -1 1 18816 models.common.C3 [64, 64, 1] 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] 4 -1 2 115712 models.common.C3 [128, 128, 2] 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] 6 -1 3 625152 models.common.C3 [256, 256, 3] 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] 8 -1 1 1182720 models.common.C3 [512, 512, 1] 9 -1 1 656896 models.common.SPPF [512, 512, 5] 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] 12 [-1, 6] 1 0 models.common.Concat [1] 13 -1 1 361984 models.common.C3 [512, 256, 1, False] 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, nearest] 16 [-1, 4] 1 0 models.common.Concat [1] 17 -1 1 90880 models.common.C3 [256, 128, 1, False] 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] 19 [-1, 14] 1 0 models.common.Concat [1] 20 -1 1 296448 models.common.C3 [256, 256, 1, False] 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] 22 [-1, 10] 1 0 models.common.Concat [1] 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] 24 [17, 20, 23] 1 229245 Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]7.5 Yolov5四种网络的深度7.6 Yolov5四种网络的宽度此篇文章学习记录到此结束后续更多精彩内容