点云网络(Point Clouds Network)—— DGCNN (Dynamic Graph CNN, TOG 2019) 详解

#点云网络(Point Clouds Network)—— DGCNN (Dynamic Graph CNN, TOG 2019) 详解


目录

  1. 简介
  2. 核心思想
  3. 网络结构概览
  4. 关键组件与数学原理
    1. 动态图构建(Dynamic Graph Construction)
    2. EdgeConv(边卷积)
    3. 层间特征拼接与全局特征提取
    4. 分类与分割头
  5. 更深入的数学推导
    1. 邻居搜索与图更新
    2. EdgeConv 形式化定义
    3. 多层特征融合与全局池化
    4. 损失函数
  6. 训练流程
  7. 优点与不足
  8. 附录:PyTorch示例代码

简介

DGCNN (Dynamic Graph CNN) 是 Wang 等人于 2019 年发表在 TOG(ACM Transactions on Graphics)的一篇高影响力论文,专注于点云(Point Cloud)深度学习。与以往的 PointNet、PointNet++ 相比,DGCNN 显式地将点云建模为图结构并在网络中进行动态更新,从而更好地刻画点与点之间的邻域关系,增强了对局部几何的刻画能力。

在 DGCNN 中,引入了关键算子 EdgeConv,在每个点与其邻居点之间计算“边特征”,并将这些边特征通过最大池化等操作更新点的表示。多层 EdgeConv 堆叠后,再通过全局池化和分类/分割头完成 3D 任务。该方法在多种数据集上表现优异,成为点云深度学习的重要里程碑。


核心思想

  1. 将点云表示为图 (Graph)

    • 每个点作为图中的顶点;
    • 通过 k 近邻 (kNN) 或基于距离阈值在点间连边,从而形成邻域结构。
  2. 动态更新图结构

    • 传统方法常使用固定邻居关系(基于坐标),DGCNN 可以在每一层根据最新的特征来重新构造 kNN,以捕捉在深层特征空间中更有意义的邻域关系。
    • 在实际实现中,也可只在坐标空间构图或隔层更新,以减少计算量。
  3. EdgeConv 算子

    • 在每个点 h i \mathbf{h}_i hi 与其邻居 h j \mathbf{h}_j hj 之间构造“边特征” ϕ ( h i , h j − h i ) \phi(\mathbf{h}_i, \mathbf{h}_j - \mathbf{h}_i) ϕ(hi,hjhi),并通过最大池化来更新点的特征;
    • 通过堆叠多层 EdgeConv 提取多级局部几何信息,同时保留“差分”维度 ( h j − h i \mathbf{h}_j - \mathbf{h}_i hjhi ),让网络对局部形状更加敏感。

网络结构概览

DGCNN 用于分类时的典型结构可分为几个阶段:

  1. 输入点云 X = { x 1 , x 2 , … , x N } \mathbf{X} = \{\mathbf{x}_1, \mathbf{x}_2, \dots, \mathbf{x}_N\} X={ x1,x2,,xN},每个 x i ∈ R d \mathbf{x}_i \in \mathbb{R}^d xiRd(最简单是 3D 坐标,但也可带颜色或法线等特征)。
  2. 初始 kNN 构图:根据坐标或初始特征找到每个点的 k 个邻居,得到邻接表 E ( 1 ) \mathcal{E}^{(1)} E(1)
  3. EdgeConv 层:对每个邻域施加边卷积,输出新的点特征 H ( l + 1 ) \mathbf{H}^{(l+1)} H(l+1),并在多层堆叠的过程中,可以在第 l + 1 l+1 l+1 层前重新更新邻居关系(Dynamic)。
  4. 多层特征拼接/聚合:将不同层学到的点特征拼接在一起,得到一个更丰富的表示。
  5. 全局特征:对拼接后特征做 Max Pooling(或 Mean Pooling) 得到全局描述子 g \mathbf{g} g
  6. 分类头:若干全连接层(含 BN/Dropout 等),输出分类结果。

分割任务中,保留逐点特征,在网络尾部为每个点输出一个标签分布(逐点分类)。


关键组件与数学原理

动态图构建(Dynamic Graph Construction)

  • 初始 kNN:在原始坐标空间 R 3 \mathbb{R}^3 R3 或初始特征空间中,对每个点 x i \mathbf{x}_i xi 寻找 k 个邻居,获得邻接列表。
  • 动态更新:在第 l l l 层得到特征 h i ( l ) \mathbf{h}_i^{(l)} hi(l) 后,可以再基于 ∥ h i ( l ) − h j ( l ) ∥ \|\mathbf{h}_i^{(l)} - \mathbf{h}_j^{(l)}\| hi(l)hj(l) 寻找新的 kNN,更新图结构 E ( l + 1 ) \mathcal{E}^{(l+1)} E(l+1)。这使得深层次的邻居关系不再拘泥于欧几里得距离,而是反映更高层的语义相似度。

