DGCNN

1. 本文结构

  1. 基本信息
  2. 摘要阅读
  3. 图表阅读
  4. 全文通读
  5. 重点分析
  6. 思考总结

2. 基本信息

  • 论文名称: An End-to-End Deep Learning Architecture for Graph Classification
  • 作者:Muhan Zhang, Zhicheng Cui, Marion Neumann, Yixin Chen
  • 会议:AAAI 2018
  • 代码:https://github.com/muhanzhang/pytorch_DGCNN

3. 摘要阅读

神经网络通常处理张量形式的数据。在本文中,我们提出了一种接收任意结构的图数据的新神经网络。考虑到一个数据集包含图和它的类别,我们目的就是要用神经网络完成分类任务。有两个主要的挑战:一个是怎么提取特征;一个是怎么序列化一致地读取图。为了解决第一个挑战,我们设计了一个局部地图卷积模型并且说明它和两个图核的联系。为了解决第二个挑战,我们设计了一个新的SortPooling层能够以一个一致的顺序分类图的节点所以传统神经网络能够在图上训练。在benchmark图分类数据集上的实验说明提出的结构达到了很高的表现。并且,这个结构允许端到端的基于梯度的训练,不需要转换图到向量。

4. 图表分析

image-20200721172129858
image-20200721172129858

Figure 1:CNNs需要一致的输入顺序。

image-20200721172243831
image-20200721172243831

Figure 2:DGCNN的整体结构。图卷积,然后SortPooling,再像传统CNN一样学得一个预测性的模型。

image-20200721172533722
image-20200721172533722

Table 1:和graph核的比较。

image-20200721172630877
image-20200721172630877

Table 2: 和其它深度学习方法的比较

5.全文通读

SortPooling和WL方法有很紧密的关系,在DGCNN,我们也可以是用节点颜色帮助完成图的分类任务。

尽可能把图卷积的层数变多,这样才能让SortPooling层把节点分出来。

SortPooling有一个显著优点是能够传递梯度给之前的层。

6. 重点分析

这部分重点查看它的代码实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
''' graph convolution layers '''
lv = 0
cur_message_layer = node_feat
cat_message_layers = []
while lv < len(self.latent_dim):
n2npool = gnn_spmm(n2n_sp, cur_message_layer) + cur_message_layer # Y = (A + I) * X
node_linear = self.conv_params[lv](n2npool) # Y = Y * W
normalized_linear = node_linear.div(node_degs) # Y = D^-1 * Y
cur_message_layer = torch.tanh(normalized_linear)
cat_message_layers.append(cur_message_layer)
lv += 1

cur_message_layer = torch.cat(cat_message_layers, 1)

''' sortpooling layer '''
sort_channel = cur_message_layer[:, -1]
batch_sortpooling_graphs = torch.zeros(len(graph_sizes), self.k, self.total_latent_dim)
if torch.cuda.is_available() and isinstance(node_feat.data, torch.cuda.FloatTensor):
batch_sortpooling_graphs = batch_sortpooling_graphs.cuda()

batch_sortpooling_graphs = Variable(batch_sortpooling_graphs)
accum_count = 0
for i in range(subg_sp.size()[0]):
to_sort = sort_channel[accum_count: accum_count + graph_sizes[i]]
k = self.k if self.k <= graph_sizes[i] else graph_sizes[i]
_, topk_indices = to_sort.topk(k)
topk_indices += accum_count
sortpooling_graph = cur_message_layer.index_select(0, topk_indices)
if k < self.k:
to_pad = torch.zeros(self.k-k, self.total_latent_dim)
if torch.cuda.is_available() and isinstance(node_feat.data, torch.cuda.FloatTensor):
to_pad = to_pad.cuda()

to_pad = Variable(to_pad)
sortpooling_graph = torch.cat((sortpooling_graph, to_pad), 0)
batch_sortpooling_graphs[i] = sortpooling_graph
accum_count += graph_sizes[i]

''' traditional 1d convlution and dense layers '''
to_conv1d = batch_sortpooling_graphs.view((-1, 1, self.k * self.total_latent_dim))
conv1d_res = self.conv1d_params1(to_conv1d)
conv1d_res = self.conv1d_activation(conv1d_res)
conv1d_res = self.maxpool1d(conv1d_res)
conv1d_res = self.conv1d_params2(conv1d_res)
conv1d_res = self.conv1d_activation(conv1d_res)

to_dense = conv1d_res.view(len(graph_sizes), -1)

if self.output_dim > 0:
out_linear = self.out_params(to_dense)
reluact_fp = self.conv1d_activation(out_linear)
else:
reluact_fp = to_dense

return self.conv1d_activation(reluact_fp)

7. 思考总结

这篇文章读下来,印象不是很深。感觉能被接收有两方面原因,一方面是sortpooling方法简单、有效、新颖,另一方面是文章中方法与其它方法关系的理论推导。这篇文章可以借鉴的方法就是SortPooling, 公式推导有时间看一下。