☰
点云3D目标检测中的voxel表示:原理、工程细节与稀疏卷积
2026/10/16 5:03:05 网站建设 项目流程

1. 为什么点云非要“切成块”:voxel表示的前世今生

1.1 先补一段背景:3D目标检测要面对的数据,本质是“一团乱麻”

做3D目标检测的第一关,不是模型,不是loss,是数据长什么样。激光雷达扫出来的点云,说白了就是一堆无序的三维坐标点,每一帧几千到几十万不等,每个点可能还带着反射强度、时间戳之类的额外属性。

你把这堆点画出来看,它不像图像那样有天然的行列结构,也不像文本那样有先后顺序。它就是一坨漂浮在三维空间里的点,谁先谁后是乱的,靠多近多远是随机的,哪些点属于同一个物体也完全看不出来。这个“无序性”是整个领域第一个需要解决的根本矛盾。

而第二个矛盾是“稀疏性”。一个20米乘20米的场景,人眼看上去挺大,但激光打在光滑地面上、远处墙面上,反射回来的点其实很少。整帧点云里,绝大多数空间区域是空的。这跟图像完全不同——图像每个像素都有值,一秒钟视频数据是规律的稠密张量,几乎所有卷积神经网络架构都默认“输入是整齐排列的网格”。点云呢?它天然就不是网格。

怎么把不规则、稀疏、无序的点云,喂给天生只能吃规则数据结构的卷积神经网络?这就是voxel representation出现在3D目标检测深度学习路线里的根本动因。它不是某个研究团队灵机一动想出来的偏方,而是把“三维空间离散化”这个三维视觉里最朴素的做法,跟深度学习的数据格式需求强行凑在一起之后诞生的标准答案之一。

1.2 voxel表示到底在做什么:一个纸箱子的比喻

我平时跟人解释voxel,最喜欢用的类比是纸箱子。

想象你面前有一个1米见方的纸箱子,你把整个三维场景按这个尺寸均匀切分,切成很多个格子。每个格子里元素多就多放点,元素少就空着。这个格子就是voxel,中文叫体素。你可以把它理解成三维版的像素:像素是二维图像里的最小单位,voxel是三维空间里的最小单位。

关键来了:切完格子之后,点云不再是散落到操作系统列表里的随机点,而是被组织进了“有位置、有邻居、有拓扑关系”的规则三维网格中。这种结构跑起三维卷积来非常顺手,因为卷积核滑动的过程,天然就需要“知道”某个点上下左右前后都有谁。

但从这也能看出一个本质问题:voxel化是一个离散化过程,一步做完,信息就有损失。格子里原本精细的相对位置关系,被粗略地归拢到了格子层面。你切得越细,信息保留得越多,但计算量也越大;切得越粗,速度和显存压力越小,可小目标可能直接碎在格子边界里了。voxel表示学里,所有后续优化、演进、踩坑,本质都是在跟这个“粒度与算力的矛盾”周旋。

1.3 两条路线之争:从点到柱,从柱到格子

我特别想强调一点:voxel representation不是一朝一夕冒出来的。早期雷达点云处理更多靠人工特征,比如统计格网、八叉树;后来深度学习方法出来,先用PointNet学会了直接从点云提取特征,于是主流吵过一架:到底是继续处理原始点,还是把点丢进二维鸟瞰图?脑洞再大一点的,干脆把点云投影到前视图。

体素化路线之所以能后来居上,是因为它在结构上钻了一个空子:既保留了三维空间信息,又绕开了原始点序列在Neural Network里不好处理的难题。最早的尝试里,研究者把点云切成规则体素网格,然后在每个网格里手工统计一堆特征塞给CNN,效果确实有但上限不高。直到某篇工作把“取网格内所有点的特征,聚合生成该网格的表示”这个思路直接改进成了可微操作,再叠上稀疏卷积以后,voxel方法才算真正变成了深度学习框架里的黄金选手。

顺便说一句,标题里那个单词拼写其实是voxel representation,我猜是随手打错。但这不是重点,重点是接下来我打算把这套技术拆开讲清楚:体素化怎么做、体素特征怎么汇集、稀疏卷积为什么是功臣、实际工程里哪些坑必须躲。整篇是系列的第一部分,所以我会把基础讲得尽量扎实。

2. 和point-based方法掰扯一下:两种技术路线的取舍

