自然语言处理知识图谱

一文详解图神经网络(二)

2022-06-29  本文已影响0人  晓柒NLP与药物设计

《The Graph Neural Network Model》

GNN模型基于信息传播机制,每⼀个节点通过相互交换信息来更新⾃⼰的节点状态,直到达到某⼀个稳定值,GNN的输出就是在每个节点处,根据当前节点状态分别计算输出

5.1.1 任务定义

图领域的应用主要可以分为两种类型:专注于图的应用(graph-focused)专注于节点的应用(node-focused)。对于graph-focused的应用,函数\tau和具体的节点无关,(即\tau(G)),训练时,在一个图的数据集中进行分类或回归。对于node-focused的应用,\tau函数依赖于具体的节点n,即\tau(G,n)

在一个图-节点对的集合\mathcal{D}=\mathcal{G} \times \mathcal{N}\mathcal{G}表示图的集合,\mathcal{N}表示节点集合,图领域问题可以表示成一个有如下数据集的监督学习框架:
\mathcal{L}=\left\{\left(\boldsymbol{G}_{i}, n_{i, j}, \boldsymbol{t}_{i, j}\right)| \boldsymbol{G}_{i}=\left(\boldsymbol{N}_{i}, \boldsymbol{E}_{i}\right) \in \mathcal{G}\right.;n_{i, j} \in \boldsymbol{N}_{i} ; \boldsymbol{t}_{i, j} \in \mathbb{R}^{m}, 1 \leq i \leq p, 1 \leq j \leq q_{i} \}\tag{30}
其中,n_{i, j} \in \boldsymbol{N}_{i}表示集合\boldsymbol{N}_{i} \in \mathcal{N}中的第j个节点,\boldsymbol{t}_{i, j}表示节点n_{ij}的期望目标(即标签)。节点n的状态用\boldsymbol{x}_{n} \in \mathbb{R}^{s}表示,该节点的输出用\boldsymbol{o}_{\boldsymbol{n}}表示,f_{\boldsymbol{w}}local transition functiong_{\boldsymbol{w}}local output function,那么\boldsymbol{x}_{n}\boldsymbol{o}_{\boldsymbol{n}}的更新方式如下:
\boldsymbol{x}_{n}=f_{\boldsymbol{w}}(l_n,l_{co[n]},\boldsymbol{x}_{ne[n]},l_{ne[n]})\\ \boldsymbol{o}_{\boldsymbol{n}}=g_{\boldsymbol{w}}(\boldsymbol{x}_n,l_n)\tag{31}
其中,l_{n}, {l}_{\operatorname{co}[n]}, \boldsymbol{x}_{\mathrm{ne}[n]}, {l}_{\mathrm{ne}[n]}分别表示节点n的特征向量、与节点n相连的边的特征向量、节点n邻居节点的状态向量、节点n邻居节点的特征向量。\boldsymbol{x}, \boldsymbol{o}, {l}, {l}_{N}分别为所有的状态、所有的输出、所有的特征向量、所有节点的特征向量的叠加起来的向量,那么上面函数可以写成如下形式:
\boldsymbol{x}=F_{\boldsymbol{w}}(\boldsymbol{x},l)\\ \boldsymbol{o}=G_{\boldsymbol{w}}(\boldsymbol{x},l_N)\tag{32}
其中,F_{\boldsymbol{w}}global transition functionG_{\boldsymbol{w}}global output function,分别是f_{\boldsymbol{w}}g_{\boldsymbol{w}}的叠加形式

根据Banach的不动点理论,假设F_{\boldsymbol{w}}是一个压缩映射函数,那么式子有唯一不动点解,而且可以通过迭代方式逼近该不动点
\boldsymbol{x}(t+1)=F_{\boldsymbol{w}}(\boldsymbol{x}(t), {l})\tag{33}
其中,\boldsymbol{x}(t)表示\boldsymbol{x}在第t个迭代时刻的值,对于任意初值,迭代的误差是以指数速度减小的,使用迭代的形式写出状态和输出的更新表达式为:
\boldsymbol{x}_{n}(t+1)=f_{\boldsymbol{w}}(l_n,l_{co[n]},\boldsymbol{x}_{ne[n]}(t),l_{ne[n]})\\ \boldsymbol{o}_{\boldsymbol{n}}(t)=g_{\boldsymbol{w}}(\boldsymbol{x}_n(t),l_n),n\in N\tag{34}

5.1.2 训练策略

