Source code for gammagl.layers.conv.gpr_conv

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


[docs] class GPRConv(MessagePassing): r"""The graph propagation oeprator from the `"Adaptive Universal Generalized PageRank Graph Neural Network" <https://arxiv.org/abs/2006.07988.pdf>`_ paper .. math:: \mathbf{H}^{(k)} = \mathbf{\hat{D}}^{-1/2} \mathbf{\hat{A}} \mathbf{\hat{D}}^{-1/2} \mathbf{H}^{(k-1)} \\ \mathbf{Z} = \sum\limits_{k=0}^{k=K}\gamma_k\mathbf{H}^{(k)}. 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. The adjacency matrix can include other values than :obj:`1` representing edge weights via the optional :obj:`edge_weight` tensor. :math:`\gamma_{k}` its learnt weights. Parameters ---------- k: steps to propagate. alpha: assgin initial value to learnt weights, used in concert with Init. Init: initialization method(SGC, PPR, NPPR, Random, WS). """ def __init__(self, K, alpha, Init='PPR', Gamma=None, **kwargs): super(GPRConv, self).__init__(**kwargs) self.K = K self.Init = Init self.alpha = alpha assert Init in ['SGC', 'PPR', 'NPPR', 'Random', 'WS'] if Init == 'SGC': # SGC-like, note that in this case, alpha has to be a integer. It means where the peak at when initializing GPR weights. TEMP = 0.0 * np.ones(K + 1) TEMP[alpha] = 1.0 elif Init == 'PPR': # PPR-like TEMP = alpha * (1 - alpha) ** np.arange(K + 1) TEMP[-1] = (1 - alpha) ** K elif Init == 'NPPR': # Negative PPR TEMP = (alpha) ** np.arange(K + 1) TEMP = TEMP / np.sum(np.abs(TEMP)) elif Init == 'Random': # Random bound = np.sqrt(3 / (K + 1)) TEMP = np.random.uniform(-bound, bound, K + 1) TEMP = TEMP / np.sum(np.abs(TEMP)) elif Init == 'WS': # Specify Gamma TEMP = Gamma init = tlx.initializers.Constant(value=TEMP) self.temp = tlx.cast(self._get_weights(var_name='Gamma', shape=(self.K + 1, ), init=init), dtype=tlx.float32)
[docs] def reset_parameters(self): self.temp = tlx.zeros_like(self.temp, dtype=tlx.float32) for k in range(self.K + 1): self.temp[k] = self.alpha * (1 - self.alpha) ** k self.temp[-1] = (1 - self.alpha) ** self.K
[docs] def forward(self, x, edge_index, edge_weight=None, num_nodes=None): hidden = x * (self.temp[0]) for k in range(self.K): x = self.propagate(x, edge_index, edge_weight=edge_weight, num_nodes=num_nodes) gamma = self.temp[k + 1] hidden = hidden + gamma * x return hidden
def __repr__(self): return '{}(K={}, temp={})'.format(self.__class__.__name__, self.K, self.temp)