一个困惑

看端到端自动驾驶的论文时,你会发现同一个任务在不同的文章里用了完全不同的 Loss:

任务UniADVADv2DiffusionDrive
轨迹规划L2 回归 + 碰撞 LossKL 散度(分布匹配)扩散去噪 Loss + 碰撞/边界/舒适
检测Focal LossFocal Loss
占用预测二值交叉熵 + Dice

这还不是最让人晕的——同一篇文章内部,Loss 也在"打架":UniAD 的 Planner 用 L2 回归,但 MotionFormer 用 L1 回归;VADv2 的分布 Loss 对 4096 条轨迹做分类,而 SparseDrive 对锚点做分类 + 残差回归,而 DiffusionDrive 又完全不用任何分类或回归——它用一个扩散去噪 Loss 隐式地学分布。

这些 Loss 背后遵循什么设计逻辑?为什么从 UniAD 到 VADv2 到 DiffusionDrive,Loss 设计的思路一直在变?

答案其实很简单:Loss 的选择反映了你对"驾驶规划"这个问题的建模方式。你对问题的认知变了,Loss 就会变。这篇文章帮大家把每类 Loss 吃透。


一、损失函数的本质

在端到端自动驾驶中,损失函数的核心作用是把"什么样的驾驶是好的"这个模糊目标,翻译成神经网络能理解的数学信号

用个比方:你教一个刚拿驾照的新手开车。

你(教练)说:
  "刚才那个弯转得太急了,下次慢一点"        ← 这是语言反馈

神经网络的 Loss 做的是类似的事:
  L2回归 → "你的轨迹和我的轨迹差了2.3米,扣分"
  碰撞 Loss → "你刚才离路沿只有10厘米了,扣分"
  Focal Loss → "你第三次没认出停止标志了,扣大分"

每种 Loss 都在告诉模型"你哪里做得不够好"。但"不够好"的定义不同,Loss 的数学形式就不同。


二、Loss 是怎么让模型"学会"的?——梯度与反向传播

讲具体 Loss 之前,先搞明白一个更基础的问题:计算了 Loss 之后,模型到底是怎么更新参数的?

很多同学看论文只看 Loss 公式,然后跳过训练过程,结果对"为什么 Loss 长这样"一知半解。这一节用最白话的方式讲清楚。

2.1 先理解这个核心公式

整个深度学习的训练过程,可以用一句话概括:

新参数 = 旧参数 − 学习率 × 梯度

或者写成公式:

\[ \theta_{new} = \theta_{old} - \eta \cdot \frac{\partial \mathcal{L}}{\partial \theta} \]

逐词翻译

符号含义大白话
\(\theta\)模型的参数就是神经网络里所有的权重 W 和偏置 b
\(\mathcal{L}\)Loss 值模型预测得有多差
\(\partial \mathcal{L} / \partial \theta\)梯度参数变化一点点,Loss 会变多少
\(\eta\)学习率每次更新的步长

2.2 梯度是什么?一个例子就懂

假设你只有一个参数 w,Loss 是 w 的函数:ℒ = w²。

w = 3 时:ℒ = 9,梯度 = ∂ℒ/∂w = 2w = 6
  解读:w 增加一点点(比如 0.1),Loss 会增加 6 × 0.1 = 0.6
   → Loss 在 w=3 处"往上走",需要往反方向走 → w 应该减小

w = -2 时:ℒ = 4,梯度 = 2w = -4
  解读:w 增加一点点,Loss 会减少 4 × 0.1 = 0.4
   → Loss 在 w=-2 处"往下走",继续往这个方向走 → w 应该增加

梯度的方向 = Loss 上升最快的方向。所以参数更新时,我们要沿着梯度的反方向走——这就是"梯度下降"名字的由来。

梯度 > 0 → Loss 随参数增大而增大 → 参数应该减小
梯度 < 0 → Loss 随参数增大而减小 → 参数应该增大

梯度下降示意图

2.3 链式法则:为什么叫"反向传播"?

神经网络有很多层,Loss 在最末端,参数在最前面。怎么把 Loss 信号传回前面的层?

答案是链式法则

假设一个 3 层的玩具网络:

输入 x → 层1 (W₁) → h₁ → 层2 (W₂) → h₂ → 层3 (W₃) → ŷ → Loss

我们要算 Loss 对 W₁ 的梯度。W₁ 在最前面,Loss 在最后面,中间隔了:

  • W₁ → h₁ → h₂ → ŷ → Loss

链式法则说:

