diff --git a/configs/transforms/liftings/graph2hypergraph/spectral_lifting.yaml b/configs/transforms/liftings/graph2hypergraph/spectral_lifting.yaml new file mode 100644 index 00000000..a247fba5 --- /dev/null +++ b/configs/transforms/liftings/graph2hypergraph/spectral_lifting.yaml @@ -0,0 +1,6 @@ +transform_type: 'lifting' +transform_name: "SpectralLifting" +n_c: null +cluster_alg: "KMeans" +eps: 1e-9 +feature_lifting: ProjectionSum \ No newline at end of file diff --git a/modules/transforms/data_transform.py b/modules/transforms/data_transform.py index 59253ecf..62762de4 100755 --- a/modules/transforms/data_transform.py +++ b/modules/transforms/data_transform.py @@ -12,6 +12,9 @@ from modules.transforms.liftings.graph2hypergraph.knn_lifting import ( HypergraphKNNLifting, ) +from modules.transforms.liftings.graph2hypergraph.spectral_lifting import ( + SpectralLifting, +) from modules.transforms.liftings.graph2simplicial.clique_lifting import ( SimplicialCliqueLifting, ) @@ -19,6 +22,7 @@ TRANSFORMS = { # Graph -> Hypergraph "HypergraphKNNLifting": HypergraphKNNLifting, + "SpectralLifting": SpectralLifting, # Graph -> Simplicial Complex "SimplicialCliqueLifting": SimplicialCliqueLifting, # Graph -> Cell Complex diff --git a/modules/transforms/liftings/graph2hypergraph/spectral_lifting.py b/modules/transforms/liftings/graph2hypergraph/spectral_lifting.py new file mode 100644 index 00000000..eb72b61a --- /dev/null +++ b/modules/transforms/liftings/graph2hypergraph/spectral_lifting.py @@ -0,0 +1,181 @@ +import warnings + +import torch +import torch_geometric +from sklearn.cluster import KMeans + +from modules.transforms.liftings.graph2hypergraph.base import Graph2HypergraphLifting + + +class SpectralLifting(Graph2HypergraphLifting): + r"""Lifts graphs to hypergraph domain by finding clusters using spectral clustering [Ng, Jordan, and Weiss (2002) [[1]](https://proceedings.neurips.cc/paper/2001/hash/801272ee79cfde7fa5960571fee36b9b-Abstract.html)] + + Parameters + ---------- + n_c : int, optional + The number of clusters. Default is None. + cluster_alg : str, optional + The clustering algorithm to use after spectral projection. Default is KMeans. + eps : float, optional + The threshold to use on the eigenvalues before inverting the matrix to avoid division by 0. Default is 1e- + **kwargs : optional + Additional arguments for the class. + """ + + def __init__( + self, + n_c=None, + cluster_alg="KMeans", + eps=1e-9, + **kwargs, + ): + super().__init__(**kwargs) + self.n_c = n_c + self.eps = eps + self.init_clust_alg(cluster_alg) + + def init_clust_alg(self, cluster_alg: str): + cluster_algs = {"KMeans": KMeans} + if cluster_alg not in cluster_algs: + warnings.warn( + f"KMeans will be used since the algorithm {cluster_alg} was not recognized. Available algorithms: {list(cluster_algs.values())}", + stacklevel=2, + ) + self.cluster_alg = cluster_algs.get(cluster_alg, KMeans) + + def get_degree_matrix(self, W: torch.Tensor): + return torch.diag(W.sum(1)) + + def get_sqrt_inv(self, D: torch.Tensor): + degrees = torch.clamp(torch.diag(D), min=self.eps) + return torch.diag(degrees ** (-0.5)) + + def to_dense(self, m: torch.Tensor): + M = torch.zeros(self.num_nodes, self.num_nodes) + n_edges = m.shape[1] + for i in range(n_edges): + M[m[0, i], m[1, i]] = 1 + M[m[1, i], m[0, i]] = 1 + return M + + def get_normalized_laplacian(self, W: torch.Tensor): + # Retrieve dense representation of W + W = self.to_dense(W) + + # Compute degree matrix + D = self.get_degree_matrix(W) + + # Compute unnormalized Laplacian + L = D - W + + # Compute the square root of the inverse of the degree matrix + Dinv = self.get_sqrt_inv(D) + + # Return normalized Laplacian + return Dinv @ L @ Dinv + + def find_gaps(self, v: torch.Tensor, a_max: int = 6, a_min: int = 2): + def find_gap(a): + """Finds index largest gap using the eigengap heuristic""" + for k in range(1, len(v)): + m = v[:k].mean() + s = v[:k].std() + if v[k] > m + s * a: + return k - 1 + return None + + def find_k_largest_diff(): + """Finds index largest gap usings absolute differences""" + max_diff = 0 + max_index = 0 + for i in range(1, len(v)): + diff = abs(v[i] - v[i - 1]) + if diff > max_diff: + max_diff = diff + max_index = i + return max_index - 1 + + # Attempt to find index largest gap using eigengap heuristic. + for a in range(a_max, a_min - 1, -1): + k = find_gap(a) + if k and k > 1: + break + + if k is None or k == 1: + # Fall back to using largest absolute difference in case gap heuristic did not work + warnings.warn( + "Unable to confidently determine the number of clusters n_c. The largest difference between consecutive eigenvalues was used to determine the number of clusters. Please provide n_c.", + stacklevel=2, + ) + k = find_k_largest_diff() + if k == 1: + warnings.warn( + "Please provide the number of clusters n_c. The heuristics identified a single cluster and n_c was set to 2.", + stacklevel=2, + ) + k += 1 + return k + + def get_first_eigenvectors(self, Lsym: torch.Tensor): + # Compute eigenvectors + Lambdas, V = torch.linalg.eig(Lsym) + Lambdas, ind_sort = torch.sort(torch.abs(Lambdas)) + + # Filter eigenvectors + if not self.n_c: + self.n_c = self.find_gaps(Lambdas) + + # Return eigenvectors associated to the self.nc smallest eigenvalues + return torch.abs(V[:, ind_sort[: self.n_c + 1]]) + + def normalize_rows(self, U: torch.Tensor): + return U / ((U**2).sum(1, keepdims=True).sqrt()) + + def build_clusters(self, U: torch.Tensor): + return torch.tensor(self.cluster_alg(n_clusters=self.n_c).fit(U).labels_) + + def build_incidence_hyperedges(self, indices_clusters): + A = torch.zeros(self.n_c, self.num_nodes) + for c in range(self.n_c): + ind_curr_clust = torch.nonzero(indices_clusters == c) + A[c, ind_curr_clust] = 1 + return A + + def transform(self, data: torch_geometric.data.Data) -> dict: + # Compute normalized Laplacian + self.num_nodes = data.x.shape[0] + Lsym = self.get_normalized_laplacian(data.edge_index) + + # Compute eigenvectors matrix + U = self.get_first_eigenvectors(Lsym) + + # Normalize rows + U = self.normalize_rows(U) + + # Build clusters + indices_clusters = self.build_clusters(U) + + # Return incidence_hyperedges matrix + return self.build_incidence_hyperedges(indices_clusters=indices_clusters).T + + def lift_topology(self, data: torch_geometric.data.Data) -> dict: + r"""Lifts graphs to hypergraph domain by finding clusters using spectral clustering [Ng, Jordan, and Weiss (2002) [[1]](https://proceedings.neurips.cc/paper/2001/hash/801272ee79cfde7fa5960571fee36b9b-Abstract.html)] + + Parameters + ---------- + data : torch_geometric.data.Data + The input data to be lifted. + + Returns + ------- + dict + The lifted topology. + """ + + data.pos = data.x + incidence_1 = self.transform(data).to_sparse_coo() + return { + "incidence_hyperedges": incidence_1, + "num_hyperedges": self.n_c, + "x_0": data.x, + } diff --git a/test/transforms/liftings/graph2hypergraph/test_spectral_lifting.py b/test/transforms/liftings/graph2hypergraph/test_spectral_lifting.py new file mode 100644 index 00000000..5e71d4d2 --- /dev/null +++ b/test/transforms/liftings/graph2hypergraph/test_spectral_lifting.py @@ -0,0 +1,27 @@ +"""Test the message passing module.""" + +from modules.data.utils.utils import load_manual_graph +from modules.transforms.liftings.graph2hypergraph.spectral_lifting import ( + SpectralLifting, +) + + +class TestSpectralLifting: + """Test the SpectralLifting class.""" + + def setup_method(self): + # Load the graph + self.data = load_manual_graph() + + # Initialise the SpectralLifting class + self.num_hyperedges = 3 + self.lifting = SpectralLifting(n_c=self.num_hyperedges) + + def test_lift_topology(self): + # Test the lift_topology method + lifted_data_k = self.lifting.forward(self.data.clone()) + + assert list(lifted_data_k.incidence_hyperedges.shape) == [ + self.data.num_nodes, + self.num_hyperedges, + ], "There were issues computing the incidence_hyperedges matrix" diff --git a/tutorials/graph2hypergraph/spectral_lifting.ipynb b/tutorials/graph2hypergraph/spectral_lifting.ipynb new file mode 100644 index 00000000..804fa0a9 --- /dev/null +++ b/tutorials/graph2hypergraph/spectral_lifting.ipynb @@ -0,0 +1,336 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Graph-to-Hypergraph Spectral Lifting Tutorial" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***\n", + "This notebook shows how to import a dataset, with the desired lifting, and how to run a neural network using the loaded data.\n", + "\n", + "The notebook is divided into sections:\n", + "\n", + "- [Loading the dataset](#loading-the-dataset) loads the config files for the data and the desired tranformation, createsa a dataset object and visualizes it.\n", + "- [Loading and applying the lifting](#loading-and-applying-the-lifting) defines a simple neural network to test that the lifting creates the expected incidence matrices.\n", + "- [Create and run a simplicial nn model](#create-and-run-a-simplicial-nn-model) simply runs a forward pass of the model to check that everything is working as expected.\n", + "\n", + "***\n", + "***\n", + "\n", + "Note that for simplicity the notebook is setup to use a simple graph. However, there is a set of available datasets that you can play with.\n", + "\n", + "To switch to one of the available datasets, simply change the *dataset_name* variable in [Dataset config](#dataset-config) to one of the following names:\n", + "\n", + "* cocitation_cora\n", + "* cocitation_citeseer\n", + "* cocitation_pubmed\n", + "* MUTAG\n", + "* NCI1\n", + "* NCI109\n", + "* PROTEINS_TU\n", + "* AQSOL\n", + "* ZINC\n", + "***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports and utilities" + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "# With this cell any imported module is reloaded before each cell execution\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "from modules.data.load.loaders import GraphLoader\n", + "from modules.data.preprocess.preprocessor import PreProcessor\n", + "from modules.utils.utils import (\n", + " describe_data,\n", + " load_dataset_config,\n", + " load_model_config,\n", + " load_transform_config,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading the Dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we just need to spicify the name of the available dataset that we want to load. First, the dataset config is read from the corresponding yaml file (located at `/configs/datasets/` directory), and then the data is loaded via the implemented `Loaders`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 237, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Dataset configuration for manual_dataset:\n", + "\n", + "{'data_domain': 'graph',\n", + " 'data_type': 'toy_dataset',\n", + " 'data_name': 'manual',\n", + " 'data_dir': 'datasets/graph/toy_dataset',\n", + " 'num_features': 1,\n", + " 'num_classes': 2,\n", + " 'task': 'classification',\n", + " 'loss_type': 'cross_entropy',\n", + " 'monitor_metric': 'accuracy',\n", + " 'task_level': 'node'}\n" + ] + } + ], + "source": [ + "dataset_name = \"manual_dataset\"\n", + "dataset_config = load_dataset_config(dataset_name)\n", + "loader = GraphLoader(dataset_config)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can then access to the data through the `load()`method:" + ] + }, + { + "cell_type": "code", + "execution_count": 238, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Dataset only contains 1 sample:\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " - Graph with 8 vertices and 13 edges.\n", + " - Features dimensions: [1, 0]\n", + " - There are 0 isolated nodes.\n", + "\n" + ] + } + ], + "source": [ + "dataset = loader.load()\n", + "describe_data(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading and Applying the Lifting" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section we will instantiate the lifting we want to apply to the data. For this example, the spectral lifting was chosen. The lifting algorithm is inspired by the spectral clustering method proposed by Ng, Jordan, and Weiss (2002) [[1]](https://proceedings.neurips.cc/paper/2001/hash/801272ee79cfde7fa5960571fee36b9b-Abstract.html) and maps the clusters identified by the algorithm to hyperedges. The method is based on computing a powerful graph representation leveraging the row-normalized eigenvectors of the normalized laplacian of the adjacency matrix. The current implementation clusters the projected datapoint using KMeans, following the original method. However, any hard of soft clustering method can be used after the implemented projection. The number of clusters can be automatically determined using eigengap heuristics, or provided by setting the n_c parameter of the configuration dictionary.\n", + "***\n", + "[[1]](https://proceedings.neurips.cc/paper/2001/hash/801272ee79cfde7fa5960571fee36b9b-Abstract.html) Ng, Andrew, Michael Jordan, and Yair Weiss. \"On spectral clustering: Analysis and an algorithm.\" Advances in neural information processing systems 14 (2001).\n", + "***\n", + "\n", + "\n", + "For hypergraphs creating a lifting involves creating the `incidence_hyperedges` matrix.\n", + "\n", + "Similarly to before, we can specify the transformation we want to apply through its type and id --the correxponding config files located at `/configs/transforms`. \n", + "\n", + "Note that the *tranform_config* dictionary generated below can contain a sequence of tranforms if it is needed.\n", + "\n", + "This can also be used to explore liftings from one topological domain to another, for example using two liftings it is possible to achieve a sequence such as: graph -> simplicial complex -> hypergraph. " + ] + }, + { + "cell_type": "code", + "execution_count": 239, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Transform configuration for graph2hypergraph/spectral_lifting:\n", + "\n", + "{'transform_type': 'lifting',\n", + " 'transform_name': 'SpectralLifting',\n", + " 'n_c': None,\n", + " 'cluster_alg': 'KMeans',\n", + " 'eps': 1e-09,\n", + " 'feature_lifting': 'ProjectionSum'}\n" + ] + } + ], + "source": [ + "# Define transformation type and id\n", + "transform_type = \"liftings\"\n", + "# If the transform is a topological lifting, it should include both the type of the lifting and the identifier\n", + "transform_id = \"graph2hypergraph/spectral_lifting\"\n", + "\n", + "# Read yaml file\n", + "transform_config = {\n", + " \"lifting\": load_transform_config(transform_type, transform_id)\n", + " # other transforms (e.g. data manipulations, feature liftings) can be added here\n", + "}\n", + "# [Optional] specify the number of hyperedges/clusters\n", + "transform_config[\"lifting\"][\"n_c\"] = 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We than apply the transform via our `PreProcesor`:" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Processing...\n", + "Done!\n" + ] + } + ], + "source": [ + "lifted_dataset = PreProcessor(dataset, transform_config, loader.data_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create and Run a Simplicial NN Model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section a simple model is created to test that the used lifting works as intended. In this case the model uses the `incidence_hyperedges` matrix so the lifting should make sure to add it to the data." + ] + }, + { + "cell_type": "code", + "execution_count": 233, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Model configuration for hypergraph UNIGCN:\n", + "\n", + "{'in_channels': None,\n", + " 'hidden_channels': 32,\n", + " 'out_channels': None,\n", + " 'n_layers': 2}\n" + ] + } + ], + "source": [ + "from modules.models.hypergraph.unigcn import UniGCNModel\n", + "\n", + "model_type = \"hypergraph\"\n", + "model_id = \"unigcn\"\n", + "model_config = load_model_config(model_type, model_id)\n", + "\n", + "model = UniGCNModel(model_config, dataset_config)" + ] + }, + { + "cell_type": "code", + "execution_count": 234, + "metadata": {}, + "outputs": [], + "source": [ + "y_hat = model(lifted_dataset.get(0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If everything is correct the cell above should execute without errors. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv_topox", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}