模块化方案的三个根本问题
传统 Pipeline 的结构
经典自动驾驶系统按功能切分五个串行模块:
感知 (Perception) → 跟踪 (Tracking) → 预测 (Prediction) → 规划 (Planning) → 控制 (Control)
每个模块独立训练,用前一个模块的输出作为输入。工程上成熟、可调试,但这条信息流有三个结构性缺陷。
问题一:信息在模块边界被压缩
感知模块内部有丰富的特征图(BEV 特征、注意力权重、目标置信度),但它向后传递的只是几个数字——3D 包围盒 (x,y,z,w,l,h,θ) + 类别 + 速度。原始特征里”这个行人正在低头看手机”或”那辆车有轻微加塞倾向”这种软信号全部丢了。
形式化地说,信息流是:
Frich压缩{(xi,yi,zi,...)}i=1N传递Fdownstream
压缩是有损的,下游模块永远看不到上游”看到但没说”的信息。
问题二:错误单向传导,无反馈修正
模块串行意味着上游错误会被下游当真。假设感知漏检了一辆车,预测模块根本不知道这辆车存在,规划就会基于”前方没车”做决策——直到碰撞。下游没有任何机制可以”质疑”上游:“你确定没车吗?我看这个图像区域有点可疑。”
这种单向无反馈是模块化方案的硬伤。端到端之所以能修正它,是因为梯度可以反向流过整个网络,让感知层在”漏检导致规划差”时被惩罚。
问题三:各模块目标函数不一致
每个模块独立训练时,优化的是各自的局部目标:
- 感知优化检测精度(mAP)。
- 预测优化轨迹误差(ADE/FDE)。
- 规划优化碰撞率和舒适度。
但这些局部最优不等于全局最优。感知层追求 mAP 时可能误检一堆静止物体(提高 recall),结果规划层被假阳性的”幽灵障碍”逼停。各模块在自己的 loss 上做到最好,组合起来反而开车开不好。
端到端要解决的就是”共享目标”
端到端范式的核心不是”做成黑盒”,而是让所有模块共享同一个最终目标——安全驾驶。梯度从规划损失一路回传到感知,全局联合优化。这直接对应上面三个问题:
| 模块化的痛点 | 端到端的解法 |
|---|
| 信息压缩 | 模块间传特征图/向量,不压缩成几个数 |
| 错误单向传导 | 梯度双向流,下游可以”反馈”上游 |
| 目标不一致 | 所有模块的 loss 都包含规划项 |
参考
端到端的真正含义
“端到端” 常被误解
最常见的误解:端到端 = 一个巨大黑盒,输入图像输出控制信号,中间全是不可解释的隐层。这种解读催生了”端到端不安全”的担忧。
更准确的定义是关于优化方式,不是关于网络结构:
端到端指训练目标来自最终任务效果,梯度从最终损失回传到最早的特征提取层,实现全局联合优化。网络内部仍然可以有清晰的可解释子任务。
三种可能的”端到端”形态
| 形态 | 结构 | 可解释性 | 代表 |
|---|
| 直接端到端 | 图像 → 隐层 → 控制信号 | 极低 | NVIDIA PilotNet |
| 任务级端到端 | 图像 → 感知/预测子任务 → 规划 | 中(有子任务监督) | UniAD |
| Sparse 端到端 | 图像 → 稀疏 query → 检测/建图/规划 | 高(每个 query 显式锚点) | SparseDriveV2 |
SparseDriveV2 属于第三种——内部结构非常清晰,有显式的检测 query(11 维 anchor)、建图 query(20 点 polyline anchor)、规划候选(26 万轨迹)。它”端到端”体现在:所有这些子模块的参数都接受来自规划损失的梯度更新。
为什么内部仍然要有子任务
完全黑盒(PilotNet 那种)有两个问题:
- 没有中间监督:模型只能从最终的”撞没撞”学,信号极稀疏,训练困难、样本效率低。
- 不可调试:撞了不知道是感知错了还是规划错了,黑盒不可归因。
SparseDriveV2 保留检测、建图、预测这些子任务,每个都有自己的 GT 监督(中间 loss)。这样:
- 训练时每个子模块都有局部信号,收敛快。
- 推理时可以查看”模型认为有哪些车、地图长什么样”——可调试。
- 但这些子模块不是独立训练的——它们的参数同时被规划损失更新,所以最终都为”开车开好”服务。
梯度回传的物理意义
形式化地说,设总损失:
L=Lplan+λ1Ldet+λ2Lmap+λ3Lmotion
其中 Lplan 是规划损失(轨迹误差 + 碰撞惩罚)。Lplan 通过规划模块反向传播经过感知模块,所以感知层的参数 θperc 接受:
∂θperc∂Lplan
这个梯度的意义是:“如果感知参数这样调整一下,规划会更好”。这就是”全局联合优化”的数学含义——感知层不再只为了 mAP,也为了下游规划质量。
端到端 vs 模块化:训练 vs 推理
注意区分:
- 训练:端到端联合训练(共享 loss),模块化独立训练(各自 loss)。
- 推理:两者结构可以一样(都有感知→规划的数据流),差别只在参数是不是联合优化出来的。
SparseDriveV2 推理时的数据流和模块化方案很像,但参数是联合训练的——这是本质区别。
参考
Dense BEV 时代
UniAD 与 CVPR 2023 Best Paper
UniAD(Unified Autonomous Driving,2022 年 arXiv、CVPR 2023 Best Paper)是第一个真正把”感知 → 跟踪 → 预测 → 规划”串成端到端可微流水线的完整系统。它的核心表示是一张密集的 BEV(Bird’s-Eye View,鸟瞰图)特征图。
BEV 特征图:把多视角图像”拍扁”到俯视图
6 个环视相机各有透视视角,看到的物体形变各不相同。UniAD(继承 BEVFormer 的思路)用 attention 机制把多视角特征”投影”到一张统一的 BEV 网格——把 H×W 个 BEV 网格点当作 query,去多视角图像里查询对应特征。
形式化地说,BEV 网格点 pbev=(x,y) 通过可学习的参考点在 3D 空间采样,再投影回各相机图像提取特征:
FBEV(x,y)=DeformAttn(qx,y, {Fcami}i=16)
得到的 FBEV∈RH×W×C 是一张俯视图特征,之后所有任务(检测、跟踪、预测、规划)都基于它。
为什么这样设计有效
统一到 BEV 的好处:
- 空间对齐:所有任务在同一坐标系下操作,目标和轨迹都是 BEV 坐标,不用反复坐标变换。
- 任务解耦但参数共享:检测、跟踪、预测、规划可以各自设计 head,但都从同一个 BEV backbone 取特征。
- 梯度全局回传:BEV 是可微 attention 的输出,规划 loss 的梯度可以经过 BEV 回传到图像 backbone。
代价:计算量爆炸
Dense BEV 的致命问题是它对每个 BEV 网格点都算特征,包括:
- 路面上方的天空(BEV 网格里那些”什么都没有”的点)。
- 远处无人区域。
- 被建筑物遮挡的盲区。
形式化地说,计算量是 O(H×W)——和 BEV 分辨率成正比。一张 200×100 的 BEV 就有 2 万个网格点,每个都要做跨视角 attention。
UniAD 的实际开销(来自论文):
| 项 | UniAD |
|---|
| 训练 | 8 × A100 GPU,约 96–144 小时 |
| 推理 | ~1.8 FPS(远低于实时) |
| Backbone | ResNet-101(参数量大) |
1.8 FPS 意味着每帧要 550 ms——根本没法实时开车(闭环评测需要 20 Hz,即 50 ms/帧)。这就是 Dense BEV 的天花板:精度好,但太慢。
这正是后续工作的出发点
Dense BEV 的”无差别全网格计算”暴露了一个根本问题:自动驾驶场景里大部分 BEV 区域是空的或无意义的。真正需要精细特征的是少数动态目标(车、行人)和有限的地图元素(车道线、边界)。
后续两种思路都是”少算点”:
- Vectorized(VAD):把场景压缩成几条向量(实例 polyline、地图 polyline),但还是先做 BEV encoder。
- Sparse(SparseDrive):彻底抛弃 BEV,只在少数 anchor 点上做计算。
参考
从 Dense → Vectorized → Sparse
三种范式的计算量来源
这是理解整个端到端自动驾驶演进的关键对比。同一个路口场景,三种范式维护的”表示”完全不同:
Dense BEV(UniAD)
整个场景画满 H×W 网格,每个点都算特征:
算力∝H×W
比如 200×100=20000 个网格点,无论该点是不是空的、是不是天空。大部分算力花在”什么都没有”的区域。
Vectorized(VAD)
把场景压缩成几条向量:
- 每个动态目标一条 polyline(运动轨迹的折线表示)。
- 每条车道/边界一条 polyline(地图向量化)。
算力∝Ninstances×Lpolyline+Nmap×Lmap-polyline
比 Dense 小一两个数量级。但 VAD 还是要先做 BEV Encoder——它从 BEV 特征里提取向量,所以 BEV 那层开销没省掉,省的只是后续任务。
Sparse(SparseDriveV2)
完全抛弃 BEV,只维护少数 anchor 点——每个点同时持有可学习特征向量 + 显式 3D 几何位置:
算力∝Nqueries
Nqueries 通常就几十到几百(如 100 个检测 query + 100 个建图 query)。空白区域根本不算——因为没有 query 锚定在那里。
同一个路口的对比
设想一个典型城市路口:5 辆车、3 个行人、4 条车道线、1 个交叉路口。
| 范式 | 维护的表示 | 算的”点数” |
|---|
| Dense BEV | 整个 200×100 网格 | 20000 |
| Vectorized | 5 条轨迹向量 + 4 条车道向量 + BEV encoder | BEV(20000) + 向量交互 |
| Sparse | 5 个车 query + 3 个行人 query + 4 个地图 query | ~12 |
Sparse 的计算量比 Dense 小三个数量级,这就是 SparseDriveV2 能在 L20 上 10 小时训完、推理实时的根本原因。
为什么 Sparse 能省掉 BEV
Sparse 范式的关键洞察:自动驾驶任务的”有效信息”集中在少数实体上——动态目标(要避让)、地图元素(要遵循)、Ego 自身(要规划)。
每个实体用一个 query 表示,query 包含两部分:
- 可学习特征向量 f∈Rd:编码”这个实体是什么、状态如何”。
- 显式几何锚点 a∈R3:3D 空间坐标,编码”这个实体在哪”。
因为锚点是显式坐标,可以通过投影直接找到它在 6 个相机视图上的对应位置,局部采样就能拿到该实体的视觉特征——不需要先拍成 BEV 再去取。这就是 Deformable Aggregation 的核心思想(EP05 详述)。
三者不是简单替代,是逐层精炼
注意:Sparse 不是”VAD 的改进版”,VAD 也不是”UniAD 的改进版”。它们的差异在表示层面——用什么形式编码场景。但都共享”端到端联合训练”的理念。Sparse 范式的代价是:
- 失去了 BEV 的”全局稠密表示”——某些需要全景信息的任务(如 occupancy prediction)在 sparse 框架下不自然。
- query 数量是超参,太少会漏目标,太多又失去稀疏优势。
参考
Sparse 范式的核心机制
Query = 可学习特征 + 显式锚点
Sparse 范式的最小单位是 query,它由两部分组成:
q=(f,a)
- f∈Rd:可学习的特征向量,编码语义信息(“这是个 1.8m 高的行人,速度 1.2 m/s”)。
- a∈R3:显式的 3D 几何锚点,编码空间位置(“在 Ego 前方 12 米、左 2 米”)。
这种”特征 + 位置”的绑定是 Sparse 区别于 Dense 的本质。Dense BEV 用网格位置隐式编码位置(第 (i,j) 格就是某个坐标),Sparse 把位置提升为 query 的一等公民——这让 query 可以直接用坐标去图像里采样,绕过 BEV。
每个 query 怎么从 6 个相机图像里拿到自己的视觉特征?答案是 Deformable Aggregation(可变形聚合),三步:
① 在锚点周围生成关键点
query 不只看锚点正中心一个点,而是在 a 周围生成 K 个采样关键点 {pk}k=1K(K 常取几十到上百)。这些关键点的偏移量是模型学出来的,覆盖目标的整个 bbox:
pk=a+Δk,Δk 由 f 预测
② 投影到相机,只在视野内采样
每个 3D 关键点 pk 投影到 6 个相机视图。投影用的是标准针孔模型 + 相机外参:
πi(pk)=Ki(Ripk+ti)
只有投影落在第 i 个相机图像范围内的关键点,才在那个相机采样。一个 3D 点通常只落在 1–2 个相机的视野里——所以大部分计算是局部的。
③ 加权聚合回 query
在采样的 2D 位置用 deformable attention 取特征,加权聚合成新的 query 特征:
f′=∑i,kwi,k⋅DeformAttn(f, πi(pk), Fcami)
权重 wi,k 由模型学出来,让 query 知道哪些关键点、哪些相机更重要。
为什么这样省算力
对比 Dense BEV:
- Dense:所有 BEV 网格点对(H×W 个)都做跨视角 attention → O(HW)。
- Sparse:只有 Nq 个 query,每个 query 在 K 个关键点、V 个相机(通常 1–2 个有效)采样 → O(Nq⋅K⋅V)。
Nq 通常几十到几百,K 几十,V≈1.5。总量级约 104,远小于 Dense 的 104(20000 网格 × 多视角)。而且空白区域没有任何 query,不浪费算力。
Query 的语义角色
不同 query 锚定不同实体,“知道”不同的事:
| Query 类型 | 锚点形式 | 编码的语义 |
|---|
| Detection query | 11 维 anchor(位置/尺寸/朝向/速度) | “这是哪辆车、多大、多快” |
| Mapping query | 20 点 polyline anchor | “车道线/边界长这样” |
| Planning query | Ego 自身(隐式) | “我要怎么开” |
通过 Sparse 的 attention 机制,planning query 可以主动查询 detection query(“前面那辆车会影响我吗”)和 mapping query(“我必须留在车道内”),实现感知-规划的信息流动。
易错点
- Deformable Aggregation 不是普通 attention:它不在所有空间位置做全局 attention,而是只在预测出的少数采样点做。这是 DETR 系列的 Deformable Attention 思想。
- 关键点偏移是模型学的,不是固定的:Δk 由 f 预测,所以每个 query 的采样点布局是自适应的。
- 投影必须用正确的外参:每个相机的外参随 Ego 运动变化,每帧都要更新。SparseDriveV2 把相机内参外参都喂给模型就是这个原因。
参考
SparseDrive → SparseDriveV2
SparseDrive v1:全稀疏端到端
SparseDrive(v1,2024 年 5 月 arXiv,正式发表于 ICRA 2025)是第一个用全稀疏表示实现端到端自动驾驶的工作。它的贡献:
- 完全抛弃 BEV,用稀疏 query 统一检测、跟踪、运动预测、规划。
- 检测和运动预测同时输出:每个检测 query 同时回归该目标的未来轨迹(motion),不用单独的预测模块。
- 规划模块是生成式的:从稀疏特征直接回归 6 条候选轨迹,每条带一个置信度,选最高的作为最终规划。
v1 的规划范式可以形式化为:
{(τi,si)}i=16=Generatorθ(Fsparse)
其中 τi 是第 i 条轨迹,si 是它的得分,最终选 τ∗=τargmaxisi。
V2 的根本改变:从生成到打分
SparseDriveV2 把规划模块从生成式(generative)改成打分式(scoring)。区别:
| v1 生成式 | V2 打分式 |
|---|
| 候选来源 | 模型自己回归出来 | 预定义的固定候选池 |
| 候选数量 | 6 条 | 26 万条 |
| 模型工作 | 生成轨迹 + 打分 | 只打分 |
| 优化目标 | 回归 GT 轨迹 | 给 GT 轨迹打高分 |
形式化地说,V2 是:
τ∗=argmaxτ∈VScoreθ(τ,Fsparse)
其中 V 是预定义候选池(vocabulary),∣V∣≈262000。
为什么改成打分
打分式有几个本质优势:
- 覆盖率高:26 万条候选几乎覆盖所有合理驾驶行为,而 6 条生成轨迹只能覆盖几种典型模式。
- 训练稳定:打分是排序问题,比回归轨迹(连续空间回归)简单得多——只要让 GT 轨迹得分高于其他轨迹即可。
- 无模式崩塌:生成式回归多条轨迹时容易”6 条都长得差不多”(mode collapse),打分式不存在这个问题。
打分式的前提是候选池足够密——如果 GT 轨迹根本不在候选池里,模型再怎么打分也选不到。这正是 V2 引入 Factorized Vocabulary 的原因(EP05 详述):怎么构造一个 26 万条候选、覆盖率高、可参数化的池子。
V2 的另一个突破:真正的闭环评测
v1 主要在 nuScenes 上做开环评测——给定 nuScenes 的图像,预测轨迹,和 GT 比误差。开环评测的局限:
- 模型的预测不影响环境,没有真实的反馈循环。
- L2 误差小不等于开车安全(轨迹偏离 0.5m 可能在一种场景里没事,另一种场景里撞车)。
V2 第一次在 CARLA 上做了真正的闭环评测——模型的规划被实际执行,环境随之演化,碰撞和违规真实发生。Bench2Drive 是这个闭环评测的协议(EP06 详述)。
演进的主线
v1 (ICRA 2025) → V2
全稀疏端到端 全稀疏 + 打分式规划 + 闭环
6 条生成轨迹 26 万候选打分
开环 (nuScenes) 闭环 (Bench2Drive)
核心变化在规划范式:从”自己生成少量候选”到”在大量预定义候选里选最优”。这个变化让规划更稳、更全面,但也带来了”怎么高效评分 26 万候选”的新挑战。
参考
生成 vs 打分:Scoring 的动机
轨迹规划的两种范式
轨迹规划本质上是”在所有可能的未来轨迹里选一条最好的”。两种实现方式:
| 范式 | 数学形式 | 候选来源 | 优化难度 |
|---|
| 生成式 | τ=Gθ(F) | 模型直接回归 | 难(连续空间回归) |
| 打分式 | τ∗=argmaxτ∈VSθ(τ,F) | 预定义候选池 V | 易(排序) |
其中 F 是场景特征,τ 是轨迹。
生成式:灵活但难优化
生成式让模型直接输出轨迹参数。优点是灵活——理论上能产生任意形状的轨迹,不受预定义集合限制。但有几个问题:
模式崩塌(Mode Collapse)
回归多条轨迹时,模型容易让所有候选都坍缩到同一形状(因为回归 loss 鼓励每条都接近 GT,多条都接近同一个 GT 就会重叠)。形式化地说,设 GT 是 τ∗,回归 6 条 {τi},loss 鼓励 τi→τ∗,结果 6 条都偏向 τ∗,丢失多样性。
v1 用 Winner-Takes-All(WTA)loss 缓解:只惩罚最接近 GT 的那条,让其他条自由探索其他模式。但这只是缓解,没根除。
覆盖率不足
6 条候选覆盖不了一个完整驾驶行为空间。真实驾驶的可行轨迹是连续的(曲率、速度、时长都有无数组合),6 条离散采样必然有盲区。如果 GT 轨迹落在 6 条都不覆盖的区域,模型就学不到。
连续空间回归本身难
回归一条 4 秒、每 0.5 秒一个点的轨迹 = 回归 8 个 (x,y) 对 = 16 维向量。16 维的回归 loss landscape 复杂,训练不稳定。
打分式:稳定但依赖候选池
打分式把规划变成排序问题:
让 GT 轨迹的得分>其他轨迹的得分
这是一个相对简单的目标——可以用对比学习式的 loss(margin loss 或 InfoNCE):
L=−logexpS(τ+,F)+∑τ−expS(τ−,F)expS(τ+,F)
其中 τ+ 是正样本(接近 GT 的候选),τ− 是负样本。这种 loss 收敛快、稳定,没有连续回归的困难。
但打分式有个致命前提:候选池 V 必须足够密。如果好轨迹根本不在 V 里,模型再怎么打分也选不到。
候选池的两难
候选池设计面临两个矛盾目标:
- 覆盖率:池子要足够大,覆盖所有合理驾驶行为 → 倾向于极大池子。
- 计算量:每条候选都要评分,池子越大推理越慢 → 倾向于小池子。
朴素方案:枚举所有曲率 × 速度 × 时长组合 → 候选数指数爆炸,评分不可承受。
SparseDriveV2 的答案:Factorized Vocabulary
V2 的解法是把轨迹分解成两个独立维度:
τ=(Geometric Path,Velocity Profile)
- Geometric Path:走哪条线(空间形状),1024 条。
- Velocity Profile:走多快(时间速度曲线),256 种。
两者笛卡尔积得到 1024×256≈262000 条候选。这个分解的好处是评分也可以分解——先用轻量 MLP 各自打分(不用两两组合),再用 Coarse-to-Fine 策略只对 Top-K 组合精细评分(EP05 详述)。
这样既保证了候选密度(26 万),又控制了计算量(粗筛只评 1280 个)。这就是 SparseDriveV2 选择打分路线的底气。
参考