\[ \frac{\partial \mathcal{L}}{\partial W_1} = \frac{\partial \mathcal{L}}{\partial \hat{y}} \times \frac{\partial \hat{y}}{\partial h_2} \times \frac{\partial h_2}{\partial h_1} \times \frac{\partial h_1}{\partial W_1} \]

逐层相乘,从后往前传

前向传播(蓝色)→:  x → h₁ → h₂ → ŷ → Loss   (逐层计算)
反向传播(红色)←:  ∂ℒ/∂ŷ → ∂ℒ/∂h₂ → ∂ℒ/∂h₁ → ∂ℒ/∂W₁  (从后往前乘回去)

这就是"反向传播"名字的来源——梯度信号从 Loss 出发,沿着网络的反方向逐层传回去

反向传播链式法则

2.4 一个完整的训练步骤(Step-by-Step)

假设 UniAD 的 Planner 输出了一条轨迹 ŷ,GT 轨迹是 y。

第 1 步:前向传播(Forward)
  → 图像进 BEVFormer → 输出 BEV 特征 B
  → B 进 TrackFormer → 输出 agent query Q_A
  → Q_A 进 MotionFormer → 输出 motion feature
  → motion + B 进 Planner → 输出轨迹 ŷ

第 2 步:算 Loss
  ℒ_plan = (ŷ₁ - y₁)² + (ŷ₂ - y₂)² + ... + (ŷ₁₂ - y₁₂)²
  得到:ℒ = 2.34(一个具体的 Loss 值)

第 3 步:反向传播(Backward)
  ∂ℒ/∂W_planner = ?    ← Planner 参数的梯度
  ∂ℒ/∂W_motion = ?     ← MotionFormer 参数的梯度
  ∂ℒ/∂W_track = ?      ← TrackFormer 参数的梯度
  ∂ℒ/∂W_backbone = ?   ← BEVFormer 参数的梯度

  这些梯度通过链式法则逐层算出来。
  注意:UniAD 是端到端的,规划 Loss 的梯度可以一路回传到 backbone!

第 4 步:更新参数
  W_planner_new = W_planner - 0.001 × ∂ℒ/∂W_planner
  W_motion_new  = W_motion  - 0.001 × ∂ℒ/∂W_motion
  ... 所有参数都按这个公式更新

第 5 步:下一轮
  用新的参数再跑一次前向传播 → 算 Loss → 反向传播 → 更新
  重复几千几万次 → Loss 逐渐下降 → 模型越开越好

2.5 为什么 Loss 的数学形式这么重要?

回到 Loss 设计——现在你应该能理解为什么 Loss 的数学形式直接决定了训练效果:

L2 Loss 的梯度:∂ℒ₂/∂ŷ = 2(ŷ - y)
  误差越大,梯度越大 → 大误差样本被优先修正
  问题:异常值主导训练

L1 Loss 的梯度:∂ℒ₁/∂ŷ = sign(ŷ - y)
  误差不管多大,梯度都是 ±1 → 大误差不会崩
  问题:小误差处梯度不变,收敛慢

Smooth L1 的梯度:
  |ŷ-y| < 1 时:梯度 = ŷ - y(像 L2,小误差平滑收敛)
  |ŷ-y| ≥ 1 时:梯度 = ±1(像 L1,大误差鲁棒)

不同 Loss 的梯度行为不同,这才是选择 Loss 时真正要考虑的——不是哪个 Loss 分数高,而是哪个 Loss 的梯度行为符合你的任务需求

2.6 学习率 η 怎么定?

学习率是训练中最关键的超参数之一。

η 太大(比如 0.1):
  θ_new = θ_old − 0.1 × 梯度
  步子太大 → 在 Loss 最低点附近来回震荡,永远不收敛

η 太小(比如 0.00001):
  θ_new = θ_old − 0.00001 × 梯度
  步子太小 → 要跑几百万步才能到最低点,训练极慢

η 适中(比如 0.001):
  刚好每一步都稳定下降 → 又快又好地收敛

实际训练中学习率通常是动态的——学习率衰减(learning rate decay):前几步大(快速接近最优),后面小(精调不震荡)。

2.7 实际训练中常见的"翻车"场景

场景 1:Loss 完全不下降
  原因:学习率太小 / 梯度消失 / 参数初始化不对
  解决:调大学习率 / 检查激活函数(别用 sigmoid 在深层)
         / 用 Xavier/Glorot 初始化

场景 2:Loss 先下降然后突然变 NaN
  原因:梯度爆炸 → 参数一下变得极大 → NaN
  解决:梯度裁剪(gradient clipping)→ 限制梯度最大值
        UniAD 等所有端到端方法都会做梯度裁剪

