PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space
NIPS 2017
摘要
以前很少有在点云的deep learning方面的研究,PointNet是这方面的先驱。然而,pointnet并不能捕获由点所在的度量空间所决定的局部结构,这会限制模型的细腻度识别能力以及对于复杂场景的泛化能力。在此次工作上,我们引入了一个分层的神经网络,该网络在输入特征点的一个嵌套分区上递归的使用pointnet。通过探索度量空间的距离,我们的网络可以通过增加相关尺度学习到局部特征结构,进一步观察到,点集采样通常是不同密度的,这导致训练在均匀密度下的网络性能大大降低,我们提出了新的数据集学习层,自适应地结合来自多个尺度的特征,实验表明我们的网络可以有效和鲁棒的学习到点集的特征。实验结果比在具有挑战性的点云基础上最好的算法要更好。
问题
PointNet ++的设计必须解决两个问题:如何生成点集的分区,以及如何通过本地特征学习器抽象点或本地特征集。
创新
(1)用PointNet做local feature learner .
(2)生成点集的重叠分区: 每个分区都定义为基础欧几里得空间中的local neighborhood balls,其参数包括质心位置和比例尺。为了均匀覆盖整个集合,质心通过最远点采样(FPS)在输入点集中进行选择 )算法。 与以固定步幅扫描空间的体积CNN相比,我们的局部感受野取决于输入数据和度量,因此更加有效。
(3)PointNet ++在多个尺度上利用邻域来实现鲁棒性和细节捕获。在训练过程中通过random input dropout进行辅助,网络学会自适应地对在不同比例尺上检测到的模式进行加权,并根据输入数据组合多比例尺特征。
数据集
网络结构
1 PointNet
where γ and h are usually multi-layer perceptron (MLP) networks.
2 PointNet++
-
Hierarchical Point Set Feature Learning
set abstraction level :Sampling layer+Grouping layer+PointNet layer.
(1)Sampling layer:采样点并定义局部区域的质心。farthest point sampling (FPS)算法采样代替随机采样1(2)Grouping layer :通过在质心周围找到“相邻”点来构造局部区域集。Ball query2 finds all points that are within a radius to the query point
(3)PointNet layer:PointNet将局部区域模式编码为特征向量。
-
density adaptive PointNet layers
不同层级的一些不同聚合方法,以克服采样密度的差异
-
Point Feature Propagation for Set Segmentation。
下采样会损失细节,但是分割任务需要原始点的细节特征。所以采用基于距离的插值和跨级跳过链接的分层传播策略(类似Unet)
we use inverse distance weighted average based on k nearest neighbors (as in Eq. 2, in default we use p = 2, k = 3).
实验结果
代码
- Ball query
def query_ball_point(radius, nsample, xyz, new_xyz):
"""
Input:
radius: local region radius
nsample: max sample number in local region
xyz: all points, [B, N, 3]
new_xyz: query points, [B, S, 3] ,s denotes the number of center points
Return:
group_idx: grouped points index, [B, S, nsample]
"""
device = xyz.device
B, N, C = xyz.shape
_, S, _ = new_xyz.shape
group_idx = torch.arange(N, dtype=torch.long).to(device).view(1, 1, N).repeat([B, S, 1])
# sqrdists: [B, S, N] 记录中心点与所有点之间的欧几里德距离
sqrdists = square_distance(new_xyz, xyz)
# 找到所有距离大于radius^2的,其group_idx直接置为N;其余的保留原来的值
group_idx[sqrdists > radius **2] = N
# 做升序排列,前面大于radius^2的都是N,会是最大值,所以会直接在剩下的点中取出前nsample个点
group_idx = group_idx.sort(dim=-1)[0][:, :, :nsample]
# 考虑到有可能前nsample个点中也有被赋值为N的点(即球形区域内不足nsample个点),这种点需要舍弃,直接用第一个点来代替即可
# group_first: [B, S, nsample], 实际就是把group_idx中的第一个点的值复制到[B, S, nsample]的维度,便利于后面的替换
# 这里要用view是因为group_idx[:, :, 0]取出之后的tensor相当于二维Tensor,因此需要用view变成三维tensor
group_first = group_idx[:, :, 0].view(B, S, 1).repeat([1, 1, nsample])
# 找到group_idx中值等于N的点,会输出0,1构成的三维Tensor,维度[B,S,nsample]
mask = group_idx == N
# 将这些点的值替换为第一个点的值
group_idx[mask] = group_first[mask]
return group_idx
引用
[1]https://blog.csdn.net/sdsc1314/article/details/106621318/