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] - [30,61, 62,45, 59,119] - [116,90, 156,198, 373,326]
|
模型主干:
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 缩放,因为其维度固定为:
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 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。
目标构建步骤:
- 每个目标复制到每个 Anchor
- 按当前检测层网格尺寸缩放坐标
- 比较目标宽高与 Anchor 宽高比例
- 最大正反比例小于
anchor_t 才匹配
- 位于网格边缘的目标额外分配到上/下/左/右邻格
- 输出类别、回归框、索引和匹配 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() 按 images → labels、扩展名 → .txt 自动映射。
5.9 数据加载与缓存
LoadImagesAndLabels:
- 扫描目录或图片清单
- 校验图像和标签
- 把标签、尺寸、分割多边形写入
.cache
- 用文件 hash 和 cache version 判断缓存是否失效
- 可把图片缓存到 RAM 或
.npy
- 矩形训练时按宽高比排序,降低 padding
5.10 数据增强
增强分为两条互斥主路径:
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 也参与训练。mosaic 和 scale 对小数据集帮助大,但过强会造成训练分布与真实场景不一致。
5.12 AutoAnchor
训练前 check_anchors() 比较数据集目标宽高和模型 Anchor。适配度差时会重新聚类/进化 Anchor。
修改输入尺寸或目标尺度分布后,应重新检查 Anchor;加载预训练权重但自定义了模型 Anchor 时,训练代码会避免迁移不兼容的 Anchor 状态。