想象你深夜开进一座陌生而漆黑的地下车库:车灯只能劈开一小片光,你得绕过水泥柱、面包车、歪倒的购物车,却永远不知道柱子后面藏着什么。人类司机会凭经验“脑补”看不见的区域,可自动驾驶汽车没有这种直觉。占用网络(Occupancy Network)就是给汽车戴上的一副“乐高透视眼镜”:它把车身周围的世界切成成千上万个小立方体——就像一盒巨大的乐高积木,然后挨个给每颗积木贴标签:“这里有东西”涂成红色,“这里是空的”涂成绿色,“暂时看不见”涂成灰色。它不纠结“这是轿车还是卡车”,只执着于“这块空间到底结不结实”。特斯拉的FSD、学术界的OpenOccupancy和OpenScene公开基准,都在围绕这套思路展开。
掌握占用网络,等于理解自动驾驶感知从“认框框”到“认空间”的范式跃迁——这是通向L4级安全兜底能力的必修课,也是当前感知算法岗面试的高频考点。
可视化演示
展示3D体素占用预测的核心机制,包括体素网格占用状态、多视角到BEV的架构流程及可行驶空间代价地图,通过交互控件探索不同分辨率下的感知效果。
本节配有交互动效(进入视口后自动加载,约 3KB)。
体素占用预测 占用 空闲 P(occ|v)=σ(f(v)) 三维空间离散化为体素网格,预测每个体素的占用概率
体素占用概念
深夜的地下车库里,保安递给你一盒乐高积木:“别怕,把周围世界想成这盒积木。每一颗凸起的小方块都是一个格子,只要你弄清楚每个格子里有没有东西,就能在黑暗里画出整层车库的地图。”占用网络的第一课,就是学习把连续的世界切成这些有编号的小格子。
这些小格子有个学名,叫体素(voxel),和“像素”是亲戚——像素是二维图像的最小单元,体素是三维空间的最小单元。汽车以自己为中心,把前后左右上下几十米的空间像切豆腐一样切成均匀的立方体,每个立方体边长通常是几十厘米。网格建好后,网络给每颗体素贴一个标签:被物体占据、确认空闲、暂时未知。三个状态地位平等,谁都不是谁的默认值。
从数学上看,整个空间被定义成一个占用指示函数,模型的全部工作就是给每颗体素输出这个标签:
有了这本“乐高字典”,后面的一切——传感器怎么喂数据、网络怎么猜标签——都围绕“把每个格子填对颜色”展开,这就是占用感知的起点。
- $\mathcal{V}$ 占用场函数把三维坐标映射成状态标签的规则,是整个占用空间的总表示。
- $(x,y,z)$ 体素坐标体素在网格中的三维下标,决定“是哪一颗乐高块”。
- $1/0/u$ 三种状态$1$ 表示有实体填充,$0$ 表示确认空闲,$u$ 表示“还没有证据”;未知不等于空,这是安全设计的第一原则。
感知输入方式
这位深夜司机不止有一种照明工具:头顶的环视相机像四支手电筒,看得清纹理却照不出距离;激光雷达像一把激光尺,能精确报距离却只留下稀疏的亮点。占用网络要回答“格子里有没有东西”,必须先把这些照明工具的读数汇在一起。
相机的优势是色彩纹理丰富、成本低、普及率高,弱点是单目图像天生没有深度;激光雷达直接给出精确距离,但点云稀疏、价格昂贵。所谓多传感器融合,就是把“手电筒的画面”和“激光尺的读数”对齐到同一个乐高盒坐标系里:先用相机内参把像素反投影成三维射线,再用深度估计确定该像素究竟落在哪一颗体素上。
相机像素要“抬升”到3D空间,依赖深度与内参的配合,反投影公式如下:
多支手电筒从不同角度照同一个格子,再配合激光尺校准,网络就能更有把握地给每颗乐高块上色——有的方案只用相机,有的方案相机雷达都上,但“把观测对齐到体素格”这一步是共通的。
- $p_{3D}$ 三维空间点像素对应的物体表面在真实世界坐标系中的位置。
- $(u,v)$ 像素坐标图像上某个像素的行列位置,是反投影的起点。
- $d$ 深度该像素到相机的距离,可由雷达测量、双目视差或网络估计得到。
- $K^{-1}$ 内参逆矩阵把像素坐标“翻译”回相机坐标系下的方向向量,乘上深度就得到三维位置。
网络架构设计
假设车库门口有一条流水线:前台小妹收齐所有手电筒的画面(图像编码器),中台大哥把画面按空间位置整理成一张“零件清单”(空间Transformer),后台工人照着清单给每颗乐高块贴标签(体素解码头)。占用网络的架构,就是这条三层流水线。
图像编码器通常用卷积网络(如ResNet)逐路提取2D特征;空间Transformer负责把多视角2D特征“抬升”并融合成统一的三维特征体,解决“同一颗体素被多路相机同时看到”的对应问题;体素解码头再对特征体做上采样与细化,输出每个体素的占用概率。
整条流水线可以浓缩成一个“特征体构造”公式——多个视角的特征被装箱成一个四维张量:
流水线一旦建成,不管车库多大、障碍多怪,它都能按同一套流程把乐高盒填满——这也是占用网络能端到端训练、不需要手工设计特征的原因。
- $\Phi_{3D}$ 三维特征体承载所有空间信息的“零件清单”,是后续分类的依据。
- $\mathrm{Lift}$ 抬升操作把2D图像特征按深度假设反投影到3D体素网格上的过程。
- $F_1,\dots,F_N$ 各路图像特征$N$ 路相机各自提取出的2D特征图。
- 维度 $X\times Y\times Z\times C$空间三个方向各有 $X,Y,Z$ 个体素,每个体素携带 $C$ 维特征表示。
三维占用预测
流水线最后一步是“盖章师傅”:他不再关心“这是轿车还是购物车”,只关心“这颗乐高块该盖红章还是绿章”。对每一颗体素,他都给出一个“这里可能有东西”的置信度分数。
这就是逐体素分类(per-voxel classification)。解码头为每个体素输出一个logit值,经过sigmoid变成0到1之间的占用概率;训练时用真实标签(该体素是否被占用)计算交叉熵损失,让预测概率尽量贴近地面真值。推理时通常设定一个阈值,概率超过阈值就判为占用。
训练损失就是经典的二分类交叉熵,对所有有效体素求平均:
盖章师傅见多识广之后,遇到“柱子后面看不见”的格子,也能根据周围格子的纹理、道路边界和物体运动规律给出合理猜测——这就是遮挡上下文推理,也是占用网络比“只看得到的地方”更强的原因。
- $N$ 体素总数参与损失计算的体素个数,通常只统计观测区域内的体素。
- $y_v$ 真实标签第 $v$ 个体素真实是否被占用,占用为1、空闲为0。
- $p_v$ 预测概率网络预测第 $v$ 个体素被占用的概率,越接近 $y_v$ 越好。
- $\log$ 与求和平均当 $p_v$ 偏离 $y_v$ 时损失变大;全部体素求和后取平均得到整体损失。
特斯拉占用网络
特斯拉是那个“只戴手电筒、不买激光尺”的老司机。它在FSD里搭了一套纯视觉占用网络:8路环视相机把图像喂进模型,直接吐出车身周围一圈“乐高盒”的占用状态,连高精地图都不依赖。
这套方案有几个鲜明特点。第一,输入纯相机,成本低、视野广、量产可落地;第二,输出不仅是占用网格(Occupancy Grid),还附带占用流(Occupancy Flow)——既知道哪里有东西,也知道东西正往哪个方向移动,相当于给乐高块加上了“速度标签”;第三,不同距离使用不同分辨率:近处体素细小,远处体素粗糙,以此控制计算量。
每个体素的占用概率,由它的特征向量经过一层线性变换再套上sigmoid得到:
老司机虽然没买激光尺,但靠着“手电筒加会推理的大脑”,照样能画出整层车库的占位图,还能看出哪个购物车正朝自己溜过来——这正是纯视觉路线的底气所在。
- $f_v$ 体素特征解码头输出的第 $v$ 个体素的特征向量,包含视觉与空间信息。
- $w$ 与 $b$ 权重偏置可学习的线性映射参数,决定特征如何转化为分数。
- $\sigma$ sigmoid函数把任意实数压缩到0到1之间,变成“占用概率”。
公开基准评估
光自己说“我能看清车库”不算数,得把车开进驾考考场让裁判打分。OpenOccupancy和OpenScene就是这样的考场:它们提供带标准答案的“车库图纸”,让各路占用网络同台竞技。
OpenOccupancy基于nuScenes等自动驾驶数据集,用激光雷达累积点云加人工标注生成稠密的3D占用标签,覆盖数十类语义;OpenScene则侧重开放词汇的场景理解,考验模型对“没见过的描述”的泛化能力。评测时,把预测的体素与真实体素逐格对比,最核心的指标是IoU(交并比)。
IoU衡量“预测占用的格子”和“真实占用的格子”的重合程度:
考场图纸一摊开,哪家网络“猜得准、漏得少”一目了然。工程师也能借此发现自己的乐高上色手艺,究竟在哪些格子上还需要打磨。
- $TP$ 真正例预测占用且实际确实占用的体素数,即“猜对的红色格子”。
- $FP$ 假正例预测占用但实际为空闲的体素数(误报),比如把空墙当成障碍。
- $FN$ 假负例预测空闲或未知但实际占用的体素数(漏报),比如被遮挡而漏掉的行人。
- 比值范围IoU越接近1越好,误报和漏报都会同时拉低分数。
价值与挑战
占用网络最大的价值,是让司机在黑暗车库里不再“因为没见过某种奇形怪状的购物车就撞上去”。它不认名牌,只看“这块空间到底实不实”——这恰恰是安全兜底最重要的能力。
对规划模块而言,一张稠密的占用图意味着“任何被占据的体素都可以围成不可驶入区域”:无论是施工围挡、侧翻货车,还是歪斜的集装箱,都能被统一建模、统一避让。这是目标检测框做不到的,因为检测器只能识别“训练集里出现过的东西”。
挑战也明摆着:体素分辨率与计算量是立方级关系。网格切细一倍,体素数就变成8倍,显存和延迟都会迅速膨胀:
所以这盒乐高不能贪大贪细——聪明的做法是近处精细、远处粗糙、只计算有内容的稀疏格子。占用网络的前沿探索,正是在“看得全”与“算得起”之间反复权衡。
- $L_x,L_y,L_z$ 感知范围三个方向覆盖的空间总长度,决定“乐高盒”有多大。
- $r$ 体素边长每个小立方体的尺寸,决定“乐高块”有多细。
- $r^3$ 立方增长分母上的三次方揭示了为什么分辨率微调、算力爆炸。
AI 应用场景
城市领航辅助的“安全兜底层”
阶段:环境感知与感知-规划接口
解决的问题:传统目标检测只能识别“见过的类别”,遇到倒在地上的货车、翘起的井盖、乱堆的施工围挡会漏检,漏检即事故。占用网络把路权空间逐体素标注为占用/空闲,规划模块直接把红色体素视为禁入区域,不依赖任何类别名称。
具体案例:某品牌城区NOA在施工路段遇到一辆侧翻的三轮车,检测器置信度飘忽不定,但占用网络稳定输出一片红色体素,车辆自动减速绕行——全程没有“认出来”,却安全通过了。
代客泊车与封闭园区物流
阶段:感知输入与局部建图
解决的问题:泊车场景里柱子、锥桶、闸杆和车辆混在一起,检测框互相遮挡、频繁跳变;占用网络像“黑暗车库里的乐高图”一样,把空间一次性稠密表达出来,支撑低速精确避障。
具体案例:一个自动代客泊车演示中,车辆用四路鱼眼相机实时输出20米内的3D占用网格。一辆婴儿车从前方货车后面探出半个身位时,网格里突然多出几个红色体素,系统在婴儿车完全露面之前就开始减速刹停。
离线数据生成与基准评测
阶段:数据标注与模型评测
解决的问题:逐体素手工标注几乎不可能完成;OpenOccupancy一类基准利用激光雷达累积点云自动生成稠密标签,让训练和评测变得可复现、可对比、可迭代。
具体案例:算法团队先在OpenOccupancy上预训练占用网络,再用自有数据集微调,将mIoU从35%提升到52%;同时用OpenScene做开放词汇评测,检验模型对“没见过的路况描述”的泛化能力,作为量产前的重要关卡。
Python 演示
import numpy as np G = 6 # 每个维度体素数: 6x6x6 # 1. 构造真实世界: 三个障碍物立方体(真实占用的体素)truth = np.zeros((G, G, G), dtype=np.int8)for x, y, z, s in [(1, 1, 1, 2), (4, 3, 1, 2), (2, 4, 3, 1)]: truth[x:x+s, y:y+s, z:z+s] = 1 # 2. 模拟传感器观测: 初始全部为未知(-1)sensor = np.full((G, G, G), -1, dtype=np.int8) # 3. 沿x方向逐束发射射线: 打中障碍即停 后面的体素保持未知for y in range(G): for z in range(G): for x in range(G): if truth[x, y, z] == 1: sensor[x, y, z] = 1 break sensor[x, y, z] = 0 # 4. 用IoU评估可见面猜测的损失tp = int(np.sum((sensor == 1) & (truth == 1)))fp = int(np.sum((sensor == 1) & (truth == 0)))fn = int(np.sum((sensor == 0) & (truth == 1)))iou = tp / max(tp + fp + fn, 1)print("真实占用体素数:", int(truth.sum()))print("射线能看到的占用体素数:", tp + fp)print("被遮挡漏掉的占用体素数:", fn)print("可见部分IoU: %.2f" % iou) # 5. 保守策略: 把未知体素都当占用 对比IoU变化safe = sensor.copy()safe[safe == -1] = 1tp2 = int(np.sum((safe == 1) & (truth == 1)))fp2 = int(np.sum((safe == 1) & (truth == 0)))fn2 = int(np.sum((safe == 0) & (truth == 1)))iou2 = tp2 / max(tp2 + fp2 + fn2, 1)print("保守策略IoU: %.2f" % iou2)
truth = np.zeros((G, G, G), dtype=np.int8)先搭好“真实世界”的小乐高盒,障碍物是三个大小不同的立方体。sensor = np.full((G, G, G), -1, dtype=np.int8)传感器的观测图,初始全部为未知,对应灰格子。if truth[x, y, z] == 1:射线沿x方向逐格前进,撞到障碍就标记占用并立即停下。sensor[x, y, z] = 0射线经过的格子标记为空闲,代表“看见并确认没东西”。tp = int(np.sum((sensor == 1) & (truth == 1)))数一数“猜对的红色格子”,即真正例。iou = tp / max(tp + fp + fn, 1)用IoU给可见面猜测打分,分母加1防止除零。safe[safe == -1] = 1保守策略:把所有未知格子都当成占用,观察误报如何上升。
常见误区
误区“占用网络不就是把目标检测从2D框升级到3D框吗?反正都要输出物体的类别和朝向。”
正解占用网络不画框、不数物体,而是把空间切成体素后逐格判断“有没有东西”。它天然能表达任意形状的障碍物,包括检测器从未见过的异形物体。是否输出语义类别是可选的,很多方案只输出占用/空闲/未知三态。检测器回答“有几个物体、是什么”,占用网络回答“哪块空间是实的”。
为何常见:自动驾驶感知课程的主线是“检测-分割-跟踪”,初学者习惯把新方法硬塞进旧框架,于是误以为占用是检测的变体。
误区“某个体素没有被传感器扫到,那就先当它是空的吧,反正撞上的概率很低。”
正解未知应该像乐高盒里没打开过的抽屉——里面可能有东西。把未知当空闲是安全大忌,特斯拉和公开基准都单独建模未知态。正确的做法是在规划层面把未知区域视为“可能占用”,减速观察后再决定是否通行。
为何常见:人眼天生会把看不见的地方脑补成“安全区”,这是大脑的乐观偏差,放到自动驾驶上就成了隐患。
误区“分辨率越高感知越精细,所以网格切得越细就越牛。”
正解网格变细一倍,体素数变成8倍,计算量和显存跟着立方级爆炸。工业界普遍用稀疏计算、多分辨率、径向分层来平衡,只在自己关心的感知范围内细化。一味求细,可能让车“想得慢”反而更危险。
为何常见:直觉上“细节等于效果”,忽略了三维网格体积随分辨率三次方增长的数学事实。
误区“特斯拉证明了纯视觉占用网络可行,那激光雷达可以退役了。”
正解特斯拉证明了纯视觉路线在特定条件下可行,但激光雷达仍有独特价值:直接测距、不依赖纹理、夜间和逆光下表现稳定,还能为训练生成高质量占用标签。多数量产方案走的是相机加雷达的多传感器融合,而不是非此即彼。
为何常见:媒体把特斯拉的“视觉优先”放大成“唯一解”,掩盖了工程上对冗余安全和成本效益的综合考量。
面试题
Q1. 占用网络中最基本的预测单元是什么?
- A.二维图像中的像素格子
- B.三维空间中的立体体素← 正确答案
- C.二维图像中的检测方框
- D.三维空间中的测量点云
答案:B。占用网络把3D空间网格化成一个个小立方体,体素是它的基本单元。像素是2D分割的粒度,检测框是目标检测的输出,点云点是雷达的原始数据,都不是“网格化空间”的最小单元。
Q2. 某个体素被预测为“占用”,意味着什么?
- A.该体素内部完全透明空旷
- B.该体素内部存在物体填充← 正确答案
- C.该体素内部传感器没覆盖
- D.该体素内部光线无法穿透
答案:B。占用表示该体素内有实体填充,就像乐高盒里这一格被积木塞满了。空闲才代表确认空旷,未知代表没有观测证据;“光线无法穿透”是造成未知的原因,而不是状态本身的定义。
Q3. 占用网络采用稀疏计算(只激活与内容相关的体素位置)的主要目的是什么?
- A.降低计算量并提升实时性← 正确答案
- B.增大训练数据集的总体规模
- C.让激光雷达的测距更加精确
- D.让相机像素分辨率更清晰
答案:A。三维空间里绝大多数体素是空地,逐个体素都算会造成巨大浪费。稀疏计算只激活有内容的位置,好比只检查抽屉里“可能藏着东西”的那几个,而非把整面墙的乐高块全部翻一遍。
Q4. 体素处于“未知”状态的最主要来源是什么?
- A.被前方障碍物遮挡看不到← 正确答案
- B.相机供电中断自动关机
- C.模型把背景误判成占用
- D.训练数据被错误标注导致
答案:A。前方障碍物会挡住射线,阴影里的体素没有任何观测证据,只能保持“未知”。相机断电、背景误判、标注错误都不是系统性成因——未知的本质是“没有证据”,就像柱子后面的乐高块无人在黑暗中照过。
Q5. 特斯拉FSD的占用网络主要输入是什么?
- A.超声波雷达回波信号数据
- B.高精度地图的矢量线数据
- C.机械式激光雷达点云数据
- D.环视多路相机拍摄图像← 正确答案
答案:D。特斯拉走纯视觉路线,用环视多路相机图像作为占用网络的输入。高精地图、超声波雷达、激光雷达都不是其占用网络的主输入——这正是“只带手电筒的老司机”方案的核心特点。
Q6. OpenOccupancy数据集的主要用途是什么?
- A.仿真车辆底盘运动动力学
- B.训练与评测三维占用网络← 正确答案
- C.自动生成高精度道路地图
- D.训练车载语音交互大模型
答案:B。OpenOccupancy基于nuScenes等自动驾驶数据,提供逐体素的稠密3D占用标签,用来训练和评测占用网络。底盘动力学、高精地图、语音交互是其他领域的数据集,与占用感知无关。
Q7. 占用网络的典型输入包括哪些?
- A.多路相机图像与激光雷达点云← 正确答案
- B.自车位置姿态等运动状态信息← 正确答案
- C.传感器内外参标定参数信息← 正确答案
- D.驾驶员心电呼吸等生理信号
答案:ABC。占用网络需要感知观测(图像/点云)、自车运动状态(用于坐标对齐)和标定参数(用于多传感器投影到同一乐高盒)。生理信号属于驾驶员监控,跟空间占用预测没有关系。
Q8. 逐体素占用分类训练时最常用的损失函数是哪个?
- A.交叉熵分类损失函数← 正确答案
- B.最大间隔铰链损失函数
- C.均方误差回归损失函数
- D.余弦相似度对比损失函数
答案:A。体素占用是典型的二分类问题,默认使用交叉熵损失,让预测概率逼近0/1标签。MSE用于回归,铰链损失用于SVM式分类,余弦对比损失用于表征学习,都不是占用分类的标准选择。
Q9. 相比目标检测,占用网络有哪些优势?
- A.无需预设障碍物的具体类别← 正确答案
- B.能感知任意形状的障碍物体← 正确答案
- C.可推理被遮挡区域的占用状态← 正确答案
- D.计算量一定比目标检测更小
答案:ABC。占用网络输出密集体素场,不预设类别、能表达任意形状,还能借上下文推理被遮挡区域。但它通常比目标检测计算量更大,所以D错——安全兜底是拿算力换来的。
Q10. 一辆卡车完全遮挡了后方的自行车,占用网络应如何建模自行车所在体素?
- A.直接删除该体素不参与计算
- B.预测为空闲来提高通行效率
- C.预测为未知并等待后续更新← 正确答案
- D.强制预测为占用以保持安全
答案:C。被完全遮挡的体素没有观测证据,应留在“未知”状态,等后续帧或自车移动后获得新观测再更新。强制预测占用会制造大量误报,预测空闲则可能撞上未发现的障碍,直接删除则丢失了“那里可能不安全”的提醒——未知本身就是信息。