场景 3:Loss 下降但验证集不降
  原因:过拟合
  解决:加正则化(weight decay)/ dropout / 数据增强

场景 4:Loss 震荡不降
  原因:学习率太大 / batch size 太小
  解决:调小学习率 / 增大 batch size

2.8 这就够了:训练的核心流程

while 没收敛:
    1. 取一批数据(图像 + GT 轨迹)
    2. 前向传播 → 模型输出预测轨迹 ŷ
    3. 算 Loss:ℒ = f(ŷ, y)          ← Loss 函数在起作用
    4. 反向传播:∂ℒ/∂θ ← 链式法则    ← 算出每个参数的梯度
    5. 更新:θ = θ - η × ∂ℒ/∂θ       ← 参数沿着梯度反方向走一步
    6. 如果 Loss 降不下去了 → 收敛

这个流程对 L1、L2、Focal、KL、扩散、碰撞 Loss——对所有 Loss 都完全一样。区别只在第 3 步的 f(ŷ, y) 不同,导致第 4 步的梯度不同,进而导致第 5 步的参数更新方向不同。

这就是为什么 Loss 设计如此重要:它决定了参数更新的方向,而参数更新的方向决定了模型能学到什么。


三、回归损失:找"最优答案"

回归损失是最直观的 Loss——给你一个场景,你认为有一条"正确答案"轨迹,让模型的预测尽量靠近它。

2.1 L1 Loss / MAE(平均绝对误差)

\[ \mathcal{L}_1 = \frac{1}{N} \sum_{i=1}^N |y_i - \hat{y}_i| \]

直觉理解:你和正确答案的距离,绝对差值。预测偏了 1 米,扣 1 分;偏了 3 米,扣 3 分。扣分和偏差成线性关系

梯度特点:梯度始终是 ±1。误差 0.1 米和误差 10 米,梯度大小一样——不会因为某个样本误差特别大就疯狂更新参数。

谁在用:UniAD 的 MotionFormer(轨迹预测)、MapFormer(地图点回归)、SparseDrive(锚点残差回归)

举个例子:UniAD 的 MotionFormer 预测每个智能体未来 3 秒的轨迹。3 秒后的位置本来就很难准确预测,即使同一场景让两个人来标,他们标的轨迹也会有差异——因为未来是不确定的。用 L1 的好处是:即使某个时间点的预测误差很大,它也不会主导整个梯度更新。L1 对"不确定的未来"很宽容。

2.2 L2 Loss / MSE(均方误差)

\[ \mathcal{L}_2 = \frac{1}{N} \sum_{i=1}^N (y_i - \hat{y}_i)^2 \]

直觉理解:偏 1 米扣 1 分,偏 3 米扣 9 分。误差越大的样本,惩罚力度呈平方级增长

梯度特点:梯度 = 2 × (y−ŷ)。误差越大,梯度越大——模型会优先"修正"那些大误差样本。

谁在用:UniAD Planner(规划轨迹回归)、Diffusion Planner(扩散去噪)、ST-P3(端到端规划)

L1 vs L2 的一个经典例子——UniAD 内部的"分裂"

UniAD 的 MotionFormer(运动预测)→ 用 L1
  原因:预测其他车辆的轨迹,3秒后的位置不确定性大
  效果:即使预测错了,也不会因为一个样本就崩掉整个训练

UniAD 的 Planner(规划)→ 用 L2
  原因:自车轨迹是执行信号,需要精确控制
  效果:偏差稍大就受到强烈惩罚,迫使模型输出高精度轨迹

同一个模型、同一个作者,却在两个相邻的模块里用了不同的回归 Loss。这不是失误,是任务目标不同导致的有意识设计

2.3 Smooth L1

ℒ_smooth = 0.5 × x²             当 |x| < 1  (小误差:像 L2 一样平滑收敛)
ℒ_smooth = |x| - 0.5            当 |x| ≥ 1  (大误差:像 L1 一样对异常值鲁棒)

直觉理解:误差小的时候用 L2(平滑),误差大的时候切到 L1(不被异常值带偏)。这是"既要又要"的聪明折中。

谁在用:Faster R-CNN(框回归)、Sparse4D、几乎所有现代 3D 检测器

为什么检测器爱用 Smooth L1? 因为框的标注有系统误差——两个标注员标的 3D 框可能差几厘米,L2 会把这种标注噪声放大,L1 在大误差处梯度不够平滑。Smooth L1 综合了两者优点。

