PointNet:直接处理点集的深度网络
论文:PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation
作者:Charles R. Qi, Hao Su, Kaichun Mo, Leonidas J. Guibas
arXiv:1612.00593v2
本地文件:/root/other/paper/1612.00593v2.pdf
这篇论文解决什么问题
PointNet 讨论的是一个很基础的问题:
能不能不把点云转成 voxel 或多视图图片,而是直接把原始点集送进神经网络?
在 PointNet 之前,很多 3D 深度学习方法会先做表示转换:
| 输入方式 | 做法 | 问题 |
|---|---|---|
| voxel | 把 3D 空间离散成体素网格 | 内存和计算随分辨率立方增长 |
| multi-view | 把 3D 物体渲染成多张 2D 图 | 依赖视角设计,不方便点级任务 |
| mesh CNN | 在网格上做卷积 | 拓扑不规则,泛化复杂 |
| handcrafted feature | 人工设计点云特征 | 任务相关,表达能力有限 |
PointNet 的核心主张是:点云本身就是一种简单、统一的表示,可以直接学习。
图源说明:根据 Qi et al., PointNet 的任务设定概念重绘,非论文原图。
点云输入的三个性质
论文把点集输入的困难概括成三个性质。
1. 无序性
点云是集合:
集合没有顺序。也就是说:
[p1, p2, p3]
和:
[p3, p1, p2]
应该表示同一个点云。
因此网络必须满足 permutation invariance:
其中 是任意排列。
2. 点之间有几何关系
点不是孤立的。点之间的距离、邻域和局部结构都有意义。
例如一把椅子的腿、靠背、扶手,都是由局部点集形成的几何结构。
3. 对几何变换应有鲁棒性
同一个物体经过旋转、平移后,类别不应该改变。
所以网络要尽量对刚体变换保持稳定。
PointNet 的核心结构
PointNet 的结构非常简洁:
- 对每个点独立使用同一个 MLP。
- 用 max pooling 聚合所有点的特征。
- 得到一个全局 shape feature。
- 用全局特征做分类,或和局部点特征拼接后做分割。
图源说明:根据 Qi et al., PointNet 的 architecture 概念重绘,非论文原图。
可以写成:
其中:
- :逐点 shared MLP。
- :对所有点做 element-wise max pooling。
- :后续 MLP,用于分类或分割。
模型架构:输入与输出
PointNet 的输入是点集,输出取决于任务:分类输出一个全局类别,分割输出每个点的标签。
通用输入
输入点云可以写成:
每个点通常是 3D 坐标:
如果带有法向、颜色或其他属性,也可以扩展成:
论文实验中,分类任务常用 个点,因此输入张量可以理解为:
n x 3
也就是 1024 个点,每个点 3 个坐标。
shared MLP 的输入与输出
PointNet 对每个点独立使用同一个 MLP:
输入是单个点 ,输出是该点的高维特征 。因为所有点共享同一个 ,所以网络不会依赖点的输入顺序。
对所有点得到:
max pooling 的输入与输出
max pooling 接收所有点特征,输出一个全局 shape feature:
这里的 max 是逐维取最大值。输出 描述整个点云,而不是某一个点。
分类网络的输入与输出
分类任务的流程是:
n x 3 points
-> shared MLP
-> max pooling
-> global feature
-> classifier MLP
-> k class scores
输入:
输出:
其中 是类别数。 经过 softmax 后得到每个类别的概率,例如 chair、table、sofa 等。
分割网络的输入与输出
分割任务需要给每个点预测一个标签,因此输出不是一个全局类别,而是 个点级预测。
流程是:
n x 3 points
-> local point features
-> max pooling gets global feature
-> concatenate local feature and copied global feature
-> shared segmentation MLP
-> n x m point labels
输入:
输出:
其中 是点级标签类别数。对第 个点,网络输出:
它表示该点属于各个 part 或 semantic class 的概率。
| 任务 | 输入 | 中间表示 | 输出 |
|---|---|---|---|
| 分类 | 点云 | 全局 shape feature | 个类别分数 |
| 部件分割 | 点云 | local feature + global feature | 个点级类别分数 |
| 语义分割 | 室内场景点云,可带额外属性 | local feature + scene/global feature | 每个点的语义类别 |
输出可以用来干什么
PointNet 的输出用途取决于具体任务。
| 输出 | 可以用来做什么 | 具体含义 |
|---|---|---|
| 全局类别分数 | 点云分类 | 判断整个点云属于哪个类别,例如 chair、table、car |
| softmax 概率 | 置信度分析 | 不只知道预测类别,还能知道模型对各类别的信心 |
| global feature | 形状描述 / 下游特征 | 作为整个点云的紧凑表示,供检索、匹配、聚类或其他网络使用 |
| 点级标签 | part segmentation | 给物体每个点分配部件标签,例如椅子的靠背、椅面、椅腿 |
| 点级语义标签 | scene semantic segmentation | 给室内场景中的每个点标出 wall、floor、chair、table 等语义类别 |
| T-Net 输出的变换矩阵 | 点云对齐 | 把输入点云或中间特征变换到更规范的坐标/特征空间 |
分类输出常用于“这个点云是什么物体”:
point cloud
-> PointNet
-> class scores
-> predicted object category
分割输出常用于“每个点属于什么部分”:
point cloud
-> PointNet segmentation network
-> point-wise labels
-> colored point cloud / part mask / semantic map
需要注意:PointNet 本身通常不直接输出 mesh,也不直接补全缺失几何。它更擅长从已有点云中提取全局特征、做分类和点级标注。如果把 PointNet 作为其他重建模型的 encoder,那么它输出的 global feature 可以继续输入 DeepSDF、Occupancy Network 或其他 decoder,用来生成隐式场或网格。
为什么 max pooling 能处理无序点集
PointNet 最关键的设计是使用 symmetric function。
一个 symmetric function 的输出不依赖输入顺序,例如:
对点云来说,如果每个点先经过同一个 得到特征:
然后对所有点取逐维最大值:
那么无论点的输入顺序怎么变,最终 都不变。
图源说明:根据 Qi et al., PointNet 的 symmetric function 思想重绘,非论文原图。
一个具体数值例子:为什么换顺序不影响 max pooling?
假设有 3 个点,经过 shared MLP 后得到:
对三个向量逐维取最大值:
如果输入顺序换成:
则:
结果完全一样。
这就是 PointNet 能直接处理无序点集的核心原因:它没有试图给点排序,而是用 max pooling 消除了顺序影响。
为什么不用 RNN 加随机排列来处理无序点云?
一种看似自然的做法是:把点云当成一个序列输入 RNN。
例如同一个点云:
可以随机打乱成很多顺序:
p1 -> p2 -> p3 -> ... -> pn
p3 -> p1 -> p2 -> ... -> pn
p7 -> p4 -> p1 -> ... -> pn
然后用这些随机排列训练 RNN,希望模型逐渐学会“不在乎输入顺序”。
这个想法的问题是:RNN 的结构本身不是置换不变的。
RNN 的隐藏状态按顺序递推:
也就是说,第 个点的处理结果依赖前面已经看过哪些点。
如果输入顺序变了,隐藏状态的演化路径也会变:
p1 -> p2 -> p3
和:
p3 -> p2 -> p1
虽然包含同样的点,但 RNN 看到的是两条不同的序列。
因此,随机排列训练最多只能让模型在训练分布里“尽量适应不同顺序”,但不能从结构上保证:
这就是论文提到 “OrderMatters” 的原因:对序列模型来说,输入顺序确实会影响计算过程,无法被完全忽略。
对于几十个元素的短序列,RNN 可能还能通过大量随机排列增强来获得不错的经验鲁棒性。
但点云通常有成百上千个点。例如论文实验常用:
这时可能的排列数量是:
这个数量大到不可能靠数据增强覆盖。
而且 RNN 逐点处理,序列越长:
- 计算越慢,难以并行。
- 长距离依赖更难学。
- 训练更不稳定。
- 输入顺序带来的偏差更明显。
PointNet 的思路更直接:不要试图让一个有序模型“学会无序”,而是在结构上使用 symmetric function。
例如 max pooling 天然满足:
所以 PointNet 的置换不变性不是靠训练碰运气学出来的,而是由网络结构保证的。
这也是 PointNet 相比 RNN 方案更适合大规模点云的关键原因。
分类网络
分类任务只需要输出一个全局类别。
流程是:
n x 3 points
-> input transform
-> shared MLP
-> feature transform
-> shared MLP
-> max pooling
-> global feature
-> MLP classifier
-> class scores
论文中常见设置是输入 1024 个点,每个点是 。
全局特征一般是 1024 维。
分类头输出 个类别分数。
分割网络
分割任务需要给每个点输出一个标签。
只用全局特征不够,因为每个点需要知道自己在物体上的局部位置。
PointNet 的做法是:
- 先得到每个点的 local point feature。
- 再得到整个点云的 global feature。
- 把 global feature 复制回每个点。
- 将 local feature 和 global feature 拼接。
- 对每个点输出 part label 或 semantic label。
所以分割网络使用的是:
local feature + global feature
直观地说:
- local feature 让点知道“我附近是什么形状”。
- global feature 让点知道“我属于哪个整体物体或场景”。
例如同样是一段细长结构,在椅子上可能是 chair leg,在桌子上可能是 table leg。全局信息能帮助点级分类消除歧义。
T-Net:学习对齐变换
点云分类和分割应该对刚体变换比较稳定。
PointNet 使用一个小网络 T-Net 来预测变换矩阵:
- input transform:预测 矩阵,对齐输入坐标。
- feature transform:预测 矩阵,对齐中间特征。
也就是说,T-Net 会学习一个变换:
让输入点云更接近网络喜欢处理的 canonical pose。
图源说明:根据 Qi et al., PointNet 的 alignment network 与 critical point set 概念重绘,非论文原图。
feature transform 的正则
论文希望 feature transform 矩阵接近正交矩阵,因此加了正则项:
如果 接近正交矩阵,它更像旋转或反射,不会任意拉伸特征空间。
这样可以减少变换矩阵过度扭曲特征。
理论解释:PointNet 学到了什么
论文给出一个重要形式:
这个结构可以近似连续的 set function。
更有意思的是,max pooling 使得全局特征实际上由一小部分点决定。
论文称这些点为:
critical point set
因为每一维 max pooled feature 都来自某个点。若有 维全局特征,那么最多有 个点真正决定这些 max 值。
critical point set 为什么能解释鲁棒性?
设:
如果某个点没有在任何一维上取得最大值,那么删掉它不会改变 。
例如:
max pooled feature 是:
其中:
- 第 1 维最大值 来自 。
- 第 2 维最大值 来自 。
- 第 3 维最大值 来自 。
所以真正影响全局特征的是 和 。
如果删掉 :
全局特征不变。
这解释了为什么 PointNet 对缺失点、扰动点有一定鲁棒性:只要关键点还在,很多非关键点的缺失不会改变全局描述。
实验结果
论文验证了三个主要任务:
- ModelNet40 形状分类。
- ShapeNet part segmentation。
- 室内场景 semantic segmentation。
主要结论:
- 在 ModelNet40 上,PointNet 在 3D 输入方法中达到当时很强的效果。
- 在 ShapeNet part segmentation 上,PointNet 达到 state-of-the-art mIoU。
- 在室内场景语义分割中,PointNet 明显优于 handcrafted feature baseline。
- 相比 voxel 和 multi-view 方法,PointNet 更高效,复杂度随点数近似线性增长。
论文还做了鲁棒性实验:
- 随机删除点。
- 插入 outlier 点。
- 对点坐标添加 Gaussian noise。
实验显示 PointNet 对这些扰动相当稳定。
优点
PointNet 的优点:
- 直接吃原始点云,不需要 voxelization。
- 天然适配无序点集。
- 结构简单,速度快。
- 同一个框架可以做分类、part segmentation、semantic segmentation。
- 理论上解释了 max pooling、critical points 和鲁棒性。
- 对点云缺失和噪声有较强鲁棒性。
局限
PointNet 的主要局限也很明显:
- 每个点先被独立处理,局部邻域结构建模较弱。
- max pooling 只保留最强响应,可能丢掉细粒度局部关系。
- 对复杂局部几何,表达能力不如后来的 PointNet++。
- T-Net 只能学习整体对齐,不能替代真正的局部几何建模。
这也是 PointNet++ 后续要解决的问题:在点云上建立 hierarchical local feature learning。
和 DeepSDF 的关系
PointNet 和 DeepSDF 都是 3D 深度表示学习的重要基线,但思路不同:
| 方法 | 输入/表示 | 核心思想 | 输出 |
|---|---|---|---|
| PointNet | 点集 | 对无序点集做 permutation-invariant learning | 分类或点级标签 |
| DeepSDF | 连续隐式场 | 用 latent code + MLP 表示 SDF | SDF 值 / 隐式表面 |
可以这样理解:
- PointNet 更像是“理解已有点云”。
- DeepSDF 更像是“生成或补全连续形状场”。
在实际系统中,它们可以互补:
- PointNet 类网络可用于点云编码、分类、分割。
- DeepSDF 类网络可用于形状补全、隐式重建、表面提取。
我的理解
PointNet 的关键贡献不是网络很深,而是它抓住了点云的本质:
点云是无序集合,所以网络结构必须从一开始就尊重集合的无序性。
它用 shared MLP 处理每个点,用 max pooling 聚合全局信息。这个设计非常简单,但非常有力。
真正值得记住的是:
这个思想后来影响了大量点云网络。
阅读时要抓住的主线
- 点云是无序集合,不能直接当序列或规则网格处理。
- shared MLP 保证每个点用同一套函数提特征。
- max pooling 保证置换不变性。
- global feature 用于分类。
- local + global feature 用于分割。
- T-Net 提供输入和特征对齐。
- critical point set 解释了 PointNet 的鲁棒性。
后续问题
读完这篇后,可以继续追问:
- PointNet 为什么局部几何建模不足?
- PointNet++ 如何用局部邻域和层次结构改进 PointNet?
- max pooling 和 average pooling 在点云任务中有什么差别?
- T-Net 学到的变换矩阵是否总是可解释?
- PointNet 能否作为 DeepSDF 或其他隐式重建方法的 encoder?