YOLOv5 7.0:模型损失与数据

05 模型损失与数据

5.1 YOLOv5s YAML

models/yolov5s.yaml 的关键配置:

1
2
3
4
5
6
7
nc: 80
depth_multiple: 0.33
width_multiple: 0.50
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

模型主干:

1
2
3
4
5
6
Conv(stride=2)
→ Conv+C3
→ P3/8
→ P4/16
→ P5/32
→ SPPF

Neck 使用上采样与 Concat 构成 FPN/PAN,最后把第 17、20、23 层送入 Detect

5.2 深度和宽度缩放

parse_model() 的规则:

1
2
实际重复数 = max(round(number × depth_multiple), 1)
实际通道数 = make_divisible(channels × width_multiple, 8)

因此 n/s/m/l/x 可以复用相同类型的拓扑定义,只改变容量。

输出层通道数不能按普通 width multiple 缩放,因为其维度固定为:

1
na × (nc + 5)

5.3 C3 与 SPPF

C3

C3 是 CSP 风格模块:

  • 一支经过若干 Bottleneck
  • 一支较短旁路
  • 两支 Concat 后再卷积

它在控制计算量的同时保留梯度路径,是 YOLOv5 backbone/neck 的主体。

SPPF

SPPF 用同一个 5×5 MaxPool 串行执行三次,得到等效 5/9/13 感受野,再拼接。相对传统并行 SPP,结构更简单、速度更快。

5.4 检测头输出

P5 模型有三层输出,每层三个 Anchor。训练输出:

1
B × 3 × H × W × (nc+5)

其中:

1
2
3
4
0:2  → xy
2:4 → wh
4 → objectness
5: → class logits

640 输入、80 类时,三层形状近似:

1
2
3
[B, 3, 80, 80, 85]
[B, 3, 40, 40, 85]
[B, 3, 20, 20, 85]

候选总数:

1
3 × (80² + 40² + 20²) = 25200

5.5 推理解码

Detect.forward() 对每层:

1
2
3
xy = (sigmoid(xy) * 2 + grid) * stride
wh = (sigmoid(wh) * 2) ** 2 * anchor_grid
conf = sigmoid(conf)

grid-0.5 偏移,因此中心可预测到相邻网格附近。宽高公式将范围扩大到约 0~4 倍 Anchor。

解码结果是中心点格式 xywh;NMS 前再转换成 xyxy。

5.6 Anchor 匹配与目标构建

入口:utils/loss.py::ComputeLoss.build_targets()

输入目标每行:

1
[image_index, class, x, y, w, h]

坐标是相对图片归一化的 xywh。

目标构建步骤:

  1. 每个目标复制到每个 Anchor
  2. 按当前检测层网格尺寸缩放坐标
  3. 比较目标宽高与 Anchor 宽高比例
  4. 最大正反比例小于 anchor_t 才匹配
  5. 位于网格边缘的目标额外分配到上/下/左/右邻格
  6. 输出类别、回归框、索引和匹配 Anchor

这种一对多分配提高了正样本数量。

5.7 检测损失

Box Loss

1
lbox = mean(1 - CIoU(pred_box, target_box))

CIoU 同时考虑:

  • 重叠面积
  • 中心点距离
  • 宽高比一致性

Objectness Loss

每个网格/Anchor 都有 Objectness BCE。正样本目标值不是固定 1,而是与匹配框的 IoU 相关:

1
tobj[b, a, gj, gi] = detached IoU

P3/P4/P5 默认 balance 为 [4.0, 1.0, 0.4],用于平衡不同尺度网格数量。

Classification Loss

多类别时对类别 logits 使用 BCEWithLogitsLoss。可启用:

  • label_smoothing
  • fl_gamma > 0 的 Focal Loss

总损失

1
2
3
4
5
loss = batch_size × (
box_gain × lbox +
obj_gain × lobj +
cls_gain × lcls
)

train.py 还会按检测层数、类别数和图像尺寸调整三项 gain。

5.8 数据集格式

数据集 YAML 示例:

1
2
3
4
5
6
7
path: ../datasets/mydata
train: images/train
val: images/val
test:
names:
0: person
1: car

检测标签为每张图片对应的 .txt

1
class x_center y_center width height

四个坐标均归一化到 0~1。目录通常为:

1
2
3
4
5
mydata/
├── images/train
├── images/val
├── labels/train
└── labels/val

img2label_paths()imageslabels、扩展名 → .txt 自动映射。

5.9 数据加载与缓存

LoadImagesAndLabels

  • 扫描目录或图片清单
  • 校验图像和标签
  • 把标签、尺寸、分割多边形写入 .cache
  • 用文件 hash 和 cache version 判断缓存是否失效
  • 可把图片缓存到 RAM 或 .npy
  • 矩形训练时按宽高比排序,降低 padding

5.10 数据增强

增强分为两条互斥主路径:

读取图像"本次使用 Mosaic?"load_mosaic: 4图拼接Copy-Paste + 随机透视可选 MixUp(再加载一组 Mosaic)Letterbox随机透视/旋转/平移/缩放/剪切可选 AlbumentationsHSV上下/左右翻转BGR→RGB, HWC→CHW

Mosaic

把当前图片和三张随机图放入 2×2 大画布;load_mosaic() 内部完成 Copy-Paste(启用时)和随机透视。返回 __getitem__() 后还可与另一组 Mosaic 做 MixUp。优点:

  • 一次看到更多物体
  • 小目标更丰富
  • 减少对大 batch 的依赖

Rectangular Training

按宽高比排序,同一 batch 使用接近的矩形尺寸,可减少灰边,但会禁用 Mosaic。

DDP 下,标签缓存的首次扫描通过 torch_distributed_zero_first() 让本地 Rank 0 优先完成,其他进程随后复用,避免同时重复构建 .cache

5.11 超参数

data/hyps/hyp.scratch-low.yaml 分四组:

  • 优化:lr0/lrf/momentum/weight_decay/warmup_*
  • 损失:box/cls/obj/*_pw/fl_gamma
  • 匹配:iou_t/anchor_t
  • 增强:hsv_* / degrees / translate / scale / shear / perspective / flip* / mosaic / mixup

anchor_t 太小会减少正样本;太大会让不合适的 Anchor 也参与训练。mosaicscale 对小数据集帮助大,但过强会造成训练分布与真实场景不一致。

5.12 AutoAnchor

训练前 check_anchors() 比较数据集目标宽高和模型 Anchor。适配度差时会重新聚类/进化 Anchor。

修改输入尺寸或目标尺度分布后,应重新检查 Anchor;加载预训练权重但自定义了模型 Anchor 时,训练代码会避免迁移不兼容的 Anchor 状态。

文章互动

阅读 --

留言

0 条留言

正在加载留言…