第九课是一个助教的实践课,所以就不写讲义了。
GNN完成了把图结构转化到向量空间,即称为一个 E n c o d e r Encoder Encoder。其基本思路是通过不同的局部图结构构成的计算图,使用共享的参数构建深度网络,把邻居结点的特征层层聚合到一个节点,完成embedding的计算。基于这个思路,GCN和GraphSage使用不同的聚合方法构建了深度图神经网络。
这个编码的过程可以用下图来示意:
第九课的内容就是把这个过程反过来,即从右侧向左侧实现一个解码器 D e c o d e r Decoder Decoder。
给定一系列真实的图,使用模型生成人造的图。问题的核心就是:
问题设定:
设定:
从一系列数据样本 { x i } \{x_i\} { xi}中学习一个生成模型。
目标:
方法:最大似然估计
为了实现让 p m o d e l ( x ; θ ) p_{model}(x; \theta) pmodel(x;θ)尽量接近 p d a t a ( x ) p_{data}(x) pdata(x),可以使用机器学习里最常见的最大似然估计的方法,具体的公式为: θ ∗ = a r g m a x θ E x ∽ p d a t a l o g p m o d e l ( x ∣ θ ) \theta^*=\underset{\theta}{argmax} \mathbb{E}_{x \backsim p_{data}}\mathrm{log}\ p_{model}(x| \theta) θ∗=θargmaxEx∽pdatalog pmodel(x∣θ)
即,找到 θ ∗ \theta^* θ∗,从而让来自分布 p d a t a p_{data} pdata的数据点 x i x_i xi,在所有的 θ \theta θ中, ∑ i l o g p m o d e l ( x i ; θ ∗ ) \sum_{i} \mathrm{log} \ p_{model}(x_i; \theta^*) ∑ilog pmodel(xi;θ∗)的值最大。
有了 p m o d e l ( x ; θ ) p_{model}(x; \theta) pmodel(x;θ),采样的方法是:
深度学习生成模型
Jure没有讲的一页关于深度学习的生成模型的结构如下图。CS231n里面曾经介绍过这个分类法,其中介绍了PixelRNN和GAN。
后面要说的模型就是“自回归模型”:用过去的行为来预测未来的行为,一个模型完成了密度估计和采样新样本两个动作。
自回归模型会应用链式规则,即它是一个条件概率分布的乘积: p m o d e l ( x ; θ ) = ∏ t = 1 n p m o d e l ( x t ∣ x 1 , ⋯ , x t − 1 ; θ ) p_{model}(x; \theta)=\displaystyle\prod_{t=1}^n p_{model}(x_t|x_1, \cdots, x_{t-1}; \theta) pmodel(x;θ)=t=1∏npmodel(xt∣x1,⋯,xt−1;θ)
这样就把生成模型变成了一个生成序列。每个 t t t对应着生成序列的一个步骤。
这是Jure的学生在2018年ICML里面发一篇论文GraphRNN: Generating Realistic Graphs with Deep Auto-regressive Models
GraphRNN的基本思路是把图生成的过程变成一个序列 S π S^{\pi} Sπ,其中 π \pi π是指的图的节点的一个固定的序列。如下图所示:
在上图中,生成的图包含5个节点,各自一个编号。生成的过程是从节点1开始,每个步骤增加1个新节点和新节点与原有节点之间的边。按照这个方法,整个生成的序列包含两个层面的任务:
这样在确定一个节点顺序后,图生成就等于是一个序列的序列。
那么整个图生成过程就转变成了如何通过学习来获得这个生成的过程。需要学习两个层面的序列,即节点层面和边层面。对于序列数据的学习,比较自然的方法就是使用RNN来训练一个参数共享的模型。
GraphGNN设置
这里如果对RNN比较熟悉的话,就能比较好地理解GraphRNN的思路。总体网络架构如下:
其中,每个方格就是一个RNN的模块,权重共享,如下图所示:
而RNN的输入和输出结构展开来看就是:
这是针对节点级别的顺序,其中需要有SOS(Start of Sequence)和EOS(End of Sequence)。而每个 y y y则可以认为是另外一个这个的RNN单元,但是生成的是边级别的顺序。一点不同是,边级别的生产可以没有SOS和EOS,因为每个新节点可以生成的最多的边是固定数量的。
对于每个步骤 t t t,它的输出 y t y_t yt成为下一步的输入 x t + 1 ∽ y t x_{t+1} \backsim y_{t} xt+1∽yt。
GraphRNN的训练过程
GraphRNN的训练过程使用了已有的Graph数据。
训练过程会对每个边计算交叉熵损失函数,并用这个损失值反向传播更新模型的参数。
GraphRNN的推断过程
在通过上面的训练得到了模型后,就可以遵循几乎一样的过程来生成新的图了。但这里面有一个问题,就是用SOS开始图生成过程的话,由于模型里面的参数都是确定了,那么使用确定的SOS作为初始的输入,节点和边级别RNN得到的计算结果就是确定的。那么如果按照0.5作为阈值来确定是否创建边,每次得到的图就完全一样了。
所以在实际生成的过程中,并不会使用模型的输出概率来直接创建边,而是按照边级别RNN的每次输出值的概率掷骰子得到0和1来确定是否要建边。然后再把是否有边的结果送给下一步的RNN来继续。
用这个方法就带来了随机性,从而保证了每次生成的图都不会完全一样。
GraphRNN的计算复杂性
对于GraphRNN算法,还有一个计算复杂度的问题,其实是空间复杂度的问题。即在推断过程,如果要每个新的节点都要和之前所有节点计算是否有边的概率。这么做的话就等于是几乎完全生成 N × N N \times N N×N的邻接矩阵。因此在这里,GraphRNN算法采用了一个trick来降低这个计算复杂度的问题。
基本思想是采用BFS的方法来对节点进行排序,从而让后续节点保证不会和2步之前的节点之间有边。这样在后续节点的边生成过程,就不再需要计算和2步之前的节点是否有边了。通过这种方法,就把生成 N × N N \times N N×N邻接矩阵的任务,变成了生成3条对角线矩阵的问题。如下图所示:
结果评估:
对于图生成,如何评估是一个难题。这个论文给了两种评估方法:
课程里介绍了图生成的另外一个应用:受限受控的分子图生成。这里就不再笔记分析了。有兴趣的去看他们论文就好了。
Graph Convolutional Policy Network for Goal-Directed Molecular Graph Generation
[第十课笔记结束]