Source code for gammagl.layers.conv.gcnii_conv

import tensorlayerx as tlx
from gammagl.layers.conv import MessagePassing

[docs] class GCNIIConv(MessagePassing): r""" The graph convolutional operator with initial residual connections and identity mapping (GCNII) from the `"Simple and Deep Graph Convolutional Networks" <https://arxiv.org/abs/2007.02133>`_ paper .. math:: \mathbf{X}^{\prime} = \left( (1 - \alpha) \mathbf{\hat{P}}\mathbf{X} + \alpha \mathbf{X^{(0)}}\right) \left( (1 - \beta) \mathbf{I} + \beta \mathbf{\Theta} \right) with :math:`\mathbf{\hat{P}} = \mathbf{\hat{D}}^{-1/2} \mathbf{\hat{A}} \mathbf{\hat{D}}^{-1/2}`, where :math:`\mathbf{\hat{A}} = \mathbf{A} + \mathbf{I}` denotes the adjacency matrix with inserted self-loops and :math:`\hat{D}_{ii} = \sum_{j=0} \hat{A}_{ij}` its diagonal degree matrix, and :math:`\mathbf{X}^{(0)}` being the initial feature representation. Here, :math:`\alpha` models the strength of the initial residual connection, while :math:`\beta` models the strength of the identity mapping. The adjacency matrix can include other values than :obj:`1` representing edge weights via the optional :obj:`edge_weight` tensor. Parameters ---------- in_channels: int Size of each input sample. out_channels: int Size of each outoput sample. alpha: float The strength of the initial residual connection :math:`\alpha`. beta: float The hyperparameter :math:`\beta` to compute \ the strength of the identity mapping :math:`\beta = \log \left( \frac{\beta}{\ell} + 1 \right)`. (default: :obj:`None`) variant: bool, optional use GCNII*, which can be fomuliazed as following: .. math:: \mathbf{H}^{(\ell+1)}= \sigma\left(\left(1-\alpha_{\ell}\right) \tilde{\mathbf{P}} \mathbf{H}^{(\ell)}\left(\left(1-\beta_{\ell}\right) \mathbf{I}_{n}+\beta_{\ell} \mathbf{W}_{1}^{(\ell)}\right)+\right.\\ \left.+\alpha_{\ell} \mathbf{H}^{(0)}\left(\left(1-\beta_{\ell}\right) \mathbf{I}_{n}+\beta_{\ell} \mathbf{W}_{2}^{(\ell)}\right)\right) """ def __init__(self, in_channels, out_channels, alpha, beta, variant=False): super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.alpha = alpha self.beta = beta self.variant = variant self.linear = tlx.layers.Linear(out_features=self.out_channels, in_features=self.in_channels, b_init=None) if self.variant: # what if same as linear self.linear0 = tlx.layers.Linear(out_features=self.out_channels, in_features=self.in_channels, b_init=None)
[docs] def forward(self, x0, x, edge_index, edge_weight, num_nodes): if self.variant: x = (1-self.alpha)*self.propagate(x, edge_index, edge_weight=edge_weight, num_nodes=num_nodes) x = (1-self.beta)*x + self.beta*self.linear(x) x0 = self.alpha*x0 x0 = (1-self.beta)*x0 + self.beta * self.linear0(x0) x = x + x0 # x = (1 - self.alpha) * self.propagate(x, sparse_adj) # x0 = self.alpha * x0 # x = x + x0 # x = (1-self.beta)*x + self.beta*self.linear(x) else: x = self.propagate(x, edge_index, edge_weight=edge_weight, num_nodes=num_nodes) x = (1-self.alpha)*x + self.alpha*x0 x = (1-self.beta)*x + self.beta*self.linear(x) return x