3D目标检测这个方向,我从几年前做点云感知项目开始就一直在跟,踩过的坑、绕过的弯路能写满一个笔记本。这次借着整理综述笔记的机会,把散落在各处的理解重新串了一遍,索性写成一篇完整的分享。如果你正在入门自动驾驶感知、机器人抓取、AR/VR空间理解,或者单纯想把3D检测的知识体系搭起来,这篇内容应该能帮你省下不少翻论文的时间。我会从整体设计思路讲到核心模块拆解,再到实操落地和问题排查,尽量把每个“为什么这么选”讲透,而不是只丢结论。
先说清楚这个笔记到底解决什么问题。2D检测告诉你图像里有个车,但它离你多远、朝向哪边、占了多大空间,这些信息在3D世界里才是真正能用的。3D目标检测要输出的就是带位置、尺寸、朝向的立体框,输入可能是点云、可能是多视角图像、也可能是两者融合。这个领域论文多、术语杂、评价指标和坐标系约定各家还不完全一样,初学者最容易在“看起来都懂、一动手就懵”的状态里打转。我整理这套笔记的核心目的,就是把数据表示、网络架构、损失设计、后处理这几条主线理清楚,让读者能自己判断一篇新论文到底改在了哪个环节。
1. 整体设计与思路拆解
1.1 为什么3D检测不能照搬2D那套
很多人刚转过来会想,2D检测的框架那么成熟,直接套到3D上不就行了。我一开始也这么天真过。问题出在数据形态上:图像是规整的网格,卷积核滑过去就行;点云是无序、稀疏、密度还不均匀的散点集合,同一个物体近处几百个点、远处可能就十几个点。你没法直接在上面滑窗口。
所以3D检测的第一层设计决策就是怎么把无序点云变成网络能吃的表示。主流路线大致三条:体素化、柱状化、以及直接在原始点上做操作。体素化是把空间切成小格子,每个格子里的点聚合成一个特征向量,这样就能复用3D卷积;柱状化是只在俯视平面切格子、高度方向不切,牺牲一点垂直分辨率换取速度;点式方法则用类似PointNet的算子直接处理点集,保留原始几何但计算效率是老大难。
我选路线时的判断逻辑很简单:看你的场景对垂直方向精度要求高不高、实时性卡得多死。自动驾驶里远处行人高度信息很关键,体素化更稳;如果是园区低速物流车,柱状化往往够用还快。这个取舍没有标准答案,但你必须知道自己为什么选它。
1.2 坐标系与评价指标的约定必须先统一
这是我在实际项目里吃过亏的地方。不同论文、不同开源代码对坐标系朝向的定义不一样,有的把x朝前、有的把x朝右,角度有的用弧度有的用度数,旋转范围有的定义在[-π, π]有的在[0, 2π)。你要是没统一就直接对比结果,数字看着差不多,实际框全歪了。
我的做法是在笔记最前面固定一套约定:相机坐标系、激光雷达坐标系、鸟瞰图坐标系三者之间的转换关系写成显式公式,所有实验都换算到同一套下面再比。评价指标上,3D检测常用的是不同IoU阈值下的平均精度,但要注意IoU是按3D体积算还是按鸟瞰投影算,两者差别不小。笔记里我专门列了张表把常见约定对齐,这个习惯后来帮我避免了好几次“复现结果对不上”的抓狂。
1.3 单模态还是多模态融合的决策
图像有丰富的纹理和语义,点云有精确的几何和深度,融合听起来很美,但工程复杂度是实打实翻倍的。我的经验是分阶段走:先把单模态基线跑通、把评价流程搭稳,再考虑融合。单模态点云方案在几何精度上通常更可靠,图像分支更多是补语义和远距离的短板。
融合又分前融合、特征融合、后融合。前融合在数据层就对齐,实现简单但对齐误差敏感;特征融合在中间层交互,效果通常最好但结构复杂;后融合各自出结果再合并,鲁棒但信息利用不充分。笔记里我把这三类的代表思路和适用条件都标了出来,方便按项目约束快速定位。
2. 核心细节解析与实操要点
2.1 点云预处理:被低估的关键环节
很多人把精力全砸在网络上,结果预处理没做好,再好的模型也白搭。点云预处理我一般分四步走,每一步都有讲究。
第一步是范围裁剪。原始点云动辄覆盖上百米,但检测任务往往只关心前方一定区域。裁得太小漏目标,裁得太大浪费算力还引入噪声。我的经验值是按最远检测距离留10%到20%的余量,比如要检测80米,裁剪范围给到90到100米。
第二步是地面点分离。地面点占了点云很大比例,对检测没帮助还干扰聚类。常用做法是基于高度阈值加平面拟合,先估计地面方程再把贴近地面的点滤掉。这里要注意坡度场景,固定高度阈值在上下坡会失效,得用局部平面拟合或者分块处理。
第三步是体素下采样。点太密没必要,用固定尺寸的体素把每格内的点取质心或随机采样一个,既降数量又保持分布。体素尺寸这个参数很关键,太小降不下来,太大细节丢失。我通常从0.05米到0.1米之间试,配合检测距离调整。
第四步是数据增强。3D的数据增强比2D讲究,旋转、缩放、平移都要考虑物理合理性。全局旋转增强要注意别把地面转歪了,我一般只做绕垂直轴的旋转。还有一类常用的“复制粘贴”增强,把其他样本里的目标贴进来增加稀有类别,但贴合位置和朝向要检查,贴到空中或者穿模就适得其反。
提示:预处理参数一定要和评价流程绑定记录。我见过有人调完预处理忘了同步更新评估脚本的裁剪范围,结果指标虚高,白高兴一场。
2.2 主干网络与特征提取的取舍
主干网络这块,体素路线常用稀疏卷积,因为点云体素化后绝大部分格子是空的,稠密卷积会把算力浪费在空区域。稀疏卷积只在实际有点的位置计算,效率提升明显。但稀疏卷积的实现细节多,索引构建、规则书管理这些如果没吃透,调参时很容易一头雾水。
柱状路线的主干相对轻,因为只在俯平面切格,高度信息压缩进特征通道。它的优势是推理快,适合对延迟敏感的场景,代价是垂直方向定位精度会打折。我在做高速场景远距离检测时试过柱状方案,远处车辆的高度估计确实不如体素稳,后来还是回到了体素。
点式主干则更贴近原始几何,但采样和分组操作的计算开销大,大规模场景下实时性压力明显。笔记里我给每条路线都标了典型的速度和精度区间,方便按需求快速筛。
2.3 检测头与框回归的设计要点
检测头负责把特征图变成最终的3D框。这里有几个设计点值得单独拎出来说。
框的参数化方式。3D框通常用中心点、尺寸、朝向角来表示。朝向角的回归是个经典难点,因为角度有周期性,直接回归数值会在边界处跳变。常见做法是把角度编码成正余弦两个分量分别回归,或者用分类加残差的方式。我倾向正余弦编码,实现简单且连续性好。
正负样本分配。2D里常用的基于IoU的分配在3D里也能用,但3D IoU计算比2D贵不少。有些方案改用中心点距离加尺寸相似度的混合准则,速度快且效果不差。分配策略直接影响收敛速度和最终精度,这块值得多花时间调。
损失函数组合。分类损失、框回归损失、朝向损失通常加权求和。权重怎么定没有万能公式,我的做法是先让各项量级大致相当,再根据验证集表现微调。分类用焦点损失缓解正负样本不平衡是常见选择,回归用平滑L1或者IoU类损失都行,朝向单独用正余弦的回归损失。
2.4 后处理:别让最后一步毁掉前面所有努力
后处理主要是非极大值抑制,把重叠的冗余框去掉。3D的抑制比2D麻烦,因为要考虑朝向和体积。直接套2D的IoU抑制在密集场景容易误删,尤其是并排停放的车辆。改进思路有按朝向分组抑制、用带方向的IoU、或者基于中心点距离的软抑制。
我在实际项目里遇到过一个典型问题:路口密集车流,抑制阈值设高了漏检、设低了重复框一堆。后来改成按距离分档设置阈值,近处严格、远处宽松,因为远处目标本来就稀疏,过度抑制反而伤召回。这个技巧在笔记里我标了重点。
3. 实操过程与核心环节实现
3.1 从零搭一套可复现的训练流程
光看论文不动手,理解永远停在表面。我建议的实操路径是这样的:先选一个开源基线,把数据加载、前向、损失、评估整条链路跑通,确认能复现论文报告的量级,再开始改。
数据加载这块,我习惯先把标注转成统一内部格式,字段包括中心点、尺寸、朝向、类别,坐标系按前面约定的来。转换脚本要写单元测试,随便挑几个样本手工核对转换前后的框位置是否一致。这一步看着笨,但能省掉后面大量“指标不对但不知道哪错了”的排查时间。
训练循环里我会记录每个损失分项的变化曲线,而不是只看总损失。分类损失降了但回归损失不降,说明框回归有问题;反过来则可能是样本分配或特征表达的问题。分项监控是定位问题最快的手段。
3.2 关键参数的计算与选择过程
拿体素尺寸来说,它不是拍脑袋定的。假设检测距离100米,体素0.1米,那单方向就是1000格,俯平面就是百万级格子,稀疏卷积能扛但显存吃紧。如果体素放大到0.2米,格子数降到四分之一,速度上来了但小目标可能整个落进一个格子里,特征被平均掉。我的计算方式是:先确定要检测的最小目标尺寸,体素边长取它的四分之一到三分之一,这样小目标至少能占几个格子,特征不至于糊成一团。
学习率方面,3D检测常用分段衰减或者余弦退火。初始值我一般从较小值起步,观察前几百步损失是否稳定下降,再决定要不要放大。批大小受显存限制时,用梯度累积模拟大batch是常见手段,但要注意归一化层的行为会受影响,得相应调整。
3.3 训练现场的记录与调试
实际训练时我会盯几个信号:损失是否震荡、梯度范数是否异常、验证集指标是否和训练集同步变化。有一次损失正常下降但验证指标纹丝不动,排查半天发现是评估脚本里的类别映射写错了,预测和标注根本不在一个类别空间里比。这种低级错误恰恰最容易发生,所以我现在坚持每次改完数据管道都跑一遍小样本端到端检查。
还有一个经验:先在小数据子集上过拟合。如果模型连几十个样本都拟合不了,那肯定是链路有bug,别急着上全量数据烧算力。这个“先过拟合再泛化”的套路帮我抓出过不少隐藏问题。
4. 常见问题与排查技巧实录
4.1 典型问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 损失不下降 | 学习率过大或过小、数据标注异常、损失权重失衡 | 先小样本过拟合验证链路,再查学习率和权重 |
| 验证指标远低于训练 | 过拟合、数据分布不一致、评估脚本错误 | 检查增强强度、核对类别映射和坐标系 |
| 框位置系统性偏移 | 坐标系转换错误、锚点或参考点设置不当 | 手工核对几个样本的转换结果 |
| 密集场景重复框多 | 抑制阈值不当、抑制未考虑朝向 | 分档设置阈值、改用带方向的抑制 |
| 远处目标漏检严重 | 点云稀疏、体素过大、感受野不足 | 调整体素尺寸、增加多尺度特征 |
| 朝向预测跳变 | 角度编码方式不当 | 改用正余弦编码或分类加残差 |
4.2 几个踩过的坑和独家技巧
第一个坑是数据增强和评估范围不一致。增强时把目标转到了裁剪范围外,训练时它被裁掉了但标注还在,模型学到的是“这里有目标但看不见”,非常伤。解决办法是增强后重新做一次范围过滤,把越界标注清掉。
第二个坑是多卡训练的指标聚合。分布式训练时每个卡算自己的指标再平均,如果各卡样本数不均,平均出来的数会偏。正确做法是把预测和标注收集到一起统一算,或者按样本数加权。这个细节不注意,多卡和单卡的指标会对不上,让人怀疑人生。
第三个技巧是用可视化做第一道防线。每次训练前随机抽几个样本,把点云和标注框画出来看一眼。框飘在空中、朝向反了、尺寸明显不对,肉眼一眼就能发现。我现在的习惯是数据管道改完必看可视化,比任何日志都直观。
第四个技巧是建立自己的小评测集。从验证集里挑一批有代表性的场景,比如密集车流、远处行人、遮挡目标,单独跟踪这些子集上的表现。整体指标涨了但密集场景掉了,说明改进有偏,这个细分视角比单一总分有用得多。
4.3 关于复现他人工作的心得
复现论文结果时,我建议先别急着改任何东西,原样跑通再说。跑不通先查环境版本、依赖库差异,这些是最常见的坑。跑通了但指标差一截,优先怀疑预处理和评估细节,而不是网络结构。很多论文的增益其实来自训练技巧和数据处理的微调,结构改动反而是次要的。笔记里我专门留了一栏记录每篇工作的“隐性细节”,比如用了什么增强、训练多久、批大小多少,这些往往比正文里的结构图更有参考价值。
5. 知识体系如何持续扩展
这套笔记我一直在往里加东西,因为3D检测这个方向更新快,隔一阵就有新思路冒出来。我的维护方式是按“数据表示、主干、检测头、损失、后处理、评估”六个模块分文件夹,每读一篇新工作就归到对应模块下,标注它改了什么、为什么改、效果如何。时间长了你会发现,大部分创新都能落到这六个格子里的某一个,判断一篇工作值不值得深读也就有了依据。
对刚入门的朋友,我的建议是别一上来就追最新最复杂的方案,先把一条单模态基线从头到尾吃透,把数据管道、训练、评估、可视化这套基础设施搭稳。基础设施稳了,后面换任何网络都只是替换中间一块的事。我见过太多人网络换了一茬又一茬,但数据管道里的坐标系问题一直没解决,结果所有实验都建立在流沙上。
最后分享一个我自己的习惯:每完成一个阶段性理解,就试着用最朴素的话把它讲给不熟悉这个方向的人听。讲不清楚的地方,往往就是自己还没真懂的地方。这套笔记里很多段落其实就是我“讲给自己听”的产物,反复打磨之后才敢拿出来。3D检测不难在某个单点技术,难在各环节的约定要自洽、细节要抠住,把这条主线抓住了,剩下的就是按部就班地填坑。