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.shape
if i==0: # 左上
output[:yc,:xc] = cv2.resize(img, (xc,yc))
... # 其他区域填充
return output
2. 模型结构
- Backbone:CSPDarknet53(跨阶段局部网络)
- 引入CSP结构降低计算量 C o u t = C i n 2 C_{out}=\frac{C_{in}}{2} Cout=2Cin
- Neck:SPP + PANet
- SPP模块:多尺度池化融合特征 f o u t = Concat ( MaxPool k × k ( f i n ) ) , 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:解决边界框回归不均衡问题
L C I o U = 1 − I o U + ρ 2 ( b , b g t ) c 2 + α 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 ( arctan w g t h g t − arctan w h ) 2 v=\frac{4}{\pi^2}(\arctan\frac{w^{gt}}{h^{gt}}-\arctan\frac{w}{h})^2 v=π24(arctanhgtwgt−arctanhw)2 - 分类损失:Focal Loss改进版缓解样本不平衡
4. 训练策略
- 余弦退火调度:学习率动态调整 η t = η m i n + 1 2 ( η m a x − η m i n ) ( 1 + cos ( T c u r T m a x π ) ) \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官方实现