2.4 三张 Loss 的对比图

L1 vs L2 vs Smooth L1 对比

图示解读:

  • L1(蓝线):V 形折线,底部尖锐,两侧斜率为 ±1。梯度处处一样大。
  • L2(红线):抛物线,底部平坦、越往外越陡。误差越大,梯度越大。
  • Smooth L1(绿线):底部像 L2(圆滑),两侧像 L1(直线)。兼顾两者优点。

2.5 怎么选?

场景推荐 Loss原因
训练数据干净,需要快速收敛L2 / MSE大误差梯度大,收敛快
数据有离群值 / 标注噪声L1对异常值不敏感
框回归(检测)Smooth L1兼顾小误差平滑 + 大误差鲁棒
轨迹回归(规划)L1 为主轨迹标注本身噪声大

四、分类损失:选"哪个答案"

4.1 交叉熵

\[ \mathcal{L}_{CE} = -\sum_{c=1}^C y_c \log(\hat{y}_c) \]

直觉理解:模型给正确答案的概率越高,Loss 越低。如果正确答案的概率是 0.9,Loss 很小;如果是 0.1,Loss 很大。

一个直观的例子:假设你要模型判断交通灯——红/黄/绿。正确答案是"红"。

情况A:模型输出 [红:0.9, 黄:0.05, 绿:0.05]  → 交叉熵 = -log(0.9) ≈ 0.1   ← Loss 低
情况B:模型输出 [红:0.3, 黄:0.3, 绿:0.4]   → 交叉熵 = -log(0.3) ≈ 1.2   ← Loss 高
情况C:模型输出 [红:0.01, 黄:0.01, 绿:0.98] → 交叉熵 = -log(0.01) ≈ 4.6  ← Loss 极高

谁在用:几乎所有分类任务——目标检测类别、交通灯状态、驾驶意图

4.2 Focal Loss

\[ \mathcal{L}_{focal} = -\alpha (1 - \hat{y}_c)^\gamma \log(\hat{y}_c) \]

和交叉熵的唯一区别:加了一个调制因子 \((1 - \hat{y}_c)^\gamma\)。

直觉理解:自动驾驶的目标检测有一个棘手的问题——正负样本极度不平衡。一张图像里有几十万个锚点/像素,但其中只有几个是真正的车/人。99.99% 都是背景。如果用普通交叉熵,模型会学会"把全部检测为背景,Loss 就很低"——因为 99.99% 的样本都对了。

Focal Loss 的解法:模型已经分得很好的样本(比如背景概率 0.999),权重被大幅压低;分类错误的难样本(比如车被分类成背景),权重保持不变。

Focal Loss 的两个参数:
  γ(聚焦参数):γ=0 → 退化为标准交叉熵;γ=2 → 常用值,效果显著
  α(平衡参数):正样本权重,处理正负样本数量差异

举个例子(γ=2):
  模型对某个背景预测 0.999:调制因子 = (1-0.999)² = 0.000001,几乎忽略
  模型对某辆车预测 0.6:调制因子 = (1-0.6)² = 0.16,保留大部分梯度

谁在用:UniAD(检测 + 地图)、VAD(检测 + 地图)、SparseDrive(检测 + 地图)、几乎所有自动驾驶检测头

论文原文: “Our novel Focal Loss focuses training on a sparse set of hard examples and prevents the vast number of easy negatives from overwhelming the detector during training.” (Lin et al., ICCV 2017)

3.3 BCE 二值交叉熵

\[ \mathcal{L}_{BCE} = -y \log(\sigma(s)) - (1-y) \log(1-\sigma(s)) \]

直觉理解:BCE 和普通交叉熵的区别在于——不用 softmax 做归一化,每个类别独立用 sigmoid 判断"是还是不是"。

关键区别

softmax(多分类 CE):
  输出 [0.9, 0.05, 0.05] → 概率和为 1
  "三个类别中我选第一个"

sigmoid(多标签 BCE):
  输出 [0.9, 0.8, 0.1] → 各维度独立
  "第一个很可能,第二个也可能,第三个不可能"

谁在用

  • VADv2 规划词表——4096 条轨迹各自独立打分,多个合理动作可以同时高概率
  • OccFormer 占用预测——BEV 中每个格子独立判断"是否被占用"
  • DiffusionDriveV2 两阶段选择器中的粗筛——对每条轨迹做"是否可通行"二分类

4.4 交叉熵 vs Focal Loss vs BCE 总结

