【YOLO系列】YOLOv4详解:模型结构、损失函数、训练方法及代码实现
YOLOv4详解:模型结构、损失函数、训练方法及代码实现
motivation
YOLO系列作者Joseph Redmon与Alexey Bochkovskiy致力于解决目标检测领域的核心矛盾:精度与速度的平衡。YOLOv4的诞生源于两大需求:
- 工业落地:在移动端/边缘设备实现实时检测(>30FPS)
- 学术突破:无需昂贵算力(如1080Ti即可训练),在MS COCO数据集达到SOTA
methods
1. 数据加载创新
- Mosaic数据增强:拼接4张图像,提升小目标检测能力
- Self-Adversarial Training:对抗训练增强遮挡场景鲁棒性
# Mosaic增强示例(简化版)
def mosaic_augment(imgs):output = np.zeros((608,608,3))xc, yc = [random.randint(300,500) for _ in range(2)] # 随机中心点indices = [0,1,2,3] # 4张图索引for i, img in enumerate(imgs):h,w,_ = img.shapeif i==0: # 左上output[:yc,:xc] = cv2.resize(img, (xc,yc))... # 其他区域填充return output
2. 模型结构
- Backbone:CSPDarknet53(跨阶段局部网络)
- 引入CSP结构降低计算量Cout=Cin2C_{out}=\frac{C_{in}}{2}Cout=2Cin
- Neck:SPP + PANet
- SPP模块:多尺度池化融合特征 fout=Concat(MaxPoolk×k(fin)),k∈{1,5,9,13}f_{out} = \text{Concat}( \text{MaxPool}_{k \times k}(f_{in}) ), k \in \{1,5,9,13\}fout=Concat(MaxPoolk×k(fin)),k∈{1,5,9,13}
- PANet:双向特征金字塔,增强浅层定位信息
- Head:解耦头结构
- 分类/回归任务分离,提升收敛效率
3. 损失函数
- CIoU Loss:解决边界框回归不均衡问题
LCIoU=1−IoU+ρ2(b,bgt)c2+αv\mathcal{L}_{CIoU} = 1 - IoU + \frac{\rho^2(b,b^{gt})}{c^2} + \alpha v LCIoU=1−IoU+c2ρ2(b,bgt)+αv
其中v=4π2(arctanwgthgt−arctanwh)2v=\frac{4}{\pi^2}(\arctan\frac{w^{gt}}{h^{gt}}-\arctan\frac{w}{h})^2v=π24(arctanhgtwgt−arctanhw)2 - 分类损失:Focal Loss改进版缓解样本不平衡
4. 训练策略
- 余弦退火调度:学习率动态调整 ηt=ηmin+12(ηmax−ηmin)(1+cos(TcurTmaxπ))\eta_t = \eta_{min} + \frac{1}{2}(\eta_{max}-\eta_{min})(1+\cos(\frac{T_{cur}}{T_{max}}\pi)) ηt=ηmin+21(ηmax−ηmin)(1+cos(TmaxTcurπ))
- SAT训练:生成对抗扰动增强决策边界鲁棒性
experiments
模型 | AP@0.5 | FPS (Tesla V100) | 参数量 |
---|---|---|---|
YOLOv3 | 55.3% | 45 | 61.5M |
YOLOv4 | 65.7% | 62 | 63.9M |
- 关键突破:
- 在MS COCO上AP50达65.7%,较v3提升10.4%
- Tesla V100实时推理速度62FPS
- 使用GIoU替换NMS,误检率降低20%
代码详解(PyTorch核心片段)
CSPDarknet块实现
class CSPBlock(nn.Module):def __init__(self, in_c, out_c, n=1):super().__init__()self.conv1 = Conv(in_c, out_c//2, 1) # 通道减半self.conv2 = Conv(in_c, out_c//2, 1)self.bottleneck = nn.Sequential(*[ResBlock(out_c//2) for _ in range(n)])def forward(self, x):x1 = self.conv1(x)x2 = self.conv2(x)x2 = self.bottleneck(x2)return torch.cat([x1, x2], dim=1) # 通道维度拼接
SPP模块结构
class SPP(nn.Module):def __init__(self, pool_sizes=(5,9,13)):super().__init__()self.pools = nn.ModuleList([nn.MaxPool2d(p, stride=1, padding=p//2) for p in pool_sizes])def forward(self, x):features = [x]for pool in self.pools:features.append(pool(x))return torch.cat(features, dim=1) # 多尺度特征融合
总结
YOLOv4通过架构创新(CSPDarknet53+SPP+PANet)与训练策略革新(Mosaic+SAT),在精度与速度间取得完美平衡。其设计哲学启示后人:
“优秀的工程不是堆砌模块,而是让每个组件在系统中发挥乘法效应”
开源代码见:YOLOv4官方实现