Occupancy Network 基础:从体素到语义理解
大家好,我是你们的老朋友。今天我们来聊聊 Occupancy Network,也就是占用网络。说实话,这个概念在自动驾驶圈子里火起来也就是这两年的事。我记得 2021 年我第一次在论文里看到它时,还觉得这玩意儿不就是 3D 语义分割的变种吗?后来真正上手做项目才发现,嗯,事情没那么简单。
什么是 Occupancy Network?
Occupancy Network,说白了,就是回答一个问题:三维空间里的每个小格子,到底有没有东西?
你想想看,传统的目标检测只告诉你「那里有一辆车」,但车具体占了哪些空间?车底下有没有空隙?车顶上的行李架算不算?这些问题检测框回答不了。而 Occupancy Network 会告诉你:这个 0.1 米见方的小立方体,被占用了;旁边那个,是空的。
我个人习惯把 Occupancy Network 理解成「三维空间的像素级分类」。就像 2D 图像里每个像素有类别一样,3D 空间里每个体素也有自己的标签——要么是「占用」,要么是「空闲」。当然,更高级的版本还会告诉你这个体素属于什么类别,比如「车」、「行人」、「路面」等等。
我在项目中遇到过一个问题:有人把 Occupancy Network 和点云分割混为一谈。其实区别很明显——点云分割只在有激光雷达点的位置做预测,而 Occupancy Network 要预测整个三维空间,包括那些没有传感器直接观测到的区域。这就像你只看了一眼房间的某个角落,却能推断出整个房间的布局。是不是有点意思?
Occupancy Network 与 BEV 的关系
聊到 BEV(Bird's Eye View,鸟瞰图),很多同学会问:BEV 和 Occupancy 到底啥关系?
我个人觉得,BEV 是二维的鸟瞰,Occupancy 是三维的立体。BEV 把三维世界压扁到地面平面上,告诉你「这个位置有东西」,但不知道这东西有多高。Occupancy 则保留了高度信息,告诉你「这个位置从地面到 2 米高处都被占了」。
举个例子:
- BEV 看到一座天桥,会认为天桥下方的区域被占用了(因为投影到地面)
- Occupancy 能区分:天桥本身占用了 4-5 米高度的体素,而天桥下方的地面是空闲的
你看,这就是维度带来的差异。我在做联合训练时发现,BEV 和 Occupancy 其实是互补的。BEV 擅长捕捉道路拓扑和物体位置,Occupancy 擅长描述三维几何细节。把两者结合起来,效果往往 1+1>2。
3D 体素表示方法
体素(Voxel)这个词,听起来高大上,其实就是「体积像素」。2D 图像的最小单位是像素,3D 空间的最小单位就是体素。
常见的体素表示方法有几种:
| 表示方法 | 特点 | 适用场景 |
|---|---|---|
| 密集体素网格 | 所有体素都存储,简单但内存大 | 小范围、高精度场景 |
| 稀疏体素网格 | 只存储被占用的体素,节省内存 | 大范围自动驾驶场景 |
| 八叉树 | 递归细分,自适应分辨率 | 需要多尺度细节的场景 |
| 三线性插值体素 | 连续空间表示,可微分 | 需要梯度反向传播的训练 |
我个人最常用的是稀疏体素网格。为什么?因为自动驾驶场景实在太大了。一个 100 米 × 100 米 × 10 米的空间,如果用 0.1 米分辨率的密集网格,那就是 1 亿个体素。每个体素存一个 float32,就是 400MB。这谁顶得住?
而稀疏体素网格只存储那些被占用的体素——在大多数场景下,被占用的体素不到总量的 5%。内存瞬间降到 20MB 左右,这才是工程上可行的方案。
语义占用预测任务定义
好了,现在我们终于可以正式定义语义占用预测任务了。
任务目标: 给定多视角相机图像(有时也包含激光雷达点云),预测自动驾驶车辆周围三维空间中每个体素的占用状态和语义类别。
数学上可以这样描述:
输入:I = {I₁, I₂, ..., Iₙ} # n 个相机图像
P = {p₁, p₂, ..., pₘ} # m 个激光雷达点(可选)
输出:O ∈ ℝ^(H×W×D×C) # 三维体素网格
O[i,j,k] = (occupied_prob, class_logits)
其中 H、W、D 分别是体素网格的高度、宽度、深度,C 是类别数(包括「空闲」这一类)。
这个任务有几个关键点:
- 多模态融合: 相机提供纹理信息,激光雷达提供精确深度,两者互补
- 时序建模: 单帧预测容易有歧义,多帧时序信息能提升稳定性
- 长尾问题: 罕见物体(比如路边的消防栓、倒下的树枝)在训练数据中很少出现,但预测时必须正确处理
我记得有一次在高速场景测试,模型对正常车辆预测得非常好,但遇到一辆装载着超长管道的卡车时,完全没预测出管道伸出来的部分。这就是长尾问题的典型表现。后来我们在训练数据里专门增加了这类异形车辆的样本,效果才有所改善。
- 计算量大:三维卷积比二维卷积重得多
- 标注成本高:人工标注三维体素极其耗时
- 传感器盲区:相机和激光雷达都有观测不到的区域
- 动态物体:运动物体的体素位置随时间变化
说到标注成本,我不得不提一句。目前业界常用的做法是用激光雷达点云自动生成伪标签——把点云投影到体素网格里,有激光点的体素标记为占用,没有的标记为空闲。但这种方法有个问题:激光雷达点太稀疏了,很多实际被占用的体素(比如车窗玻璃)可能没有激光点打到,就被错误地标记为空闲。
所以,纯激光雷达生成的伪标签只能作为预训练使用,最终还是要靠人工标注或者多传感器融合来提升质量。这是我踩过的坑,分享给大家。
小结
今天的内容就到这里。我们聊了 Occupancy Network 是什么、它和 BEV 的区别、体素的几种表示方法,以及语义占用预测的任务定义。下一章我会带大家手撸一个简单的 Occupancy Network 模型,从数据加载到训练推理,一步步走通。
如果你对某个细节有疑问,欢迎在评论区留言。咱们下期见。