想象一辆自动驾驶汽车面前堆着乱七八糟的东西:有正常的小轿车、有被撞歪的护栏、有从货车上滑落的箱子,甚至还有一棵倒下的大树。过去,自动驾驶习惯给每个东西“套盒子”——先判断这是车还是人,再画一个 3D 包围框。可一旦东西形状不规矩,盒子就套不准。现在,特斯拉带火了一种新思路:与其费劲套盒子,不如把车头前方整片空间当成一张巨大的乐高底板,切成一个个小立方体,逐格回答“这格有没有被东西占据”。这就是 Occupancy Network,中文常叫“占据网络”。 占据网络不输出“这是车”或“这是人”,而是输出一张三维的“积木拼图”:哪些格子被占住,哪些格子空着。它擅长处理长尾障碍物和异形物体,又能和 BEV 感知、数据自动标注、规划控制串成一套完整流水线。本文会用“乐高积木”这个比喻,带你从零看懂这个感知新范式。
掌握 Occupancy Network,等于掌握自动驾驶感知从“框选物体”走向“空间建模”的行业方向,对自动驾驶感知、BEV 与占据网络相关岗位是核心竞争力。
可视化演示
展示自动驾驶Occupancy Network如何用体素网格表示3D空间并检测长尾障碍物,支持模式切换查看体素占据与检测对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
体素网格空间占据表示 占据体素:检测到障碍物的空间单元 空闲体素:可通行区域 异形物:长尾障碍物检测 occ(v) = sigmoid(MLP(voxel_feat)) Occupancy Network逐体素预测占据概率。
核心概念
想象你在搭乐高:比起先猜“这堆零件是一辆车还是一棵树”,更稳妥的办法是拿出一块底板,把空间一格一格铺满,然后问“这一格有没有被积木塞住”。Occupancy Network 干的就是这件事。它不是先去识别物体类别,而是把车头前方的三维空间切成大量小立方体,像点灯一样逐格标记“被占”或“空闲”。
这里的“小立方体”就是体素(Voxel),类似乐高积木的单个凸点。传统感知盯着“一个物体”,而占据网络盯着“一片空间”。只要某个体素内有东西,无论是小石子、倒下的树干、还是卡车掉落的货箱,它都会被点亮。这让自动驾驶在面对长尾障碍物时,比“先分类再套框”的思路更不容易漏。
从数学上看,网络对每个体素输出一个占用概率:
1. 体素 v:表示三维空间中某一个小立方格,它带有自己的坐标和周围特征。
2. 特征网络 fθ:把体素坐标、图像特征或点云特征编码成一个实数分数。
3. Sigmoid 归一化 σ:把任意实数分数压缩到 0 到 1,解释为“被占据的概率”。
回到乐高比喻:车辆眼前的世界变成一张会发光的积木地图,哪些格子亮起来,哪些暗下去,就是它理解空间的方式。这种“逐格建模”的思路,正是取代部分传统 3D 检测的底层原因。
对比传统检测
传统 3D 目标检测像一个熟练的包装员,手里只有几种固定尺寸的纸箱:车、人、骑行的人。遇到规规矩矩的小轿车,纸箱一扣刚刚好;可一旦遇到横在路上的大树、被撞弯的护栏,纸箱根本套不进去,于是这辆感知系统就“选择性失明”了。
占据网络换了一套玩法:它放弃纸箱,改拿乐高积木。不追求把物体塞进某个标准框,而是沿着物体轮廓,一格一格把占用格子点亮。哪怕这个物体从没见过,只要它真的占住了空间,体素就能把它“拼”出来。这就是它对异形物体和长尾障碍物更友好的根本原因。
训练时,每个体素其实都在回答一个二分类问题:这格到底是空还是被占。常用的损失函数是二元交叉熵:
1. 体素总数 N:参与训练的体素数量,通常等于真值网格中所有格子。
2. 真值标签 yi:表示第 i 个体素是否真的被占用,1 为占用,0 为空闲。
3. 预测概率 pi:模型输出的第 i 个体素占用概率。
4. 对数项:当预测与真值方向一致时损失小,不一致时损失大。
回到纸箱和积木的对比:纸箱套不住的东西,积木总能一格一格贴合出来。占据网络并不会完全取代 3D 检测,但它把传统检测最头疼的“长尾异形障碍物”这块短板,用空间建模补上了。
BEV融合
用乐高搭一个场景时,如果只有正面照片,很难知道背面有什么。聪明的做法是让多个设计师从不同角度画草图,最后统一铺在同一张底板上。BEV(Bird's Eye View,鸟瞰视角)就是自动驾驶的那张公共底板。
Occupancy Network 和 BEV 感知经常成对出现。系统先通过多个摄像头提取图像特征,再把这些特征投影到统一的俯视网格上;得到 BEV 特征图后,占据网络再沿着高度方向把网格切成柱子,逐柱预测哪些体素被占。这样既能利用多相机看到的丰富纹理,又能在统一坐标系里做空间推理。
用公式表示,就是先把多张图像编码成一张 BEV 特征图:
1. 多相机图像 I1 到 IN:环视摄像头拍摄到的不同视角画面。
2. BEV 变换网络 F_bev:负责把图像特征从透视视角变换到鸟瞰视角。
3. 特征图维度 H×W×C:俯瞰特征图的高度、宽度和通道数,对应真实世界的平面位置。
最终,多张草图拼成一张统一的俯瞰积木底板。占据网络在这张底板上继续向上“搭积木”,把 2D 俯视图扩展成 3D 占用空间,这也是纯视觉方案能输出立体栅格的关键路径。
数据标注
给真实世界搭乐高图纸,最难的不是算法,而是“说明书”从哪里来。如果让标注员在 3D 空间里人工点出每一个体素,成本高到无法想象。现实中的做法更像“扫描实物,自动生成图纸”。
自动驾驶公司通常用激光雷达点云或多帧相机重建,离线生成场景的三维表面,再把三维表面体素化,自动得到每个格子的真值标签。整个过程只需要少量人工复核,尤其适合施工路段、事故现场这类困难场景。除此之外,还会用“影子模式”在量产车上悄悄收集罕见场景,持续挖掘难例,让标注闭环越跑越顺。
真值标签的生成规则可以写成:
1. 体素 v:三维空间中的一个小立方格,用于判断是否被物体占据。
2. 重建表面 reconstructed surface:多帧点云或图像重建出的三维几何曲面。
3. 命中判定:体素与重建表面相交则取 1,否则取 0。
回到乐高比喻:我们不必让人手工画每一个凸点,而是用 3D 扫描仪自动生成图纸。占据网络的落地效率,很大程度上取决于这套“自动扫描 + 人工抽检”的数据标注体系能跑多快。
感知管线
在自动驾驶这间乐高工厂里,Occupancy Network 不是厂长,只是一名可靠的质检员。传感器是原料进货口,规划器是最终决策者,占据网络则站在中间,负责把“空间哪里被占、哪里可走”这份检查结果整理清楚,交给下一道工序。
在实际感知 pipeline 中,占据网络通常放在 BEV 特征提取之后、预测与规划之前。它既要接收当前帧的静态特征,也要接收多帧时序运动特征,这样才不会把“正在移动的车”和“停在路边的车”混为一谈。最终输出的占用体素,会被下游规划模块用来寻找可行驶区域。
整体关系可以简洁表达为:
1. 当前 BEV 特征 F_bev:多相机融合后得到的俯瞰特征图。
2. 时序运动特征 F_motion:多帧信息编码后提供的速度、朝向等动态线索。
3. 拼接 concat:把静态特征和动态特征在通道维度上合并。
4. 当前时刻输出 Ot:第 t 帧的占据网格结果,供规划器做避障决策。
回到工厂比喻:质检员不直接操控机器,但它给厂长递上的“积木占用图”决定了车敢不敢往前走。占据网络之所以能成为视觉感知的新枢纽,正是因为它卡在了“看懂空间”和“做出行动”之间最关键的位置。
业界进展
特斯拉最早把占据网络推到聚光灯下,在 AI Day 上展示了如何用它处理复杂路口的异形障碍物。随后,国内自动驾驶公司纷纷跟进,把 BEV 感知和 Occupancy 合并成新一代量产感知架构,用来补充 3D 检测的盲区。
在工程评价中,业界常用 mIoU 来衡量体素预测质量。所谓 mIoU,就是把每个类别的预测区域和真值区域求“交集除以并集”,再对所有类别取平均:
1. 类别数 K:占据网格中需要区分的类别数量,比如车、行人、可行驶区域等。
2. 单类 IoU_i:第 i 类物体的预测占据体素与真值体素的交并比。
3. 取平均:把各类 IoU 加总后除以类别数,得到整体精度指标。
回到行业视角:占据网络就像一套刚发布的新款乐高套装,说明书还不完整,拼法仍在迭代。特斯拉跑在最前面,国内厂商在量产车上快速跟牌,但算力消耗、标注成本、评测标准都还没有统一,这既是挑战,也是从业者的机会。
AI 应用场景
长尾异形障碍物识别
阶段:感知与预测
解决的问题:传统 3D 检测要求物体能被标准包围框套住,遇到侧翻集装箱、倒伏树木、施工路障等异形物体时容易漏检。占据网络用体素逐格表示空间占用,不依赖固定形状,因此能把这些长尾障碍物完整“拼”出来,给规划器提前避让的理由。
具体案例:某 Robotaxi 在城区路段遇到被撞弯的隔离护栏,传统检测只输出一个不稳定的框;切换 BEV + Occupancy 方案后,护栏被连续的体素点亮,车辆在 30 米外就开始减速绕行,接管率明显下降。
自动标注与数据闭环
阶段:数据与评测
解决的问题:人工在三维空间里逐个标注体素几乎不可行。借助激光雷达点云和多帧重建,可以自动生成占据真值,再通过影子模式筛选难例,把人工集中在模型最容易犯错的地方,大幅降低标注成本。
具体案例:一家量产车企的地库场景中,标注团队先用多帧点云重建停车位和柱子表面,自动生成体素标签;夜间车灯照射造成的反光难例再交给人工复核,整体标注效率提升约 70%。
BEV+Occupancy 的全景栅格输出
阶段:多传感器融合
解决的问题:多路摄像头各自看到局部视角,缺少统一的三维空间表示;BEV 提供俯瞰特征,Occupancy 提供高度方向占用,两者结合可以输出 360° 的立体栅格地图,支撑高速和城区 NOA 决策。
具体案例:某高速 NOA 系统遇到一辆装满超宽货物的货车,普通检测无法判断货箱边缘是否侵入自车道;BEV+Occ 输出车身周围的连续占用体素,系统准确判断出剐蹭风险,主动减速并发出变道提示。
Python 演示
import numpy as np def build_sparse_points(seed=7): rng = np.random.default_rng(seed) points = [] for _ in range(120): x = 4 + rng.normal(0, 0.6) y = 4 + rng.normal(0, 0.6) z = 3 + rng.normal(0, 0.7) points.append([x, y, z]) for _ in range(80): x = rng.uniform(1.0, 3.2) y = 3.0 + rng.normal(0, 0.25) z = 1.0 + rng.normal(0, 0.25) points.append([x, y, z]) return np.array(points) def voxelize(points, grid_size=8, voxel_size=1.0): grid = np.zeros((grid_size, grid_size, grid_size), dtype=np.float64) for p in points: i, j, k = np.floor(p / voxel_size).astype(int) if 0 <= i < grid_size and 0 <= j < grid_size and 0 <= k < grid_size: grid[i, j, k] = 1.0 return grid def build_dataset(grid): feats, labels = [], [] n = grid.shape[0] for i in range(n): for j in range(n): for k in range(n): i0, i1 = max(0, i - 1), min(n, i + 2) j0, j1 = max(0, j - 1), min(n, j + 2) k0, k1 = max(0, k - 1), min(n, k + 2) density = grid[i0:i1, j0:j1, k0:k1].sum() feats.append([1.0, density]) labels.append(grid[i, j, k]) return np.array(feats), np.array(labels) class TinyOccNet: def __init__(self): self.w = np.array([-2.0, 0.8]) def predict(self, x): return 1.0 / (1.0 + np.exp(-(x @ self.w))) def train(self, x, y, epochs=200, lr=0.3): for _ in range(epochs): p = self.predict(x) grad = x.T @ (p - y) / len(y) self.w = self.w - lr * grad def bce(self, x, y): p = self.predict(x) p = np.clip(p, 1e-8, 1 - 1e-8) return -(y * np.log(p) + (1 - y) * np.log(1 - p)).mean() def iou(self, x, y): p = self.predict(x) pred = (p >= 0.5).astype(float) inter = np.sum(pred * y) union = np.sum(pred + y > 0) return inter / union if union > 0 else 1.0 if __name__ == "__main__": pts = build_sparse_points() grid = voxelize(pts) X, y = build_dataset(grid) model = TinyOccNet() model.train(X, y, epochs=200, lr=0.3) print("BCE:", round(model.bce(X, y), 4)) print("IoU:", round(model.iou(X, y), 4))
grid[i, j, k] = 1.0把点云命中的体素标记为占用,这是真值标签的来源。density = grid[i0:i1, j0:j1, k0:k1].sum()计算每个体素周围被占邻居的数量,作为预测特征。self.w = self.w - lr * grad用梯度下降更新线性模型权重,模拟最小化体素分类损失。pred = (p >= 0.5).astype(float)把概率大于 0.5 的体素视为“被占用”。inter = np.sum(pred * y)计算预测占用和真值占用同时为 1 的体素数量,即交集。union = np.sum(pred + y > 0)计算预测或真值至少一方为 1 的体素数量,即并集。model.train(X, y, epochs=200, lr=0.3)训练微型模型,让它在简单场景中学会用邻居密度推断体素是否被占。
常见误区
误区以为 OccNet 和 3D 检测一样,会输出“这是第几辆车”“这是行人还是卡车”的 ID 和类别。
正解占据网络回答的是“这个体素是否被占据”,本质是空间几何建模,不负责区分实例。物体类别、ID、运动状态通常还要靠检测或跟踪模块补充。它更像一张“哪里被占位”的乐高地图,而不是“谁是谁”的花名册。
为何常见:因为可视化里体素彩色点很像语义分割,容易让人误以为它自带身份和类别信息。
误区占据网络能表达任意形状,干脆把传统 3D 目标检测整个淘汰掉。
正解占据网络擅长补“形状”和“长尾场景”,但车辆、行人等核心目标的类别、ID、速度、朝向仍需 3D 检测或跟踪提供。工业系统普遍让两者并行,占据结果与检测结果相互校验,而不是互相替代。
为何常见:行业宣传强调“取代传统检测”,让很多人误以为 OccNet 是全新替代品。
误区训练体素模型需要标注员在 3D 空间里逐个格子涂色,成本高到无法量产落地。
正解主流方案是激光雷达点云或多帧重建自动生成表面,再体素化得到真值;影子模式负责收集困难场景,人工只复核少量难例。这个流程使量产数据闭环成为可能。
为何常见:人们习惯用 2D 图像标注的直觉去理解 3D 空间标注,忽略了自动重建工具的存在。
误区认为它只输出“哪里有障碍物”,对可行驶区域没有帮助。
正解占据网络对每个体素输出占用概率,空闲体素本身就是“这里可通行”的证据。把占用概率低于阈值的区域聚合起来,就能得到自由空间地图,规划器可以直接用它找路。
为何常见:名字里的“Occupancy”太强调“被占”,让人忽略“没被占”同样是重要信息。
误区总觉得 BEV感知 是 2D 俯视分割,Occupancy 是 3D 体素,二者互不相干。
正解当前主流方案常把多相机特征先投影到 BEV 网格,再在 BEV 特征上预测体素占用。BEV 提供统一俯瞰坐标,Occ 在高度方向补全立体信息,二者是特征共享、上下游配合的关系。
为何常见:两个新概念都太火,容易被误读成相互竞争的路线,而忽略它们在 pipeline 中是串联的。
面试题
Q1. 占据网络的空间最小输出单元通常是什么?
- A.矩形包围框
- B.单个像素
- C.小立方体单元← 正确答案
- D.特征图通道
答案:C。占据网络把三维空间切成小立方体,也就是体素。它不像检测输出 3D 框,也不像图像分割输出像素,而是输出体素级别的占用概率,所以正确答案是 C。
Q2. 传统 3D 目标检测的主要痛点是?
- A.无法识别红绿灯
- B.难以精准框住异形物← 正确答案
- C.计算量必然比占网大
- D.无法输出类别概率
答案:B。传统检测依赖固定形状的包围框,遇到倒树、侧翻货车等异形物体就容易漏检或框不准。计算量不是必然更大,检测本身也能输出类别概率,所以正确答案是 B。
Q3. 体素真值标签通常如何获得?
- A.人工逐格涂色
- B.点云重建自动生成← 正确答案
- C.全部来自仿真引擎
- D.高清地图直接提供
答案:B。逐格人工标注成本极高,行业主要使用激光雷达点云或多帧重建生成三维表面再体素化。仿真能补充数据,但真实场景仍靠自动重建,所以正确答案是 B。
Q4. 纯视觉 BEV+Occupancy 中,多相机特征如何进入占网?
- A.先做像素级语义分割
- B.多相机特征投影到鸟瞰网格← 正确答案
- C.直接输出规则包围框
- D.仅依赖激光雷达做后融合
答案:B。纯视觉方案先把多路相机图像编码成 BEV 特征图,然后占网在 BEV 特征上逐列预测体素。像素级分割不是必经步骤,仅靠激光雷达也不叫纯视觉,所以正确答案是 B。
Q5. 哪些场景适合用占据网络补充传统 3D 检测?
- A.道路上倒伏的树木← 正确答案
- B.侧翻集装箱货车← 正确答案
- C.正常姿态的小轿车
- D.路肩堆放的杂物← 正确答案
答案:ABD。倒树、侧翻车、堆放杂物都属于异形或不规则物体,传统 3D 框难以精确表达;正常姿态的小轿车反而是 3D 检测最擅长的目标,不需要占用网络额外补位,所以选 A、B、D。
Q6. 在感知 pipeline 中,占据网络通常放在哪里?
- A.传感器信号发出前
- B.特征编码与规划器之间← 正确答案
- C.运动控制执行之后
- D.取代整个端到端框架
答案:B。占据网络通常接收传感器特征和时序特征,输出占用网格给预测或规划器,因此夹在特征编码和规划之间。它不会取代整个端到端框架,也不会跑到传感器和执行器两端,所以正确答案是 B。
Q7. 相比 3D 目标检测,占据网络的优势有哪些?
- A.可建模非规则障碍物← 正确答案
- B.能表达可通行空闲区← 正确答案
- C.直接输出目标唯一 ID
- D.对长尾物体更鲁棒← 正确答案
答案:ABD。占网逐体素建模,天然适合非规则形状,空闲体素也能暗示可通行区域;但它不负责实例识别,不能直接输出目标唯一 ID,所以不选 C,答案是 A、B、D。
Q8. 体素逻辑分数转成占用概率,通常用哪个函数?
- A.ReLU 激活函数
- B.Sigmoid 激活函数← 正确答案
- C.Tanh 激活函数
- D.最大池化操作
答案:B。Sigmoid 能把任意实数映射到 0 到 1 之间,正好解释为占用概率。ReLU 输出无上界,Tanh 输出范围是 -1 到 1,最大池化不是逐点激活函数,所以选 B。
Q9. 下列哪些做法可以降低占据网络数据标注成本?
- A.多帧点云离线重建← 正确答案
- B.影子模式收集难例← 正确答案
- C.人工标注每一体素
- D.纯视觉生成伪标签← 正确答案
答案:ABD。多帧点云离线重建能自动生成几何真值,影子模式聚焦难例,纯视觉也可以产生伪标签;人工标注每一体素成本最高且不现实,所以不选 C,答案是 A、B、D。
Q10. 衡量体素预测质量的 mIoU 指标是?
- A.各类别 IoU 取平均← 正确答案
- B.只统计被占格子召回
- C.计算所有体素回归误差
- D.与目标检测 AP 相同
答案:A。mIoU 先计算每个类别的预测体素和真值体素的交并比,再对所有类别平均。它不是召回率,不是回归误差,也不等同于目标检测 AP,所以正确答案是 A。