状态:草稿(2026-10-13),部分实测。 示例为笔记本电脑 CPU 亲测的数值(
code/04_losses.py,1 秒以内)。论文数据摘自原文献并标注了条件。 编写规则:实测数据为基本原则,未测出的项标记为“未实测”。
目录
1. 损失函数就是“评分标准”
正如第 1 篇中所见,训练本质上是朝着减少损失的方向调整权重的过程。因此,模型学到什么完全取决于 如何设定损失函数。如果评分标准是“错误题目的数量”,学生就会倾向于去答对很多简单的题目;如果是“对难题给予加分”,就会把精力花在难题上。在目标检测中,这种差异实际上会成为一个大问题。
2. 交叉熵
分类任务的基础损失是 交叉熵(CE)。如果把模型给出的正确类别的概率设为 p_t ,那么损失就是 −log(p_t) 。如果给正确类别预测 1,损失为 0;如果接近 0,损失会趋于无限大。
| p_t | 0.1 | 0.5 | 0.9 | 0.99 |
|---|---|---|---|---|
| CE | 2.303 | 0.693 | 0.105 | 0.010 |
(直接计算。)对于已经预测得很准的样本(p_t = 0.9),损失仍然高达 0.1。单个来看可能很小,但如果这样的样本 非常多 ,情况就完全不同了。
3. focal loss:让简单的样本安静下来
问题:10 万个背景网格
单阶段检测器(第 6 篇)会对图像中预先铺设在各个位置的每个框(锚框,anchor)判断“是否为物体”。RetinaNet 论文中指出,单张图片上的这种候选框大约有 10 万个。其中只有极少数是物体,其余的都是天空、墙壁和地面。绝大多数都是模型很容易就能准确判定为“背景”的简单样本。
我们亲自计算了一下。这是已经预测准确的 10 万个背景网格(p_t 为 0.95–0.999)与尚未预测准确的 100 个物体网格(p_t 为 0.05–0.5)的损失总和。
| 损失 | 10 万个背景网格的总和 | 100 个物体网格的总和 | 物体占总体的份额 |
|---|---|---|---|
| 交叉熵 | 2,595.7 | 145.7 | 5.3% |
| focal (γ=2) | 3.3 | 91.2 | 96.5% |
(实测, code/04_losses.py [2]。)在使用 CE 时,95% 的训练信号来自“已经认识的事物”。真正需要学习的物体却被噪声淹没了。
解法:乘以 (1 − p_t)^γ
Lin 等人提出的 focal loss 在 CE 的基础上乘以了 (1 − p_t)^γ 。
FL(p_t) = −α_t · (1 − p_t)^γ · log(p_t)
当 p_t 接近 1 时,即简单的样本, (1 − p_t)^γ 接近 0,从而使损失几乎消失,而困难的样本则几乎保持不变。当 γ=2 时,p_t=0.9 的样本损失是 CE 的 1/100,p_t=0.99 时则是 1/10,000(如上图曲线所示,直接计算结果与论文说明一致)。
论文数据:γ=2 的效果最好,在 0.5–5 的范围内也没有太大波动。当 γ=2 时,α=0.25 的效果最好,但与 α=0.5 相比,AP 仅相差 0.4。损失计算作用于大约 10 万个锚框的整体,并除以分配给真实标签的锚框数量。使用该损失函数训练的单阶段检测器 RetinaNet(ResNet-101-FPN,短边 800px,包含尺度抖动增强且训练时间延长 1.5 倍)在 COCO test-dev 上达到了 39.1 AP ,超越了当时的双阶段检测器。
回顾这种设计的意义,过去人们是通过 采样来丢弃简单的背景(只挑选困难的负样本进行训练)。而 focal loss 没有丢弃它们,而是 连续地降低其权重 。它用损失函数的一行代码替代了数据筛选。
4. 热图损失
第 3 篇中的热图输出是用什么损失来训练的呢?主要有两种分支。
- MSE:真实高斯峰值与预测图之间按像素计算的均方误差。Stacked Hourglass 和 HRNet 采用这种方法。
- 减分较少的 focal:CornerNet(2018)将其用于角点热图,CenterNet(2019)随后将其用于物体中心热图。对于真实点(值为 1)采用类似 focal 的损失,而其余像素则乘以
(1 − 정답값)^β,从而 对真实点附近的像素给予较轻的惩罚。 其中使用 α=2, β=4,并除以真实点的数量。
我们在 64×64 的热图上,针对 σ=2 的真实峰值测量了几种预测结果的损失(实测)。
| 预测 | MSE | 减分较少的 focal |
|---|---|---|
| 全为 0(什么也没找到) | 0.00307 | 9.21 |
| 完全吻合真实值 | 0.00000 | 0.31 |
| 偏移 1 个像素的峰值 | 0.00037 | 0.66 |
| 偏移 4 个像素的峰值 | 0.00388 | 14.73 |
从 MSE 这一侧来看,“什么也没找到”(0.00307)的损失比“偏移 4 个像素”(0.00388) 还要低 。由于大部分像素都是 0 的地图求了平均,对模型而言,与其把峰值画在错误的地方,不如全部涂成 0 带来的损失更小。这就是为什么在训练初期,热图模型有时会陷入“全盘归零”的状态。减分较少的 focal 因为除以了真实点的数量,所以数值大小不会淹没在像素数量中,它对“全盘归零”也会施加很大的损失(9.21)。不过在这个例子中,偏移 4 个像素受到的惩罚比“全盘归零”还要重。这张表展示了不同的损失函数对于“什么更糟糕”有着不同的定义。
5. 数据增强
数据增强就是在训练时提前向模型展示实际中可能遇到的变化。增强什么,实际上就等于宣告了“模型应该忽略哪些变化”。
- AlexNet(2012):通过随机裁剪 + 左右翻转,将训练数据实际上扩大了 2048 倍,并通过颜色抖动将 top-1 错误率降低了 1% 以上(第 1 篇)。
- U-Net(2015):弹性变形,因为细胞在现实中确实会发生这种弯曲(第 3 篇)。
- mixup(2018):以相同的比例混合两张图像和两个标签。
x̃ = λx_i + (1−λ)x_j,ỹ = λy_i + (1−λ)y_j,其中 λ 采样自 Beta(α, α)。当对 ImageNet 上的 ResNet-50 进行 200 个周期的训练时,top-1 错误率从 23.6% 下降到了 22.1%(α=0.2),但在 90 个周期时,从 23.5% 下降到 23.3%,收益较小。当有余力进行长时间训练时,数据增强的效果最为显著。 - 第 7 篇中的 ViT 系列(DeiT)极大地依赖于数据增强。如果同时去掉 mixup 和 CutMix,ImageNet 的 top-1 准确率就会从 81.8% 下降到 75.8%。
数据增强必须与标签同步修改。如果将图像左右翻转,不仅球的 x 坐标需要改变,姿态标签中的“左手·右手”名称也需要更改。在乒乓球运动中,时间轴也必须格外小心。如果把连续帧输入寻球模型,却给它输入了帧顺序颠倒的视频,球的运动方向就会发生错乱。
6. 学习率调度与大批次
学习率是梯度下降的步幅。经验表明,与其从头到尾使用相同的步幅,不如动态调整效果更好。
- 热身(Warmup):前几个周期从较小的学习率线性增加到目标值。由于随机初始化的权重梯度非常剧烈,如果一开始就使用大步幅,模型很容易发生发散。
- 余弦退火(SGDR, 2017):
η_t = η_min + ½(η_max − η_min)(1 + cos(π·T_cur/T))。起初减慢,中期加快,最后再次减慢。原始论文提出了每个周期重新增大学习率(重启)的方案,但在实际应用中,很多情况下不进行重启,只使用一个周期。
热身 5 个周期 + 余弦退火,总共 100 个周期,最高值为 0.1(直接计算)。
에폭 0 2 4 5 25 50 75 99
lr 0.020 0.060 0.100 0.100 0.089 0.054 0.016 0.000
大批次的线性缩放规则。 Goyal 等人(2017)提出,如果将小批量(minibatch)扩大 k 倍,学习率也应该扩大 k 倍(lr = 0.1 · 배치/256)。不过,这需要在前 5 个周期内进行从 0.1 逐渐增加到 3.2 的热身。通过这种方式,他们使用批次大小为 8192、256 张数据中心 GPU,在短短 1 小时 内完成了 90 个周期的训练,其 ImageNet 验证集 top-1 错误率为 23.74%(±0.09),与批次大小为 256 的基准线 23.60%(±0.12)相差无几。如果没有热身,错误率则高达 24.84%。
7. 混合精度
GPU 计算 16 位浮点数(半精度)的速度远快于 32 位,并且只消耗一半的内存。然而,如果直接切换到 16 位,训练就会崩溃。我们亲自对此进行了验证(实测)。
FP16 가장 작은 정규수 6.10e-05, 가장 큰 수 65504
FP32 기울기 3.00e-04 2.00e-06 5.00e-08 1.00e-08
FP16 로 바로 3.00e-04 2.03e-06 5.96e-08 0.00e+00 ← 1e-8 이 0 이 되고 5e-8 은 6e-8 로 뭉개진다
×1024 → FP16 → ÷1024 3.00e-04 2.00e-06 5.00e-08 1.00e-08 ← 손실 스케일
FP16 가중치 1.0 에 1e-4 를 더하면 1.0 ← 갱신이 사라진다
这里出现了两个问题:极小的梯度会变成 0(下溢),而将小的更新值加到大的权重上时,数值会因舍入而消失。Micikevicius 等人(2018)提出的混合精度训练通过以下三种方法防止了这些问题:
- FP32 主权重:保留一份权重的 32 位副本并在其上进行更新。仅在计算时四舍五入为 16 位(上述最后一行问题的解法)。
- 损失缩放(Loss Scaling):在反向传播之前,将损失乘以一个较大的数(论文中在 8 到 32K 之间,许多网络并不需要),将梯度提升到 FP16 可以表示的范围内,并在更新前除以该数(上述第三行)。
- FP32 累加:将 16 位乘法的结果以 32 位进行累加。
论文报告称,虽然权重副本使权重内存增加了 50%,但占据内存大部分的激活值变为了 16 位,因此整体训练内存几乎减少了一半。如今,由于广泛使用指数范围与 FP32 相同的 bfloat16 ,即使没有损失缩放也很少发生下溢。SAM 2 论文的速度测量也是通过 bfloat16 自动混合精度进行的(第 10 篇)。
8. 局限性与我们的项目
- 损失函数会忠实地学习 标签的约定。TT Score 的 BlurBall 将标签的标注位置从模糊球的边缘改到了 中心,相同架构的模型在快球召回率上有了显著提升(TT Score 模型剖析第 2 篇)。更改标签规则和更改损失函数一样,都是在改变“评分标准”。
- 虽然可以通过数据增强提前展示退化条件(昏暗、低分辨率、长曝光),但我们尚未用这种增强重新训练,退化条件仅用于 评估(同文第 6 节)。使用手机视频进行的微调正在进行中。
- focal loss 的 γ、学习率、热身长度等参数都是需要针对具体问题重新调整的值。论文中的数值仅仅是一个起点。
从下一篇开始将进入目标检测。首先我们来看双阶段检测器(R-CNN → Faster R-CNN)与锚框。
Titi 的碎碎念。 如果 10 万个背景网格一起喊着“就是那个背景!”,就会盖过一个球的声音。Focal Loss 就是让那些已经预测正确的网格安静下来。
参考文献
- Lin, T.-Y., Goyal, P., Girshick, R., He, K., Dollár, P. (2017). Focal Loss for Dense Object Detection. ICCV 2017. https://arxiv.org/abs/1708.02002
- Law, H., Deng, J. (2018). CornerNet: Detecting Objects as Paired Keypoints. ECCV 2018. https://arxiv.org/abs/1808.01244
- Zhou, X., Wang, D., Krähenbühl, P. (2019). Objects as Points. arXiv. https://arxiv.org/abs/1904.07850
- Zhang, H., Cisse, M., Dauphin, Y. N., Lopez-Paz, D. (2018). mixup: Beyond Empirical Risk Minimization. ICLR 2018. https://arxiv.org/abs/1710.09412
- Loshchilov, I., Hutter, F. (2017). SGDR: Stochastic Gradient Descent with Warm Restarts. ICLR 2017. https://arxiv.org/abs/1608.03983
- Goyal, P. et al. (2017). Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour. arXiv. https://arxiv.org/abs/1706.02677
- Micikevicius, P. et al. (2018). Mixed Precision Training. ICLR 2018. https://arxiv.org/abs/1710.03740
- Touvron, H. et al. (2021). Training data-efficient image transformers & distillation through attention. ICML 2021. https://arxiv.org/abs/2012.12877
- 示例代码与输出:此文件夹中的
code/04_losses.py,code/04_losses.out.txt