2.1 原汁原味 vs 整理归纳

既然已经聊了voxel表示的存在意义,就不能不提它对面那条同样主流的路线——point-based方法,也就是直接对原始点云做操作的那一套,代表就是PointNet以及后来各种PointNet++变体。

两条路线的差别,本质上很像两种处理采访录音的方式:一种是把录音一字一句全部转写出来,每句话都保留原样,这叫point-based;另一种是把内容按主题归纳成要点卡片,每个要点只提取核心意思,然后丢掉语气和停顿,这才叫voxel-based。

point-based方法最大的优势在于精度潜力——它操作的是原始坐标,局部的几何细节几乎不会在“切格”过程里被破坏,对精细形状的小物体理论上更友好。但代价也很沉重:每个点都要参与若干次特征传播,点一多,计算图就爆炸;而且PointNet系列在无序集合上的操作,天生不太擅长捕捉远距离点之间的结构化关系——两个点明明很近,却可能在特征空间里一点交互都建立不起来。

voxel-based方法正好相反。它先做一个“归纳整理”,把每个格子里的点压成一个向量,这个“压缩整理”的过程天然丢失了一点细节。可整理完以后,数据有了整齐的三维结构,卷积、池化、区域提案这些在二维图像上被验证了无数次的操作,全部可以直接照搬到三维上。工程上极其舒坦。

2.2 三类表示的核心指标对比

为了让你直观对比,我把现在主流三种点云表示方式的特性拉了一个表格:

表示方式数据结构空间信息保留计算复杂度适合的任务场景主要痛点
point-based(原始点)无序集合最强,坐标级随点数线性上升,但全量计算点云补全、部件分割、小规模检测大规模场景下算力吃紧,难捕捉局部交互
voxel-based(体素网格)规则三维网格取决于体素大小,切得越细越强受稀疏卷积影响,大致随占据格数量浮动大规模室外点云检测、多类别3D检测离散化信息损失,体素尺寸调参敏感
pillar-based(柱状网格)俯视平面网格保留高度维度,损失水平面内细节相对低,因为有效维度只有二维高速实时检测、算力受限的落地点对竖向几何结构极敏感的目标表现不稳定

point-based强在“局部细节原汁原味”,voxel-based强在“结构化与并行化”,pillar-based则是voxel路线的极简变体——它干脆只把平面上切成格子,竖向整条保留,相当于把三维问题降成二维问题来做,后面我会专门展开讲。

2.3 为什么很少有纯point-based的工业落地

我说个读者可能不太注意的事实:现在工业界真正跑在线推理的3D检测器,绝大多数都是基于体素或柱体的。原因很简单,自动驾驶、机器人这类场景需要实时响应,算力基本都被“焊死”在边缘设备上。

纯point-based方法在单机阶段跑论文数据很漂亮,可一旦点云稠密到几十万点一帧,体素方法的稀疏卷积还能靠“只计算有值区域”偷个闲,point-based方法的全量计算就容易被拖垮。这不是说point-based一无是处,而是说在“画面规模大、实时性要求高”这个约束下,voxel表示天然更接近工程解。学术上两条腿走路,落地时多数人都押注了格状表示。

3. voxel化过程中的“魔鬼细节”

3.1 论文里不写、工程上踩坑的“预设骨架”

体素化这件事,理论上就是把点按坐标除以体素尺寸后取整。可我第一次自己复现时,发现代码远没有这么干净。有一个关键细节,几乎所有论文都不讲:你必须在三维空间里先预设一个虚拟的包围盒。

真实激光雷达扫描范围不是无限大的,它有最远探测距离,也有垂直方向的扫描角度范围。体素化之前你得先决定:x轴方向从-50米算到50米,y轴方向0到70米,z轴方向-3米到1米,这个范围叫坐标范围,或者叫侦查域。体素尺寸定了,网格数量其实就已经被这个范围决定了。

如果预设范围太小,远处的目标直接被切在范围外面,整个目标点云被裁掉,检测器对这一片区域就是全盲;如果范围太大,空的体素数量膨胀,虽然稀疏卷积在后面兜底,但可视化调试时满屏空网格,下一步特征提取的有效表示里也会混进大量无意义的边界体素。更麻烦的是,不同数据集里目标的分布范围天差地别,比如城市场景和高速场景的目标距离分布完全不同,你把城市场景标定的坐标范围直接套到高速场景,几乎必挂。

