自动驾驶-第四阶段 4.1-VLA—当前最前沿方向强化学习微调——超越模仿学习
从“学人类开车”到“比人类开得更好”。
在前边的课程中,我们用 VLA 赋予了模型“思考”的能力。但有一个更深层的问题:无论是第 3 章的 ResNet、第 5 章的 VAD、第 6 章的 DiffusionDrive 还是第 7 章的 VLA,它们都在做同一件事——模仿人类驾驶数据。而模仿学习有一个无法突破的天花板:模型最多和人类一样好,不能更好。
本章将引入强化学习(Reinforcement Learning)来突破这个天花板。具体用的是 DeepSeek 提出的 GRPO(Group Relative Policy Optimization)——它比传统的 PPO 更简单、更高效。
模仿学习的天花板在哪

上图下半部分清晰地展示了 SFT 和 GRPO 的核心区别:
模仿学习(SFT)的问题:人类数据包含 70% 正常驾驶 + 20% 犹豫不决 + 10% 危险操作。模型学到的是一个“平均”策略,包含犹豫和危险的成分。天花板:模型最多和人类一样好,不能更好。
强化学习(GRPO)的突破:不再模仿人类数据,而是让模型自己探索。生成多条轨迹,用奖励函数评分,强化好的、抑制差的。结果:模型可以学到比人类更优的策略。
💡 类比理解
模仿学习就像学生照抄老师的解题步骤——学生最多和老师一样好。强化学习就像学生自己做试卷,对答案看分数,慢慢探索出比老师更高效的解法。这正是 AlphaGo 超越所有人类围棋手的原理——它不是模仿人类下棋,而是通过自我对弈发现了人类从未想过的棋路。
| 对比项 | SFT (模仿学习) | GRPO (强化学习) |
|---|---|---|
| 训练信号 | 人类驾驶数据 (GT 轨迹) | 奖励函数 (碰撞/进度/舒适度) |
| 学习方式 | 模仿专家行为 | 自己探索 + 奖励反馈 |
| 性能上限 | 最多和人类一样好 | 可以超越人类 |
| 需要的数据 | 大量标注数据 | 只需要奖励函数 |
| 代表方法 | VAD/SparseDrive/VLA SFT | GRPO/PPO/RLHF |
| 行业案例 | 特斯拉 FSD V12 | 特斯拉 FSD V14 + 理想 VLA |
GRPO 原理:组内相对策略优化
什么是 GRPO?
GRPO(Group Relative Policy Optimization)是 DeepSeek 提出的强化学习方法。它比 OpenAI 用的 PPO 更简单高效,核心思想是:
- 对同一个场景,让模型生成 K 条候选轨迹(一个“组”)
- 用奖励函数给每条轨迹打分
- 在组内做相对排名(标准化)——第一名奖励最大,最后一名惩罚最大
- 用排名结果更新模型参数——增加高分轨迹的生成概率,降低低分轨迹的生成概率
概念解释:为什么叫“Group Relative”?
“Group”是因为它把同一场景下的 K 条轨迹当作一个“组”。“Relative”是因为它不看绝对分数,只看组内相对排名。这有一个巨大的优势:不需要单独训练一个 Critic 网络(PPO 需要),简化了训练流程。DeepSeek 正是用 GRPO 训练出了超越 GPT-4 的推理能力。
GRPO vs PPO
| 对比项 | PPO (OpenAI) | GRPO (DeepSeek) |
|---|---|---|
| 是否需要 Critic | 需要训练一个价值网络 | 不需要,用组内排名替代 |
| 基线 (baseline) | 价值函数估计 | 组内均值 |
| 训练复杂度 | 高(两个网络同时训练) | 低(只训练策略网络) |
| 显存占用 | 大(Actor + Critic) | 小(只有 Actor) |
| 效果 | 经典有效 | 同样有效且更简单 |
驾驶奖励函数设计
奖励函数是强化学习的“灵魂”——它定义了“什么是好的驾驶”。设计不好,模型会学到奇怪的行为(比如“原地不动就不会碰撞”)。
def compute_driving_reward(trajectory, gt_traj, obstacles, lane_center):
'''
驾驶奖励函数: 评估一条轨迹的质量
奖励 = 进度奖励 - 碰撞惩罚 - 偏离惩罚 - 不舒适惩罚
'''
reward = 0.0
# 1. 进度奖励: 你到底往前开了多少?
forward_progress = trajectory[-1, 0] # 最后一个点的x坐标
reward += forward_progress * 0.5
# 2. 碰撞惩罚: 撞了就严重扣分
for obs in obstacles:
min_dist = torch.min(torch.norm(trajectory - obs['position'], dim=1))
if min_dist < obs['radius']:
reward -= 10.0 # 碰撞了!
elif min_dist < obs['radius'] * 2:
reward -= 2.0 # 太近了, 警告
# 3. 偏离车道中心的惩罚
lateral_dev = torch.mean(torch.abs(trajectory[:, 1] - lane_center))
reward -= lateral_dev * 2.0
# 4. 不舒适惩罚: 急转弯、急加速
acceleration = torch.diff(trajectory, dim=0)
jerk = torch.diff(acceleration, dim=0)
comfort = torch.mean(torch.norm(jerk, dim=1))
reward -= comfort * 0.5
return reward
⚠️ 奖励函数设计的坑
最常见的坑是“奖励黑客”(Reward Hacking)——模型找到了你没想到的“作弊”方式来获取高分。比如:如果只有碰撞惩罚没有进度奖励,模型会学到“原地不动”;如果进度奖励太大,模型会“横冲直撞”不管障碍物。好的奖励函数需要平衡多个目标。
GRPO 训练流程实操
以下是完整的 GRPO 训练代码,基于第 7 章的 MiniVLA 模型:
# grpo_training.py
import torch
import torch.nn.functional as F
def grpo_step(model, scene_input, obstacles, lane_center,
num_samples=8, temperature=1.0):
'''
GRPO 的一个训练步骤
'''
# Step 1: 生成 K 条候选轨迹
trajectories = []
log_probs = []
for _ in range(num_samples):
traj = model.sample(scene_input, temperature=temperature)
trajectories.append(traj)
lp = model.log_probability(scene_input, traj)
log_probs.append(lp)
trajectories = torch.stack(trajectories) # (K, 6, 2)
log_probs = torch.stack(log_probs) # (K,)
# Step 2: 计算每条轨迹的奖励
rewards = torch.tensor([
compute_driving_reward(traj, None, obstacles, lane_center)
for traj in trajectories
])
# Step 3: 组内标准化 (Group Relative 的核心!)
rewards_norm = (rewards - rewards.mean()) / (rewards.std() + 1e-8)
# 第一名得到正奖励, 最后一名得到负奖励
# Step 4: 计算 GRPO loss
loss = -(log_probs * rewards_norm).mean()
# 直觉: 好的轨迹(+奖励) -> 增加概率
# 差的轨迹(-奖励) -> 降低概率
return loss, rewards.mean().item()
# ===== 完整训练循环 =====
model = MiniVLA(freeze_vlm=False).cuda() # 这次不冻结VLM!
optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)
for epoch in range(100):
total_reward = 0
for scene in dataloader:
loss, avg_reward = grpo_step(
model, scene['input'], scene['obstacles'],
scene['lane_center'], num_samples=8)
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
total_reward += avg_reward
print(f'Epoch {epoch}: avg_reward={total_reward/len(dataloader):.3f}')
关键代码解读
第 3 步的rewards_norm = (rewards - rewards.mean()) / rewards.std()是 GRPO 的灵魂。它把绝对分数转换为相对排名——第一名的标准化奖励是正的(增加生成概率),最后一名是负的(降低生成概率)。这样就不需要单独训练 Critic 网络,比 PPO 简单得多。
SFT → GRPO 的完整 Pipeline
在实际应用中,GRPO 不是从零开始训练,而是在 SFT 的基础上微调。完整的三阶段 pipeline 是:
| 阶段 | 方法 | 目的 | 数据来源 |
|---|---|---|---|
| 阶段 1: 预训练 | VLM 预训练 (Qwen2.5-VL) | 学会“看图说话” | 互联网图文数据 |
| 阶段 2: SFT | CoT 监督微调 | 学会“看图开车” | nuScenes 驾驶数据 |
| 阶段 3: GRPO | 强化学习微调 | 学会“开得更好” | 奖励函数反馈 |
三阶段之间的关系
- 阶段 1 → 阶段 2:预训练提供了“看图”和“说话”的基础能力。SFT 在这个基础上让模型学会“看图开车”。如果跳过预训练直接做 SFT,模型连图都看不懂,更别说开车了。
- 阶段 2 → 阶段 3:SFT 提供了一个“还行”的初始策略。GRPO 在这个基础上微调,让模型“更好”。如果跳过 SFT 直接做 GRPO,模型的初始策略太差,探索效率极低。
🎯 面试答题模板
“为什么不能直接用强化学习,要先做 SFT?”参考回答:“强化学习需要一个“还行”的初始策略作为起点。如果从随机策略开始探索,几乎所有采样都会得到极低分(比如立刻撞墙),模型根本学不到东西。SFT 提供了一个“能走直线但弯道差”的起点,GRPO 在这个基础上微调就很高效了。”
实际应用中的考量
- 安全约束:在自动驾驶中,强化学习的探索不能在真车上做(太危险)。所以需要在仿真器(CARLA/NAVSIM)或世界模型中做。这正是华为“世界引擎”的价值——提供安全的探索环境。
- 奖励函数调试:奖励函数的权重需要反复调试。建议先用小规模数据快速迭代,观察模型是否学到了奖励黑客行为,及时调整。
- KL 散度约束:GRPO 训练时通常加一个 KL 散度项,限制模型不能偏离 SFT 的策略太远,避免“死学”奖励函数的漏洞。
本章小结
本章是第三篇(前沿技术)的最后一章。你学到了:
- 模仿学习的天花板——最多和人类一样好,不能更好
- GRPO 原理——采样K条轨迹、奖励打分、组内排名、更新策略
- 奖励函数设计——进度+碰撞+偏离+舒适度的平衡
- GRPO 完整训练代码——基于 MiniVLA 的强化学习微调
- SFT → GRPO 三阶段 pipeline——预训练→监督微调→强化学习
用最通俗、最直观、自动驾驶专属的方式,给你讲透:
奖励函数到底怎么控制模型,让好轨迹变多、坏轨迹变少?
我完全基于你这份课程内容来讲,不讲复杂公式,只讲直觉 + 原理 + 代码对应。
先给你一句最核心的结论(一定要记住)
奖励函数不直接“改轨迹”,它告诉模型:哪条轨迹应该下次多生成,哪条应该少生成。
模型靠“概率”开车,奖励函数靠“调整概率”控制行为。
1. 先理解:你的模型是个“概率生成器”
在 GRPO 里,你的 MiniVLA 模型不是“计算轨迹”,而是:
模型 = 轨迹概率分布发生器
给模型一张图,它不会只输出一条轨迹,
它内部有一个概率分布:
- 轨迹A:概率 10%
- 轨迹B:概率 25%
- 轨迹C:概率 5%
- 轨迹D:概率 60%
模型每次生成轨迹,都是按这个概率随机采样的。
2. GRPO 做的事:给同一帧画面生成 K 条轨迹
就像让司机凭感觉开 8 次:
- 开得很稳 → 好
- 压线了 → 差
- 撞了 → 很差
- 完美贴车道中心 → 极好
...
这就是代码里的:
for _ in range(num_samples):
traj = model.sample(scene_input) # 生成一条轨迹
log_probs.append(model.log_probability(traj)) # 记录这条轨迹的概率
3. 奖励函数做什么?
给每条轨迹打分,告诉模型:哪条好,哪条坏。
你课程里的奖励函数包含:
- 往前开得越远 → 分越高
- 离障碍物越近 → 分越低
- 偏离车道中心 → 扣分
- 颠簸、急转弯 → 扣分
最终分数 = 这条轨迹的“好坏程度”。
4. 最关键:GRPO 如何用分数调整概率?(核心机制)
一句话:
高分轨迹 → 下次生成概率 ↑
低分轨迹 → 下次生成概率 ↓
代码里的灵魂公式:
loss = -(log_probs * rewards_norm).mean()
这个公式的直觉解释:
① 如果一条轨迹 奖励为正(好轨迹)
log_probs * 正数
→ 损失变小
→ 反向传播后
→ 模型会提高这条轨迹的概率
② 如果一条轨迹 奖励为负(坏轨迹)
log_probs * 负数
→ 损失变大
→ 反向传播后
→ 模型会降低这条轨迹的概率
训练的本质:
不断重复:生成 → 打分 → 调概率 → 生成 → 打分 → 调概率
最后模型就学会了:
- 高概率输出:安全、居中、前进、舒适的轨迹
- 低概率输出:碰撞、压线、不动、颠簸的轨迹
5. 为什么要“组内相对”(Group Relative)?
因为绝对分数没用,相对排名才有用。
例子:
- 轨迹1得分:10
- 轨迹2得分:8
- 轨迹3得分:-50
GRPO 不看绝对值,只看:
- 第1名 → 奖励+
- 第2名 → 奖励0
- 第3名 → 奖励-
好处:模型只需要学“哪条更好”,不用管“好到什么程度”。
这就是 GRPO 比 PPO 简单的原因。
6. 用一个超级简单的比喻让你彻底懂
模型 = 射手
轨迹 = 子弹
奖励函数 = 靶纸
- 射手(模型)随机打 8 枪(生成8条轨迹)
- 靶纸(奖励函数)告诉你:哪枪中靶、哪枪脱靶
- 教练(GRPO)告诉射手:
- 中靶的动作,下次多用!
- 脱靶的动作,下次少用!
射手不需要理解原理,只需要根据反馈调整动作概率。
7. 回到你的自动驾驶:最终效果是什么?
训练前:
- 轨迹随机
- 乱开、乱拐、碰撞、不动
训练后:
- 安全轨迹概率最大
- 居中轨迹概率最大
- 前进轨迹概率最大
- 舒适轨迹概率最大
模型不是被编程好的,
而是被奖励函数引导成这样的。
8. 最终总结(面试/理解都能用)
GRPO 训练的本质 = 调整轨迹生成概率
- 模型生成多条轨迹
- 奖励函数判断好坏
- 好轨迹 → 提高下次生成概率
- 坏轨迹 → 降低下次生成概率
- 越训练,模型生成好轨迹的概率越大
奖励函数不控制轨迹长什么样,它控制轨迹出现的概率!
如果你愿意,我可以用你课程里的 GRPO 代码,
逐行给你讲:loss = -(log_probs * rewards_norm).mean()
到底是怎么让“好轨迹概率上升、坏轨迹下降”的。
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)