Source code for gammagl.transforms.sign

import numpy as np
import scipy.sparse as sp
import tensorlayerx as tlx
from gammagl.transforms import BaseTransform


[docs] class SIGN(BaseTransform): r"""The Scalable Inception Graph Neural Network module (SIGN) from the `"SIGN: Scalable Inception Graph Neural Networks" <https://arxiv.org/abs/2004.11198>`_ paper (functional name: :obj:`sign`), which precomputes the fixed representations .. math:: \mathbf{X}^{(i)} = {\left( \mathbf{D}^{-1/2} \mathbf{A} \mathbf{D}^{-1/2} \right)}^i \mathbf{X} for :math:`i \in \{ 1, \ldots, K \}` and saves them in :obj:`data.x1`, :obj:`data.x2`, ... .. note:: Since intermediate node representations are pre-computed, this operator is able to scale well to large graphs via classic mini-batching. For an example of using SIGN, see `examples/sign.py <https://github.com/BUPT-GAMMA/GammaGL/tree/main/examples/sign>`_. Parameters ---------- K: int The number of hops/layer. """ def __init__(self, K): self.K = K def __call__(self, graph): assert graph.edge_index is not None if tlx.is_tensor(graph.edge_index): row, col = tlx.convert_to_numpy(graph.edge_index) else: row, col = graph.edge_index weight = np.ones_like(row, dtype=np.float32) # Here the graph is undirected. deg = np.bincount(row) deg_inv_sqrt = np.power(deg, -0.5, dtype=np.float32).flatten() deg_inv_sqrt[deg_inv_sqrt == float('inf')] = 0 new_weight = deg_inv_sqrt[row] * weight * deg_inv_sqrt[col] new_adj = sp.coo_matrix((new_weight, [col, row])) assert graph.x is not None if tlx.is_tensor(graph.x): x = tlx.convert_to_numpy(graph.x) else: x = graph.x xs = [x] for i in range(1, self.K + 1): xs += [new_adj @ xs[-1]] graph[f'x{i}'] = xs[-1] return graph def __repr__(self) -> str: return f'{self.__class__.__name__}(K={self.K})'