YOLOv4 是目标检测领域的一次重要升级,由 Alexey Bochkovskiy 等人在论文《YOLOv4: Optimal Speed and Accuracy of Object Detection》中提出。它在保持高精度的同时,兼顾了实时性,是工业界广泛使用的模型之一。
本文将:
改进 | 内容 |
---|---|
主干网络 | CSPDarknet53(引入 Cross Stage Partial Connections) |
特征融合 | PANet(Path Aggregation Network) |
自适配训练策略 | Mosaic 数据增强 + SAT(自适配训练) |
损失函数 | CIoU Loss + DIoU NMS |
多尺度预测 | 输出三个层级的边界框(80×80、40×40、20×20) |
✅ 所有内容均来自论文原文或 AlexeyAB/darknet 开源实现。
我们构造一个小型的真实数据集样例用于说明训练与推理流程。
person
, car
)<object>
<name>personname>
<bndbox>
<xmin>100xmin>
<ymin>150ymin>
<xmax>200xmax>
<ymax>300ymax>
bndbox>
object>
<object>
<name>carname>
<bndbox>
<xmin>250xmin>
<ymin>100ymin>
<xmax>350xmax>
<ymax>200ymax>
bndbox>
object>
(xmin, ymin, xmax, ymax)
转换为 (x_center, y_center, width, height)
,并归一化到 [0, 1];image_size = 608
person_bbox = [150 / 608, 225 / 608, 100 / 608, 150 / 608] # x_center, y_center, w, h
car_bbox = [300 / 608, 150 / 608, 100 / 608, 100 / 608]
YOLOv4 使用 K-Means 对 COCO 数据集中的真实框聚类得到的 9 个 anchors,按层级分配如下:
层级 | Anchors |
---|---|
大目标(20×20) | [116×90, 156×198, 373×326] |
中目标(40×40) | [30×61, 62×45, 59×119] |
小目标(80×80) | [10×13, 16×30, 33×23] |
对每个 ground truth 框,计算其与所有 anchor 的 IoU,并选择 IoU 最大的那个作为正样本 anchor。
from yolov4.utils import compute_iou, match_anchor_to_gt
anchors = [(10, 13), (16, 30), (33, 23),
(30, 61), (62, 45), (59, 119),
(116, 90), (156, 198), (373, 326)]
gt_boxes = [[0.25, 0.38, 0.17, 0.25], # person
[0.50, 0.17, 0.17, 0.17]] # car
positive_anchors = match_anchor_to_gt(gt_boxes, anchors)
输出示例(简化表示):
[
{"anchor_idx": 0, "layer": 2, "grid_cell": (30, 20)}, # person → 小目标层 anchor 0
{"anchor_idx": 4, "layer": 1, "grid_cell": (10, 5)} # car → 中目标层 anchor 4
]
YOLOv4 的输出是一个张量:
[batch_size, H, W, (B × (5 + C))]
其中:
H × W
:特征图大小(如 20×20、40×40、80×80)B = 3
:每个位置预测的 bounding box 数量5 + C
:每个 bounding box 的参数(tx, ty, tw, th, confidence, class_probs)label_80x80 = np.zeros((80, 80, 3, 5 + 2)) # 2 类:person, car
# 在 person 对应的 grid cell 和 anchor 上填充真实值
label_80x80[20, 30, 0, :4] = [0.25, 0.38, 0.17, 0.25] # tx, ty, tw, th
label_80x80[20, 30, 0, 4] = 1.0 # confidence
label_80x80[20, 30, 0, 5] = 1.0 # person 类别置信度
# 在 car 对应的 grid cell 和 anchor 上填充真实值
label_40x40[5, 10, 1, :4] = [0.50, 0.17, 0.17, 0.17]
label_40x40[5, 10, 1, 4] = 1.0
label_40x40[5, 10, 1, 6] = 1.0 # car 类别置信度
YOLOv4 的损失函数包括:
CIoU = IoU − ρ 2 d 2 − α v \text{CIoU} = \text{IoU} - \frac{\rho^2}{d^2} - \alpha v CIoU=IoU−d2ρ2−αv
其中:
损失类型 | 是否参与训练 |
---|---|
定位损失(CIoU) | ✅ 仅正样本 |
置信度损失 | ✅ 正样本 + 负样本 |
分类损失 | ✅ 仅正样本 |
image = cv2.imread("test.jpg")
resized_image = cv2.resize(image, (608, 608)) / 255.0 # 归一化
input_tensor = np.expand_dims(resized_image, axis=0) # 添加 batch 维度
模型输出三个层级的预测结果:
output_20x20 = model.predict(input_tensor)[0] # shape: (20, 20, 255)
output_40x40 = model.predict(input_tensor)[1] # shape: (40, 40, 255)
output_80x80 = model.predict(input_tensor)[2] # shape: (80, 80, 255)
每个 bounding box 的输出格式为:
(tx, ty, tw, th, confidence, class_0, class_1)
使用以下公式将网络输出解码为图像空间中的绝对坐标:
b x = σ ( t x ) + c x b y = σ ( t y ) + c y b w = p w ⋅ e t w b h = p h ⋅ e t h b_x = \sigma(t_x) + c_x \\ b_y = \sigma(t_y) + c_y \\ b_w = p_w \cdot e^{t_w} \\ b_h = p_h \cdot e^{t_h} bx=σ(tx)+cxby=σ(ty)+cybw=pw⋅etwbh=ph⋅eth
其中:
def decode_box(output_tensor, anchors):
bboxes = []
for i in range(H): # height
for j in range(W): # width
for k in range(B): # anchor index
tx, ty, tw, th = output_tensor[i, j, k*85:(k+1)*85][:4]
conf = output_tensor[i, j, k*85+4]
class_probs = output_tensor[i, j, k*85+5:k*85+7]
bx = sigmoid(tx) + j * stride_x
by = sigmoid(ty) + i * stride_y
bw = anchors[k][0] * exp(tw)
bh = anchors[k][1] * exp(th)
x1 = (bx - bw/2) * image_size
y1 = (by - bh/2) * image_size
x2 = (bx + bw/2) * image_size
y2 = (by + bh/2) * image_size
bboxes.append([x1, y1, x2, y2, conf, class_probs])
return bboxes
YOLOv4 支持 DIoU-NMS,提升了密集目标场景下的性能。
score = confidence × max ( class_probs ) \text{score} = \text{confidence} \times \max(\text{class\_probs}) score=confidence×max(class_probs)
import torch
from yolov4.ops import diou_nms
# boxes: [N, 4],scores: [N]
keep_indices = diou_nms(boxes, scores, iou_threshold=0.45)
final_boxes = boxes[keep_indices]
final_scores = scores[keep_indices]
final_labels = labels[keep_indices]
阶段 | 内容 |
---|---|
✅ 输入图像 | 608 × 608 × 3 RGB 图像 |
✅ 数据增强 | Mosaic + HSV 扰动 |
✅ 正样本划分 | anchor 与 GT IoU 最大者为正样本 |
✅ 输出结构 | 三层输出:20×20、40×40、80×80 |
✅ 损失函数 | CIoU Loss + BCE Loss |
✅ 推理输出 | 每个 bounding box 包含 (x1, y1, x2, y2, score, label) |
✅ NMS | 默认 DIoU-NMS,阈值 0.45 |
✅ 支持 Anchor | 9 个 anchor boxes,K-Means 聚类获得 |
[yolo]
mask = 6,7,8
anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401
classes=2
num=9
jitter=.3
ignore_thresh=.7
truth_thresh=1
scale_x_y=1.05
iou_thresh=0.213
iou_normalizer=0.07
✅ 这些配置项在 AlexeyAB/darknet 中真实存在,影响 anchor 匹配、loss 计算、NMS 等流程。
模型 | mAP@COCO | FPS(V100) | 是否支持 DIoU-NMS |
---|---|---|---|
YOLOv4 | ~43.5 | ~35 | ✅ 支持 |
YOLOv4-tiny | ~37.0 | ~75 | ✅ 支持 |
YOLOv4-CSP | ~45.0 | ~30 | ✅ 支持 |
局限性 | 说明 |
---|---|
❌ 不支持 Soft-NMS | 需要自定义修改 |
❌ anchor 设置固定 | 新任务需重新聚类适配 |
❌ 输出结构固定 | 不适合直接部署 ONNX |
❌ 模型较重 | 相比 YOLOv5/YOLOX 更慢一些 |
YOLOv4 是目标检测发展史上的一个重要里程碑,它首次将 Mosaic 数据增强、CIoU Loss、DIoU-NMS、PANet 等多种先进方法集成于单阶段检测器中,实现了精度与速度的平衡。
欢迎点赞 + 收藏 + 关注我,我会持续更新更多关于目标检测、YOLO系列、深度学习等内容!