GNN的学习就是估计参数\boldsymbol{w},使得函数\varphi_{\boldsymbol{w}}能够近似估计训练集
\mathcal{L}=\left\{\left(\boldsymbol{G}_{i}, n_{i, j}, \boldsymbol{t}_{i, j}\right)| \boldsymbol{G}_{i}=\left(\boldsymbol{N}_{i}, \boldsymbol{E}_{i}\right) \in \mathcal{G}\right.;n_{i, j} \in \boldsymbol{N}_{i} ; \boldsymbol{t}_{i, j} \in \mathbb{R}^{m}, 1 \leq i \leq p, 1 \leq j \leq q_{i} \}\tag{30}
其中,q_i表示在图G_{i}中监督学习的节点,对于graph-focused的任务,需要增加一个特殊的节点,该节点用来作为目标节点,这样,graph-focused任务和node-focused任务都能统一到节点预测任务上,学习目标可以是最小化如下二次损失函数
e_{\boldsymbol{w}}=\sum_{i=1}^{p} \sum_{j=1}^{q_{i}}\left(\boldsymbol{t}_{i, j}-\varphi_{\boldsymbol{w}}\left(\boldsymbol{G}_{i}, n_{i, j}\right)\right)^{2}\tag{35}
优化算法基于随机梯度下降的策略,优化步骤按照如下几步进行:

这里假设函数F_{\boldsymbol{w}}是压缩映射函数,保证最终能够收敛到不动点。另外,这里的梯度的计算使用backpropagation-through-time algorithm

理论1(可微性):令F_{\boldsymbol{w}}G_{\boldsymbol{w}}分别是global transition functionglobal output function,如果F_{\boldsymbol{w}}(\boldsymbol{x}, {l})G_{\boldsymbol{w}}\left(\boldsymbol{x}, {l}_{\boldsymbol{N}}\right)对于\boldsymbol{x}\boldsymbol{w}是连续可微的,那么\varphi_{\boldsymbol{w}}\boldsymbol{w}也是连续可微的

理论2(反向传播):令F_{\boldsymbol{w}}G_{\boldsymbol{w}}分别是global transition functionglobal output function,如果F_{\boldsymbol{w}}(\boldsymbol{x}, {l})G_{\boldsymbol{w}}\left(\boldsymbol{x}, {l}_{\boldsymbol{N}}\right)对于\boldsymbol{x}\boldsymbol{w}是连续可微的。令\boldsymbol{z}(t)定义为:
(t)=z(t+1) \cdot \frac{\partial F_{w}}{\partial x}(x, l)+\frac{\partial e_{w}}{\partial o} \cdot \frac{\partial G_{w}}{\partial x}\left(x, l_{N}\right)\tag{36}
那么,序列\boldsymbol{z}(T), \boldsymbol{z}(T-1), \ldots收敛到一个向量,z=\lim _{t \rightarrow-\infty} z(t),并且收敛速度为指数级收敛以及与初值\boldsymbol{z}(T)无关,另外,还存在:
\frac{\partial e_{w}}{\partial \boldsymbol{w}}=\frac{\partial e_{\boldsymbol{w}}}{\partial \boldsymbol{o}} \cdot \frac{\partial G_{\boldsymbol{w}}}{\partial \boldsymbol{w}}\left(\boldsymbol{x}, {l}_{N}\right)+\boldsymbol{z} \cdot \frac{\partial F_{\boldsymbol{w}}}{\partial \boldsymbol{w}}(\boldsymbol{x}, {l})\tag{37}
其中,\boldsymbol{x}是GNN的稳定状态

5.1.3 Transition和Output函数

在GNN中,函数g_{\boldsymbol{w}}不需要满足特定的约束,直接使用多层前馈神经网络,对于函数f_{\boldsymbol{w}},则需要着重考虑,因为f_{\boldsymbol{w}}需要满足压缩映射的条件,而且与不动点计算相关。下面提出两种神经网络和不同的策略来满足这些需求

  1. Linear(nonpositional) GNN:

对于节点n nn状态的计算,将f_{\boldsymbol{w}}改成如下形式
\boldsymbol{x}_{n}=\sum_{u \in \text { ne } | n ]} h_{\boldsymbol{w}}\left({l}_{n}, {l}_{(n, u)}, \boldsymbol{x}_{u}, {l}_{u}\right), \quad n \in \boldsymbol{N}\tag{38}
相当于是对节点n的每一个邻居节点使用h_{\boldsymbol{w}},并将得到的值求和来作为节点n的状态,由此,对上式中的函数h_{\boldsymbol{w}}按照如下方式实现:
h_{\boldsymbol{w}}\left({l}_{n}, {l}_{(n, \mathfrak{a})}, \boldsymbol{x}_{u}, {l}_{u}\right) = \boldsymbol{A}_{n, u} \boldsymbol{x}_{u}+\boldsymbol{b}_{n}\tag{39}
其中,向量\boldsymbol{b}_{n} \in \mathbb{R}^{s},矩阵\boldsymbol{A}_{n, u} \in \mathbb{R}^{s \times s}定义为两个前向神经网络的输出。更确切地说,令产生矩阵\boldsymbol{A}_{n, u}的网络为transition network,产生向量\boldsymbol{b}_{n}的网络为forcing network

其中,\mu \in(0,1)\Xi=\operatorname{resize}\left(\phi_{\boldsymbol{w}}\left({l}_{n}, {l}_{(n, u)}, {l}_{u}\right)\right)\text{resize}(\cdot)表示将s^2维的向量整理(reshape)成s\times{s}的矩阵,也就是说,将transition network的输出整理成方形矩阵,然后乘以一个系数就得到\boldsymbol{A}_{n, u}\boldsymbol{b}_{n}就是forcing network的输出

