规划器想问的是“前方 8 米、偏左 2 米这一格里有没有东西”,可 6–8 个相机交出来的是各自视角里的像素,单张图像里每个像素离车多远并不知道。把所有相机的特征放进同一张俯视网格(bird's-eye view,BEV),规划才有统一的米制坐标;难点始终是深度:lift-splat 让每个像素沿视线按一个深度分布把特征摊开,BEV query 反过来让每个格子去图像里取特征,占用网格再把输出细化到“这块空间有没有被占”,不必先认出是什么。

待审核草稿。 这一篇还没有经过站主审阅,事实、取舍和措辞都可能修改;引用前请回到文中链接的一手资料核对。

为什么要一张俯视图

相机图像是透视的:远处的车小,近处的车大,一辆车跨在两个相机的边界上会被切成两半。规划要的是米制、俯视、所有传感器共用的坐标:车道朝哪个方向,前车离我几米,旁边那格能不能开进去。BEV 网格把自车周围划成格子,每格存一个特征向量;检测头、地图头、规划头都在这张网格上工作。lidar 点云本来就带三维坐标,可以直接投进去;相机缺的正是深度。

两个常见设置:Lift-Splat-Shoot(Philion 与 Fidler,ECCV 2020)在自车周围 ±50 m 内按 0.5 m 一格,得到 200×200 的网格;BEVFormer(ECCV 2022)用 ±51.2 m、0.512 m 一格,也是 200×200。若每格存 64 个 float16 通道,一张 BEV 特征图约 $200\times200\times64\times2\approx5.1$ MB,这是教学估算。

针孔相机模型里,一个像素对应一条从相机中心出发的射线,射线上每一点都投到同一个像素上。只看一张图,就不知道这个像素里的东西在射线上的哪个位置。投影怎样推导,见相机几何。

先算一次:一个像素怎样摊进鸟瞰格子

下面的数字都是教学设定。相机装在自车原点,朝前($x$ 轴)。某个像素在图像中心偏左,它的射线满足 $y=0.25\,d$:$d$ 是沿光轴的深度,$y$ 是向左的横向距离。只看俯视平面,暂时不管高度。

LSS 论文 §3.1 的做法:网络对每个像素输出一个上下文特征 $c\in\mathbb R^C$,和一个在 $|D|$ 个离散深度上的分布 $\alpha$;放在深度 $d$ 那一点上的特征是两者相乘:

$$ c_d=\alpha_d\,c,\qquad \sum_{d\in D}\alpha_d=1 . $$

设深度只有 4 档 $D=\{4,8,12,16\}$ m,网络输出 $\alpha=(0.1,0.6,0.2,0.1)$,$c=(2,1)$。这里 $C=2$,两个通道可以想成“像车”和“像路面”的程度;真实网络的通道没有这么直白的含义,这样写只是为了好读。BEV 格子取 8 m × 8 m(论文是 0.5 m,这里放大是为了让一个格子里落进两个点)。

深度 $d$ $\alpha_d$ 俯视坐标 $(x,y)$ 特征 $c_d=\alpha_d c$ 落进的格子
4 m 0.1 (4, 1) (0.2, 0.1) $x\in[0,8)$
8 m 0.6 (8, 2) (1.2, 0.6) $x\in[8,16)$
12 m 0.2 (12, 3) (0.4, 0.2) $x\in[8,16)$
16 m 0.1 (16, 4) (0.2, 0.1) $x\in[16,24)$

这是 lift:一个像素变成射线上 4 个带特征的点。接着 splat:论文把每个点分到最近的 pillar(高度无限的竖直格子),同一格里的特征直接相加(sum pooling)。4 个点的 $y$ 都在 $[0,8)$ 里,于是:

  • 格子 $[0,8)$:$(0.2,0.1)$
  • 格子 $[8,16)$:$(1.2+0.4,\;0.6+0.2)=(1.6,0.8)$
  • 格子 $[16,24)$:$(0.2,0.1)$

三格加起来是 $(2.0,1.0)=c$。因为 $\sum\alpha_d=1$,这个像素的特征总量不变,只是沿射线分配到不同距离。如果车真在 8 m 处,它“像车”的特征有 80% 落进了对的格子,10% 落在更近的格子,10% 落在更远的格子。相机 BEV 常见的“沿视线方向拖尾”就是这样来的。

在论文的真实分辨率下(0.5 m 一格、深度每 1 m 一档),同一条射线上相邻的深度点很少落进同一格;相加更多发生在相邻像素之间,以及两个相机视野重叠的区域。

换一个条件:分布变尖、变平,或者放错了

  • 变尖。 $\alpha=(0,1,0,0)$:全部特征落进 $[8,16)$。这相当于先估一个深度再投影;论文把它比作 pseudo-lidar。
  • 变平。 $\alpha=(0.25,0.25,0.25,0.25)$:每个深度点都是 $(0.5,0.25)$,$[8,16)$ 得到 $(1.0,0.5)$,另外两格各得 $(0.5,0.25)$。射线上每个位置的表示都一样,论文把它比作 OFT。论文的说法是:网络因此可以自己选择,是把特征放到一个位置,还是在深度说不准时沿整条射线摊开。
  • 放错。 车其实在 16 m,$\alpha$ 仍然是 $(0.1,0.6,0.2,0.1)$:对的格子 $[16,24)$ 只拿到 10%,大部分落在 $[8,16)$。在俯视图(view)里,这辆车看起来近了大约 8 m。相机的深度误差直接变成 BEV 里的位置误差,这是相机加 lidar 融合最直接的动机。
动画 一个像素摊进三格:特征沿视线拖尾

这张图需要启用 JavaScript。

论文里的真实设置与开销

LSS 论文 §4.1 的设置:深度限定在 4 m 到 45 m 之间,每 1 m 一档;输入图像缩放、裁剪到 128×352;BEV 网格 200×200。一张 $H\times W$ 的特征图会生成 $|D|\cdot HW$ 个点(这里 $|D|=41$),再乘以相机数,点数很大。论文 §4.2 用一个 “cumsum trick” 做 sum pooling:按格子编号把点排序,对特征做累加和,再在每段边界处相减;他们推了这一层的解析梯度,训练快了 2 倍。论文报告整个前向在一块 Titan V 上跑 35 Hz,这是 2020 年硬件上的作者测量。

名字里的 shoot 是规划:网络在 BEV 上输出一张代价图,把 1,000 条模板轨迹(对专家轨迹做 K-means 得到)“打”到代价图上,沿轨迹累加代价,训练时当作分类,测试时取代价最低的那条。这是第 2 篇“候选(candidate)轨迹加打分”的一个学习版本。

反过来取:BEV query

BEVFormer 不从像素往外推,而是从格子往图像里拉。它为每个 BEV 格子准备一个可学习的 query。论文 §3.3 和 §4.2 的做法是:把每个格子升成一根竖直的柱子,在 −5 m 到 3 m 的高度之间均匀取 4 个参考点;用相机内外参把这些点投到图像上,只在“打中”的相机里取特征;每个投影点附近用 deformable attention 再采 4 个点。另有 temporal self-attention,把按自车运动对齐过的上一时刻 BEV 融进来。摘要报告在 nuScenes test 上 NDS 56.9,比之前最好的方法高 9.0。

BEVFormer 的整体结构:(a) 编码层由网格状的 BEV query、时序自注意力和空间交叉注意力组成;(b) 在空间交叉注意力里,每个 BEV query 只和它投影落到的图像区域交互;(c) 在时序自注意力里,每个 query 同时看当前时刻的 BEV query 和上一时刻的 BEV 特征。
原文图BEVFormer 的整体结构:(a) 编码层由网格状的 BEV query、时序自注意力和空间交叉注意力组成;(b) 在空间交叉注意力里,每个 BEV query 只和它投影落到的图像区域交互;(c) 在时序自注意力里,每个 query 同时看当前时刻的 BEV query 和上一时刻的 BEV 特征。图源:Li et al., 2022 · BEVFormer · Figure 2 · CC BY 4.0 · 转为 WebP

用前面同一个相机看:格子中心 $(12,3)$ 满足 $3=0.25\times12$,正好在刚才那条射线上,投到同一个像素。$(4,1)$、$(8,2)$、$(16,4)$ 也都投到同一列。如果每个格子只是照搬那个像素的特征,这 4 个格子会得到一模一样的东西:射线上的歧义并没有消失,只是换了地方。能把它们分开的是:同一个格子被另一个相机、或在下一时刻从另一个角度看到;不同高度的参考点投到不同的像素行,车身和路面在不同高度上看起来不一样;以及注意力权重本身是学出来的。

对比 Lift-splat(推) BEV query(拉)
方向 每个像素把特征推到射线上多个深度 每个 BEV 格子去图像里取特征
深度怎么处理 显式预测深度分布 $\alpha$ 不预测深度,靠多视角、多高度采样和注意力
计算随什么增长 像素数 × 深度档数 格子数 × 参考点数 × 采样点数
典型失败 深度分布错,特征沿射线拖尾 投到同一像素的格子分不开,要靠时序和多视角

Tesla 在 2021-08-19 的 AI Day 上介绍过同一类思路:用铺满位置编码(positional encoding)的输出空间栅格去 attend 图像特征,把图像空间转成 BEV,再用特征队列和视频模块做时序融合(视频,据演讲自动字幕)。那是 Tesla 早期模块化栈的描述。

不铺满网格:稀疏 query

200×200 的网格里大部分格子是空路面。另一条路线不建稠密 BEV,只用一组 object query。PETR(ECCV 2022)的摘要说,它把三维坐标的位置信息编码进图像特征,object query 直接 attend 这些“知道三维位置”的特征去做检测,报告 nuScenes 50.4 NDS、44.1 mAP。StreamPETR 按摘要把 object query 逐帧往后传,做时序融合;Sparse4D 做稀疏的时空采样。SparseDrive 把这条路线接到了规划:全稀疏的感知,加一个并行的运动规划器(据其 README)。

好处是计算随 query 数而不是网格面积增长;代价是不会白送一张稠密的可行驶区域图。不是“物体”的东西,比如路面形状、一堆碎石,需要另加地图头或占用头。

相机加 lidar:BEVFusion

BEVFusion(ICRA 2023)把相机特征和 lidar 特征放进同一张 BEV 里再融合,服务多个任务。摘要报告:nuScenes 三维检测的 mAP 和 NDS 各高 1.3%,BEV 地图分割的 mIoU 高 13.6%,计算量低 1.9 倍;优化 BEV pooling 后,视角转换的延迟降低 40 倍以上。放回上面的例子:lidar 直接测出 16 m,特征就不必靠 $\alpha$ 去猜。

工业界两种立场都有。Waymo 2025-12 的 Foundation Model 用一个 Sensor Fusion Encoder 融合相机、lidar 和 radar(博客);Tesla 在 2025 年第一季度股东信中描述的是纯视觉、端到端神经网络的架构。

占用:先问占没占,不先问是什么

一个 3D 框通常是中心 3 个数、尺寸 3 个数、朝向 1 个数,再加一个类别。横在车道上的梯子、伸出来的树枝、形状不规则的货物,框都描述不好;类别表里没有的东西,检测器也可能直接漏掉。Occ3D(NeurIPS 2023)的摘要把占用预测定义为估计场景中每个位置的占用状态和语义,用来弥补框在细粒度几何和词表(vocabulary)外物体上的不足。

CVPR 2023 占用预测挑战赛用 Occ3D-nuScenes:体素 0.4 m,网格 200×200×16,18 个类别(其中一类是“空”,free),推理时只用相机,按 mIoU 排名。算一下:水平方向 $200\times0.4=80$ m 见方,竖直方向 $16\times0.4=6.4$ m 高;每帧 $200\times200\times16=640{,}000$ 个体素,每个都要给一个类别。按技术报告的摘要,冠军 FB-OCC 的 mIoU 是 54.19%。

mIoU 先对每个类别算交并比,再对类别取平均。比如“车”这一类,预测了 120 个体素,真值 100 个,重合 80 个:

$$ \text{IoU}=\frac{80}{120+100-80}=\frac{80}{140}\approx0.571 . $$

稀有类别和常见类别权重相同,所以几个小类做得差,mIoU 会明显下降。

Tesla 在 2022 年两次介绍过占用网络,都是演讲,下面据自动字幕转述。CVPR 2022 WAD 主题演讲(2022-06-20,视频):8 个相机的视频流一起输出体素占用概率和占用流(occupancy flow),用带三维位置编码的 query 去 attend 多相机图像特征;演讲给的数字是 8 个 1.2 MP、36 fps 的相机,网络在 10 ms 内跑完(公司自报)。AI Day 2022(2022-09-30,视频):输入是未经 ISP 处理的 12 位原始光子计数图像;固定体素对规划不够精细,所以每个体素带特征,可以用一个 MLP 在任意位置查询;训练用的是自动标注,不靠人工标。

标签从哪来

每帧 64 万个体素,不可能人工逐个标。几种做法:

  • 把稀疏的 lidar 补成稠密体素。 Occ3D 的摘要列出三步:体素稠密化、遮挡推理、用图像引导细化体素,得到“考虑可见性”的标签。SurroundOcc(ICCV 2023)按摘要用多帧 lidar 加 Poisson 重建生成稠密真值。
  • 离线自动标注。 车载模型只能看过去;离线标注可以看整段序列的前后帧,用更大的模型。Waymo 的 3D Auto Labeling(Qi 等,2021)就是从整段点云序列离线检测物体。

这样得到的标签继承了 lidar 的盲区:被挡住、没扫到的体素没有可靠真值。所以评测常常只在“可见”体素上算分:CVPR 2023 挑战赛的 README 写明,只在当前相机看得到的体素上算 mIoU,看不见的体素不计入。读别的结果时要看清楚用的是哪一种。

进了端到端栈,它们变成了什么

Tesla 在 2025 年 10 月的 ICCV 演讲中说,显式感知现在是可选的辅助输出,同一个模型可以被要求输出占用、物体等(视频,据演讲自动字幕)。Waymo 的 Foundation Model 仍有一个 World Decoder 输出其他交通参与者的行为、地图和轨迹。Bench2Drive 0.0.4(2026-08)新增了占用模态。BEV 和占用没有消失:它们成了辅助监督、调试视图,以及安全检查能读懂的中间结果。

复现和排错时看什么

先试什么 应该观察什么 不能据此推出什么
用 lidar 深度替换预测的深度分布 BEV 里物体不再沿视线拖尾,距离误差变小 相机深度估计已经够用
训练时随机丢掉一个相机 测试时缺相机的退化变小;LSS 论文报告这样训出的模型在 6 个相机都在时也最好 冗余相机可以省掉
训练和测试时给外参加噪声 LSS 论文报告:测试噪声小时不加噪声训练最好,噪声大时加噪声训练更稳 训练加噪声能抵消真实标定漂移
按距离分段算 mAP / mIoU 远处是否明显变差 平均分好就说明远距离可靠
只在可见体素上评测 vs 全部体素 两个分数差多少 看不见的地方模型也猜对了

参考:Lift-Splat-Shoot · BEVFormer · BEVFusion · Occ3D。下一篇:预测与规划。相机投影见相机几何,用重建做驾驶仿真见三维重建与神经渲染。

本页术语 4
视图 view
同一个对象的一种侧面表示;用户可以同时有画像视图和历史视图
候选 candidate
召回阶段捞出来、等待精排挑选的内容
位置编码 positional encoding
把「第几个 token」的信息注入表示
词表 vocabulary
模型能输出的所有 token 的集合