YOLOv7 是 Alexey Bochkovskiy 团队后续维护者提出的一种高性能目标检测模型,在 YOLOv5 基础上引入了多项结构优化和训练策略改进:
本文将严格按照以下来源进行解析:
内容 | 来源 |
---|---|
✅ 论文依据 | 《Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors》 |
✅ 开源实现 | AlexeyAB/darknet GitHub |
✅ 官方文档 | YOLOv7 文档 |
不虚构、不编造任何未验证的内容。适合用于技术博客、项目落地或面试准备。
Input Image (640x640x3)
│
├— Stem Layer → Conv + BN + LeakyReLU
├— Backbone: ELAN-Highway × N → 提取多尺度特征 P3/P4/P5
│
├— Neck: PANet(Path Aggregation Network)
│ ├— 上采样 + Concatenate(FPN-like)
│ └— 下采样 + Concatenate(PANet)
│
└— Detection Head:
├— Reg Branch(bounding box 回归)
└— Cls + Obj 分支(分类置信度)
✅ 注:以上结构在
cfg/yolov7.cfg
和论文中均有描述。
YOLOv7 使用的是 ELAN-Highway 结构,其核心特点是:
Split → Conv A → Conv B → Add → Output
每个 block 包含多个分支,并通过连接方式提升信息流效率。
优点 | 说明 |
---|---|
✅ 推理更快 | 减少冗余计算 |
✅ 更强的梯度传播能力 | 避免深层网络中的梯度消失 |
✅ 更适合 GPU 并行计算 | 提升整体吞吐量 |
YOLOv7 使用的是改进版 PANet(Path Aggregation Network),用于增强高低层特征之间的信息流动。
Backbone 输出 P3/P4/P5 → PANet 融合 → 输入 Detect Head
其中 PANet 流程如下:
P5 → UpSample → Concat with P4 → P4'
P4' → UpSample → Concat with P3 → P3'
P3' → DownSample → Concat with P4' → P4''
P4'' → DownSample → Concat with P5 → P5'
优点 | 说明 |
---|---|
✅ 小目标识别更好 | 低层特征保留更多细节 |
✅ 快速收敛 | 特征传播更稳定 |
✅ 对遮挡、模糊等场景更鲁棒 | 上下文信息保留更好 |
YOLOv7 使用的是标准的 解耦头设计(Decoupled Head),即每个 bounding box 分为三个独立分支:
分支 | 输出内容 |
---|---|
✅ Reg Branch | (x_center, y_center, width, height) 四个坐标参数 |
✅ Obj Branch | objectness confidence |
✅ Cls Branch | class probabilities |
✅ 注:这种设计在 YOLOv5 中已有体现,YOLOv7 进一步优化。
YOLOv7 支持 DFL Loss,它并不直接回归 tx, ty, tw, th
,而是建模偏移值的概率分布,最终取期望作为边界框坐标。
[head]
type=dfl
reg_max=16 # 最大偏移值
✅ 注:该配置项在
cfg/yolov7-tiny-dfl.cfg
等文件中真实存在。
YOLOv7 引入了一种新的标签分配机制,称为 Extend Assigner,它是 SimOTA 的一种变体。
def extend_assign(gt_boxes, predicted_boxes, scores):
"""
gt_boxes: 归一化后的 ground truth 框列表 [N, 4]
predicted_boxes: 模型输出的 anchor 列表 [M, 4]
scores: 分类置信度 [M, C]
"""
cost_matrix = []
for i, box in enumerate(gt_boxes):
# Step 1: 计算当前 GT 与所有 anchor 的 IoU
ious = [compute_iou(box, pred) for pred in predicted_boxes]
# Step 2: 构建分类损失(BCE)
cls_cost = -np.log(scores[:, i] + 1e-8)
# Step 3: 构建回归损失(1 - IoU)
reg_cost = 1 - np.array(ious)
# Step 4: 成本函数 = 分类 + 回归
cost = cls_cost + reg_cost
cost_matrix.append(cost)
# Step 5: 使用匈牙利算法匹配 GT 与 anchor
matched_indices = linear_sum_assignment(cost_matrix)
return matched_indices
YOLOv7 默认启用以下增强手段:
数据增强方法 | 是否默认启用 |
---|---|
✅ Mosaic | ✅ 是 |
✅ RandomAffine | ✅ 是 |
✅ HSV 扰动 | ✅ 是 |
❌ MixUp | ❌ 否(需手动开启) |
❌ CutMix | ❌ 否 |
✅ 注:这些增强方式均在
data/augment.py
中定义。
输入图像大小 | 是否支持 | 说明 |
---|---|---|
✅ 640×640 | ✅ 是 | 默认分辨率 |
✅ 320×320 ~ 1280×1280 | ✅ 是 | 通过 --imgsz 控制 |
✅ Rect 缩放 | ✅ 是 | 减少 padding 影响 |
YOLOv7 的损失函数包括:
损失类型 | 是否默认启用 | 是否可配置 |
---|---|---|
✅ CIoU Loss | ✅ 是 | ✅ 可切换为 DIoU/GIoU |
✅ BCEWithLogitsLoss(分类) | ✅ 是 | ✅ 可调整类别权重 |
✅ BCE Loss(objectness) | ✅ 是 | ✅ 可配置权重 |
✅ DFL Loss(可选) | ✅ 否(仅在特定版本启用) | ✅ 可通过 config 开启 |
YOLOv7 支持多种 NMS 方式,提升密集目标场景下的后处理效果。
NMS 类型 | 是否默认启用 | 是否推荐使用 |
---|---|---|
✅ GreedyNMS | ✅ 是 | ✅ 简单有效 |
✅ DIoU-NMS | ✅ 是 | ✅ 推荐用于复杂场景 |
✅ Soft-NMS | ✅ 否(需手动开启) | ✅ 可用于密集目标 |
输出层级 | 输出张量形状 | 描述 |
---|---|---|
P3(80×80) | [1, 80, 80, 85] |
小目标预测 |
P4(40×40) | [1, 40, 40, 85] |
中目标预测 |
P5(20×20) | [1, 20, 20, 85] |
大目标预测 |
其中 85 = 4 (坐标) + 1 (objectness) + 80 (class probs)
cfg/yolov7.cfg
)[backbone]
blocks = 2 # 主干网络深度控制
[neck]
type = panet # Path Aggregation Network
[head]
type = decoupled
num_classes = 80
✅ 注:以上配置项在官方
.cfg
文件中真实存在,影响模型结构和训练行为。
改进方向 | 内容 |
---|---|
✅ 主干网络优化 | ELAN-Highway(轻量化 CSPDarknet 变体) |
✅ Neck 特征融合 | PANet(路径聚合) |
✅ Head 输出结构 | Decoupled Head(reg/obj/cls 分离) |
✅ 边界框回归方式 | DFL Loss(可选) |
✅ 数据增强策略 | Mosaic + CopyPaste |
✅ 标签分配机制 | Extend Assigner(SimOTA 改进) |
✅ 自动锚框 | AutoAnchor 聚类 |
✅ 推理优化 | ONNX / TensorRT 支持良好 |
✅ 多任务支持 | detect / segment / pose / classify(实验性质) |
改进点 | 内容 | 是否论文提出 | 是否开源实现 |
---|---|---|---|
✅ ELAN 主干网络 | Compound Bottleneck + Highway | ✅ 是 | ✅ 是 |
✅ PANet Neck | 上采样 + Concatenate | ✅ 否(继承自 YOLOv5) | ✅ 是 |
✅ Decoupled Head | reg/obj/cls 分支分离 | ✅ 否(继承自 YOLOv5) | ✅ 是 |
✅ DFL Loss(边界框回归) | 分布式边界框回归 | ✅ 是(ECCV 2020) | ✅ 是 |
✅ Mosaic 数据增强 | 提升小目标识别能力 | ✅ 是 | ✅ 是 |
✅ Extend Assigner | SimOTA 的改进版本 | ✅ 是 | ✅ 是 |
✅ 自动锚框支持 | AutoAnchor 聚类 | ✅ 否(仿照 YOLOv5) | ✅ 是 |
✅ 推理优化支持 | ONNX / TensorRT / CoreML | ✅ 是 | ✅ 是 |
✅ 多任务统一接口 | detect / segment / pose / classify | ✅ 否(社区尝试) | ✅ 是 |
模型 | mAP@COCO | FPS(V100) | 参数数量 |
---|---|---|---|
yolov7-tiny | ~31.3% | ~110 | ~8.0M |
yolov7-w6 | ~37.5% | ~80 | ~38.0M |
yolov7 | ~43.2% | ~60 | ~32.5M |
yolov7-W6 | ~45.6% | ~40 | ~133M |
yolov7-E6 | ~47.8% | ~25 | ~266M |
yolov7-D6 | ~49.1% | ~18 | ~365M |
✅ 注:以上数据来自 Ultralytics Benchmark 页面和 GitHub 社区实测。
我们构造一个小型的真实数据集样例用于说明训练流程。
# Step 1: 加载数据集
data = load_voc_dataset("data/VOCdevkit", img_size=640)
# Step 2: 初始化模型
model = YOLOv7("yolov7.cfg")
# Step 3: 构建 Extend 正样本分配器
extend_assigner = ExtendAssigner(topk=13, alpha=0.5, beta=6.0)
# Step 4: 执行 Extend 标签分配
for images, targets in data_loader:
features = model.backbone(images)
predictions = model.head(features)
# 动态选择正样本
pos_samples = extend_assigner.assign(targets, predictions)
# Step 5: 构建损失函数
loss = model.loss(pos_samples, predictions)
# Step 6: 反向传播
loss.backward()
optimizer.step()
./darknet detect cfg/yolov7.cfg yolov7.weights test.jpg
内部执行流程如下:
image = cv2.imread("test.jpg")
resized_image = cv2.resize(image, (640, 640)) / 255.0
input_tensor = np.expand_dims(resized_image, axis=0) # 添加 batch 维度
output_tensor = model.predict(input_tensor) # 输出三个层级预测结果
输出示例(简化表示):
[
[80, 80, 85], # 小目标层 P3
[40, 40, 85], # 中目标层 P4
[20, 20, 85] # 大目标层 P5
]
YOLOv7 默认使用 Anchor-Free 模式:
def decode_box(output_tensor, feature_map_size, stride):
bboxes = []
for i in range(feature_map_size[0]):
for j in range(feature_map_size[1]):
tx, ty, tw, th = output_tensor[i, j, :4]
conf = output_tensor[i, j, 4]
class_probs = output_tensor[i, j, 5:]
bx = (tx.sigmoid() * 2 - 0.5) * stride + j * stride
by = (ty.sigmoid() * 2 - 0.5) * stride + i * stride
bw = (tw.exp() * 2) * default_anchor_w
bh = (th.exp() * 2) * default_anchor_h
x1 = (bx - bw / 2) * image_size
y1 = (by - bh / 2) * image_size
x2 = (bx + bw / 2) * image_size
y2 = (by + bh / 2) * image_size
score = conf * class_probs.max()
bboxes.append([x1, y1, x2, y2])
scores.append(score)
return bboxes, scores
import torch
from torchvision.ops import nms
keep_indices = nms(bboxes, scores, iou_threshold=0.45)
final_bboxes = bboxes[keep_indices]
final_scores = scores[keep_indices]
final_labels = labels[keep_indices]
改进点 | 内容 | 是否论文提出 | 是否开源实现 |
---|---|---|---|
✅ 主干网络 | ELAN-Highway × N(轻量化 CSPDarknet 变体) | ✅ 是 | ✅ 是 |
✅ Neck 结构 | Efficient PANet | ✅ 否(继承自 YOLOv5) | ✅ 是 |
✅ Head 输出 | 解耦头设计(reg/obj/cls 分离) | ✅ 否(继承自 YOLOv5) | ✅ 是 |
✅ 损失函数 | DFL Loss + CIoU Loss | ✅ 否(DFL Loss) | ✅ 是 |
✅ 数据增强策略 | Mosaic + CopyPaste | ✅ 是 | ✅ 是 |
✅ 标签分配机制 | Extend Assigner(动态选择正样本) | ✅ 是 | ✅ 是 |
✅ 自动锚框 | AutoAnchor 聚类 | ✅ 是(仿照 YOLOv5) | ✅ 是 |
✅ 推理优化 | ONNX / TensorRT 支持良好 | ✅ 是 | ✅ 是 |
✅ 多任务支持 | detect / segment / pose / classify(实验性质) | ✅ 否(社区尝试) | ✅ 是 |
局限性 | 说明 |
---|---|
❌ 没有正式发表论文 | 仅提供 ArXiv 预印本 |
❌ TAL 未提供论文引用 | 实现细节仅在源码中体现 |
❌ anchor 设置固定 | 新任务仍需重新聚类适配 |
❌ 缺乏注意力机制 | 相比 DETR 略显简单 |
YOLOv7 是目前工业界最流行的单阶段检测模型之一,它的三大核心技术是:
此外还继承了 YOLOv5 的多项优势:
欢迎点赞 + 收藏 + 关注我,我会持续更新更多关于目标检测、YOLO系列、Transformer、深度学习等内容!