端到端自动驾驶:从感知到控制
智能无人车核心课程 · 大学前沿篇
第一章:端到端范式的崛起
1.1 模块化 vs 端到端
传统自动驾驶采用模块化流水线:
传统模块化架构:
摄像头/激光雷达 → [感知模块] → 目标列表
↓
高精地图 + 定位 → [预测模块] → 轨迹预测
↓
[规划模块] → 期望轨迹
↓
[控制模块] → 方向盘/油门/刹车
问题:
- 模块间信息传递有损(感知只输出目标框,丢失了原始场景的丰富信息)
- 误差逐级累积(感知误差 → 预测偏差 → 规划失败)
- 难以处理"长尾场景"(训练数据中罕见的情况)
1.2 端到端的核心思想
端到端架构:
原始传感器输入 → [神经网络] → 直接输出控制指令
核心优势:
├── 信息无损:直接从原始像素/点云学习到最终控制
├── 全局优化:损失函数直接定义在最终任务上
├── 隐式学习:网络自动学习中间表示(无需人工定义"目标检测""语义分割"等子任务)
└── 泛化能力:对未见过的场景组合有更好的鲁棒性
1.3 端到端自动驾驶发展史
| 年份 | 系统 | 机构 | 核心贡献 |
| 2016 | End-to-End Learning | NVIDIA | 首次用 CNN 从摄像头直接预测转向角 |
| 2019 | Learning by Cheating | Princeton | 用"上帝视角"训练,再迁移到真实场景 |
| 2020 | L5Kit | Toyota Research | 大规模自动驾驶数据集与学习框架 |
| 2021 | UniAD 前身 | 上海 AI Lab | 统一感知-预测-规划框架 |
| 2022 | FSD Beta | Tesla | 纯视觉端到端,大规模量产部署 |
| 2023 | UniAD | 上海 AI Lab | 首个端到端感知-规划联合优化框架 |
| 2023 | DriveVLM | 理想汽车 | 视觉语言模型驱动的驾驶决策 |
| 2024 | VAD / SparseDrive | 多机构 | 高效稀疏特征表示的端到端规划 |
第二章:NVIDIA 的开创性工作
2.1 原始端到端模型(2016)
# NVIDIA 端到端驾驶网络(简化版)
# 输入:3 个摄像头的图像(左/中/右)
# 输出:转向角
import torch
import torch.nn as nn
class NVIDIAEndToEnd(nn.Module):
def __init__(self):
super().__init__()
# 5 层卷积 + 4 层全连接
self.conv = nn.Sequential(
# Conv1: 200×66×3 → 98×31×24
nn.Conv2d(3, 24, kernel_size=5, stride=2),
nn.ELU(),
# Conv2: 98×31×24 → 48×14×36
nn.Conv2d(24, 36, kernel_size=5, stride=2),
nn.ELU(),
# Conv3: 48×14×36 → 22×5×48
nn.Conv2d(36, 48, kernel_size=5, stride=2),
nn.ELU(),
# Conv4: 22×5×48 → 20×3×64
nn.Conv2d(48, 64, kernel_size=3, stride=1),
nn.ELU(),
# Conv5: 20×3×64 → 18×1×64
nn.Conv2d(64, 64, kernel_size=3, stride=1),
nn.ELU(),
)
self.fc = nn.Sequential(
nn.Linear(18 * 1 * 64, 1164),
nn.ELU(),
nn.Dropout(0.5),
nn.Linear(1164, 100),
nn.ELU(),
nn.Dropout(0.5),
nn.Linear(100, 50),
nn.ELU(),
nn.Dropout(0.5),
nn.Linear(50, 10),
nn.ELU(),
nn.Linear(10, 1), # 输出:转向角
)
def forward(self, x):
x = self.conv(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
训练技巧:
def training_tricks():
"""NVIDIA 论文中的关键训练技巧"""
tricks = {
"1. 数据增强": {
"随机左右翻转": "配合转向角取反",
"随机亮度调整": "模拟不同光照",
"随机添加阴影": "模拟树荫/建筑阴影",
"使用右摄像头训练": "转向角 + 修正值(如 0.2 弧度)",
"使用左摄像头训练": "转向角 - 修正值",
},
"2. 损失函数": {
"MSE Loss": "L = (ŷ - y)²",
"为何不用分类": "转向角是连续值,分类会丢失精度",
},
"3. 训练策略": {
"batch_size": "100(大 batch 稳定梯度)",
"optimizer": "Adam, lr=1e-4",
"epochs": "约 30-50",
"early_stopping": "验证集 loss 不降时停止",
},
}
return tricks
2.2 从模拟到现实(Sim-to-Real)
迁移学习流程:
阶段 1:在模拟器中训练
├── 使用 GTA V / CARLA / Unity 等模拟器
├── 优势:可获取完美标注、可重置场景、可并行采集
├── 数据量:数百万帧
└── 模型学习到基本驾驶策略
阶段 2:域适应(Domain Adaptation)
├── 问题:模拟器图像与真实图像分布不同(Sim-to-Real Gap)
├── 方法:
│ ├── 无监督域适应:对齐特征分布
│ ├── 风格迁移:将真实图像转为模拟风格
│ └── 微调:用少量真实数据 fine-tune
└── 数据量:仅需数千帧真实数据
阶段 3:真实道路部署
├── 安全约束:输出层加限幅、加入安全兜底策略
├── 持续学习:收集难例数据,定期更新模型
└── 监控:实时检测模型置信度,低置信度时交还人类
第三章:Tesla FSD 的端到端实践
3.1 纯视觉架构
Tesla FSD 感知栈(2023+):
8 个摄像头(120 万像素,360° 覆盖)
├── 前视主摄像头(FOV 50°):远距离目标
├── 前视广角摄像头(FOV 120°):近距离大视野
├── 左/右 柱摄像头(FOV 100°):侧方
├── 左/右 前翼子板摄像头(FOV 90°):侧前方
└── 左/右 后翼子板摄像头(FOV 100°):侧后方
↓
[BEV 特征提取]
├── 每个摄像头图像独立提取特征
├── 通过 Transformer 进行跨摄像头注意力
├── 投影到统一鸟瞰图(BEV)空间
└── 输出:BEV 特征图
↓
[多任务头]
├── 3D 目标检测(车辆/行人/自行车/...)
├── 车道线检测
├── 交通标志/信号灯识别
├── 可行驶区域分割
├── 深度估计(单目深度)
└── 运动预测(每个目标的速度/航向变化)
↓
[规划网络]
├── 输入:BEV 特征 + 导航目标点
├── 输出:未来 7 秒的规划轨迹(每 0.1 秒一个点)
└── 约束:碰撞检测 + 舒适度 + 交通规则
3.2 HydraNet:共享骨干 + 任务分支
HydraNet 架构设计:
输入图像
↓
┌────────────────┐
│ 共享骨干网络 │ ← 所有任务共享
│ (ResNet/Swin) │
└────────────────┘
↓
┌────────┼────────┬────────┐
↓ ↓ ↓ ↓
┌────────┐┌────────┐┌────────┐┌────────┐
│目标检测││车道线 ││深度估计││运动预测│ ...
│ 头 ││ 头 ││ 头 ││ 头 │
└────────┘└────────┘└────────┘└────────┘
↓ ↓ ↓ ↓
各任务独立 Loss → 加权求和 → 反向传播
优势:
├── 共享骨干减少计算量(只跑一次特征提取)
├── 各任务头可独立训练和更新
├── 不同任务间隐式共享特征表示
└── 部署灵活:可只启用部分任务头
第四章:UniAD:统一自主驾驶
4.1 架构设计
UniAD 是首个将感知、预测、规划统一优化的框架。
UniAD 架构:
输入:多摄像头图像 I₁, I₂, ..., Iₙ
↓
[Scene Encoder]
├── Image Backbone(ResNet-101)
├── 多尺度特征提取(FPN)
├── View Transformer(LSS):图像 → BEV
└── 输出:BEV 特征 F_bev
↓
[Track Query 初始化]
├── 可学习的 track queries:Q₁, Q₂, ..., Qₘ
├── 每个 query 编码一个目标的信息
├── 包含:位置、速度、类别、历史轨迹
└── 通过跨帧注意力实现目标跟踪
↓
[Task Heads(顺序执行)]
│
├── Track Head(跟踪头)
│ ├── 输入:BEV 特征 + track queries
│ ├── 操作:自注意力(同一帧内目标交互)
│ │ + 时间注意力(跨帧跟踪)
│ └── 输出:更新后的 track queries(含跟踪信息)
│
├── Map Head(地图头)
│ ├── 输入:BEV 特征
│ ├── 操作:Transformer Decoder 查询车道线
│ └── 输出:车道线向量(多项式系数)
│
├── Motion Head(运动预测头)
│ ├── 输入:更新后的 track queries + 地图信息
│ ├── 操作:预测每个目标的多条未来轨迹
│ └── 输出:K 条候选轨迹 + 概率
│
└── Planning Head(规划头)
├── 输入:自车 track query + 地图 + 其他目标预测
├── 操作:基于交互的轨迹规划
├── 损失函数:
│ ├── 碰撞损失:规划轨迹与其他目标预测轨迹的距离
│ ├── 进度损失:鼓励向目标点前进
│ └── 舒适度损失:限制加速度/加加速度
└── 输出:自车的规划轨迹
4.2 联合训练策略
class UniADLoss(nn.Module):
"""UniAD 联合损失函数"""
def __init__(self):
super().__init__()
# 各任务权重
self.w_track = 1.0
self.w_map = 1.0
self.w_motion = 1.0
self.w_plan = 2.0 # 规划损失权重更高
def forward(self, predictions, targets):
# 跟踪损失:分类 + 回归
loss_track = (
self.track_cls_loss(predictions['track'], targets['track']) +
self.track_reg_loss(predictions['track'], targets['track'])
)
# 地图损失:车道线预测
loss_map = self.map_loss(predictions['map'], targets['map'])
# 运动损失:多模态轨迹预测
loss_motion = self.motion_loss(
predictions['motion'], # K 条候选轨迹
targets['motion'], # GT 轨迹
mode='minADE' # 取最小 ADE 的轨迹计算损失
)
# 规划损失:带安全约束的轨迹规划
loss_plan = self.planning_loss(
predictions['plan'],
targets['plan'],
predictions['motion'] # 需要考虑其他目标的预测
)
total = (self.w_track * loss_track +
self.w_map * loss_map +
self.w_motion * loss_motion +
self.w_plan * loss_plan)
return total
def planning_loss(self, pred_traj, gt_traj, other_preds):
"""规划损失:包含碰撞惩罚"""
# L2 损失
l2 = F.smooth_l1_loss(pred_traj, gt_traj)
# 碰撞惩罚
collision_penalty = 0
for other_traj in other_preds:
# 计算最小距离
dist = torch.norm(pred_traj - other_traj, dim=-1).min()
if dist < 1.0: # 距离小于 1 米
collision_penalty += (1.0 - dist) * 10.0
return l2 + collision_penalty
第五章:大语言模型与自动驾驶
5.1 为什么需要 LLM?
传统自动驾驶的局限:
├── 无法理解自然语言指令("在前面那栋红色建筑前右转")
├── 无法处理"长尾"场景(训练数据中没见过的情况)
├── 无法进行常识推理("那个球滚到路上了,可能有小孩追出来")
└── 无法解释决策("为什么突然刹车?" → "因为...")
LLM 带来的能力:
├── 语言理解:将自然语言指令转化为驾驶目标
├── 常识推理:利用预训练知识处理罕见场景
├── 场景描述:用自然语言描述当前驾驶场景
└── 决策解释:解释为什么做出某个驾驶决策
5.2 DriveGPT4:多模态驾驶大模型
DriveGPT4 架构:
输入:
├── 多摄像头图像(视觉 token)
├── 车辆状态(速度、转向角、GPS)
├── 导航指令("在下一个路口左转")
└── 驾驶场景问答("前方发生了什么?")
↓
[视觉编码器]
├── CLIP ViT-L/14 提取图像特征
├── 线性投影层将视觉特征映射到语言空间
└── 输出:视觉 token 序列
↓
[大语言模型(Vicuna/LLaMA)]
├── 输入:视觉 token + 文本 token(拼接)
├── 自回归生成:逐 token 预测
└── 输出:
├── 场景描述:"前方有一辆红色卡车正在变道"
├── 驾驶决策:"减速并保持车距,等待卡车完成变道"
└── 轨迹预测:将文本解码为轨迹坐标
5.3 实际应用场景
class DrivingLLMAgent:
"""基于 LLM 的驾驶智能体"""
def __init__(self, llm, perception_module, planner):
self.llm = llm
self.perception = perception_module
self.planner = planner
def reason_about_scene(self, images, vehicle_state, question=None):
"""对当前场景进行推理"""
# 1. 感知模块提取结构化信息
perception_result = self.perception.process(images)
# 2. 构建 prompt
prompt = f"""
当前驾驶场景分析:
- 自车状态:速度 {vehicle_state.speed} m/s,车道 {vehicle_state.lane}
- 感知结果:
- 前方 {perception_result.front_distance}m 有 {perception_result.front_object}
- 左侧:{perception_result.left_description}
- 右侧:{perception_result.right_description}
- 交通信号:{perception_result.traffic_light}
- 天气:{perception_result.weather}
请分析:
1. 当前场景的主要风险是什么?
2. 推荐的驾驶策略是什么?
3. 未来 5 秒内最可能发生什么?
"""
if question:
prompt += f"\n额外问题:{question}"
# 3. LLM 推理
response = self.llm.generate(prompt)
# 4. 解析响应,生成规划
plan = self.parse_and_plan(response, vehicle_state)
return plan
def handle_edge_case(self, scenario_description):
"""处理长尾场景"""
prompt = f"""
你是一位自动驾驶系统的决策引擎。请分析以下罕见场景并给出安全策略:
场景:{scenario_description}
请给出:
1. 可能的风险分析
2. 推荐的保守策略
3. 需要额外确认的信息
"""
return self.llm.generate(prompt)
第六章:仿真与测试
6.1 CARLA 仿真平台
# CARLA 中使用端到端模型进行测试
import carla
import numpy as np
class CarlaEndToEndEvaluator:
"""在 CARLA 中评估端到端模型"""
def __init__(self, model, town='Town05', weather='clear'):
self.client = carla.Client('localhost', 2000)
self.world = self.client.load_world(town)
self.model = model
# 设置天气
self.set_weather(weather)
# 生成车辆
self.vehicle = self.spawn_vehicle()
# 安装摄像头
self.camera = self.attach_camera()
def run_episode(self, route, max_steps=1000):
"""运行一个测试 episode"""
# 设置导航路线
waypoint = self.world.get_map().get_waypoint(route.start)
observations = []
actions = []
collisions = 0
for step in range(max_steps):
# 获取摄像头图像
image = self.camera.get_image()
# 模型推理
steering, throttle = self.model.predict(image)
# 执行动作
self.vehicle.apply_control(carla.VehicleControl(
steer=steering,
throttle=throttle,
brake=0.0
))
# 记录
observations.append(image)
actions.append((steering, throttle))
# 检查碰撞
if self.check_collision():
collisions += 1
break
# 检查是否到达
if self.distance_to_goal(route.end) < 5.0:
break
return {
'distance': self.distance_traveled(),
'collisions': collisions,
'steps': step,
'success': self.distance_to_goal(route.end) < 5.0
}
6.2 闭环测试指标
评估指标体系:
安全性指标:
├── 碰撞率(Collision Rate):每千公里碰撞次数
├── 最小 TTC(Time-to-Collision):最小碰撞时间
├── 紧急制动次数(Hard Brake):减速度 > 4m/s² 的次数
└── 偏离道路次数(Off-road):驶出可行驶区域的次数
效率指标:
├── 到达率(Success Rate):成功到达目的地的比例
├── 平均速度(Average Speed)
├── 路线完成率(Route Completion):行驶距离 / 总距离
└── 平均行驶时间
舒适度指标:
├── 加速度标准差( Jerk):加加速度的标准差
├── 转向平滑度(Steering Smoothness):转向角变化率
└── 横向偏移(Lateral Offset):与车道中心的偏差
鲁棒性指标:
├── 不同天气下的表现(晴天/雨天/雾天/夜间)
├── 不同交通密度下的表现
└── 不同城镇地图的泛化能力
课后项目
项目 1:在 CARLA 中训练端到端模型
# 环境搭建
pip install carla==0.9.15
pip install torch torchvision
pip install wandb # 实验追踪
# 数据采集
python collect_data.py --town Town05 --routes 100 --weather clear
# 训练
python train_end2end.py --model cnn --epochs 50 --batch_size 64
# 评估
python evaluate.py --model checkpoints/best.pth --town Town05 --weather rain
项目 2:实现简单的行为克隆
class BehavioralCloning:
"""行为克隆:模仿人类驾驶"""
def __init__(self, model):
self.model = model
def train(self, expert_demos):
"""
expert_demos: [(image, steering, throttle), ...]
从人类驾驶演示中学习
"""
dataset = DemoDataset(expert_demos)
dataloader = DataLoader(dataset, batch_size=64, shuffle=True)
optimizer = torch.optim.Adam(self.model.parameters(), lr=1e-4)
criterion = nn.MSELoss()
for epoch in range(50):
total_loss = 0
for images, steerings, throttles in dataloader:
pred_steer, pred_throttle = self.model(images)
loss = (
criterion(pred_steer, steerings) +
0.5 * criterion(pred_throttle, throttles)
)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch}: Loss = {total_loss / len(dataloader):.4f}")
前沿论文推荐
- UniAD (CVPR 2023 Best Paper)
- "Planning-Oriented Autonomous Driving"
- 首次将规划作为端到端优化的目标
- DriveVLM (2024)
- "The Convergence of Large Language Models and Autonomous Driving"
- 理想汽车的多模态驾驶大模型实践
- VAD (NeurIPS 2023)
- "Vectorized Scene Representation for Efficient Online Planning"
- 向量化场景表示的高效规划
- Occupancy Networks (2023)
- "Tesla AI Day 2022: Occupancy Networks for the Real World"
- Tesla 的占用网络表示方法
- GPT-Driver (2023)
- "Language Model Meets Motion Planning"
- 将运动规划转化为语言建模问题
参考资源:
- CARLA Simulator
- nuScenes Devkit
- UniAD 官方代码
- Tesla AI Day 2022 视频
- Apollo 开放平台