EdgeConv(边卷积)

EdgeConv 是 DGCNN 的核心算子,用于将每个点的特征与邻域特征结合起来,提升对局部几何的敏感度。
h i ( l + 1 ) = max ⁡ j ∈ N i ( l ) ϕ ( h i ( l ) ,    h j ( l ) − h i ( l ) ) , \mathbf{h}_i^{(l+1)} = \max_{j \in \mathcal{N}_i^{(l)}} \phi\Big(\mathbf{h}_i^{(l)}, \;\mathbf{h}_j^{(l)} - \mathbf{h}_i^{(l)}\Big), hi(l+1)=jNi(l)maxϕ(hi(l),hj(l)hi(l)),

  • h i ( l ) \mathbf{h}_i^{(l)} hi(l) 表示第 l l l 层中点 i i i 的特征向量(维度可大于 3);
  • N i ( l ) \mathcal{N}_i^{(l)} Ni(l) 是第 l l l 层图中点 i i i 的邻居集合;
  • h j ( l ) − h i ( l ) \mathbf{h}_j^{(l)} - \mathbf{h}_i^{(l)}
### DGCNN模型的PyTorch实现 DGCNNDynamic Graph Convolutional Neural Networks)是一种用于点云数据处理的有效方法。以下是基于PyTorch框架复现DGCNN模型的核心思路和代码示例。 #### 1. 数据预处理 为了构建动态图卷积层,通常需要计算输入点之间的k近邻关系并提取局部特征。这一步可以通过`scipy.spatial.KDTree`或其他库完成[^1]。 ```python import numpy as np from scipy.spatial import KDTree def knn(x, k): """ 计算每一点的K近邻 """ inner = -2 * torch.matmul(x.transpose(2, 1), x) xx = torch.sum(x ** 2, dim=1, keepdim=True) pairwise_distance = -xx - inner - xx.transpose(2, 1) idx = pairwise_distance.topk(k=k, dim=-1)[1] # (batch_size, num_points, k) return idx ``` #### 2. 动态图卷积模块 动态图卷积通过聚合邻居节点的信息来增强局部特征表示能力。以下是一个简单的动态图卷积实现: ```python import torch.nn.functional as F from torch_geometric.nn import EdgeConv class DynamicEdgeConv(EdgeConv): def __init__(self, nn, aggr='max', k=20): super(DynamicEdgeConv, self).__init__(nn, aggr) self.k = k def forward(self, x, batch=None): edge_index = knn(x, self.k).contiguous() # 使用上述定义的knn函数 return super().forward(x, edge_index) ``` #### 3. 整体网络架构 完整的DGCNN模型由多个动态图卷积层组成,并最终连接全连接层进行分类或回归任务。 ```python import torch.nn as nn class DGCNN(nn.Module): def __init__(self, output_channels=40, k=20): super(DGCNN, self).__init__() self.conv1 = DynamicEdgeConv(nn.Sequential( nn.Conv2d(6, 64, kernel_size=1, bias=False), nn.BatchNorm2d(64), nn.LeakyReLU(negative_slope=0.2)), k=k) self.conv2 = DynamicEdgeConv(nn.Sequential( nn.Conv2d(64*2, 64, kernel_size=1, bias=False), nn.BatchNorm2d(64), nn.LeakyReLU(negative_slope=0.2)), k=k) self.fc1 = nn.Linear(1024, 512, bias=False) self.bn1 = nn.BatchNorm1d(512) self.drop1 = nn.Dropout(p=0.5) self.fc2 = nn.Linear(512, 256, bias=False) self.bn2 = nn.BatchNorm1d(256) self.drop2 = nn.Dropout(p=0.5) self.fc3 = nn.Linear(256, output_channels) def forward(self, x): batch_size = x.size(0) x = get_graph_feature(x) # 提取局部特征 x1 = self.conv1(x) x2 = self.conv2(x1) x = torch.cat((x1.max(dim=-1, keepdim=False)[0], x2.max(dim=-1, keepdim=False)[0]), dim=1) x = F.adaptive_max_pool1d(x, 1).view(batch_size, -1) x = F.leaky_relu(self.bn1(self.fc1(x)), negative_slope=0.2) x = self.drop1(x) x = F.leaky_relu(self.bn2(self.fc2(x)), negative_slope=0.2) x = self.drop2(x) x = self.fc3(x) return x ``` #### TensorFlow 实现注意事项 虽然本回答主要关注于PyTorch实现,但在TensorFlow中也可以采用类似的逻辑。需要注意的是,TensorFlow中的操作可能更依赖于静态图模式下的自定义梯度计算[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DuHz

喜欢就支持一下 ~ 谢谢啦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值