所以严格意义上讲,voxel化不是单纯“切格子”,而是“先圈场地再切格子”。这个场地范围的参数,在很多开源实现里是一个超参,但实际调的时候绝对没有超参那么云淡风轻——它直接决定了你网络能“看到”多远,配合每帧点云数目和体素大小,又决定了每个格子平均装满多少点。

3.2 每个格子该塞多少点?——随机采样和max点数限制

点云进voxel之后,下一个现实问题来了:假设体素尺寸是0.1米,那么一个30米外的汽车目标,大概会占几千个点;而另一辆远在70米外的同型号汽车,它的点云可能只有几十个点。如果每个格子的点数差距几十倍,神经元和梯度都会被“大块头”格子带偏。

现在的通行做法是给每个 voxel 内部做一个点数截断:比如最多保留32个点或64个点,多余的随机丢弃,不够的就重复采样补到固定数量。这个上限值是另一个重要超参,设太小会丢失细节,尤其是对远处反射点数很少的物体;设太大则计算浪费,因为大部分格子里根本凑不齐那么多点。

你可能想不到的是,这个看似丑陋的随机丢弃操作,实际效果反而带一点正则化的味道。随机丢弃让模型对有点雲采样的扰动不那么敏感,训练时同一物体同一姿态的两次体素化结果并不完全一样,迫使网络学到更稳定的特征。我自己实验时,把最大点数从16提到32,多数检测指标有轻微提升,但继续提到64又下滑了。倒不是64点本身有害,而是显存和计算开始吃不消,训练的batch size被迫下降,模型收益反而吃不下这个亏。

3.3 坐标打架:局部坐标与全局坐标

点云在原始数据里都是全局三维坐标,比如(23.5,-12.3,0.8)。但体素化后,有些实现习惯把这些点归一化成“相对体素中心的局部坐标”——每个点仍然有全局位置信息,但它存进体素特征的时候,还要算出自己相对于格子中心的偏移量。

为什么要这么干?因为一个格子内部若干个点如果只用全局坐标,网络很难知道这些点到底在格子内部的哪个位置;而如果只用归一化后的偏移量,格子本身的绝对位置信息又丢了。所以成熟的方法里,经常把两种坐标都保留:有的网络把全局坐标和局部偏移拼一起当输入特征,有的网络干脆只给局部特征,让后面的稀疏卷积去“背”全局位置信息。

这个设计选择看上去小,实际上影响不小。我试过把两种方式各跑一轮对比,全局坐标直接输入的版本在距离较远的目标上定位精度稍好,局部偏移输入的版本在小目标分类上更稳。没有绝对优劣,论文里也很少讨论,但工程选型时值得留意。

3.4 稀疏张量如何存储:哈希索引与规则化填充

从点云切成格子以后,你得到的并不是一个像素紧密排列的完整三维大数组——那会撑爆内存。室外场景切0.1米体素后网格数量轻松几百万甚至上千万,绝大多数是空的,直接开一个稠密数组是在跟显存和内存过不去。

所以工程实现里几乎都用稀疏张量存储。两种主流做法:

  • 哈希索引(hash-based):只存非空体素,用一个哈希表把连续三维索引映射到特征行,内存占用极小,但卷积时要频繁进行哈希查找,速度受哈希冲突影响。
  • 规则化填充(dense-then-pad):某些深层特征图分辨率低时,非空体素数量会越来越多,干脆直接分配完整密集张量,换计算速度,牺牲内存。

选择哪种存储方式,取决于你的体素尺寸和场景大小。早期baseline实现偏爱哈希,因为在分辨率高、稀疏度极大的早期特征图上哈希优势明显;但进入深层特征图后,稀疏度下降,哈希查找反而变成瓶颈,很多框架会自动切成密集张量。这一块建议在选型时多看几个开源后端的实现差异,别被某一种固定实现绑死了。

4. 聚合:从一堆散点到一个格子特征

4.1 最朴素的“取均值”:PointNet式聚合

体素内部塞了一堆点之后,下一步是把这些点“拧”成一个固定维度的特征向量,代表这个格子。最经典的操作就是PointNet里的对称聚合函数——取最大值、均值或者二者结合。