在这里,假定\left\|\phi_{\boldsymbol{w}}\left({l}_{n}, {l}_{(\boldsymbol{n}, \boldsymbol{u})}, {l}_{u}\right)\right\|_{1} \leq \boldsymbol{s},这个可以通过设定transition function的激活函数来满足,比如设定激活函数为tanh()。在这种情况下,F_{\boldsymbol{w}}(\boldsymbol{x}, {l})=\boldsymbol{A} \boldsymbol{x}+\boldsymbol{b}\boldsymbol{A}\boldsymbol{b}分别是\boldsymbol{A}_{n, u}的块矩阵形式和\boldsymbol{b}_{n}的堆叠形式,可得:
\|\frac{∂F_\boldsymbol{w}}{∂\boldsymbol{x}}\|_{1}=\|A\|_{1}≤max_{u\in N}\Bigg(\sum_{n\in ne[u]}\|\boldsymbol{A}_{n,u}\|_1\Bigg)\\ ≤max_{u\in N}\Bigg(\frac{\mu}{s|ne[u|}\cdot\sum_{n\in ne[u]}\|\Xi\|_1\Bigg)≤\mu\tag{43}
该式表示F_{\boldsymbol{w}}对于任意的参数\boldsymbol{w}是一个压缩映射,矩阵M1-norm定义为:
\|M\|_{1}=\max _{j} \sum_{i}\left|m_{i, j}\right|\tag{44}

  1. Nonelinear(nonpositional) GNN:

在这个结构中,h_{\boldsymbol{w}}通过多层前馈网络实现,但是,并不是所有的参数\boldsymbol{w}都会被使用,因为同样需要保证F_{\boldsymbol{w}}是一个压缩映射函数,这个可以通过惩罚项来实现
e_{\boldsymbol{w}}=\sum_{i=1}^{p} \sum_{j=1}^{q_{i}}\left(\boldsymbol{t}_{i, j}-\varphi_{\boldsymbol{w}}\left(\boldsymbol{G}_{i}, n_{i, j}\right)\right)^{2}+\beta L\left(\left\|\frac{\partial F_{\boldsymbol{w}}}{\partial \boldsymbol{x}}\right\|\right)\tag{45}
其中,惩罚项L(y)y>\mu时为(y-\mu)^2,在y\le{\mu}时为0,参数\mu\in(0,1)定义为希望的F_{\boldsymbol{w}}的压缩系数

5.1.4 代码实现
class GNN(nn.Module):
    def __init__(self, config, state_net=None, out_net=None):
        super(GNN, self).__init__()
        self.config = config
        # hyperparameters and general properties
        self.convergence_threshold = config.convergence_threshold
        self.max_iterations = config.max_iterations
        self.n_nodes = config.n_nodes
        self.state_dim = config.state_dim
        self.label_dim = config.label_dim
        self.output_dim = config.output_dim
        self.state_transition_hidden_dims = config.state_transition_hidden_dims
        self.output_function_hidden_dims = config.output_function_hidden_dims
        # node state initialization
        self.node_state = torch.zeros(*[self.n_nodes, self.state_dim]).to(self.config.device)  # (n,d_n)
        self.converged_states = torch.zeros(*[self.n_nodes, self.state_dim]).to(self.config.device)
        # state and output transition functions
        if state_net is None:
            self.state_transition_function = StateTransition(self.state_dim, self.label_dim,
                                                             mlp_hidden_dim=self.state_transition_hidden_dims,
                                                             activation_function=config.activation)
        else:
            self.state_transition_function = state_net
        if out_net is None:
            self.output_function = MLP(self.state_dim, self.output_function_hidden_dims, self.output_dim)
        else:
            self.output_function = out_net
        self.graph_based = self.config.graph_based
    def reset_parameters(self):
        self.state_transition_function.mlp.init()
        self.output_function.init()
    def forward(self,
                edges,
                agg_matrix,
                node_labels,
                node_states=None,
                graph_agg=None
                ):
        n_iterations = 0
        # convergence loop
        # state initialization
        node_states = self.node_state if node_states is None else node_states
        while n_iterations < self.max_iterations:
            new_state = self.state_transition_function(node_states, node_labels, edges, agg_matrix)
            n_iterations += 1
            # convergence condition
            with torch.no_grad():
                distance = torch.norm(input=new_state - node_states,
                                      dim=1)  # checked, they are the same (in cuda, some bug)
                check_min = distance < self.convergence_threshold
            node_states = new_state
            if check_min.all():
                break
        states = node_states
        self.converged_states = states
        if self.graph_based:
            states = torch.matmul(graph_agg, node_states)
        output = self.output_function(states)
        return output, n_iterations

NLP新人,欢迎大家一起交流,互相学习,共同成长~~

上一篇 下一篇

猜你喜欢

热点阅读