损失适用场景特点
交叉熵多分类(N选1)标准分类 Loss
Focal Loss类别极度不平衡压住易分样本,聚焦难样本
BCE多标签分类(可同时选多个)各维度独立,互不排斥

五、分布损失:学"正确答案的分布"

分类损失要求动作之间互斥,回归损失在非凸空间会取平均。当这两种 Loss 都面临根本缺陷时——分布损失出现了。

4.1 为什么需要分布损失?

先看三个 Loss 面对同一个问题时的表现差异:

场景:自车在路口,前方有对向来车
合理动作:减速让行(概率 0.6),加速抢道(概率 0.3),急刹(概率 0.1)

回归 Loss:
  模型学"正确答案" → 取所有合理轨迹的平均 → 输出一条"半减速半加速"的危险轨迹
  这就像让你回答"3和7的平均是什么"——答案是5,但5根本不在选项里

分类 Loss(softmax):
  强制概率和为 1 → 加速和让行的概率互相挤压
  但问题在于:两条都是合理轨迹,概率不应该互相排斥

BCE + sigmoid:
  每条轨迹独立打分 → 加速0.6、让行0.3、急刹0.1
  这才是"多模态"的正确建模方式

这就是 VADv2 采用 BCE + sigmoid 而不是 softmax 的根本原因。

5.2 KL 散度

\[ D_{KL}(P \parallel Q) = \sum_x P(x) \log \frac{P(x)}{Q(x)} \]

直觉理解:KL 散度衡量两个分布的距离——你预测的分布 Q 和真实分布 P 有多像。

VADv2 怎么算数据分布 P_data?

VADv2 的数据分布统计方法:
1. 对训练集中每一帧数据,从规划词表中找到与人类轨迹最匹配的词条
2. 该词条标记为"最佳匹配"
3. 统计所有帧中每个词条成为最佳匹配的频次
4. 归一化 → p_data(a):每条轨迹被人类选择的概率

然后让模型的预测分布 p_pred(a) 尽量接近 p_data(a):
  ℒ_distribution = D_KL(p_data || p_pred) = -∑ p_data(a) · log p_pred(a) + 常数
  (常数是 p_data 的熵,训练中不变,所以等价于最小化交叉熵)

谁在用:VADv2(规划分布)、知识蒸馏(教师分布 → 学生分布)

5.3 扩散 Loss

\[ \mathcal{L}_{simple} = \mathbb{E}_{t, x_0, \epsilon} \left[ \|\epsilon - \epsilon_\theta(x_t, t)\|^2 \right] \]

扩散模型的特殊之处:它的 Loss 既不是回归也不是分类——它预测的是"当前噪声图像里的噪声是什么",而不是"正确答案在哪"。

直觉理解

训练过程:
  1. 拿一条真实轨迹 x₀
  2. 加噪声到时间 t,得到 x_t
  3. 告诉模型:"现在给你 x_t 和时间 t,请猜我加的是什么噪声"
  4. Loss = 预测的噪声和实际加的噪声之间的 MSE
  5. 模型本质上学会了:给定一个"损坏版本",如何一步步恢复原样

推理过程:
  1. 从纯噪声 x_T 开始
  2. 用模型预测当前步该去多少噪声
  3. 去掉一点噪声 → x_{T-1}
  4. 重复直到 x₀(干净轨迹)

关键 Insight:扩散 Loss 隐式地建模了整个数据分布,而不只是"一个正确答案"。因为模型学会的不是"场景→输出"的映射,而是"噪声→数据"的去噪过程。在这个过程中,多样的训练数据使模型学会了多样的轨迹分布。

谁在用

  • DiffusionDrive — 锚定截断扩散 + 安全 Loss 组合
  • Diffusion Planner — 联合预测-规划扩散
  • Gen-Drive — 扩散生成未来场景 + RL 微调

5.4 Flow Matching Loss

\[ \mathcal{L}_{FM} = \mathbb{E}_{t, x_0, x_1} \left[ \|v_\theta(x_t, t) - (x_1 - x_0)\|^2 \right] \]

和扩散 Loss 的区别

扩散:走一条弯曲的随机路径从噪声到数据(SDE)
Flow Matching:走一条从噪声到数据的直线路径(ODE)

扩散路径 → 步数多(50-1000步),质量高
FM 路径 → 步数少(2-10步),速度快

谁在用:π0(机器人 VLA)、GoalFlow(自动驾驶规划)

5.5 分布损失总结

