啊,学完PointNet和PointNet++入门,学点新网络,打个基础。DGCNN这个网络现在感觉好简单,但是效果又很不错,能发一篇不错的论文,真羡慕啊,要是我当时也搞这个,能发一篇这种文章,应该也很爽吧,奖学金我高低也能有点。
1.前言
DGCNN(Dynamic graph CNN)动态图卷积网络,这个用PointNet++网络对比的话,会比较容易理解,他的独到之处。
根据我之前的文章啊,PointNet++网络学习-CSDN博客,PointNe++这个是每一个SA模块中,会对当前输入的所有点,划分成N个区域,每个区域由采样点和其附近的点组成。N个区域内的点、点对应的特征进行组合计算。
DGCNN呢,简单粗暴的一,直接对所有点找附近距离最近的K个点进行组合,第一层的EdgeConv还是对点xyz进行组合计算,后续的是直接对高维特征进行相似度最近的K个进行组合计算。这样有啥区别呢,见小D的释义:

也就是说DGCNN的领域是动态的,PointNet++设定是点空间上附近的领域,而DGCNN是特征近似度最高的领域,它在空间上的位置是随机的、动态的。

2 Graph Feature
理解了Graph Feature这个部分,DGCNN的关键也就清楚了,后面就是老一套的卷积神经网络了,详见实现代码。
第一步,先计算所有点和本点之间的欧式距离排序,从小到大,得到每个点对应距离最近的K个点的索引位置:
python
#距离矩阵用平方欧氏距离 ||x_i - x_j||^2 = ||x_i||^2 + ||x_j||^2 - 2 x_i·x_j
B, C, N = x.shape
# 内积矩阵: (B, N, N)
inner = -2 * torch.matmul(x.transpose(1, 2), x) # -2 x_i · x_j
# ||x_i||^2, ||x_j||^2
xx = torch.sum(x ** 2, dim=1, keepdim=True) # (B, 1, N)
pairwise_distance = -xx - inner - xx.transpose(1, 2) # (B, N, N) 负平方距离 (topk 找最大等价于找最小距离)
# 取距离最小的 k 个 -> (B, N, k), 返回索引
idx = pairwise_distance.topk(k=k, dim=-1)[1] # (B, N, k)
第二步,将每个点的领域K个点组合起来,得到(B,N,K,C),之后再计算每个点和领域内K个点之间的特征差值,并进行拼接得到(B,N,K,2C):
python
# gather 出所有邻居
neighbors = x_flat[idx, :].view(B, N, k, C) # (B, N, k, C)
# 自身特征广播到 (B, N, k, C), 与邻居差分拼接
feature = torch.cat((neighbors - x_expanded, x_expanded), dim=3) # (B, N, k, 2C)
3. EdgeConv
EdgeConv刚开始看到这个名字的时候,再想是啥高级卷积,Edge在哪,后面看代码实现和AI解释确实非常简单,就是计算组合了特征计算边向量了。

4.结语
简单粗暴又有效,厉害。但也有点弊端吧,显而易见的容易显存爆炸。后面针对这个问题改进加了个FPS就能发CVPR?哇哦,应该没有AI说的这么简单吧,羡慕啊~
