恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
【YOLO】YOLOv5原理
首页
资讯中心
/
【YOLO】YOLOv5原理
【YOLO】YOLOv5原理
发布时间:2026/10/10 2:54:56
===== 【相关资源获取途径】 =====1.CSDN:YOLO专栏2.---------: XiaoJ1234567目录1. YOLOv5 概述1)目标检测与 YOLO2)检测网络三段式(Backbone,Neck,Head)3)YOLOv5 介绍2. YOLOv5 结构及参数1)YOLOv5 模型整体结构2)YOLOv5 整体参数(yaml 里)3)YOLOv5 模型宽度和深度4)YOLOv5 网络层参数3. YOLOv5 结构子模块1)CBS 模块2)Focus 模块3)C3 模块(CSP)4)SPPF 模块(SPP、SPPF 介绍)5)FPN + PAN 结构5)FPN + PAN 结构4. YOLOv5 主要工作1)Mosaic 数据增强2)自适应锚框计算3)自适应图片缩放4)SiLU 激活函数5)目标框回归6)正负样本匹配7)各类 IoU(IoU、GIoU、DIoU、CIoU)5. YOLOv5 损失函数6. YOLOv5 项目实战1)YOLOv5 整体项目代码2)YOLOv5 模型训练3)YOLOv5 模型验证4)YOLOv5 模型预测5)YOLOv5 模型导出6)YOLOv5 结果分析本文从零讲清 YOLOv5 模型。主要包含网络结构、网络参数、损失函数、项目整体代码、模型的训练验证预测导出等。1. YOLOv5 概述1)目标检测与 YOLO目标检测(Object Detection):给一张图,找出所有物体的位置(用边界框( x 1 , y 1 , x 2 , y 2 ) (x_1,y_1,x_2,y_2)(x1,y1,x2,y2)框住)和类别(是猫、是车还是人)。训练集里人工标好的「正确答案」叫GT(Ground Truth,真值框),模型要学会让预测尽量接近 GT。检测网络分两派:两阶段(如 R-CNN)先生成候选框再逐个分类,精度高但慢;单阶段(如 YOLO、SSD)一次前向直接出全部框,快。YOLO = You Only Look Once,把检测压缩成「一次前向 + 一次 NMS(非极大值抑制,推理时去重复框的后处理)」。2)检测网络三段式(Backbone,Neck,Head)现代检测网络通常分三段:Backbone(主干)从图像提取特征,Neck(颈部)融合多个分辨率的特征,Head(检测头)在特征图上预测框和类别。输入图像 │ ▼ Backbone(骨干) ── 提特征,逐级下采样得到多尺度特征 │ ▼ Neck(颈部) ── 融合多尺度特征(深层语义 ↔ 浅层细节) │ ▼ Head(头部) ── 在各尺度上输出「类别 + 位置 + 置信度」 │ ▼ 后处理(NMS 等)──► 最终检测框卷积一层层把图像变成「特征图」(H×W×C 的张量)。特征图 1 格对应原图stride个像素——这个 stride 是后面把距离还原回原图的关键。3)YOLOv5 介绍YOLOv5由 Ultralytics 团队的 Glenn Jocher 于2020 年 6 月发布。Ultralytics 成立于 2019 年。YOLOv5 名叫 v5,实际是对 YOLO 系列的一次独立实现,不是原 YOLO 作者的下一个版本。它是单阶段 Anchor-Based 检测器:一张图一次前向,同时给出位置、类别、置信度。YOLOv5 沿用「一次前向 + 一次 NMS」的单阶段范式,在 v4 思路基础上做了大量工程化简化:输入端:Mosaic 增强、自适应锚框、自适应缩放;Backbone:Focus / CBS / C3(CSP),后期版本去掉 Focus,SPP 换 SPPF;Neck:FPN + PAN 双向融合;Head:耦合头(分类 + 定位于一体),基于 anchor 回归。整体算法思路可概括如下:输入端 → Mosaic 四图拼接 / 自适应锚框 / 最少黑边缩放 主干 → Focus 切片 + C3(CSP) + SPPF 颈部 → FPN + PAN 双向融合 头部 → 耦合头:三尺度同出类别与框 回归 → anchor 偏移,中心限幅(-0.5, 1.5) 匹配 → 中心越界,跨格共担正样本 损失 → CIoU + BCE置信度 + BCE分类2. YOLOv5 结构及参数1)YOLOv5 模型整体结构YOLOv5结构:Backbone + Neck + Head结构要点:Backbone:CBS 逐级下采样 + C3_1(带残差)提特征 + SPPF 收尾。跳接到 Neck 的三路是 76×76×256、38×38×512、19×19×1024;Neck:上采样 + Concat 自顶向下(FPN),再 CBS 下采样 + Concat 自底向上(PAN)。Neck 里的 C3 是 C3_2,Bottleneck 不带残差;Head:三个尺度各接一个 CBS,分类和回归在同一条分支里。输出 76×76×255、38×38×255、19×19×255。255 = 3 × ( 4 + 1 + 80 ) 255=3\times(4+1+80)255=3×(4+1+80),即 3 个锚框 ×(4 个坐标 + 1 个置信度 + 80 类)。以输入608×608×3为例(608 能被总 stride 32 整除)。三个尺度是:层级特征图尺寸(输入 608)通道(跳接)stride锚框数负责P376×7625683小物体P438×38512163中物体P519×191024323大物体608÷8=76,608÷16=38,608÷32=19。检测头再把每个尺度压成255通道:76×76×255、38×38×255、19×19×255。候选框总数:76 2 × 3 + 38 2 × 3 + 19 2 × 3 = 17328 + 4332 + 1083 = 22743 76^2 \times 3 + 38^2 \times 3 + 19^2 \times 3 = 17328 + 4332 + 1083 = \mathbf{22743}762×3+382×3+192×3=17328+4332+1083=22743。2)YOLOv5 整体参数(yaml 里)网络结构写在 yaml 里,每行格式为[from, number, module, args]:字段含义from该层输入来自哪一层(-1 表示上一层)number该模块重复次数(再乘 depth)module模块名称(Conv / C3 / SPPF / Concat / Detect 等)args模块参数(输出通道、卷积核、步幅等)# Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple width_multiple: 1.0 # layer channel multiple 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 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # cat head P4 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) ]Neck 写在 yaml 的head:段里。C3 的第二个参数False表示这是 C3_2,Bottleneck 不带残差;Backbone 里的 C3_1 默认带残差。这份 yaml 是 v6.0 版本 YOLOv5 对应文件。读它时有两点要注意:第 0 层写成Conv [64, 6, 2, 2](6×6、步幅 2、填充 2),用来替换 Focus。早期版本把这一层画成3×3、S=2、P=1的 CBS。输入 608 时两种写法都得到 304×304×64,后面的 76 / 38 / 19 不变。yaml 在第 23 层 C3 结束。实际网络在第 17、20、23 层之后各再接一个 1×1 CBS,把通道收成255作为检测输出(这一层不在上面的 yaml 列表里)。自底向上的两次 Concat 接的是第 14 层(38×38×256)和第 10 层(19×19×512),不是第 13 层的 512 通道,也不是 SPPF 的 1024 通道。3)YOLOv5 模型宽度和深度YOLOv5 提供 5 种规格,由 yaml 里depth_multiple(depth)和width_multiple(width)两个缩放系数控制,共用同一份结构定义。下表的深度按 s / m / l / x 列出;n 和 s 的 depth 相同,只是 width 更小。型号depth(深度)width(宽度)n0.330.25s0.330.50m0.670.75l1.001.00x1.331.25width(宽度):用这个系数去乘每一层卷积的通道数(卷积核个数)。depth(深度):控制 C3 内 Bottleneck 的堆叠次数。实际次数= r o u n d ( d e p t h × n u m b e r ) = \mathrm{round}(\mathrm{depth} \times \mathrm{number})=round(depth×number),至少为 1。上面 yaml 按 l 档来写,C3_1 的 number 是 3、6、9、3,四个 C3_2 的 number 都是 3;(1)width:控制通道数实际通道 = yaml 标称通道 × width,再向下取整到 8 的倍数。「标称通道」就是 yaml 每行args里的第一个数。下面把 yaml 里几种典型行标出来:# 每行格式:[from, number, module, args] # args 的第一个数 = 该层标称输出通道(再乘 width 才是实际通道) [-1, 1, Conv, [64, 6, 2, 2]], # 标称通道 64 ← 第 0 层 [-1, 1, Conv, [128, 3, 2]], # 标称通道 128 ← 第 1 层 [-1, 3, C3, [128]], # 标称通道 128 ← C3 的输出通道 [-1, 9, C3, [512]], # 标称通道 512 [-1, 1, SPPF, [1024, 5]], # 标称通道 1024(第二个 5 是池化核)以第 0 层 CBS、标称通道 64 为例:型号width计算实际通道YOLOv5n0.2564 × 0.2516YOLOv5s0.5064 × 0.5032YOLOv5m0.7564 × 0.7548YOLOv5l1.0064 × 1.0064YOLOv5x1.2564 × 1.2580(2)depth:控制 C3 的重复次数下标就是 Bottleneck 的重复次数。s 档depth_multiple: 0.33,例如第三个 C3_1:r o u n d ( 0.33 × 9 ) = 3 \mathrm{round}(0.33 \times 9)=3round(0.33×9)=3,写成 C3_1_3。x 档 depth 是1.33,同一个位置是r o u n d ( 1.33 × 9 ) = 12 \mathrm{round}(1.33 \times 9)=12round(1.33×9)=12,写成 C3_1_12。n 的 depth 也是 0.33,重复次数和 s 相同。模块YOLOv5sYOLOv5mYOLOv5lYOLOv5x第 1 个 C3_1C3_1_1C3_1_2C3_1_3C3_1_4第 2 个 C3_1C3_1_2C3_1_4C3_1_6C3_1_8第 3 个 C3_1C3_1_3C3_1_6C3_1_9C3_1_12第 4 个 C3_1C3_1_1C3_1_2C3_1_3C3_1_4第 1 个 C3_2C3_2_1C3_2_2C3_2_3C3_2_4第 2 个 C3_2C3_2_1C3_2_2C3_2_3C3_2_4第 3 个 C3_2C3_2_1C3_2_2C3_2_3C3_2_4第 4 个 C3_2C3_2_1C3_2_2C3_2_3C3_2_4要点:width 管「每层多宽」、depth 管「C3 里堆多少个 Bottleneck」。l 档(depth=1.0)下,C3_1 的重复次数就是 3、6、9、3,C3_2 的重复次数都是 3。4)YOLOv5 网络层参数空间尺寸公式:O H = H + 2 P − K H S + 1 , O W = W + 2 P − K W S + 1 OH = \frac{H + 2P - KH}{S} + 1,\qquad OW = \frac{W + 2P - KW}{S} + 1OH=SH+2P−KH+1,OW=SW+2P−KW+1符号含义备注H, W输入特征图的高、宽即上一层的输出尺寸OH, OW输出特征图的高、宽本层计算结果KH, KW卷积核的高、宽整体参数图的下采样 CBS 是 3×3;S=2、P=1 时尺寸减半。v6.0 yaml 第 0 层是 6×6、P=2,608 上同样得到 304PPadding(填充)YOLOv5 的 Conv 自动取 P = K/2 向下取整SStride(步幅)1 = 尺寸不变,2 = 尺寸减半通道数公式:实际通道 = 标称通道 × 宽度系数,再向上取整到 8 的倍数。C 实际 = ⌈ C 标称 × w i d t h 8 ⌉ × 8 C_{实际} = \left\lceil \frac{C_{标称} \times width}{8} \right\rceil \times 8C实际=⌈8C标称×width⌉×8符号含义备注C_标称yaml 中args的第一个值即该层「标称」输出通道,如[64, 6, 2, 2]中的 64width该型号的宽度系数yaml 里的width_multiple:n=0.25,s=0.50,m=0.75,l=1.00,x=1.258通道对齐基数通道数取 8、16、24、32…… 这种能被 8 整除的整数C_实际该层真正的输出通道数训练/推理时实际使用的通道8 的倍数:通道数只能是 8、16、24、32……,不能是 17、50 这种。GPU 卷积常按 8 个通道一组打包,对齐后计算更整齐。乘完 width 若不是 8 的倍数,就向上补到最近的一档(例如 50 → 56)。n / s / m / l / x 这五个 width 乘完一般都已经是 8 的倍数,这一步通常不用改。Detect 检测头的 255 通道不乘 width。参数计算:Backbone 主干网络(输入 608×608×3;通道按 yaml 标称值。3×3、S=2、P=1 时尺寸减半):层模块输入输出说明0CBS608×608×3304×304×64S=21CBS304×304×64152×152×128S=22C3_1_3152×152×128152×152×128带残差3CBS152×152×12876×76×256S=24C3_1_676×76×25676×76×256P3,跳接到 Neck5CBS76×76×25638×38×512S=26C3_1_938×38×51238×38×512P4,跳接到 Neck7CBS38×38×51219×19×1024S=28C3_1_319×19×102419×19×1024带残差9SPPF19×19×102419×19×1024P5,尺寸不变关键:5 次 S=2,608 → 304 → 152 → 76 → 38 → 19。接到 Neck 的是第 4 层 76×76×256、第 6 层 38×38×512、第 9 层 19×19×1024。参数计算:Neck + Head 网络(接第 9 层 19×19×1024,depth=1.0 时 Neck 的 C3 是 C3_2_3)。层号与上面的 yaml 一致。三个 255 通道的 CBS 画在 Head 上,不占 yaml 里的层号:层模块输入输出说明10CBS19×19×102419×19×5121×111上采样19×19×51238×38×512×212Concat38×38×512 + #6(38×38×512)38×38×1024拼 backbone P413C3_2_338×38×102438×38×512不带残差14CBS38×38×51238×38×2561×1,后面 PAN 要拼这一层15上采样38×38×25676×76×256×216Concat76×76×256 + #4(76×76×256)76×76×512拼 backbone P317C3_2_376×76×51276×76×256小目标特征—CBS76×76×25676×76×255Head,1×118CBS#17 的 76×76×25638×38×256K=3,S=219Concat38×38×256 + #14(38×38×256)38×38×512256+256=51220C3_2_338×38×51238×38×512中目标特征—CBS38×38×51238×38×255Head,1×121CBS#20 的 38×38×51219×19×512K=3,S=222Concat19×19×512 + #10(19×19×512)19×19×1024512+512=102423C3_2_319×19×102419×19×1024大目标特征—CBS19×19×102419×19×255Head,1×1关键:FPN 把 19×19 放大到 76×76,PAN 再收回到 38×38 和 19×19。PAN 拼的是 Neck 里已经压过通道的第 14 层和第 10 层。三个 1×1 CBS 把通道收成 255,就是三个尺度的检测输出。3. YOLOv5 结构子模块YOLOv5 由若干基础模块堆叠而成。这一节自包含地介绍每个模块:先讲最基础的 CBS 卷积块,再讲 Focus、C3、SPPF 三个功能模块,最后讲 Neck 用的 FPN+PAN 结构。1)CBS 模块CBS是 YOLOv5 里最基本的卷积块,全网络几乎每一层都由它拼出来,名字来自三步:Conv:二维卷积。YOLOv5 关掉卷积的偏置(bias=False),因为后面紧跟 BN,偏置会被 BN 抵消,省掉无用的参数;BN:BatchNorm,批归一化,稳定训练、加速收敛;SiLU:激活函数x ⋅ σ ( x ) x\cdot\sigma(x)x⋅σ(x),比 ReLU 更平滑,负半轴不直接截断。三步串起来:输入 → Conv → BN → SiLU → 输出。autopad按卷积核大小自动算填充,让 stride=1 时特征图尺寸不变、stride=2 时尺寸减半,不用手动填 padding。输入 X │ Conv2d(k, s, autopad(k,p), bias=False) │ BatchNorm2d │ SiLU │ 输出对应代码就是models/common.py里的Conv类:class Conv(nn.Module): def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): super().__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) self.bn = nn.BatchNorm2d(c2) self.act = nn.SiLU() if act is True else nn.Identity() def forward(self, x): return self.act(self.bn(self.conv(x)))参数含义:c1输入通道、c2输出通道、k卷积核、s步幅、p填充(None 时用 autopad)、g分组卷积组数、act是否激活。后续的 C3、SPPF 都以 CBS 为积木。2)Focus 模块Focus是早期 YOLOv5 的第一层,用来对输入图像做一次「不丢信息」的下采样。它把空间维度的像素搬到通道维度:空间缩小一半、通道变成 4 倍,所有像素都保留,再接一个卷积整合。切片(slice)原理:把输入按2 × 2 2\times22×2邻域拆成 4 份。每个2 × 2 2\times22×2小块里的左上、右上、左下、右下四个像素分别归到 4 张子图。一张H × W × C H\times W\times CH×W×C的图,拆成 4 张H 2 × W 2 × C \frac{H}{2}\times\frac{W}{2}\times C2H×2W×C,在通道维拼成H 2 × W 2 × 4 C \frac{H}{2}\times\frac{W}{2}\times 4C2H×2W×4C。以输入 608×608×3 为例,Focus 内部流程:输入 608×608×3 │ 按 2×2 邻域切片,取 4 个相位 ├─ slice 1(左上像素)→ 304×304×3 ├─ slice 2(右上像素)→ 304×304×3 ├─ slice 3(左下像素)→ 304×304×3 └─ slice 4(右下像素)→ 304×304×3 │ ▼ Concat(通道维拼接) 304×304×12 │ ▼ Conv(3×3) 304×304×64切片后空间从 608 缩到 304(减半),通道从 3 涨到 12(4 倍),再卷积压成 64 通道。像素一个没扔,只是换了排列。为什么用 Focus:它能减少层数、参数量和计算量,降低 CUDA 显存占用;mAP 影响很小,推理和反向传播更快。后期版本(v6.0 起)去掉了 Focus,第一层直接换成步幅 2 的 6×6 卷积(即一个 CBS),导出兼容性更好,效果接近。Focus和 Passthrough 的关系:两者都是「空间转通道」的思路,但用法不同。Passthrough 用在检测器中部做特征融合,把高分辨率特征拆叠成多通道,再和低分辨率特征拼到一起;Focus 用在网络入口做下采样。Passthrough 的一个具体例子:YOLOv2 Passthrough(特征融合): 26×26×512 ── 拆成 4 张 13×13×512 ── 叠成 13×13×2048 ─┐ ├─ Concat → 13×13×3072 26×26×512 ── Pooling + Conv ───────────── 13×13×1024 ┘上路把 26×26×512 拆成 4 份 13×13×512,叠成 13×13×2048;下路经池化加卷积得到 13×13×1024;两路拼成 13×13×3072,让检测头同时看到高分辨率的细节和低分辨率的语义。3)C3 模块(CSP)C3(Cross Stage Partial bottleneck with 3 convolutions,跨阶段部分三卷积瓶颈模块):YOLOv5 的核心特征提取模块,借鉴 CSPNet 的跨阶段思想——把特征拆成两路,一路不计算直接保留,另一路过 Bottleneck(先用 1×1 卷积降维、再用 3×3 卷积升维,存在有无残差两种),最后拼接融合。# ============================================ # 1. C3(CSP) 模块 # ============================================ X │ ┌────┴─────┐ │ │ CBS(1×1) CBS(1×1) │ │ │ Bottleneck × n │ │ ▼ ▼ ┌──────────────┐ │ Concat │ └──────────────┘ │ CBS(1×1) │ 输出 # ============================================ # 2. Bottleneck模块 # ============================================ 不带残差(shortcut=False 或 c1≠c2): X ──► CBS(1,1) ──► CBS(3,1) ──► 输出 带残差(shortcut=True 且 c1==c2): X ──┬──► CBS(1,1) ──► CBS(3,1) ───┐ │ ⊕ ──► 输出 └─────────────────────────────┘ (恒等映射:输入直接跳到末尾,与卷积结果逐元素相加)要点:最后拼接的是两路。按 Bottleneck 是否带残差分成两种:C3_1_X(用在 Backbone):Bottleneck 是 Res Unit-T,两层 CBS 之后与输入add,带残差;C3_2_X(用在 Neck):Bottleneck 是 Res Unit-F,只有两层 CBS,不加残差。下标 X 对应 Bottleneck 的重复次数,例如 C3_1_3、C3_1_6、C3_1_9 就是 Bottleneck 重复 3、6、9 次。YOLOv4 的CSPX和这里的 C3 是同一类跨阶段结构,模块不一样:CSPX 里的卷积块是CBM = Conv + BN + Mish,残差单元也用 CBM;C3 用的是CBS = Conv + BN + SiLU。对应代码里就是C3模块:两路 1×1 卷积,一路进n个 Bottleneck(nn.Sequential),一路直连;拼接后再用 1×1 压回c2。shortcut控制 Bottleneck 是否残差相加——Backb