具体来说,每个点先用一个MLP升维,从原始的点特征(坐标、强度、局部偏移)映射到高维表示;然后对这一组点特征做逐通道的max或mean,得到该体素的整体表示。这个操作最大的好处是可微、计算量小、对点数不敏感,任意数量的点进来都能输出固定维度的特征。

但均值操作天然会被“平庸化”:一个体素里如果既有车身的大平面点,又有几个杂乱的噪声点,均值会把尖锐的几何特征磨掉一些;max则相反,容易对极端的离群点过于敏感。很多方法干脆把max和mean一起拼起来用,增加鲁棒性。

4.2 动态体素化,用注意力代替平均

朴素的max/mean聚合有一个隐约的短板:它对格子里每个点的“重要性”不做区分。后来有一类工作打起了“每个点对体素特征的贡献权重应该由网络自己学习”的主意,这就是动态体素化的思路。

核心做法是:格内的点先各自提取特征,然后计算这些点之间一个类似注意力权重的矩阵,加权求和得到体素特征。权重不是固定的,而是根据点与点之间的特征相似度动态生成,比如某个点正好是物体边缘的关键几何点,它的权重就会被训练得更高。

这种做法的代价是计算变复杂,实时性敏感的场景不一定撑得住。但它确实让体素特征的质量上了一个台阶——毕竟“哪些点是关键特征”这种事,反应到数据里说到底是不可预设的,强制网络自己学,远比人肉选规则靠谱。

4.3 从voxel到pillar:维度取舍的艺术

voxel表示再往下压缩一步,就是pillar。

有些方法把三维体素在高度维彻底“放开”,只把平面(x-y平面)切格子,每个柱体里保留所有竖直方向上的点,然后直接用类似体素聚合的方式生成每根柱子的特征。这样一来,网格从三维减少到二维,但z轴信息没有完全丢弃,而是被压缩成了特征。

这个方案最大的优势是算力友好,因为卷积变成了二维卷积,很多原本为图像准备的高性能卷积库可以直接复用;同时感受野跟二维语义分割、检测里几乎一模一样,工程甜点很高。代价就是它对“高度方向上点云分布”的信息保留变得很粗糙,遇到地下车库、高架桥、高低参差的复杂场景,性能不如完整三维体素。

在选型时,我的判断标准很简单:如果你的任务是室外道路场景、目标类别相对固定、车载算力有限,pillar是性价比最高的方案;如果任务要求精细的垂直结构感知或多层复杂场景,老老实实上三维体素加稀疏卷积。

5. 稀疏卷积,voxel方法最大的功臣

5.1 稀疏卷积要解决什么问题:空体素别白算

普通三维卷积对voxel化后的张量直接跑,需要遍历三维空间里每一个网格位置,做乘加运算。问题是我前面反复强调过了——场景里90%以上的体素是空的,这些空位置参与的乘法全是在给0乘权重,浪费算力还增大显存占用。

稀疏卷积的核心思想就一句话:只对非空的位置计算卷积输出。给定一个输入点(体素)位置,标准的稀疏卷积会去“问”一下它的邻居位置是否有值,如果某个邻居位置是空的,那这次贡献就是0,跳过不计算。

这个机制让voxel方法在三维大场景里有了立足之地。空体素比例越高,稀疏卷积节省的算力越高。室外自动驾驶点云里,这个比例经常超过95%,所以voxel方法能跑到实时,稀疏卷积功不可没。

5.2 从稀疏到稠密:感受野扩散的微妙变化

初学的时候容易有误解:稀疏卷积输出张量是不是还是稀疏的?答案是“不一定”。

有两个经典子结构。普通的稀疏卷积,输入非空位置输出才非空,随着层数加深,输出张量会变得越来越稠密,因为一个非空位置经过多次卷积之后,会“波及”到越来越多的邻居。而另一种叫做稀疏子流形卷积的操作更克制:它只在输入本来就非空的位置计算并保持输出位置,非空体的数量不变。

这两种操作组合使用,正好对应一个经典网络的骨架:早期用子流形卷积保持空间稀疏度来提特征,最后用普通稀疏卷积把特征“铺开”到更多位置,再接区域提案。同样的稀疏卷积结构,参数怎么分配,在很多时候比更花哨的网络模块更能决定性能。这也是为什么很多paper明明网络结构改动不大,只要稀疏卷积编排得好,指标就能稳步提升。