方法Loss本质步数谁在用
VADv2KL 散度(分布匹配)离散词表分类1步VADv2
扩散噪声预测 MSE连续去噪10-1000步DiffusionDrive
Flow Matching矢量场预测直线去噪1-10步π0, GoalFlow

六、安全约束 Loss:让模型学会"绝对不能做什么"

这是端到端自动驾驶最有特色的 Loss 类别——纯模仿学习不管安全

5.1 碰撞 Loss(UniAD)

\[ \mathcal{L}_{collision} = \sum_t \max(0, \text{dist}(\tau_t, O_t) - \text{margin}) \]

直觉理解:模型产出一条规划轨迹 τ,把它和 OccFormer 预测的未来占用 O_t 对比。如果轨迹太靠近占用区域(小于安全距离 margin),就被惩罚。

为什么需要 margin? 你不需要轨迹离障碍物无限远——那会开成"老奶奶开车",安全但没法走。margin = 0.5 米意味着只要轨迹和障碍物保持 0.5 米以上就不扣分,只有小于 0.5 米才被惩罚。

UniAD 消融实验:只有加上了碰撞 Loss,3 秒碰撞率才从 1.58 降到 1.39(降 12%)。再加占用优化,降到 1.05(降 36%)。

6.2 冲突 Loss(VADv2)

\[ \mathcal{L}_{conflict} = \sum_{a \in V} \mathbb{1}_{\text{conflict}}(a) \cdot \log p_{\text{pred}}(a) \]

直觉理解:VADv2 对规划词表里的 4096 条轨迹做两件事:

  • 统计每条轨迹被人类选的频率 → 分布 Loss
  • 判断每条轨迹是否碰撞/偏离道路 → 冲突 Loss

冲突的轨迹被标记为正样本,Log Loss 让它们的概率被压低。

谁在用:VADv2、Hydra-MDP

6.3 DiffusionDrive 的安全 Loss 组合

ℒ_total = ℒ_diff                     ← 学得像人类(扩散 Loss)
         + λ_collision ℒ_collision   ← 别撞上
         + λ_boundary ℒ_boundary     ← 别出车道
         + λ_comfort ℒ_comfort       ← 别急刹急转(jerk 约束)

工程经验:不能只靠扩散 Loss。纯生成目标只关心"分布像不像数据",但驾驶是安全攸关任务。必须把碰撞、合规等硬约束作为辅助 Loss 显式注入。

6.4 碰撞 Loss 的演进

论文安全 Loss方式特点
UniAD碰撞 Loss + 占用优化可微 Loss用 OccFormer 的占用预测做碰撞检查
VAD向量化规划约束可微几何约束把矢量地图变成可微的"安全距离场"
VADv2冲突 Loss词表负采样对词表中冲突轨迹压低概率
DiffusionDrive碰撞 + 边界 + 舒适多 Loss 加权扩散 Loss 做生成 + 三个安全约束

七、多任务 Loss 平衡

7.1 问题:Loss 在打架

端到端模型有 5+ 个 Loss 同时优化。它们天然会打架:

UniAD 的 Loss 构成:
  ℒ = ℒ_track + ℒ_map + ℒ_motion + ℒ_occ + ℒ_plan

每个 Loss 的典型量级:
  ℒ_plan(L2 回归):≈ 1.0 量级
  ℒ_track(Focal + L1):分类 ≈ 0.01,回归 ≈ 0.1
  ℒ_occ(BCE + Dice):≈ 0.5

如果直接相加 → ℒ_plan 的梯度把 ℒ_track 的梯度淹没了
模型学到的全是规划,感知部分几乎不更新

7.2 解决方式 1:手动加权(最简单)

给每个 Loss 手动配权重:

\[ \mathcal{L} = \lambda_1 \mathcal{L}_{track} + \lambda_2 \mathcal{L}_{map} + \lambda_3 \mathcal{L}_{motion} + \lambda_4 \mathcal{L}_{occ} + \lambda_5 \mathcal{L}_{plan} \]

UniAD 就这么干的。缺点是需要反复试,每个权重都是超参数。

7.3 解决方式 2:不确定性加权(最常用)

\[ \mathcal{L} = \sum_i \frac{1}{2\sigma_i^2} \mathcal{L}_i + \log \sigma_i \]

每个任务有一个可学习的 \(\sigma_i\)。任务噪声大 → 权重自动低;任务噪声小 → 权重自动高。

直觉理解:模型的 Loss 自动学会"什么时候该相信哪个任务"。如果跟踪模块当前不确定性高,跟踪 Loss 的权重自动降低,不让它干扰其他任务。

