3.3 PointNet layer( 四 )


上面就是一次set 操作了. ++是有3次set 操作的:
这里有一个细节问题, 可以看到C1和C2后面都加了3, 这是在学到特征的基础上又加了位置信息(x, y, z), 重新作为新的特征来送入网络 。
3.4分类任务在提取特征后是怎么操作的,loss是什么
在提取了每个点云的特征(C3, )之后, 接下来就和图像里的分类任务一样了,C3维的特征作为输入,然后通过通过两个全连接层和一个分类层(分类层的是输出节点等于类别数的全连接层),输出每一类的概率 。
损失函数采用的是交叉熵损失函数,对应中的nn.().
3.5分割任务中如何进行上采样, loss是什么?
分割任务需要对点云P中的每个点进行分类,而++中的set 由于操作减少了输入点云P中的点的数量,如何进行上采样使点云数量恢复输入时的点云数量呢?
在图像分割任务中,为了恢复图像的分辨率, 往往采用反卷积或者插值的方式来操作呢, 在点云中该如何恢复点云的数量呢?
其实,在++中的set 模块里,当前点云Q和下采样后的点云Q’的中的点位置信息一直是保存的,点云的上采样就是利用了这一特性 。这里利用二维图直观的解释一下,下方左图中红色的倒三角形表示下采样后的点云Q’, 蓝色的点云表示下采样之前的点云Q, 点云里的上采样就是用学习后的点云Q’的特征表示下采样之前点云Q的特征 。采用的方式是k近邻算法,论文中k=3 。如图所示,对于Q中的每一个点O,在Q’中寻找其最近的k个点,基于距离加权(距离O近,其权重大; 距离O远, 其权重大)求和这k个点的特征来表示点O的特征,具体计算方式为:
上采样得到了C’维的特征, 而且点的数量已经恢复到了下采样之前的数量; 将C’维的特征与set 中相同点数量的点云(对称位置)特征(C维)进行进行操作,进而进行多个+ Bn + ReLU操作,来得到新的特征 。
经过三次上采样操作后,点云恢复了初始输入点云中点的数量, 再经过一次 + bn + relu层 和一个对点的分类层,最终得到对每个点的分类 。
上采样部分的实现代码如下:
def three_nn(xyz1, xyz2):''':param xyz1: shape=(B, N1, 3):param xyz2: shape=(B, N2, 3):return: dists: shape=(B, N1, 3), inds: shape=(B, N1, 3)'''dists = get_dists(xyz1, xyz2)dists, inds = torch.sort(dists, dim=-1)dists, inds = dists[:, :, :3], inds[:, :, :3]return dists, indsdef three_interpolate(xyz1, xyz2, points2):''':param xyz1: shape=(B, N1, 3):param xyz2: shape=(B, N2, 3):param points2: shape=(B, N2, C2):return: interpolated_points: shape=(B, N1, C2)'''_, _, C2 = points2.shapedists, inds = three_nn(xyz1, xyz2)inversed_dists = 1.0 / (dists + 1e-8)weight = inversed_dists / torch.sum(inversed_dists, dim=-1, keepdim=True) # shape=(B, N1, 3)weight = torch.unsqueeze(weight, -1).repeat(1, 1, 1, C2)interpolated_points = gather_points(points2, inds)# shape=(B, N1, 3, C2)interpolated_points = torch.sum(weight * interpolated_points, dim=2)return interpolated_points
分割任务中损失函数采用的也是交叉熵损失函数,对应中的nn.().
3.6以解析++网络中维度和尺寸是怎么变化的 ?
骨干网络:
Input data(B, N, 6) -> Set [(B, 512, 3) -> group(B, 512, 32, 6) -> (B, 512, 32, 128) -> (B, 512, 128)] -> Set [(B, 128, 3) -> group(B, 128, 64, 128 + 3) -> (B, 128, 64, 256) -> (B, 128, 256) ] -> Set [(B, 1, 3) -> group(B, 1, 128, 256 + 3) -> (B, 1, 128, 1024) -> (B, 1, 1024)] -> (B, 1, 1024)
分类模块:
(B, 1024) -> FC(B, 512) -> FC(B, 256) -> (B, )
分割模块:
(B, 1, 1024) -> FP[(B, 128, 1024) -> (B, 128, 1024+256)->(B, 128, 256)]
-> FP((B, 512, 256) -> (B, 512, 256+128) -> (B, 512, 128))
-> FP((B, N, 128) -> (B, N, 128+6)->(B, N, 128))