5.3 实际框架里值得注意的坑:稀疏卷积也有“密集角落”

稀疏卷积在实现的时候,不是完全“一个非空点独自美丽”。它要把非空点的特征收集到紧凑的矩阵里,一次性做矩阵乘法,再把结果写回输出位置。这个收集和写回的过程涉及索引映射表。如果体素网格特别大、非空点特别多,索引构建的耗时可能反噬卷积加速的好处。有些框架在低稀疏度层上会强制切回密集卷积,别觉得这是实现粗糙——这其实是很务实的性能优化。

还有一点常被忽略:稀疏卷积对体素大小极其敏感。体素切小了,非空占比上升,稀疏优势减弱、索引开销变大;体素切大了,非空点变少,但几何细节丢失严重。所以调参的时候不要只盯着网络的AP曲线,还得顺带观察每层稀疏度、索引构建耗时这些指标,综合判断瓶颈到底在模型容量还是在算子层面。

6. 我的实测体会与避坑经验

6.1 体素尺寸的“玄学”选择,其实有大方向

关于体素尺寸,很多文章只告诉你“越大越快,越小越准”,这话对但没用。我自己的经验是这样分的:小目标(行人、自行车、锥桶)密集的场景,体素边长不要超过目标尺寸的四分之一。0.1米量级的体素可以处理大多数行人;纯乘用车场景,0.2米体素也可以接受;如果场景里只有大卡车,0.4米体素配合充分点数也勉强能用。

但精调的时候,我建议把目标检测的视角、距离分布一起拉出来看。远处目标点少,检测难度不取决于体素尺寸本身,而取决于“每个目标至少能分到几个非空体素”。算一下体素尺寸和目标最小边长,保证目标在x、y方向至少能跨越两个体素,这是最低底线,比玄学调参靠谱得多。

6.2 排查模型性能问题时的体素可视化技巧

模型训练完效果不对,先别急着改网络。我的习惯是,第一步把中间层的稀疏张量导出来,转成稠密体素后按类别做可视化,跟原始点云叠一起对比。这个步骤能一次性暴露出很多问题:预设坐标范围是不是把目标切了边?点数截断的上限是不是把远处的目标“抽空”了?聚合函数输出分布是不是集中在很窄的范围?

具体做法是,把体素矩形的占用情况画出来,检查一下实际的非空位置分布是否跟激光雷达扫描线夹角接近,判断是不是体素尺寸太大导致同一个物体被合并到同一个位置;也可以把各层稀疏卷积输出的非空体素数变化曲线画出来,如果指数下降得太快,说明感受野被限制得太死,下一层根本看不到足够大的上下文。

这一套可视化排查下来,我踩过的坑——比如坐标范围设置错误、体素特征数值饱和、最大点数被无意间设成极小值——基本都在半小时内定位了。可视化不是锦上添花,是voxel系方法开发和调优的必备工具。

6.3 什么时候应该放弃voxel,回到point-based或其他表示

最后说句泼冷水的话:voxel表示虽好,但不是万能药。如果一个任务里目标半径极小、密度也低,同时你对局部精细几何形状敏感度要求很高,体素化这一步带来的量化误差可能直接卡死指标上限。这种时候,点级方法或者“先voxel粗提特征、再point精修”的混合方案,往往能救回来。

另一个容易被忽略的点是,大部分voxel方法的性能收益高度依赖数据集的标注质量。如果标注框抖动很大,你再精细的体素划分也学不出稳定的边界回归。准备数据的时候,清洗和一致性校验花的功夫,往往比后面调体素参数更值得。

6.4 系列下一部分,我准备聊什么

这篇作为系列的第一部分,我把voxel表示的基础、路线的对比、体素化和聚合作业里的核心细节、稀疏卷积的作用都串了一遍。下一部分,我打算重点拆解几个经典检测框架——从早期把voxel化与区域提案结合的代表作,到让检测头部直接基于体素特征做分类回归的演进,再到各种稀疏卷积在检测骨干网络里的具体排布方式。

还会穿插讲我在复现实验时遇到的训练细节:学习率怎么配、正负样本采样怎么调、输出特征金字塔在voxel表示里的处理手法。都是我自己踩完坑以后觉得值得写下来的东西,希望到时候能给你省点时间。

先谢过读到这里的各位,咱们下篇见。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询