谁在用:多任务分割、Multi-Task Learning Using Uncertainty to Weigh Losses (Kendall et al., 2018) 系列方法

7.4 解决方式 3:两阶段训练(最可靠)

阶段一:各模块分别预训练
  1. 训练 BEVFormer(骨干)
  2. 训练 TrackFormer + MapFormer(感知)
  3. 固定感知,训练 MotionFormer(预测)
  4. 固定 MotionFormer,训练 OccFormer(占用)
  5. 固定所有上游,训练 Planner(规划)

阶段二:端到端联合微调
  1. 打开所有梯度
  2. 规划 Loss 的梯度回传至感知
  3. 各模块在规划目标下做精调

关键经验:直接从头端到端训练一定崩。梯度尺度差异大一两个量级。先让每个模块各自学个差不多,再联合微调。

谁在用:UniAD(经典两阶段)、SparseDrive(逐步端到端)、几乎所有多模块融合的端到端方法

UniAD 多任务 Loss 设计


八、强化学习 Loss:从"模仿"到"探索"

监督学习的学生永远只能学到老师做过的。RL 让模型自己探索"怎么做更好"。

7.1 PPO-Clip(Proximal Policy Optimization)

\[ \mathcal{L}_{PPO} = -\mathbb{E} \left[ \min\left( \frac{\pi_\theta(a|s)}{\pi_{\theta_{old}}(a|s)} A, \text{clip}\left( \frac{\pi_\theta(a|s)}{\pi_{\theta_{old}}(a|s)}, 1-\epsilon, 1+\epsilon \right) A \right) \right] \]

用大白话翻译

1. 旧策略在场景 s 下选了动作 a,获得了"相对优势"A
   (A > 0 表示这个动作比平均水平好,A < 0 表示比平均水平差)

2. 新策略现在要更新自己
   - 对好动作(A > 0):提高选这个动作的概率
   - 对坏动作(A < 0):降低选这个动作的概率

3. 但不准一次改太多
   - clip(ratio, 1-ε, 1+ε):新旧策略的比率不能超过 1±ε
   - 这就像"每次只迈一小步",保证训练的稳定性

谁在用:多智能体交互策略、传统 RL 驾驶

7.2 GRPO(Group Relative Policy Optimization)

GRPO 是 PPO 在端到端自动驾驶中的"特化版本"。

PPO 的痛点:需要训练一个价值网络(critic)来估计"这个状态有多好"。价值网络和策略网络一起训,不稳定且显存翻倍。

GRPO 的解法:不要价值网络了。模型自己生成一组候选轨迹,在这组内部算相对优势。

GRPO 的组内优势计算:
  场景 → 模型生成 8 条候选轨迹 → 每条打分

  候选 A:85 分    候选 B:92 分    候选 C:60 分    ...

  平均分:78 分,标准差:12

  A 的优势 = (85 - 78) / 12 = +0.58  (比平均好)
  B 的优势 = (92 - 78) / 12 = +1.17  (明显好)
  C 的优势 = (60 - 78) / 12 = -1.50  (明显差)

为什么 GRPO 在自动驾驶里尤其流行?因为端到端自动驾驶天然产出一组候选轨迹——你不需要额外采样,模型的前向传播本身就在产出多条候选。组内比较比绝对评分更稳、更简单。

谁在用

  • AlphaDrive-GRPO — 元动作分类 + GRPO 精调
  • AutoVLA — 连续轨迹 + GRPO 后训练
  • DiffusionDriveV2 — 截断扩散 + 锚内 GRPO
  • Flow-GRPO — Flow Matching + GRPO

7.3 DiffusionDriveV2 的截断 GRPO(一个具体例子)

DiffusionDriveV2 把扩散和 GRPO 做了个聪明的结合:

1. 截断扩散:
   - 正常扩散去噪要 100 步
   - 截断扩散只保留最后 2 步的梯度
   - 前面 98 步完全忽略梯度

2. 为何能截断?
   - 扩散的前期去噪是全体的、粗粒度的
   - 后期去噪是局部的、精调的
   - RL 的目标是"精调轨迹质量",所以只对最后几步做 RL

3. 锚内比较:
   - 直行锚的候选和直行锚的候选比
   - 转弯锚的候选和转弯锚的候选比
   - 不同锚之间不直接比较——直行和转弯没有优劣之分

7.4 RL Loss 总结

Loss需要价值网络?计算量谁在用
PPO✅ 是传统 RL 驾驶
GRPO❌ 否AlphaDrive, AutoVLA, Flow-GRPO
REINFORCE❌ 否策略梯度基础方法
截断 GRPO❌ 否DiffusionDriveV2

