自动驾驶-第四阶段-VLA—当前最前沿方向
第四阶段:VLA——当前最前沿方向
用视觉语言大模型的"思考能力"让车学会像人一样开车
前置要求: 完成第三阶段(一段式端到端 + 扩散模型)
时间规划: 3周(每天3-4小时)
硬件要求: RTX 3090 24GB(VLA推理需要16-20GB显存)
先搞清楚:VLA到底是什么?
从V到VL到VLA——三代技术的演进
V(Vision)模型——第1-3阶段你学的:
摄像头图像 → 神经网络 → 轨迹/控制
特点:能看,但不会"想"。遇到没见过的场景就懵了。
VL(Vision-Language)模型——ChatGPT看图时代:
图像 + 文字提问 → 大模型 → 文字回答
特点:能看也能说,但只能动嘴不能动手。
VLA(Vision-Language-Action)模型——本阶段要学的:
图像 + 语言指令 → 大模型 → 轨迹/控制动作
特点:能看、能想、还能动手!是自动驾驶的"终极形态"。
类比理解:
V模型 = 一个只会条件反射的司机(看到红灯就停,但不知道为什么停)
VL模型 = 一个坐在副驾给你讲解的教练(能分析路况但自己不开车)
VLA模型 = 一个既能讲解又能亲自开车的老司机(知道为什么要这样开,并且真的去开)
为什么VLA这么热门?
VLA解决的核心问题:
1. 长尾场景泛化
传统模型:训练数据里没见过施工路段+逆行电动车的组合 → 不知道怎么办
VLA模型:从互联网文本学到了"施工要绕行""逆行车要让" → 能推理出应对策略
2. 可解释性
传统模型:输出轨迹,但不知道为什么这么开
VLA模型:先用文字说"前方有行人横穿,应减速让行",再输出减速轨迹
3. 指令跟随
传统模型:只能按导航开,不理解"在前面那家星巴克停一下"
VLA模型:理解自然语言指令,并转化为驾驶动作
当前行业格局:谁在用VLA?
小鹏 VLA 2.0:去掉Language中间层,Vision直接到Action
720亿参数基座模型,阿里云3万卡训练
理想 MindVLA:快慢双系统,VLM辅助端到端决策
用视觉语言模型做"慢思考"增强安全性
华为 ADS4.0:不叫VLA,叫WA(World Action)
去掉Language,用世界模型直接控车
特斯拉 FSD:不公开叫VLA,但核心也是
百亿参数端到端网络 + 数据闭环
Week 1:VLA基础——从Qwen2.5-VL到驾驶场景理解
Day 1-2:用Qwen2.5-VL理解驾驶场景
什么是VLM(Vision-Language Model)?
VLM是VLA的基础——先学会"看图说话",再学会"看图开车"。Qwen2.5-VL是目前最好的开源VLM之一,支持图像理解、视频理解和多语言。
VLM的工作原理:
┌──────────────┐
图像 ─────→ │ 视觉编码器 │──→ 图像Token
│ (ViT) │ ↓
└──────────────┘ ┌──────────┐
│ 大语言 │──→ 文字回答
文字提问 ──→ 文字Token ────→ │ 模型 │
│ (LLM) │
└──────────┘
概念解释:Token(令牌)
Token是大模型处理信息的最小单位。对于文字,一个Token大约是一个汉字或半个英文单词。对于图像,视觉编码器会把图片切成小块(patch),每个patch变成一个Token。大语言模型把文字Token和图像Token放在一起处理,就能"看图说话"了。
实操:安装Qwen2.5-VL并分析驾驶场景
# 安装依赖
pip install transformers accelerate torch torchvision
pip install qwen-vl-utils
# 注意:Qwen2.5-VL-3B需要约8GB显存,7B需要约16GB
"""
driving_scene_understanding.py
用Qwen2.5-VL分析驾驶场景图片
"""
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch
# 加载模型(3B版本,适合RTX 3090)
model_name = "Qwen/Qwen2.5-VL-3B-Instruct"
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.float16, # 半精度节省显存
device_map="auto"
)
processor = AutoProcessor.from_pretrained(model_name)
# ===== 场景1:基础场景描述 =====
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "path/to/driving_scene.jpg"},
{"type": "text", "text":
"You are an autonomous driving AI. "
"Describe this driving scene in detail: "
"1. What objects are visible? "
"2. What is the road condition? "
"3. What should the ego vehicle do next?"}
]
}
]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(text=[text], images=image_inputs, videos=video_inputs,
padding=True, return_tensors="pt").to(model.device)
output_ids = model.generate(**inputs, max_new_tokens=256)
response = processor.batch_decode(output_ids, skip_special_tokens=True)[0]
print(f"场景分析:\n{response}")
# ===== 场景2:多层次CoT驾驶推理 =====
# 这就是VLA中最关键的"链式思维"(Chain-of-Thought)
cot_prompt = """You are an expert autonomous driving system.
Analyze this driving scene step by step:
Step 1 - PERCEPTION: List all important objects and their positions
(e.g., "car ahead at 20m", "pedestrian on right sidewalk")
Step 2 - PREDICTION: Predict what each object will do in the next 3 seconds
(e.g., "the car ahead is slowing down", "pedestrian may cross")
Step 3 - DECISION: Based on steps 1 and 2, what should the ego vehicle do?
(e.g., "slow down and prepare to stop")
Step 4 - TRAJECTORY: Output 6 waypoints for the next 3 seconds as coordinates
Format: [(x1,y1), (x2,y2), ..., (x6,y6)]
where x is forward distance (meters), y is lateral offset (positive=left)
"""
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "path/to/driving_scene.jpg"},
{"type": "text", "text": cot_prompt}
]
}
]
# ... (同样的推理代码)
概念解释:CoT(Chain-of-Thought,链式思维)
CoT是让大模型"一步步思考"而不是直接给答案。就像你考数学题时,老师要求写出解题过程——这不仅让答案更准确,还让你的思路可以被检查。
在VLA中,CoT的典型流程是:
感知(看到了什么)→ 预测(它们会怎么动)→ 决策(我应该怎么做)→ 动作(输出轨迹)这个流程和人类开车时的思考过程完全一致。
Day 3-4:用nuScenes图片做批量驾驶场景分析
"""
batch_scene_analysis.py
批量分析nuScenes中的驾驶场景,生成训练VLA的CoT标注数据
"""
from nuscenes.nuscenes import NuScenes
import json
from pathlib import Path
nusc = NuScenes(version='v1.0-mini', dataroot='./data/nuscenes')
# 为每个关键帧生成多层次CoT标注
cot_annotations = []
for sample in nusc.sample[:50]: # 先处理50帧
# 获取前视摄像头图像
cam_token = sample['data']['CAM_FRONT']
cam_data = nusc.get('sample_data', cam_token)
img_path = f"./data/nuscenes/{cam_data['filename']}"
# 获取真实标注信息
anns = []
for ann_token in sample['anns']:
ann = nusc.get('sample_annotation', ann_token)
anns.append({
'category': ann['category_name'],
'distance': round(ann['translation'][0], 1), # 前方距离
'lateral': round(ann['translation'][1], 1), # 横向偏移
})
# 获取自车未来轨迹(作为GT)
ego_pose = nusc.get('ego_pose', cam_data['ego_pose_token'])
# 构造CoT标注
cot_annotations.append({
'image_path': img_path,
'perception': anns, # 感知结果
'prediction': 'auto_generated', # 后续用VLM生成
'decision': 'auto_generated',
'trajectory': ego_pose['translation'] # 真实轨迹
})
# 保存标注
with open('cot_annotations.json', 'w') as f:
json.dump(cot_annotations, f, indent=2)
print(f"生成了 {len(cot_annotations)} 条CoT标注")
Week 2:ORION——小米的开源VLA方案
Day 5-6:理解ORION架构
ORION是什么?
ORION是小米汽车和华中科技大学联合发表的VLA框架(ICCV 2025),它的核心创新是用生成式规划器打通VLM的"推理空间"和轨迹的"动作空间"。
ORION的整体架构:
┌─────────────────────────────────────────────────────────┐
│ ORION Framework │
│ │
│ ┌──────────┐ │
│ │ 多视角 │──→ 视觉编码器 ──→ 视觉Token │
│ │ 摄像头图像 │ ↓ │
│ └──────────┘ ┌───────────────────────┐ │
│ │ QT-Former │ │
│ ┌──────────┐ │ (时序Query聚合器) │ │
│ │ 历史帧 │──→ │ 压缩多帧视觉信息 │──→ 历史Token │
│ │ 记忆库 │ │ 解决VLM输入长度限制 │ │
│ └──────────┘ └───────────────────────┘ │
│ ↓ │
│ ┌───────────────────────┐ │
│ ┌──────────┐ │ VLM (大语言模型) │ │
│ │ 文字指令 │──→ │ 推理空间:场景描述 │ │
│ │"直行到路口"│ │ + 行为分析 + 决策 │ │
│ └──────────┘ │ 输出:规划Token │ │
│ └──────────┬────────────┘ │
│ ↓ │
│ ┌───────────────────────┐ │
│ │ 生成式规划器 │ │
│ │ (VAE / 扩散模型) │ │
│ │ 规划Token → 多条轨迹 │ │
│ │ 对齐推理空间和动作空间 │ │
│ └──────────┬────────────┘ │
│ ↓ │
│ 最优驾驶轨迹 (waypoints) │
└─────────────────────────────────────────────────────────┘
ORION的三大核心创新
创新1:QT-Former——解决VLM的"短期记忆"问题
VLM一次只能处理有限长度的Token。如果把过去10帧的6个摄像头图像都塞进去,Token数量会爆炸。QT-Former用类似Q-Former的方法,把多帧视觉信息"压缩"成少量Token。
没有QT-Former:
第1帧6张图(500token) + 第2帧6张图(500token) + ... + 第10帧(500token)
= 5000 token → 超过VLM的输入限制!
有QT-Former:
10帧历史信息 → QT-Former压缩 → 64个Token
= 大幅降低计算量,同时保留关键时序信息
概念解释:Q-Former
Q-Former来自BLIP-2论文,它的核心思想是:用一组可学习的"查询向量"(Query)去"询问"图像特征,只提取最重要的信息。就像你让实习生看一段很长的视频,然后只用3句话总结要点。QT-Former在此基础上加入了时序(Temporal)维度,能跨越多帧总结历史信息。
创新2:VLM推理→规划Token
ORION让VLM做完场景分析后,除了输出文字,还额外输出一组"规划Token"。这些Token不是人类可读的文字,而是一种隐含的"驾驶意图表示"——类似于一种"驾驶密码"。
# VLM的输出(伪代码)
vlm_output = {
# 人类可读的文字输出
'text': "前方20米有行人正在横穿马路,应减速让行",
# 机器可用的规划Token(不是文字,是向量)
'planning_tokens': tensor(shape=[1, 8, 256]) # 8个256维的Token
}
创新3:生成式规划器——打通推理和动作
规划Token通过一个VAE(变分自编码器)或扩散模型,被转化为具体的驾驶轨迹。关键在于:这个转化过程是可微分的——意味着轨迹的误差可以反向传播到VLM,让VLM学会输出更好的规划Token。
概念解释:VAE(变分自编码器)
VAE是一种生成模型。它做两件事:
- 编码器:把复杂数据(轨迹)压缩成一个简短的"编码"(潜在向量)
- 解码器:从"编码"恢复出原始数据(轨迹)
在ORION中,VAE把VLM输出的规划Token当作"条件",控制轨迹的生成方向。
Day 7-8:跑通ORION推理
# 克隆ORION
git clone https://github.com/xiaomi-mlab/Orion.git
cd Orion
# 安装依赖(参考README.md)
pip install -r requirements.txt
# 下载预训练权重(从GitHub Releases或HuggingFace)
# ORION使用Vicuna 1.5作为LLM backbone
# 在Bench2Drive数据上运行推理
python inference.py \
--config configs/orion_base.py \
--checkpoint ckpts/orion_base.pth \
--visualize
阅读ORION代码的重点
Orion/
├── configs/
│ └── orion_base.py # ← 第1个读:模型配置
├── models/
│ ├── orion.py # ← 第2个读:主模型forward
│ ├── qt_former.py # ← 第3个读:QT-Former实现
│ ├── vlm_wrapper.py # ← 第4个读:VLM封装
│ └── generative_planner.py # ← 第5个读:生成式规划器
├── datasets/
│ └── bench2drive_dataset.py # 数据加载
└── inference.py # 推理脚本
Week 3:构建你自己的轻量VLA + 模型部署
Day 9-11:构建简化版VLA
设计思路
我们要在NAVSIM上构建一个轻量VLA。核心思想:用Qwen2.5-VL-3B做场景理解,输出CoT文字描述,然后用一个MLP把VLM的隐藏层特征映射为轨迹。
"""
mini_vla.py
简化版VLA:Qwen2.5-VL + MLP轨迹预测头
"""
import torch
import torch.nn as nn
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
class MiniVLA(nn.Module):
"""
最简化的VLA架构:
1. 用Qwen2.5-VL编码图像+指令
2. 取VLM最后一层隐藏状态
3. 用MLP映射到轨迹
"""
def __init__(self, vlm_name="Qwen/Qwen2.5-VL-3B-Instruct",
num_waypoints=6, freeze_vlm=True):
super().__init__()
# 加载预训练VLM
self.vlm = Qwen2_5_VLForConditionalGeneration.from_pretrained(
vlm_name, torch_dtype=torch.float16
)
self.processor = AutoProcessor.from_pretrained(vlm_name)
# 冻结VLM参数(先不微调,只训练轨迹头)
if freeze_vlm:
for param in self.vlm.parameters():
param.requires_grad = False
# 轨迹预测头:VLM隐藏维度 → waypoints
hidden_dim = self.vlm.config.hidden_size # 通常是2048或3584
self.trajectory_head = nn.Sequential(
nn.Linear(hidden_dim, 512),
nn.ReLU(),
nn.Dropout(0.1),
nn.Linear(512, 256),
nn.ReLU(),
nn.Linear(256, num_waypoints * 2) # 6个点 × (x, y)
)
self.num_waypoints = num_waypoints
def forward(self, images, driving_command, ego_status):
"""
images: 前视摄像头图像
driving_command: "go straight" / "turn left" / "turn right"
ego_status: 自车速度等
"""
# 构造VLM输入
prompt = f"Driving command: {driving_command}. " \
f"Current speed: {ego_status['speed']:.1f} m/s. " \
f"Analyze the scene and plan the trajectory."
# VLM前向传播(只取隐藏状态,不生成文字)
inputs = self.processor(
text=prompt,
images=images,
return_tensors="pt"
).to(self.vlm.device)
with torch.no_grad():
vlm_output = self.vlm(**inputs, output_hidden_states=True)
# 取最后一层隐藏状态的最后一个Token
# 这个Token聚合了图像+文字的全部信息
hidden = vlm_output.hidden_states[-1][:, -1, :] # (B, hidden_dim)
hidden = hidden.float() # 转回FP32做MLP
# 通过轨迹预测头输出waypoints
traj = self.trajectory_head(hidden) # (B, 12)
traj = traj.view(-1, self.num_waypoints, 2) # (B, 6, 2)
return traj
训练这个MiniVLA
"""
train_mini_vla.py
训练简化版VLA的轨迹预测头
"""
import torch
from torch.utils.data import DataLoader
from mini_vla import MiniVLA
# 配置
EPOCHS = 20
LR = 1e-3 # 只训练MLP头,可以用较大学习率
DEVICE = 'cuda'
# 加载模型(VLM冻结,只训练trajectory_head)
model = MiniVLA(freeze_vlm=True).to(DEVICE)
# 只优化轨迹预测头的参数
optimizer = torch.optim.Adam(
model.trajectory_head.parameters(), lr=LR
)
loss_fn = torch.nn.SmoothL1Loss() # 比MSE更鲁棒
# 训练循环
for epoch in range(EPOCHS):
model.train()
for batch in dataloader:
images = batch['image'].to(DEVICE)
commands = batch['driving_command']
ego_status = batch['ego_status']
gt_traj = batch['trajectory'].to(DEVICE) # (B, 6, 2)
# 前向传播
pred_traj = model(images, commands, ego_status)
# 计算损失
loss = loss_fn(pred_traj, gt_traj)
# 反向传播(只更新trajectory_head)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
torch.save(model.trajectory_head.state_dict(), 'vla_traj_head.pth')
Day 12-13:GRPO强化学习微调
什么是GRPO?为什么需要它?
SFT(监督微调)让模型学会了"模仿人类开车",但模仿有一个致命问题:人类的开车数据本身就包含不好的习惯(急刹车、犹豫不决等)。强化学习(RL)可以让模型学到比人类数据更好的策略。
SFT的问题:
人类数据中:70%正常驾驶 + 20%犹豫不决 + 10%危险操作
SFT学到的:一个"平均"策略,包含犹豫和危险的成分
GRPO的解决:
让模型自己生成多条轨迹 → 用奖励函数评分 → 强化好的、抑制差的
概念解释:GRPO(Group Relative Policy Optimization)
GRPO是DeepSeek提出的强化学习方法,比PPO(OpenAI用的)更简单高效。核心思想:
- 对同一个场景,让模型生成K条候选轨迹
- 用奖励函数给每条轨迹打分(有没有碰撞?偏离车道多少?)
- 好的轨迹 → 增加概率;差的轨迹 → 降低概率
- 不需要单独训练Critic网络(PPO需要),直接用组内相对排名
为什么叫"Group Relative"? 因为它不看绝对分数,只看"这条轨迹在这一组里排第几"。第一名奖励最大,最后一名惩罚最大。
"""
grpo_driving.py
简化版GRPO驾驶策略优化
注意:这是概念性代码,帮助你理解GRPO的核心流程
实际应用中需要配合完整的VLA模型和数据pipeline
"""
import torch
import torch.nn.functional as F
def compute_driving_reward(trajectory, gt_trajectory, obstacles):
"""
驾驶奖励函数:评估一条轨迹的质量
奖励 = 进度奖励 - 碰撞惩罚 - 偏离惩罚 - 不舒适惩罚
"""
reward = 0.0
# 1. 进度奖励:你到底往前开了多少?
forward_progress = trajectory[-1, 0] # 最后一个waypoint的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 # 碰撞了,严重惩罚
# 3. 偏离车道中心的惩罚
lateral_deviation = torch.mean(torch.abs(trajectory[:, 1])) # y方向偏差
reward -= lateral_deviation * 2.0
# 4. 不舒适惩罚(急转弯、急加速)
acceleration = torch.diff(trajectory, dim=0)
jerk = torch.diff(acceleration, dim=0)
comfort_penalty = torch.mean(torch.norm(jerk, dim=1))
reward -= comfort_penalty * 0.5
return reward
def grpo_step(model, scene_input, gt_trajectory, obstacles,
num_samples=8, temperature=1.0):
"""
GRPO的一个训练步骤
1. 生成K条候选轨迹
2. 用奖励函数打分
3. 计算GRPO loss
"""
# Step 1: 生成K条候选轨迹
trajectories = []
log_probs = []
for _ in range(num_samples):
with torch.no_grad():
traj = model.sample_trajectory(scene_input, temperature=temperature)
trajectories.append(traj)
# 计算每条轨迹的对数概率
log_prob = model.log_probability(scene_input, traj)
log_probs.append(log_prob)
trajectories = torch.stack(trajectories) # (K, 6, 2)
log_probs = torch.stack(log_probs) # (K,)
# Step 2: 计算每条轨迹的奖励
rewards = torch.tensor([
compute_driving_reward(traj, gt_trajectory, obstacles)
for traj in trajectories
])
# Step 3: 组内标准化(Group Relative的关键)
# 不看绝对分数,只看相对排名
rewards_normalized = (rewards - rewards.mean()) / (rewards.std() + 1e-8)
# Step 4: 计算GRPO loss
# 好的轨迹(正奖励)→ 增加概率;差的轨迹(负奖励)→ 降低概率
loss = -(log_probs * rewards_normalized).mean()
return loss
Day 14:模型部署基础——TensorRT加速
为什么需要TensorRT?
VLA模型很大(3-7B参数),推理慢。车端部署需要实时性(至少10Hz)。TensorRT是NVIDIA的推理加速工具,能把PyTorch模型转换为高度优化的推理引擎。
"""
model_export.py
将训练好的轨迹预测头导出为ONNX → TensorRT
"""
import torch
import onnx
# 1. 导出ONNX
model = MiniVLA(freeze_vlm=True)
model.trajectory_head.load_state_dict(torch.load('vla_traj_head.pth'))
model.eval()
# 只导出轨迹预测头(VLM部分用其他方式优化)
dummy_input = torch.randn(1, 2048) # 模拟VLM的隐藏层输出
torch.onnx.export(
model.trajectory_head,
dummy_input,
"trajectory_head.onnx",
input_names=['vlm_features'],
output_names=['trajectory'],
dynamic_axes={'vlm_features': {0: 'batch'}, 'trajectory': {0: 'batch'}}
)
print("ONNX模型已导出!")
# 2. 用TensorRT优化
# trtexec --onnx=trajectory_head.onnx \
# --saveEngine=trajectory_head.trt \
# --fp16 # 使用半精度加速
# 3. TensorRT推理
import tensorrt as trt
import numpy as np
# 加载TensorRT引擎
with open('trajectory_head.trt', 'rb') as f:
engine = trt.Runtime(trt.Logger()).deserialize_cuda_engine(f.read())
# 推理速度对比
# PyTorch FP32: ~5ms
# PyTorch FP16: ~3ms
# TensorRT FP16: ~0.5ms ← 10倍加速!
总结:你的完整技术能力树
第一阶段 ✅ CARLA仿真 + 简单模仿学习 + 闭环测试
第二阶段 ✅ BEV感知(BEVFormer) + 端到端(VAD) + nuScenes评测
第三阶段 ✅ 一段式端到端(SparseDrive) + 扩散模型(DiffusionDrive) + NAVSIM
第四阶段 ✅ VLA(ORION) + 强化学习(GRPO) + 模型部署(TensorRT)
面试时你的"故事线"
"我从CARLA仿真入手建立了端到端自动驾驶的闭环实验能力,然后在nuScenes上复现了BEVFormer和VAD。接着研究了一段式端到端方案SparseDrive和基于扩散模型的DiffusionDrive,在NAVSIM上做了标准化评测。最后进入VLA方向,跑通了小米的ORION框架,自己实现了一个基于Qwen2.5-VL的轻量VLA,并用GRPO做了强化学习微调。整个过程覆盖了从感知到规划的完整技术栈,也掌握了TensorRT模型部署的基础。"
求职目标岗位
| 岗位 | 匹配的技术栈 | 你的竞争力 |
|---|---|---|
| 端到端算法工程师 | BEV + VAD + SparseDrive | 有完整的开环+闭环复现经验 |
| 规划算法工程师 | DiffusionDrive + NAVSIM | 理解扩散模型和多模态规划 |
| VLA/大模型算法工程师 | ORION + Qwen2.5-VL + GRPO | 掌握最前沿的VLA技术栈 |
| 数据闭环工程师 | CARLA + nuScenes + 工程化 | 10年工程经验 + 算法理解 |
| 模型部署工程师 | TensorRT + ONNX + 量化 | 工程化背景 + 算法知识 |
你的差异化优势: 有10年Java/Python工程经验的候选人学VLA算法,比纯学术背景的候选人更懂工程化落地,在车企非常稀缺。
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)