九、排序 / 对比 Loss

8.1 Margin-Rank Loss

\[ \mathcal{L}_{rank} = \sum_{i,j} \max(0, -(\hat{s}_i - \hat{s}_j) + m) \]

直觉理解:好轨迹的分数要比坏轨迹高至少 m 分。只关注"相对排序"而不关心绝对分数。

谁在用:DiffusionDriveV2 的两阶段选择器——先用 BCE 粗筛,再用 Margin-Rank 精排。

和 MSE / 交叉熵的区别

MSE:让预测分数 = 真实分数 0.95(精确拟合)
Margin-Rank:让好轨迹分数 > 坏轨迹分数 + m(只关心排序)
交叉熵:正确答案概率高,其他低(硬分类)

8.2 对比 Loss

\[ \mathcal{L}_{contrast} = -\log \frac{\exp(\text{sim}(q, k_+) / \tau)}{\sum \exp(\text{sim}(q, k_i) / \tau)} \]

直觉理解:把相似的东西拉近,把不同的推远。

谁在用

  • JEPA-DRIVE(自监督表征学习)
  • VLA-World(跨模态对齐)
  • ReWorld(世界模型表征学习)

十、全景总结

损失函数全景

演进路线:Loss 设计的"三代"

第一代:确定论
  Loss:L1 / L2 / Smooth L1
  哲学:"每条轨迹有唯一正确答案"
  局限:多模态场景下输出"平均"
  代表:ST-P3、TCP

第二代:分布论
  Loss:交叉熵 / Focal / BCE / KL / 扩散
  哲学:"动作空间有分布,不应只取一点"
  局限:安全只能软约束
  代表:VADv2、DiffusionDrive

第三代:策论
  Loss:PPO / GRPO / Rank
  哲学:"让它自己探索更好"
  局限:奖励设计难、训练不稳定
  代表:AlphaDrive、DiffusionDriveV2

十条设计原则

  1. 回归适合精确控制,不适合多模态 — 轨迹回归用 L1,框回归用 Smooth L1
  2. 分类解决多模态,但受限于词表覆盖 — Focal Loss 解决正负样本不平衡
  3. 分布匹配是"不丢信息"的回归替代方案 — KL 散度允许分布呈任意形状
  4. 扩散 Loss 同时做生成 + 分布建模 — 简单 Loss 即可学复杂分布
  5. 安全约束不能靠学,要硬编码进 Loss — collision / conflict loss 是必需的
  6. 多任务 Loss 需要显式平衡 — 两阶段训练是最可靠的工程经验
  7. RL Loss 让模型超越人类 — GRPO 是当前端到端规划的主流选择
  8. 不同 Loss 服务于不同的优化目标 — 理解目标比理解公式更重要
  9. 没有万能 Loss — 每个 Loss 都是对驾驶某个维度的建模
  10. Loss 进化的方向:从"找答案"到"学分布"再到"定策略"

十一、各论文 Loss 配置速查表

论文检测建图运动预测占用预测规划
UniADFocal + L1Focal + L1L1 + FocalBCE + DiceL2 + 碰撞 Loss
VADFocal + L1Focal + L1L1 + 终点 LossL1 + 向量约束 ×3
VADv2Focal + L1Focal + L1KL + Conflict + Token
SparseDriveFocal + L1Focal + L1L1 + 分类锚点分类 + 残差 L1
DiffusionDrive扩散 + 碰撞 + 边界 + 舒适
DiffusionDriverV2扩散 + 碰撞 + RL(GRPO)
SparseDriveV2Focal + L1Focal + L1L1 + 分类锚分类 + 残差 L1 + 碰撞
AlphaDriveSFT(CE) + GRPO

十二、写在最后

端到端自动驾驶是一个多目标优化问题——要像人(模仿)、要安全(碰撞)、要舒适(jerk)、要合法(车道)、还要能处理不确定性(多模态)。每个目标都是一个 Loss,每个 Loss 都有适合它的数学形式。

一个好的 Loss 设计,不是在选"哪个 Loss 最好",而是在搞清楚这个 Loss 让模型把注意力放在哪里——是让模型"猜得准"(L2),还是"选得对"(分类),还是"不犯错"(碰撞 Loss),还是"敢于尝试"(GRPO)。

这篇文章覆盖了所有主流 Loss,但实际中你可能还需要根据具体场景做组合和改动。如果有特定的 Loss 或论文配置想了解,欢迎继续问。