From 448a22a0362ca5dfcfce32b51079db4a946d9e6c Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Tue, 28 Jul 2026 17:47:30 +0200 Subject: [PATCH 01/21] An implementation of HyperGCN --- .../hypergraph/hypergraph_convolution.yaml | 8 + configs/transforms/hypergraph_laplacian.yaml | 4 + pyproject.toml | 4 +- .../hypergraph/hypergraph_convolution.py | 147 ++++++++++++ .../graph2hypergraph/hypergraph_laplacian.py | 219 ++++++++++++++++++ .../tutorial_custom_data_transformation.ipynb | 108 +++------ 6 files changed, 416 insertions(+), 74 deletions(-) create mode 100644 configs/model/hypergraph/hypergraph_convolution.yaml create mode 100644 configs/transforms/hypergraph_laplacian.yaml create mode 100644 topobench/nn/backbones/hypergraph/hypergraph_convolution.py create mode 100644 topobench/transforms/liftings/graph2hypergraph/hypergraph_laplacian.py diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml new file mode 100644 index 000000000..88f92b258 --- /dev/null +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -0,0 +1,8 @@ +# @package _global_ + +model: + _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution + a: 64 + b: 64 + reapproximate: true + cuda: null diff --git a/configs/transforms/hypergraph_laplacian.yaml b/configs/transforms/hypergraph_laplacian.yaml new file mode 100644 index 000000000..5051a290e --- /dev/null +++ b/configs/transforms/hypergraph_laplacian.yaml @@ -0,0 +1,4 @@ +_target_: topobench.transforms.data_transform.DataTransform +transform_name: "HypergraphLaplacian" +transform_type: "liftings" +m: true diff --git a/pyproject.toml b/pyproject.toml index 1918105d7..299b8355e 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,12 +120,12 @@ explicit = true # Default find-links (will be overwritten by bash script) [tool.uv] -find-links = ["https://data.pyg.org/whl/torch-2.3.0+cu121.html"] +find-links = ["https://data.pyg.org/whl/torch-2.3.0+cpu.html"] [tool.uv.sources] torch = [ { index = "pytorch-cpu", marker = "sys_platform == 'darwin' or sys_platform == 'win32'" }, - { index = "pytorch-cu121", marker = "sys_platform == 'linux'" }, + { index = "pytorch-cpu", marker = "sys_platform == 'linux'" }, ] [tool.uv.extra-build-dependencies] diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py new file mode 100644 index 000000000..978edc570 --- /dev/null +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -0,0 +1,147 @@ +"""Define the hypergraph convolution neural network layer.""" + +import math + +import torch +from torch.autograd import Variable +from torch.nn.modules.module import Module +from torch.nn.parameter import Parameter + +from topobench.transforms.liftings.graph2hypergraph.hypergraph_laplacian import ( + Laplacian, +) + + +class SparseMM(torch.autograd.Function): + """Provide sparse times dense matrix multiplication with autograd support.""" + + @staticmethod + def forward(ctx, M1, M2): + """Compute the forward pass for sparse matrix multiplication. + + Parameters + ---------- + ctx : object + The context object. + M1 : torch.Tensor + The sparse matrix. + M2 : torch.Tensor + The dense matrix. + + Returns + ------- + torch.Tensor + The resulting multiplied matrix. + """ + ctx.save_for_backward(M1, M2) + return torch.mm(M1, M2) + + @staticmethod + def backward(ctx, g): + """Compute the backward pass for sparse matrix multiplication. + + Parameters + ---------- + ctx : object + The context object. + g : torch.Tensor + The gradient tensor. + + Returns + ------- + tuple + The gradients for M1 and M2. + """ + M1, M2 = ctx.saved_tensors + g1 = g2 = None + + if ctx.needs_input_grad[0]: + g1 = torch.mm(g, M2.t()) + + if ctx.needs_input_grad[1]: + g2 = torch.mm(M1.t(), g) + + return g1, g2 + + +class HyperGraphConvolution(Module): + """Define a simple GCN layer. + + Parameters + ---------- + a : int + The input feature dimension. + b : int + The output feature dimension. + reapproximate : bool, optional + Whether to reapproximate the Laplacian, by default True. + cuda : int or None, optional + The CUDA device index, by default None. + """ + + def __init__(self, a, b, reapproximate=True, cuda=None): + super().__init__() + self.a, self.b = a, b + self.reapproximate = reapproximate + self.device = torch.device( + "cuda:" + str(cuda) if cuda is not None else "cpu" + ) + + self.W = Parameter(torch.FloatTensor(a, b)) + self.bias = Parameter(torch.FloatTensor(b)) + self.reset_parameters() + + def reset_parameters(self): + """Reset the layer parameters.""" + std = 1.0 / math.sqrt(self.W.size(1)) + self.W.data.uniform_(-std, std) + self.bias.data.uniform_(-std, std) + + def forward(self, structure, H, m=True): + """Compute the forward pass of the HyperGraph Convolution layer. + + Parameters + ---------- + structure : torch.Tensor or dict + The structural matrix or hyperedge dictionary. + H : torch.Tensor + The hidden node features. + m : bool, optional + Whether to use mediators, by default True. + + Returns + ------- + torch.Tensor + The updated node features. + """ + W, b = self.W, self.bias + HW = torch.mm(H, W) + + if self.reapproximate: + n, X = H.shape[0], HW.cpu().detach().numpy() + A = Laplacian(n, structure, X, m) + else: + A = structure + + A = A.to(self.device) + A = Variable(A) + + AHW = SparseMM.apply(A, HW) + return AHW + b + + def __repr__(self): + """Return the string representation of the module. + + Returns + ------- + str + The module string representation. + """ + return ( + self.__class__.__name__ + + " (" + + str(self.a) + + " -> " + + str(self.b) + + ")" + ) diff --git a/topobench/transforms/liftings/graph2hypergraph/hypergraph_laplacian.py b/topobench/transforms/liftings/graph2hypergraph/hypergraph_laplacian.py new file mode 100644 index 000000000..598912d98 --- /dev/null +++ b/topobench/transforms/liftings/graph2hypergraph/hypergraph_laplacian.py @@ -0,0 +1,219 @@ +"""Provide functions to compute the hypergraph Laplacian.""" + +import numpy as np +import scipy.sparse as sp +import torch + + +def Laplacian(V, E, X, m): + """Approximate the hypergraph Laplacian with or without mediators. + + Parameters + ---------- + V : int + The number of vertices. + E : dict + The dictionary of hyperedges. + X : numpy.ndarray + The node feature matrix. + m : bool + Whether to use mediators. + + Returns + ------- + torch.sparse.FloatTensor + The approximate hypergraph Laplacian matrix. + """ + edges, weights = [], {} + rv = np.random.rand(X.shape[1]) + + for k in E: + hyperedge = list(E[k]) + + p = np.dot(X[hyperedge], rv) # projection onto a random vector rv + s, i = np.argmax(p), np.argmin(p) + Se, Ie = hyperedge[s], hyperedge[i] + + # two stars with mediators + c = 2 * len(hyperedge) - 3 # normalisation constant + if m: + # connect the supremum (Se) with the infimum (Ie) + edges.extend([[Se, Ie], [Ie, Se]]) + + if (Se, Ie) not in weights: + weights[(Se, Ie)] = 0 + weights[(Se, Ie)] += float(1 / c) + + if (Ie, Se) not in weights: + weights[(Ie, Se)] = 0 + weights[(Ie, Se)] += float(1 / c) + + # connect the supremum (Se) and the infimum (Ie) with each mediator + for mediator in hyperedge: + if mediator != Se and mediator != Ie: + edges.extend( + [ + [Se, mediator], + [Ie, mediator], + [mediator, Se], + [mediator, Ie], + ] + ) + weights = update(Se, Ie, mediator, weights, c) + else: + edges.extend([[Se, Ie], [Ie, Se]]) + e = len(hyperedge) + + if (Se, Ie) not in weights: + weights[(Se, Ie)] = 0 + weights[(Se, Ie)] += float(1 / e) + + if (Ie, Se) not in weights: + weights[(Ie, Se)] = 0 + weights[(Ie, Se)] += float(1 / e) + + return adjacency(edges, weights, V) + + +def update(Se, Ie, mediator, weights, c): + """Update the weights on edges connecting extremes to the mediator. + + Parameters + ---------- + Se : int + The supremum node index. + Ie : int + The infimum node index. + mediator : int + The mediator node index. + weights : dict + The dictionary tracking edge weights. + c : float + The normalization constant. + + Returns + ------- + dict + The updated edge weights dictionary. + """ + if (Se, mediator) not in weights: + weights[(Se, mediator)] = 0 + weights[(Se, mediator)] += float(1 / c) + + if (Ie, mediator) not in weights: + weights[(Ie, mediator)] = 0 + weights[(Ie, mediator)] += float(1 / c) + + if (mediator, Se) not in weights: + weights[(mediator, Se)] = 0 + weights[(mediator, Se)] += float(1 / c) + + if (mediator, Ie) not in weights: + weights[(mediator, Ie)] = 0 + weights[(mediator, Ie)] += float(1 / c) + + return weights + + +def adjacency(edges, weights, n): + """Compute a sparse adjacency matrix from given edges and weights. + + Parameters + ---------- + edges : list + The list of edges. + weights : dict + The dictionary of weights for each edge. + n : int + The number of nodes in the graph. + + Returns + ------- + torch.sparse.FloatTensor + The normalized sparse PyTorch tensor. + """ + dictionary = {tuple(item): index for index, item in enumerate(edges)} + edges = [list(itm) for itm in dictionary] + organised = [] + + for e in edges: + i, j = e[0], e[1] + w = weights[(i, j)] + organised.append(w) + + edges, weights = np.array(edges), np.array(organised) + adj = sp.coo_matrix( + (weights, (edges[:, 0], edges[:, 1])), shape=(n, n), dtype=np.float32 + ) + adj = adj + sp.eye(n) + + A = symnormalise(sp.csr_matrix(adj, dtype=np.float32)) + A = ssm2tst(A) + return A + + +def symnormalise(M): + """Symmetrically normalize a sparse matrix. + + Parameters + ---------- + M : scipy.sparse.csr_matrix + The input sparse matrix. + + Returns + ------- + scipy.sparse.csr_matrix + The symmetrically normalized sparse matrix. + """ + d = np.array(M.sum(1)) + + dhi = np.power(d, -1 / 2).flatten() + dhi[np.isinf(dhi)] = 0.0 + DHI = sp.diags(dhi) # D half inverse i.e. D^{-1/2} + + return (DHI.dot(M)).dot(DHI) + + +def ssm2tst(M): + """Convert a scipy sparse matrix to a torch sparse tensor. + + Parameters + ---------- + M : scipy.sparse.coo_matrix + The input scipy sparse matrix. + + Returns + ------- + torch.sparse.FloatTensor + The converted PyTorch sparse tensor. + """ + M = M.tocoo().astype(np.float32) + + indices = torch.from_numpy(np.vstack((M.row, M.col))).long() + values = torch.from_numpy(M.data) + shape = torch.Size(M.shape) + + return torch.sparse.FloatTensor(indices, values, shape) + + +def normalise(M): + """Row-normalize a sparse matrix. + + Parameters + ---------- + M : scipy.sparse.csr_matrix + The input sparse matrix. + + Returns + ------- + scipy.sparse.csr_matrix + The row-normalized sparse matrix. + """ + d = np.array(M.sum(1)) + + di = np.power(d, -1).flatten() + di[np.isinf(di)] = 0.0 + di = np.nan_to_num(di) + DI = sp.diags(di) # D inverse i.e. D^{-1} + + return DI.dot(M) diff --git a/tutorials/tutorial_custom_data_transformation.ipynb b/tutorials/tutorial_custom_data_transformation.ipynb index c1d046f68..3c089c1a2 100644 --- a/tutorials/tutorial_custom_data_transformation.ipynb +++ b/tutorials/tutorial_custom_data_transformation.ipynb @@ -105,9 +105,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PROJECT_ROOT set to: /home/luigi_13/TopoBench\n" + ] + } + ], "source": [ "import os\n", "from pathlib import Path\n", @@ -127,7 +135,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -179,26 +187,22 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "metadata": {}, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_2458422/3549809466.py:1: UserWarning: \n", - "The version_base parameter is not specified.\n", - "Please specify a compatability version level, or None.\n", - "Will assume defaults for version 1.1\n", - " initialize(config_path=\"../configs\", job_name=\"job\")\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Transform name: dict_keys(['graph2hypergraph_lifting'])\n", - "Transform parameters: {'_target_': 'topobench.transforms.data_transform.DataTransform', 'transform_type': 'lifting', 'transform_name': 'HypergraphKHopLifting', 'k_value': 1, 'feature_lifting': 'ProjectionSum', 'preserve_edge_attr': False, 'complex_dim': 1, 'neighborhoods': '${oc.select:model.backbone.neighborhoods,null}'}\n" + "ename": "ValueError", + "evalue": "GlobalHydra is already initialized, call GlobalHydra.instance().clear() if you want to re-initialize", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[11]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m initialize(config_path=\u001b[33m\"../configs\"\u001b[39m, job_name=\u001b[33m\"job\"\u001b[39m)\n\u001b[32m 2\u001b[39m cfg = compose(\n\u001b[32m 3\u001b[39m config_name=\u001b[33m\"run.yaml\"\u001b[39m,\n\u001b[32m 4\u001b[39m overrides=[\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/initialize.py:91\u001b[39m, in \u001b[36minitialize.__init__\u001b[39m\u001b[34m(self, config_path, job_name, caller_stack_depth, version_base)\u001b[39m\n\u001b[32m 86\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m job_name \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 87\u001b[39m job_name = detect_task_name(\n\u001b[32m 88\u001b[39m calling_file=calling_file, calling_module=calling_module\n\u001b[32m 89\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m91\u001b[39m \u001b[30;43mHydra\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mcreate_main_hydra_file_or_module\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 92\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcalling_file\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcalling_file\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 93\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcalling_module\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcalling_module\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 94\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mconfig_path\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mconfig_path\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 95\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mjob_name\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mjob_name\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 96\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/hydra.py:53\u001b[39m, in \u001b[36mHydra.create_main_hydra_file_or_module\u001b[39m\u001b[34m(cls, calling_file, calling_module, config_path, job_name)\u001b[39m\n\u001b[32m 41\u001b[39m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[32m 42\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mcreate_main_hydra_file_or_module\u001b[39m(\n\u001b[32m 43\u001b[39m \u001b[38;5;28mcls\u001b[39m: Type[\u001b[33m\"\u001b[39m\u001b[33mHydra\u001b[39m\u001b[33m\"\u001b[39m],\n\u001b[32m (...)\u001b[39m\u001b[32m 47\u001b[39m job_name: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m 48\u001b[39m ) -> \u001b[33m\"\u001b[39m\u001b[33mHydra\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 49\u001b[39m config_search_path = create_automatic_config_search_path(\n\u001b[32m 50\u001b[39m calling_file, calling_module, config_path\n\u001b[32m 51\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m53\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mHydra\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mcreate_main_hydra2\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mjob_name\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mconfig_search_path\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/hydra.py:68\u001b[39m, in \u001b[36mHydra.create_main_hydra2\u001b[39m\u001b[34m(cls, task_name, config_search_path)\u001b[39m\n\u001b[32m 65\u001b[39m hydra = \u001b[38;5;28mcls\u001b[39m(task_name=task_name, config_loader=config_loader)\n\u001b[32m 66\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mhydra\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mcore\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mglobal_hydra\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m GlobalHydra\n\u001b[32m---> \u001b[39m\u001b[32m68\u001b[39m \u001b[30;43mGlobalHydra\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43minstance\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43minitialize\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mhydra\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 69\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m hydra\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/core/global_hydra.py:16\u001b[39m, in \u001b[36mGlobalHydra.initialize\u001b[39m\u001b[34m(self, hydra)\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(hydra, Hydra), \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUnexpected Hydra type : \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(hydra)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 15\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.is_initialized():\n\u001b[32m---> \u001b[39m\u001b[32m16\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 17\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mGlobalHydra is already initialized, call GlobalHydra.instance().clear() if you want to re-initialize\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 18\u001b[39m )\n\u001b[32m 19\u001b[39m \u001b[38;5;28mself\u001b[39m.hydra = hydra\n", + "\u001b[31mValueError\u001b[39m: GlobalHydra is already initialized, call GlobalHydra.instance().clear() if you want to re-initialize" ] } ], @@ -248,7 +252,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -269,20 +273,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Data(edge_index=[2, 480], y=[1], num_nodes=218)" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "dataset[0]" ] @@ -296,18 +289,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Transform name: dict_keys(['equal_gaus_features', 'graph2hypergraph_lifting'])\n", - "Transform parameters: {'_target_': 'topobench.transforms.data_transform.DataTransform', 'transform_name': 'EqualGausFeatures', 'transform_type': 'data manipulation', 'mean': 0, 'std': 0.1, 'num_features': '${dataset.parameters.num_features}'}\n" - ] - } - ], + "outputs": [], "source": [ "print('Transform name:', cfg.transforms.keys())\n", "print('Transform parameters:', cfg.transforms['equal_gaus_features'])" @@ -315,18 +299,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Processing...\n", - "Done!\n" - ] - } - ], + "outputs": [], "source": [ "from topobench.data.preprocessor import PreProcessor\n", "preprocessed_dataset = PreProcessor(dataset, dataset_dir, cfg['transforms'])" @@ -334,20 +309,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Data(x=[218, 10], edge_index=[2, 480], y=[1], incidence_hyperedges=[218, 218], num_hyperedges=[1], x_0=[218, 10], x_hyperedges=[218, 10], num_nodes=218)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "preprocessed_dataset[0]" ] @@ -514,7 +478,7 @@ ], "metadata": { "kernelspec": { - "display_name": "tb", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -528,9 +492,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.15" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From c61ce6ce9c237e50c2b9bf903921f5bd27e2cbef Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Wed, 29 Jul 2026 09:18:56 +0200 Subject: [PATCH 02/21] Modified file function input --- 2026_tdl_challenge/run_evaluation.ipynb | 152 ++++++++++++++++-- .../hypergraph/hypergraph_convolution.py | 4 +- 2 files changed, 144 insertions(+), 12 deletions(-) diff --git a/2026_tdl_challenge/run_evaluation.ipynb b/2026_tdl_challenge/run_evaluation.ipynb index 8542dbaab..007c40691 100644 --- a/2026_tdl_challenge/run_evaluation.ipynb +++ b/2026_tdl_challenge/run_evaluation.ipynb @@ -62,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 6, "id": "53c1d2fb", "metadata": {}, "outputs": [], @@ -98,13 +98,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "id": "config_cell", "metadata": {}, "outputs": [], "source": [ "# Your model configuration (e.g., \"graph/gcn\", \"graph/gin\", \"graph/gat\")\n", - "MODEL_CONFIG = \"graph/gin\"" + "MODEL_CONFIG = \"hypergraph/hypergraph_convolution\"" ] }, { @@ -119,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 8, "id": "f52c90bd", "metadata": {}, "outputs": [], @@ -131,10 +131,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "df0a6def", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Computed hash: ec61c1d64175acca938ae591af1e959ee4b311f545692e89e8363db4b69185a5\n", + "Notebook content is verified.\n" + ] + } + ], "source": [ "# UNIQUE_HASH_MARKER\n", "import hashlib\n", @@ -208,10 +217,131 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "6a439451", - "metadata": {}, - "outputs": [], + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting sanity check for 24 configurations...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 42\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1/24] Checking community_detection | h_lo__d_lo__pl_lo ... " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Seed set to 42\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "--- captured stdout (tail) ---\n", + " Transform parameters are the same, using existing data_dir: /home/luigi_13/TopoBench/datasets/graph/GraphUniverse/K_20_edge_prop_var_0.5/homophily_0.0_to_0.1/n_graphs_1000_n_nodes_50_to_300/n_communities_5_to_10/task_community_detection/hash_259380a92b674bffabc62e01e71a7107a259fb428d78e91a41b45ac05c5592f2/graph2hypergraph_lifting/304036748\n", + "FAILED\n", + "\n", + "❌ CHECK FAILED: community_detection | h_lo__d_lo__pl_lo\n", + "Error: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\n", + "MisconfigurationException('No supported gpu backend found!')\n", + "full_key: trainer\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "--- captured stderr (tail) ---\n", + " [rank: 0] \n", + "Traceback (most recent call last):\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 92, in _call_target\n", + " return _target_(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/utilities/argparse.py\", line 70, in insert_env_defaults\n", + " return fn(self, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/trainer.py\", line 395, in __init__\n", + " self._accelerator_connector = _AcceleratorConnector(\n", + " ^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py\", line 143, in __init__\n", + " self._accelerator_flag = self._choose_gpu_accelerator_backend()\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py\", line 353, in _choose_gpu_accelerator_backend\n", + " raise MisconfigurationException(\"No supported gpu backend found!\")\n", + "lightning.fabric.utilities.exceptions.MisconfigurationException: No supported gpu backend found!\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/luigi_13/TopoBench/topobench/utils/utils.py\", line 95, in wrap\n", + " metric_dict, object_dict = task_func(cfg=cfg)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/topobench/run.py\", line 164, in run\n", + " trainer: Trainer = hydra.utils.instantiate(\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 226, in instantiate\n", + " return instantiate_node(\n", + " ^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 347, in instantiate_node\n", + " return _call_target(_target_, partial, args, kwargs, full_key)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 97, in _call_target\n", + " raise InstantiationException(msg) from e\n", + "hydra.errors.InstantiationException: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\n", + "MisconfigurationException('No supported gpu backend found!')\n", + "full_key: trainer\n", + "\n" + ] + }, + { + "ename": "InstantiationException", + "evalue": "Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\nMisconfigurationException('No supported gpu backend found!')\nfull_key: trainer", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMisconfigurationException\u001b[39m Traceback (most recent call last)", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:92\u001b[39m, in \u001b[36m_call_target\u001b[39m\u001b[34m(_target_, _partial_, args, kwargs, full_key)\u001b[39m\n\u001b[32m 91\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m92\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43m_target_\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 93\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/utilities/argparse.py:70\u001b[39m, in \u001b[36m_defaults_from_env_vars..insert_env_defaults\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 69\u001b[39m \u001b[38;5;66;03m# all args were already moved to kwargs\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m70\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mfn\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mself\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/trainer.py:395\u001b[39m, in \u001b[36mTrainer.__init__\u001b[39m\u001b[34m(self, accelerator, strategy, devices, num_nodes, precision, logger, callbacks, fast_dev_run, max_epochs, min_epochs, max_steps, min_steps, max_time, limit_train_batches, limit_val_batches, limit_test_batches, limit_predict_batches, overfit_batches, val_check_interval, check_val_every_n_epoch, num_sanity_val_steps, log_every_n_steps, enable_checkpointing, enable_progress_bar, enable_model_summary, accumulate_grad_batches, gradient_clip_val, gradient_clip_algorithm, deterministic, benchmark, inference_mode, use_distributed_sampler, profiler, detect_anomaly, barebones, plugins, sync_batchnorm, reload_dataloaders_every_n_epochs, default_root_dir)\u001b[39m\n\u001b[32m 393\u001b[39m \u001b[38;5;28mself\u001b[39m._data_connector = _DataConnector(\u001b[38;5;28mself\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m395\u001b[39m \u001b[38;5;28mself\u001b[39m._accelerator_connector = \u001b[30;43m_AcceleratorConnector\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 396\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdevices\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdevices\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 397\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43maccelerator\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43maccelerator\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 398\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mstrategy\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mstrategy\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 399\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mnum_nodes\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mnum_nodes\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 400\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43msync_batchnorm\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43msync_batchnorm\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 401\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mbenchmark\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mbenchmark\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 402\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43muse_distributed_sampler\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43muse_distributed_sampler\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 403\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdeterministic\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdeterministic\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 404\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mprecision\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mprecision\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 405\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mplugins\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mplugins\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 406\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 407\u001b[39m \u001b[38;5;28mself\u001b[39m._logger_connector = _LoggerConnector(\u001b[38;5;28mself\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:143\u001b[39m, in \u001b[36m_AcceleratorConnector.__init__\u001b[39m\u001b[34m(self, devices, num_nodes, accelerator, strategy, plugins, precision, sync_batchnorm, benchmark, use_distributed_sampler, deterministic)\u001b[39m\n\u001b[32m 142\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._accelerator_flag == \u001b[33m\"\u001b[39m\u001b[33mgpu\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m143\u001b[39m \u001b[38;5;28mself\u001b[39m._accelerator_flag = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_choose_gpu_accelerator_backend\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 145\u001b[39m \u001b[38;5;28mself\u001b[39m._check_device_config_and_set_final_flags(devices=devices, num_nodes=num_nodes)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:353\u001b[39m, in \u001b[36m_AcceleratorConnector._choose_gpu_accelerator_backend\u001b[39m\u001b[34m()\u001b[39m\n\u001b[32m 352\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mcuda\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m--> \u001b[39m\u001b[32m353\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MisconfigurationException(\u001b[33m\"\u001b[39m\u001b[33mNo supported gpu backend found!\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mMisconfigurationException\u001b[39m: No supported gpu backend found!", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[31mInstantiationException\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[10]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m check_challenge_grid(\n\u001b[32m 2\u001b[39m project_root=PROJECT_ROOT,\n\u001b[32m 3\u001b[39m model_config=MODEL_CONFIG,\n\u001b[32m 4\u001b[39m quiet=\u001b[38;5;28;01mFalse\u001b[39;00m,\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/2026_tdl_challenge/utils.py:705\u001b[39m, in \u001b[36mcheck_challenge_grid\u001b[39m\u001b[34m(project_root, model_config, extra_overrides, quiet)\u001b[39m\n\u001b[32m 703\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m❌ CHECK FAILED: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmode_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m | \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mrun_slug\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 704\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mError: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m705\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[32m 707\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m quiet:\n\u001b[32m 708\u001b[39m \u001b[38;5;28mprint\u001b[39m(\n\u001b[32m 709\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m✅ All \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtotal_checks\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m configurations passed the sanity check.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 710\u001b[39m )\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/2026_tdl_challenge/utils.py:697\u001b[39m, in \u001b[36mcheck_challenge_grid\u001b[39m\u001b[34m(project_root, model_config, extra_overrides, quiet)\u001b[39m\n\u001b[32m 695\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m _challenge_quiet(\u001b[38;5;28;01mTrue\u001b[39;00m):\n\u001b[32m 696\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m697\u001b[39m \u001b[30;43mrun\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 698\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m quiet:\n\u001b[32m 699\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mOK\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/utils/utils.py:105\u001b[39m, in \u001b[36mtask_wrapper..wrap\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 100\u001b[39m log.exception(\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 102\u001b[39m \u001b[38;5;66;03m# some hyperparameter combinations might be invalid or cause out-of-memory errors\u001b[39;00m\n\u001b[32m 103\u001b[39m \u001b[38;5;66;03m# so when using hparam search plugins like Optuna, you might want to disable\u001b[39;00m\n\u001b[32m 104\u001b[39m \u001b[38;5;66;03m# raising the below exception to avoid multirun failure\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m105\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m ex\n\u001b[32m 107\u001b[39m \u001b[38;5;66;03m# things to always do after either success or exception\u001b[39;00m\n\u001b[32m 108\u001b[39m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[32m 109\u001b[39m \u001b[38;5;66;03m# display output dir path in terminal\u001b[39;00m\n\u001b[32m 110\u001b[39m log.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mOutput dir: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcfg.paths.output_dir\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/utils/utils.py:95\u001b[39m, in \u001b[36mtask_wrapper..wrap\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 82\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Wrapper function that executes the task function.\u001b[39;00m\n\u001b[32m 83\u001b[39m \n\u001b[32m 84\u001b[39m \u001b[33;03mParameters\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 92\u001b[39m \u001b[33;03m The metric and object dictionaries returned by the task function.\u001b[39;00m\n\u001b[32m 93\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 94\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m95\u001b[39m metric_dict, object_dict = \u001b[30;43mtask_func\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 97\u001b[39m \u001b[38;5;66;03m# things to do if exception occurs\u001b[39;00m\n\u001b[32m 98\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m ex:\n\u001b[32m 99\u001b[39m \u001b[38;5;66;03m# save exception to `.log` file\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/run.py:164\u001b[39m, in \u001b[36mrun\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 157\u001b[39m log_temp.log_metrics(\n\u001b[32m 158\u001b[39m {\n\u001b[32m 159\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mpreprocessor_time\u001b[39m\u001b[33m\"\u001b[39m: preprocessor.preprocessing_time,\n\u001b[32m 160\u001b[39m }\n\u001b[32m 161\u001b[39m )\n\u001b[32m 163\u001b[39m log.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mInstantiating trainer <\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcfg.trainer._target_\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m>\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m164\u001b[39m trainer: Trainer = \u001b[30;43mhydra\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mutils\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43minstantiate\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 165\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mtrainer\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 166\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcallbacks\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcallbacks\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 167\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlogger\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mlogger\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 168\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mnum_sanity_val_steps\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m0\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 169\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlog_every_n_steps\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m1\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;03m# Log metrics every step (Lightning requires >=1)\u001b[39;49;00m\n\u001b[32m 170\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 172\u001b[39m object_dict = {\n\u001b[32m 173\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mcfg\u001b[39m\u001b[33m\"\u001b[39m: cfg,\n\u001b[32m 174\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mdatamodule\u001b[39m\u001b[33m\"\u001b[39m: datamodule,\n\u001b[32m (...)\u001b[39m\u001b[32m 178\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mtrainer\u001b[39m\u001b[33m\"\u001b[39m: trainer,\n\u001b[32m 179\u001b[39m }\n\u001b[32m 181\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m logger:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:226\u001b[39m, in \u001b[36minstantiate\u001b[39m\u001b[34m(config, *args, **kwargs)\u001b[39m\n\u001b[32m 223\u001b[39m _convert_ = config.pop(_Keys.CONVERT, ConvertMode.NONE)\n\u001b[32m 224\u001b[39m _partial_ = config.pop(_Keys.PARTIAL, \u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[32m--> \u001b[39m\u001b[32m226\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43minstantiate_node\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 227\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mconfig\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mrecursive\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_recursive_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mconvert\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_convert_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mpartial\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_partial_\u001b[39;49m\n\u001b[32m 228\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 229\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m OmegaConf.is_list(config):\n\u001b[32m 230\u001b[39m \u001b[38;5;66;03m# Finalize config (convert targets to strings, merge with kwargs)\u001b[39;00m\n\u001b[32m 231\u001b[39m config_copy = copy.deepcopy(config)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:347\u001b[39m, in \u001b[36minstantiate_node\u001b[39m\u001b[34m(node, convert, recursive, partial, *args)\u001b[39m\n\u001b[32m 342\u001b[39m value = instantiate_node(\n\u001b[32m 343\u001b[39m value, convert=convert, recursive=recursive\n\u001b[32m 344\u001b[39m )\n\u001b[32m 345\u001b[39m kwargs[key] = _convert_node(value, convert)\n\u001b[32m--> \u001b[39m\u001b[32m347\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43m_call_target\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m_target_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mpartial\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mfull_key\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 348\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 349\u001b[39m \u001b[38;5;66;03m# If ALL or PARTIAL non structured or OBJECT non structured,\u001b[39;00m\n\u001b[32m 350\u001b[39m \u001b[38;5;66;03m# instantiate in dict and resolve interpolations eagerly.\u001b[39;00m\n\u001b[32m 351\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m convert == ConvertMode.ALL \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[32m 352\u001b[39m convert \u001b[38;5;129;01min\u001b[39;00m (ConvertMode.PARTIAL, ConvertMode.OBJECT)\n\u001b[32m 353\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m node._metadata.object_type \u001b[38;5;129;01min\u001b[39;00m (\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;28mdict\u001b[39m)\n\u001b[32m 354\u001b[39m ):\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:97\u001b[39m, in \u001b[36m_call_target\u001b[39m\u001b[34m(_target_, _partial_, args, kwargs, full_key)\u001b[39m\n\u001b[32m 95\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m full_key:\n\u001b[32m 96\u001b[39m msg += \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33mfull_key: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfull_key\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m---> \u001b[39m\u001b[32m97\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m InstantiationException(msg) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01me\u001b[39;00m\n", + "\u001b[31mInstantiationException\u001b[39m: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\nMisconfigurationException('No supported gpu backend found!')\nfull_key: trainer" + ] + } + ], "source": [ "check_challenge_grid(\n", " project_root=PROJECT_ROOT,\n", @@ -295,7 +425,7 @@ ], "metadata": { "kernelspec": { - "display_name": "tb", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -309,7 +439,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.15" } }, "nbformat": 4, diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index 978edc570..b34e51728 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -77,9 +77,11 @@ class HyperGraphConvolution(Module): Whether to reapproximate the Laplacian, by default True. cuda : int or None, optional The CUDA device index, by default None. + **kwargs : dict, optional + Required for TopoBench to do evaluation. """ - def __init__(self, a, b, reapproximate=True, cuda=None): + def __init__(self, a, b, reapproximate=True, cuda=None, **kwargs): super().__init__() self.a, self.b = a, b self.reapproximate = reapproximate From e8f6409d83f52cc50225700cfa9568acfac73ef0 Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Thu, 30 Jul 2026 09:29:04 +0200 Subject: [PATCH 03/21] Implementation on GPU --- configs/model/hypergraph/hypergraph_convolution.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 88f92b258..90ea34bad 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -1,8 +1,8 @@ -# @package _global_ +_target_: topobench.models.base_model.BaseModel -model: +backbone: _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution - a: 64 - b: 64 - reapproximate: true - cuda: null + a: 16 + b: 8 + reapproximate: False + cuda: 0 From b89e11c0f962ae325338aa19d0272fcdadde6d9f Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Thu, 30 Jul 2026 09:56:14 +0200 Subject: [PATCH 04/21] Implementation on GPU --- configs/model/hypergraph/hypergraph_convolution.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 90ea34bad..0b4c4d742 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -6,3 +6,6 @@ backbone: b: 8 reapproximate: False cuda: 0 + +loss: + _target_: torch.nn.CrossEntropyLoss From 8159154f9f8d10d6dee5f352d2f72b9fe4244ef9 Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Thu, 30 Jul 2026 14:06:50 +0200 Subject: [PATCH 05/21] Fixing errors: the old version provided topobench.models, but we corrected it with topobench.model --- .../hypergraph/hypergraph_convolution.yaml | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 0b4c4d742..3eb6e6480 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -1,4 +1,17 @@ -_target_: topobench.models.base_model.BaseModel +_target_: topobench.model.TBModel + +model_name: hypergraph_convolution +model_domain: hypergraph + +feature_encoder: + _target_: topobench.nn.encoders.${model.feature_encoder.encoder_name} + encoder_name: AllCellFeatureEncoder + in_channels: ${infer_in_channels:${dataset},${oc.select:transforms,null}} + out_channels: 32 + proj_dropout: 0.0 + selected_dimensions: + - 0 + - 1 backbone: _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution @@ -6,6 +19,21 @@ backbone: b: 8 reapproximate: False cuda: 0 + loss: + _target_: torch.nn.CrossEntropyLoss + +backbone_wrapper: + _target_: topobench.nn.wrappers.HypergraphWrapper + _partial_: true + wrapper_name: HypergraphWrapper + out_channels: ${model.feature_encoder.out_channels} + num_cell_dimensions: ${infer_num_cell_dimensions:${oc.select:model.feature_encoder.selected_dimensions,null},${model.feature_encoder.in_channels}} -loss: - _target_: torch.nn.CrossEntropyLoss +readout: + _target_: topobench.nn.readouts.${model.readout.readout_name} + readout_name: PropagateSignalDown + num_cell_dimensions: ${infer_num_cell_dimensions:${oc.select:model.feature_encoder.selected_dimensions,null},${model.feature_encoder.in_channels}} + hidden_dim: ${model.feature_encoder.out_channels} + out_channels: ${dataset.parameters.num_classes} + task_level: ${define_task_level:${dataset.parameters.task_level},${dataset.split_params.learning_setting}} + pooling_type: sum From 02b6a2fe90aee8a9f6a3e78d58e4d276713c621d Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Thu, 30 Jul 2026 14:31:49 +0200 Subject: [PATCH 06/21] Fixing errors --- configs/model/hypergraph/hypergraph_convolution.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 3eb6e6480..fdd5239c8 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -37,3 +37,5 @@ readout: out_channels: ${dataset.parameters.num_classes} task_level: ${define_task_level:${dataset.parameters.task_level},${dataset.split_params.learning_setting}} pooling_type: sum + +compile: false From 3c378384b0131c341479d1fa49ee70f91b4a87b8 Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Fri, 31 Jul 2026 08:47:46 +0200 Subject: [PATCH 07/21] Fixed docstring indentation --- configs/model/hypergraph/hypergraph_convolution.yaml | 2 +- topobench/nn/backbones/hypergraph/hypergraph_convolution.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index fdd5239c8..1ae6f197f 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -15,7 +15,7 @@ feature_encoder: backbone: _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution - a: 16 + a: ${model.feature_encoder.out_channels} b: 8 reapproximate: False cuda: 0 diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index b34e51728..dc1fa179d 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -99,15 +99,15 @@ def reset_parameters(self): self.W.data.uniform_(-std, std) self.bias.data.uniform_(-std, std) - def forward(self, structure, H, m=True): + def forward(self, H, structure, m=True): """Compute the forward pass of the HyperGraph Convolution layer. Parameters ---------- - structure : torch.Tensor or dict - The structural matrix or hyperedge dictionary. H : torch.Tensor The hidden node features. + structure : torch.Tensor or dict + The structural matrix or hyperedge dictionary. m : bool, optional Whether to use mediators, by default True. From d378d9df0aec106b298189e59b9e6b82b18c22bd Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Fri, 31 Jul 2026 09:53:52 +0200 Subject: [PATCH 08/21] Fixed docstring indentation --- topobench/nn/backbones/hypergraph/hypergraph_convolution.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index dc1fa179d..690116a46 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -113,8 +113,8 @@ def forward(self, H, structure, m=True): Returns ------- - torch.Tensor - The updated node features. + tuple + A tuple containing the updated node features and None. """ W, b = self.W, self.bias HW = torch.mm(H, W) @@ -129,7 +129,7 @@ def forward(self, H, structure, m=True): A = Variable(A) AHW = SparseMM.apply(A, HW) - return AHW + b + return AHW + b, None def __repr__(self): """Return the string representation of the module. From 2bb9979d35be13cf24a0ff10a4a1bd5731538b60 Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Fri, 31 Jul 2026 10:13:10 +0200 Subject: [PATCH 09/21] Fix dimension mismatch in residual connection --- configs/model/hypergraph/hypergraph_convolution.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 1ae6f197f..7920bf468 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -16,7 +16,7 @@ feature_encoder: backbone: _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution a: ${model.feature_encoder.out_channels} - b: 8 + b: ${model.feature_encoder.out_channels} reapproximate: False cuda: 0 loss: From 60397408a7d0d662de81d401def27219ae1484f0 Mon Sep 17 00:00:00 2001 From: Luigi Petti Date: Fri, 31 Jul 2026 10:24:36 +0200 Subject: [PATCH 10/21] Return dummy zero tensor for x_1 to satisfy PropagateSignalDown readout --- .../nn/backbones/hypergraph/hypergraph_convolution.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index 690116a46..1488bb406 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -114,7 +114,7 @@ def forward(self, H, structure, m=True): Returns ------- tuple - A tuple containing the updated node features and None. + A tuple containing the updated node features and hyperedge features. """ W, b = self.W, self.bias HW = torch.mm(H, W) @@ -129,7 +129,10 @@ def forward(self, H, structure, m=True): A = Variable(A) AHW = SparseMM.apply(A, HW) - return AHW + b, None + x_1 = torch.zeros( + (structure.shape[1], self.W.shape[1]), device=H.device + ) + return AHW + b, x_1 def __repr__(self): """Return the string representation of the module. From bf37dce9f5f4a864b0cb5764a722a1b8425cb5cd Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Fri, 31 Jul 2026 18:13:10 +0900 Subject: [PATCH 11/21] Set num_cell_dimensions to 1 in hypergraph config --- configs/model/hypergraph/hypergraph_convolution.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 7920bf468..779cd5ffd 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -27,12 +27,11 @@ backbone_wrapper: _partial_: true wrapper_name: HypergraphWrapper out_channels: ${model.feature_encoder.out_channels} - num_cell_dimensions: ${infer_num_cell_dimensions:${oc.select:model.feature_encoder.selected_dimensions,null},${model.feature_encoder.in_channels}} - + num_cell_dimensions: 1 readout: _target_: topobench.nn.readouts.${model.readout.readout_name} readout_name: PropagateSignalDown - num_cell_dimensions: ${infer_num_cell_dimensions:${oc.select:model.feature_encoder.selected_dimensions,null},${model.feature_encoder.in_channels}} + num_cell_dimensions: 1 hidden_dim: ${model.feature_encoder.out_channels} out_channels: ${dataset.parameters.num_classes} task_level: ${define_task_level:${dataset.parameters.task_level},${dataset.split_params.learning_setting}} From 8fb06255aa131057780f51e3d16d8ce79f633b7d Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 11:42:46 +0900 Subject: [PATCH 12/21] Refactor hypergraph_convolution.yaml Updated hypergraph_convolution.yaml to clarify loss handling and added comments for readout configuration. --- configs/model/hypergraph/hypergraph_convolution.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 779cd5ffd..7664be064 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -17,10 +17,15 @@ backbone: _target_: topobench.nn.backbones.hypergraph.hypergraph_convolution.HyperGraphConvolution a: ${model.feature_encoder.out_channels} b: ${model.feature_encoder.out_channels} + # False -> propagate with the raw incidence matrix (works only because the khop + # lifting produces a square [N, N] incidence). + # True -> build the actual HyperGCN Laplacian from the hyperedges each forward. reapproximate: False cuda: 0 - loss: - _target_: torch.nn.CrossEntropyLoss + # NOTE: do NOT add a `loss:` key here. configs/loss/default.yaml pulls + # `model.backbone.loss` into TBLoss.modules_losses and calls it as + # loss(model_out: dict, batch), so only AbstractLoss subclasses belong here. + # The task loss (cross-entropy / MSE) comes from dataset.parameters.loss_type. backbone_wrapper: _target_: topobench.nn.wrappers.HypergraphWrapper @@ -28,9 +33,12 @@ backbone_wrapper: wrapper_name: HypergraphWrapper out_channels: ${model.feature_encoder.out_channels} num_cell_dimensions: 1 + readout: _target_: topobench.nn.readouts.${model.readout.readout_name} readout_name: PropagateSignalDown + # Must stay 1: PropagateSignalDown would otherwise look for model_out["x_1"] + # and batch["incidence_1"], neither of which exists for the hypergraph domain. num_cell_dimensions: 1 hidden_dim: ${model.feature_encoder.out_channels} out_channels: ${dataset.parameters.num_classes} From 1f33e6046a35cdf916136908162dafff4e322949 Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 11:44:58 +0900 Subject: [PATCH 13/21] Implement incidence_to_hyperedges function Added a function to convert incidence matrix to hyperedges, updating the HyperGraphConvolution class to utilize this function. --- .../hypergraph/hypergraph_convolution.py | 72 ++++++++++++++++--- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index 1488bb406..eb0f90968 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -3,7 +3,6 @@ import math import torch -from torch.autograd import Variable from torch.nn.modules.module import Module from torch.nn.parameter import Parameter @@ -64,6 +63,47 @@ def backward(ctx, g): return g1, g2 +def incidence_to_hyperedges(incidence, min_size=2): + """Convert a sparse node-hyperedge incidence matrix to a hyperedge dict. + + ``Laplacian`` expects hyperedges as a mapping from hyperedge id to the list + of node ids it contains, whereas ``HypergraphWrapper`` hands the backbone + the sparse ``[num_nodes, num_hyperedges]`` incidence matrix. + + Hyperedges with fewer than ``min_size`` nodes are dropped: for a singleton + the supremum and the infimum coincide and the normalisation constant + ``2 * len(e) - 3`` becomes negative, which would inject negative weights + into the adjacency and break the symmetric normalisation. Singletons do + occur here, since the k-hop lifting gives every isolated node a hyperedge + containing only itself. + + Parameters + ---------- + incidence : torch.Tensor + Sparse incidence matrix of shape ``[num_nodes, num_hyperedges]``. + min_size : int, optional + Minimum number of nodes for a hyperedge to be kept, by default 2. + + Returns + ------- + dict + Mapping from hyperedge index to the list of its node indices. + """ + indices = incidence.coalesce().indices().cpu() + nodes = indices[0].tolist() + edges = indices[1].tolist() + + hyperedges = {} + for node, edge in zip(nodes, edges, strict=True): + hyperedges.setdefault(edge, []).append(node) + + return { + edge: members + for edge, members in hyperedges.items() + if len(members) >= min_size + } + + class HyperGraphConvolution(Module): """Define a simple GCN layer. @@ -106,8 +146,9 @@ def forward(self, H, structure, m=True): ---------- H : torch.Tensor The hidden node features. - structure : torch.Tensor or dict - The structural matrix or hyperedge dictionary. + structure : torch.Tensor + The sparse node-hyperedge incidence matrix, of shape + ``[num_nodes, num_hyperedges]``. m : bool, optional Whether to use mediators, by default True. @@ -119,19 +160,32 @@ def forward(self, H, structure, m=True): W, b = self.W, self.bias HW = torch.mm(H, W) + n = H.shape[0] + num_hyperedges = structure.shape[1] + if self.reapproximate: - n, X = H.shape[0], HW.cpu().detach().numpy() - A = Laplacian(n, structure, X, m) + X = HW.cpu().detach().numpy() + hyperedges = incidence_to_hyperedges(structure) + + if len(hyperedges) > 0: + A = Laplacian(n, hyperedges, X, m) + else: + # Every hyperedge was a singleton: fall back to the identity, + # i.e. self-loops only, which is what the normalised Laplacian + # would reduce to anyway. + A = torch.sparse_coo_tensor( + torch.arange(n).repeat(2, 1), + torch.ones(n), + (n, n), + ) else: A = structure A = A.to(self.device) - A = Variable(A) AHW = SparseMM.apply(A, HW) - x_1 = torch.zeros( - (structure.shape[1], self.W.shape[1]), device=H.device - ) + + x_1 = torch.zeros((num_hyperedges, self.b), device=H.device) return AHW + b, x_1 def __repr__(self): From fc6bc5d25d45c8f26779e8d7798c7a89d952bc62 Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 12:02:46 +0900 Subject: [PATCH 14/21] Add unit tests for HyperGraphConvolution This file contains unit tests for the HyperGraphConvolution class, covering various functionalities including incidence matrix conversion, forward and backward passes, and parameter initialization. --- .../hypergraph/test_hypergraph_convolution.py | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 test/nn/backbones/hypergraph/test_hypergraph_convolution.py diff --git a/test/nn/backbones/hypergraph/test_hypergraph_convolution.py b/test/nn/backbones/hypergraph/test_hypergraph_convolution.py new file mode 100644 index 000000000..a24c5f17f --- /dev/null +++ b/test/nn/backbones/hypergraph/test_hypergraph_convolution.py @@ -0,0 +1,195 @@ +"""Unit tests for HyperGraphConvolution.""" + +import pytest +import torch +import torch_geometric + +from topobench.nn.backbones.hypergraph.hypergraph_convolution import ( + HyperGraphConvolution, + SparseMM, + incidence_to_hyperedges, +) +from topobench.nn.wrappers import HypergraphWrapper + + +def _square_incidence(num_nodes, seed=0): + """Build a square sparse incidence matrix with no empty hyperedge. + + Parameters + ---------- + num_nodes : int + Number of nodes, also used as the number of hyperedges. + seed : int, optional + Seed for reproducibility, by default 0. + + Returns + ------- + torch.Tensor + Sparse incidence matrix of shape ``[num_nodes, num_nodes]``. + """ + generator = torch.Generator().manual_seed(seed) + incidence = ( + torch.rand(num_nodes, num_nodes, generator=generator) > 0.4 + ).float() + # Guarantee every hyperedge has at least two members. + incidence[0, :] = 1.0 + incidence[1, :] = 1.0 + return incidence.to_sparse_coo() + + +def test_incidence_to_hyperedges(): + """Unit test for incidence_to_hyperedges.""" + incidence = torch.tensor( + [ + [1.0, 0.0, 1.0], + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [1.0, 0.0, 0.0], + ] + ).to_sparse_coo() + + # Hyperedges 1 and 2 are singletons and must be dropped. + hyperedges = incidence_to_hyperedges(incidence) + assert set(hyperedges) == {0} + assert sorted(hyperedges[0]) == [0, 1, 3] + + # Lowering min_size keeps them. + hyperedges = incidence_to_hyperedges(incidence, min_size=1) + assert set(hyperedges) == {0, 1, 2} + assert sorted(hyperedges[1]) == [2] + assert sorted(hyperedges[2]) == [0] + + # Every hyperedge is a singleton -> empty dict. + assert incidence_to_hyperedges(torch.eye(4).to_sparse_coo()) == {} + + +def test_forward_without_reapproximation(): + """Unit test for the forward pass reusing the incidence matrix.""" + num_nodes, in_channels, out_channels = 6, 5, 3 + x_0 = torch.randn(num_nodes, in_channels) + incidence = _square_incidence(num_nodes) + + model = HyperGraphConvolution( + in_channels, out_channels, reapproximate=False + ) + x_0_out, x_1_out = model(x_0, incidence) + + assert x_0_out.shape == (num_nodes, out_channels) + assert x_1_out.shape == (num_nodes, out_channels) + assert torch.isfinite(x_0_out).all() + + +@pytest.mark.parametrize("mediators", [True, False]) +def test_forward_with_reapproximation(mediators): + """Unit test for the forward pass rebuilding the Laplacian. + + Parameters + ---------- + mediators : bool + Whether the Laplacian approximation uses mediators. + """ + num_nodes, num_hyperedges, in_channels, out_channels = 8, 5, 4, 3 + x_0 = torch.randn(num_nodes, in_channels) + + incidence = torch.zeros(num_nodes, num_hyperedges) + for edge in range(num_hyperedges): + members = torch.arange(edge, min(edge + 3, num_nodes)) + incidence[members, edge] = 1.0 + incidence = incidence.to_sparse_coo() + + model = HyperGraphConvolution( + in_channels, out_channels, reapproximate=True + ) + x_0_out, x_1_out = model(x_0, incidence, m=mediators) + + assert x_0_out.shape == (num_nodes, out_channels) + assert x_1_out.shape == (num_hyperedges, out_channels) + assert torch.isfinite(x_0_out).all() + + +def test_forward_with_only_singleton_hyperedges(): + """Unit test for the identity fallback when no hyperedge survives.""" + num_nodes, in_channels, out_channels = 4, 3, 2 + x_0 = torch.randn(num_nodes, in_channels) + incidence = torch.eye(num_nodes).to_sparse_coo() + + model = HyperGraphConvolution( + in_channels, out_channels, reapproximate=True + ) + x_0_out, _ = model(x_0, incidence) + + expected = x_0 @ model.W + model.bias + assert torch.allclose(x_0_out, expected, atol=1e-5) + + +def test_backward(): + """Unit test that gradients reach the layer parameters.""" + num_nodes, in_channels, out_channels = 6, 5, 3 + x_0 = torch.randn(num_nodes, in_channels) + incidence = _square_incidence(num_nodes) + + model = HyperGraphConvolution( + in_channels, out_channels, reapproximate=False + ) + x_0_out, _ = model(x_0, incidence) + x_0_out.sum().backward() + + assert model.W.grad is not None + assert model.W.grad.shape == model.W.shape + assert model.bias.grad is not None + + +def test_sparse_mm(): + """Unit test for SparseMM covering both backward branches.""" + m1 = torch.randn(3, 4, requires_grad=True) + m2 = torch.randn(4, 2, requires_grad=True) + + out = SparseMM.apply(m1, m2) + assert torch.allclose(out, m1 @ m2, atol=1e-6) + + out.sum().backward() + assert m1.grad.shape == m1.shape + assert m2.grad.shape == m2.shape + + +def test_reset_parameters(): + """Unit test that parameters are reinitialised in range.""" + model = HyperGraphConvolution(4, 16) + model.reset_parameters() + + bound = 1.0 / (16**0.5) + assert model.W.abs().max().item() <= bound + assert model.bias.abs().max().item() <= bound + + +def test_repr(): + """Unit test for the string representation.""" + model = HyperGraphConvolution(4, 3) + assert repr(model) == "HyperGraphConvolution (4 -> 3)" + + +def test_hypergraph_wrapper(): + """Unit test for HyperGraphConvolution behind its wrapper.""" + num_nodes, channels = 6, 4 + x_0 = torch.randn(num_nodes, channels) + incidence = _square_incidence(num_nodes) + + batch = torch_geometric.data.Data( + x_0=x_0, + y=torch.randint(0, 2, (num_nodes,)), + incidence_hyperedges=incidence, + batch_0=torch.zeros(num_nodes, dtype=torch.long), + ) + + backbone = HyperGraphConvolution(channels, channels, reapproximate=False) + wrapper = HypergraphWrapper( + backbone, **{"out_channels": channels, "num_cell_dimensions": 1} + ) + + _ = wrapper.__repr__() + model_out = wrapper(batch) + + assert model_out["x_0"].shape == x_0.shape + assert model_out["hyperedge"].shape == (num_nodes, channels) + assert "labels" in model_out + assert "batch_0" in model_out From b46f9f422e6c2434b24e542660ba6f5c650c42de Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 12:04:14 +0900 Subject: [PATCH 15/21] Implement unit tests for hypergraph Laplacian Add unit tests for hypergraph Laplacian functions including Laplacian, update, adjacency, symnormalise, normalise, and ssm2tst. --- .../test_hypergraph_laplacian.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 test/transforms/liftings/graph2hypergraph/test_hypergraph_laplacian.py diff --git a/test/transforms/liftings/graph2hypergraph/test_hypergraph_laplacian.py b/test/transforms/liftings/graph2hypergraph/test_hypergraph_laplacian.py new file mode 100644 index 000000000..e517cde0d --- /dev/null +++ b/test/transforms/liftings/graph2hypergraph/test_hypergraph_laplacian.py @@ -0,0 +1,100 @@ +"""Unit tests for the hypergraph Laplacian approximation.""" + +import numpy as np +import pytest +import scipy.sparse as sp +import torch + +from topobench.transforms.liftings.graph2hypergraph.hypergraph_laplacian import ( + Laplacian, + adjacency, + normalise, + ssm2tst, + symnormalise, + update, +) + + +@pytest.mark.parametrize("mediators", [True, False]) +def test_laplacian(mediators): + """Unit test for Laplacian. + + Parameters + ---------- + mediators : bool + Whether the approximation uses mediators. + """ + num_nodes = 6 + hyperedges = {0: [0, 1, 2], 1: [2, 3], 2: [3, 4, 5]} + features = np.random.default_rng(0).normal(size=(num_nodes, 4)) + + A = Laplacian(num_nodes, hyperedges, features, mediators) + + assert A.shape == (num_nodes, num_nodes) + assert A.is_sparse + dense = A.to_dense() + assert torch.isfinite(dense).all() + # Self loops are added before normalisation, so the diagonal is non-zero. + assert (dense.diagonal() > 0).all() + + +def test_update(): + """Unit test for update.""" + weights = update(0, 1, 2, {}, c=3.0) + + assert set(weights) == {(0, 2), (1, 2), (2, 0), (2, 1)} + for value in weights.values(): + assert value == pytest.approx(1 / 3) + + # Calling again accumulates on the existing keys. + weights = update(0, 1, 2, weights, c=3.0) + for value in weights.values(): + assert value == pytest.approx(2 / 3) + + +def test_adjacency(): + """Unit test for adjacency.""" + edges = [[0, 1], [1, 0], [0, 1]] # duplicated pair is deduplicated + weights = {(0, 1): 0.5, (1, 0): 0.5} + + A = adjacency(edges, weights, n=3) + dense = A.to_dense() + + assert dense.shape == (3, 3) + assert torch.allclose(dense, dense.t(), atol=1e-6) + # Isolated node 2 only has its self loop, normalised to one. + assert dense[2, 2].item() == pytest.approx(1.0, abs=1e-6) + + +def test_symnormalise(): + """Unit test for symnormalise.""" + M = sp.csr_matrix(np.array([[2.0, 0.0], [0.0, 4.0]], dtype=np.float32)) + out = np.asarray(symnormalise(M).todense()) + + assert np.allclose(out, np.eye(2), atol=1e-6) + + # A zero row yields a zero scaling factor rather than an infinity. + M = sp.csr_matrix(np.array([[0.0, 0.0], [0.0, 4.0]], dtype=np.float32)) + out = np.asarray(symnormalise(M).todense()) + assert np.isfinite(out).all() + + +def test_normalise(): + """Unit test for normalise.""" + M = sp.csr_matrix(np.array([[1.0, 3.0], [0.0, 0.0]], dtype=np.float32)) + out = np.asarray(normalise(M).todense()) + + assert out[0].sum() == pytest.approx(1.0) + assert np.isfinite(out).all() + + +def test_ssm2tst(): + """Unit test for ssm2tst.""" + M = sp.coo_matrix(np.array([[1.0, 0.0], [0.0, 2.0]], dtype=np.float32)) + A = ssm2tst(M) + + assert A.is_sparse + assert A.shape == (2, 2) + assert torch.allclose( + A.to_dense(), torch.tensor([[1.0, 0.0], [0.0, 2.0]]), atol=1e-6 + ) From ab05af4f57c9e3d98d6eaa6c44bc8a5a405042c6 Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 14:38:06 +0900 Subject: [PATCH 16/21] Reload original notebook --- 2026_tdl_challenge/run_evaluation.ipynb | 152 ++---------------------- 1 file changed, 11 insertions(+), 141 deletions(-) diff --git a/2026_tdl_challenge/run_evaluation.ipynb b/2026_tdl_challenge/run_evaluation.ipynb index 007c40691..8542dbaab 100644 --- a/2026_tdl_challenge/run_evaluation.ipynb +++ b/2026_tdl_challenge/run_evaluation.ipynb @@ -62,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "id": "53c1d2fb", "metadata": {}, "outputs": [], @@ -98,13 +98,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "id": "config_cell", "metadata": {}, "outputs": [], "source": [ "# Your model configuration (e.g., \"graph/gcn\", \"graph/gin\", \"graph/gat\")\n", - "MODEL_CONFIG = \"hypergraph/hypergraph_convolution\"" + "MODEL_CONFIG = \"graph/gin\"" ] }, { @@ -119,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 51, "id": "f52c90bd", "metadata": {}, "outputs": [], @@ -131,19 +131,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "df0a6def", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Computed hash: ec61c1d64175acca938ae591af1e959ee4b311f545692e89e8363db4b69185a5\n", - "Notebook content is verified.\n" - ] - } - ], + "outputs": [], "source": [ "# UNIQUE_HASH_MARKER\n", "import hashlib\n", @@ -217,131 +208,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "6a439451", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting sanity check for 24 configurations...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Seed set to 42\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1/24] Checking community_detection | h_lo__d_lo__pl_lo ... " - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Seed set to 42\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "--- captured stdout (tail) ---\n", - " Transform parameters are the same, using existing data_dir: /home/luigi_13/TopoBench/datasets/graph/GraphUniverse/K_20_edge_prop_var_0.5/homophily_0.0_to_0.1/n_graphs_1000_n_nodes_50_to_300/n_communities_5_to_10/task_community_detection/hash_259380a92b674bffabc62e01e71a7107a259fb428d78e91a41b45ac05c5592f2/graph2hypergraph_lifting/304036748\n", - "FAILED\n", - "\n", - "❌ CHECK FAILED: community_detection | h_lo__d_lo__pl_lo\n", - "Error: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\n", - "MisconfigurationException('No supported gpu backend found!')\n", - "full_key: trainer\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n", - "--- captured stderr (tail) ---\n", - " [rank: 0] \n", - "Traceback (most recent call last):\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 92, in _call_target\n", - " return _target_(*args, **kwargs)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/utilities/argparse.py\", line 70, in insert_env_defaults\n", - " return fn(self, **kwargs)\n", - " ^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/trainer.py\", line 395, in __init__\n", - " self._accelerator_connector = _AcceleratorConnector(\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py\", line 143, in __init__\n", - " self._accelerator_flag = self._choose_gpu_accelerator_backend()\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py\", line 353, in _choose_gpu_accelerator_backend\n", - " raise MisconfigurationException(\"No supported gpu backend found!\")\n", - "lightning.fabric.utilities.exceptions.MisconfigurationException: No supported gpu backend found!\n", - "\n", - "The above exception was the direct cause of the following exception:\n", - "\n", - "Traceback (most recent call last):\n", - " File \"/home/luigi_13/TopoBench/topobench/utils/utils.py\", line 95, in wrap\n", - " metric_dict, object_dict = task_func(cfg=cfg)\n", - " ^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/topobench/run.py\", line 164, in run\n", - " trainer: Trainer = hydra.utils.instantiate(\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 226, in instantiate\n", - " return instantiate_node(\n", - " ^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 347, in instantiate_node\n", - " return _call_target(_target_, partial, args, kwargs, full_key)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"/home/luigi_13/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py\", line 97, in _call_target\n", - " raise InstantiationException(msg) from e\n", - "hydra.errors.InstantiationException: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\n", - "MisconfigurationException('No supported gpu backend found!')\n", - "full_key: trainer\n", - "\n" - ] - }, - { - "ename": "InstantiationException", - "evalue": "Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\nMisconfigurationException('No supported gpu backend found!')\nfull_key: trainer", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMisconfigurationException\u001b[39m Traceback (most recent call last)", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:92\u001b[39m, in \u001b[36m_call_target\u001b[39m\u001b[34m(_target_, _partial_, args, kwargs, full_key)\u001b[39m\n\u001b[32m 91\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m92\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43m_target_\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 93\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/utilities/argparse.py:70\u001b[39m, in \u001b[36m_defaults_from_env_vars..insert_env_defaults\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 69\u001b[39m \u001b[38;5;66;03m# all args were already moved to kwargs\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m70\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mfn\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mself\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/trainer.py:395\u001b[39m, in \u001b[36mTrainer.__init__\u001b[39m\u001b[34m(self, accelerator, strategy, devices, num_nodes, precision, logger, callbacks, fast_dev_run, max_epochs, min_epochs, max_steps, min_steps, max_time, limit_train_batches, limit_val_batches, limit_test_batches, limit_predict_batches, overfit_batches, val_check_interval, check_val_every_n_epoch, num_sanity_val_steps, log_every_n_steps, enable_checkpointing, enable_progress_bar, enable_model_summary, accumulate_grad_batches, gradient_clip_val, gradient_clip_algorithm, deterministic, benchmark, inference_mode, use_distributed_sampler, profiler, detect_anomaly, barebones, plugins, sync_batchnorm, reload_dataloaders_every_n_epochs, default_root_dir)\u001b[39m\n\u001b[32m 393\u001b[39m \u001b[38;5;28mself\u001b[39m._data_connector = _DataConnector(\u001b[38;5;28mself\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m395\u001b[39m \u001b[38;5;28mself\u001b[39m._accelerator_connector = \u001b[30;43m_AcceleratorConnector\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 396\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdevices\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdevices\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 397\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43maccelerator\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43maccelerator\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 398\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mstrategy\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mstrategy\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 399\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mnum_nodes\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mnum_nodes\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 400\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43msync_batchnorm\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43msync_batchnorm\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 401\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mbenchmark\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mbenchmark\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 402\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43muse_distributed_sampler\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43muse_distributed_sampler\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 403\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mdeterministic\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdeterministic\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 404\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mprecision\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mprecision\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 405\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mplugins\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mplugins\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 406\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 407\u001b[39m \u001b[38;5;28mself\u001b[39m._logger_connector = _LoggerConnector(\u001b[38;5;28mself\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:143\u001b[39m, in \u001b[36m_AcceleratorConnector.__init__\u001b[39m\u001b[34m(self, devices, num_nodes, accelerator, strategy, plugins, precision, sync_batchnorm, benchmark, use_distributed_sampler, deterministic)\u001b[39m\n\u001b[32m 142\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._accelerator_flag == \u001b[33m\"\u001b[39m\u001b[33mgpu\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m143\u001b[39m \u001b[38;5;28mself\u001b[39m._accelerator_flag = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_choose_gpu_accelerator_backend\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 145\u001b[39m \u001b[38;5;28mself\u001b[39m._check_device_config_and_set_final_flags(devices=devices, num_nodes=num_nodes)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:353\u001b[39m, in \u001b[36m_AcceleratorConnector._choose_gpu_accelerator_backend\u001b[39m\u001b[34m()\u001b[39m\n\u001b[32m 352\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mcuda\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m--> \u001b[39m\u001b[32m353\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MisconfigurationException(\u001b[33m\"\u001b[39m\u001b[33mNo supported gpu backend found!\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mMisconfigurationException\u001b[39m: No supported gpu backend found!", - "\nThe above exception was the direct cause of the following exception:\n", - "\u001b[31mInstantiationException\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[10]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m check_challenge_grid(\n\u001b[32m 2\u001b[39m project_root=PROJECT_ROOT,\n\u001b[32m 3\u001b[39m model_config=MODEL_CONFIG,\n\u001b[32m 4\u001b[39m quiet=\u001b[38;5;28;01mFalse\u001b[39;00m,\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/2026_tdl_challenge/utils.py:705\u001b[39m, in \u001b[36mcheck_challenge_grid\u001b[39m\u001b[34m(project_root, model_config, extra_overrides, quiet)\u001b[39m\n\u001b[32m 703\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m❌ CHECK FAILED: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmode_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m | \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mrun_slug\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 704\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mError: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m705\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[32m 707\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m quiet:\n\u001b[32m 708\u001b[39m \u001b[38;5;28mprint\u001b[39m(\n\u001b[32m 709\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m✅ All \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtotal_checks\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m configurations passed the sanity check.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 710\u001b[39m )\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/2026_tdl_challenge/utils.py:697\u001b[39m, in \u001b[36mcheck_challenge_grid\u001b[39m\u001b[34m(project_root, model_config, extra_overrides, quiet)\u001b[39m\n\u001b[32m 695\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m _challenge_quiet(\u001b[38;5;28;01mTrue\u001b[39;00m):\n\u001b[32m 696\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m697\u001b[39m \u001b[30;43mrun\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 698\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m quiet:\n\u001b[32m 699\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mOK\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/utils/utils.py:105\u001b[39m, in \u001b[36mtask_wrapper..wrap\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 100\u001b[39m log.exception(\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 102\u001b[39m \u001b[38;5;66;03m# some hyperparameter combinations might be invalid or cause out-of-memory errors\u001b[39;00m\n\u001b[32m 103\u001b[39m \u001b[38;5;66;03m# so when using hparam search plugins like Optuna, you might want to disable\u001b[39;00m\n\u001b[32m 104\u001b[39m \u001b[38;5;66;03m# raising the below exception to avoid multirun failure\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m105\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m ex\n\u001b[32m 107\u001b[39m \u001b[38;5;66;03m# things to always do after either success or exception\u001b[39;00m\n\u001b[32m 108\u001b[39m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[32m 109\u001b[39m \u001b[38;5;66;03m# display output dir path in terminal\u001b[39;00m\n\u001b[32m 110\u001b[39m log.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mOutput dir: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcfg.paths.output_dir\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/utils/utils.py:95\u001b[39m, in \u001b[36mtask_wrapper..wrap\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 82\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Wrapper function that executes the task function.\u001b[39;00m\n\u001b[32m 83\u001b[39m \n\u001b[32m 84\u001b[39m \u001b[33;03mParameters\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 92\u001b[39m \u001b[33;03m The metric and object dictionaries returned by the task function.\u001b[39;00m\n\u001b[32m 93\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 94\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m95\u001b[39m metric_dict, object_dict = \u001b[30;43mtask_func\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 97\u001b[39m \u001b[38;5;66;03m# things to do if exception occurs\u001b[39;00m\n\u001b[32m 98\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m ex:\n\u001b[32m 99\u001b[39m \u001b[38;5;66;03m# save exception to `.log` file\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/topobench/run.py:164\u001b[39m, in \u001b[36mrun\u001b[39m\u001b[34m(cfg)\u001b[39m\n\u001b[32m 157\u001b[39m log_temp.log_metrics(\n\u001b[32m 158\u001b[39m {\n\u001b[32m 159\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mpreprocessor_time\u001b[39m\u001b[33m\"\u001b[39m: preprocessor.preprocessing_time,\n\u001b[32m 160\u001b[39m }\n\u001b[32m 161\u001b[39m )\n\u001b[32m 163\u001b[39m log.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mInstantiating trainer <\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcfg.trainer._target_\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m>\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m164\u001b[39m trainer: Trainer = \u001b[30;43mhydra\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mutils\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43minstantiate\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 165\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcfg\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mtrainer\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 166\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mcallbacks\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcallbacks\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 167\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlogger\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mlogger\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 168\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mnum_sanity_val_steps\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m0\u001b[39;49m\u001b[30;43m,\u001b[39;49m\n\u001b[32m 169\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mlog_every_n_steps\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m1\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43;03m# Log metrics every step (Lightning requires >=1)\u001b[39;49;00m\n\u001b[32m 170\u001b[39m \u001b[30;43m\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 172\u001b[39m object_dict = {\n\u001b[32m 173\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mcfg\u001b[39m\u001b[33m\"\u001b[39m: cfg,\n\u001b[32m 174\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mdatamodule\u001b[39m\u001b[33m\"\u001b[39m: datamodule,\n\u001b[32m (...)\u001b[39m\u001b[32m 178\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mtrainer\u001b[39m\u001b[33m\"\u001b[39m: trainer,\n\u001b[32m 179\u001b[39m }\n\u001b[32m 181\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m logger:\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:226\u001b[39m, in \u001b[36minstantiate\u001b[39m\u001b[34m(config, *args, **kwargs)\u001b[39m\n\u001b[32m 223\u001b[39m _convert_ = config.pop(_Keys.CONVERT, ConvertMode.NONE)\n\u001b[32m 224\u001b[39m _partial_ = config.pop(_Keys.PARTIAL, \u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[32m--> \u001b[39m\u001b[32m226\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43minstantiate_node\u001b[39;49m\u001b[30;43m(\u001b[39;49m\n\u001b[32m 227\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43mconfig\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43m*\u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mrecursive\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_recursive_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mconvert\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_convert_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mpartial\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43m_partial_\u001b[39;49m\n\u001b[32m 228\u001b[39m \u001b[30;43m \u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 229\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m OmegaConf.is_list(config):\n\u001b[32m 230\u001b[39m \u001b[38;5;66;03m# Finalize config (convert targets to strings, merge with kwargs)\u001b[39;00m\n\u001b[32m 231\u001b[39m config_copy = copy.deepcopy(config)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:347\u001b[39m, in \u001b[36minstantiate_node\u001b[39m\u001b[34m(node, convert, recursive, partial, *args)\u001b[39m\n\u001b[32m 342\u001b[39m value = instantiate_node(\n\u001b[32m 343\u001b[39m value, convert=convert, recursive=recursive\n\u001b[32m 344\u001b[39m )\n\u001b[32m 345\u001b[39m kwargs[key] = _convert_node(value, convert)\n\u001b[32m--> \u001b[39m\u001b[32m347\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43m_call_target\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m_target_\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mpartial\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43margs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mkwargs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mfull_key\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 348\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 349\u001b[39m \u001b[38;5;66;03m# If ALL or PARTIAL non structured or OBJECT non structured,\u001b[39;00m\n\u001b[32m 350\u001b[39m \u001b[38;5;66;03m# instantiate in dict and resolve interpolations eagerly.\u001b[39;00m\n\u001b[32m 351\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m convert == ConvertMode.ALL \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[32m 352\u001b[39m convert \u001b[38;5;129;01min\u001b[39;00m (ConvertMode.PARTIAL, ConvertMode.OBJECT)\n\u001b[32m 353\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m node._metadata.object_type \u001b[38;5;129;01min\u001b[39;00m (\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;28mdict\u001b[39m)\n\u001b[32m 354\u001b[39m ):\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/TopoBench/.venv/lib/python3.11/site-packages/hydra/_internal/instantiate/_instantiate2.py:97\u001b[39m, in \u001b[36m_call_target\u001b[39m\u001b[34m(_target_, _partial_, args, kwargs, full_key)\u001b[39m\n\u001b[32m 95\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m full_key:\n\u001b[32m 96\u001b[39m msg += \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33mfull_key: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfull_key\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m---> \u001b[39m\u001b[32m97\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m InstantiationException(msg) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01me\u001b[39;00m\n", - "\u001b[31mInstantiationException\u001b[39m: Error in call to target 'lightning.pytorch.trainer.trainer.Trainer':\nMisconfigurationException('No supported gpu backend found!')\nfull_key: trainer" - ] - } - ], + "metadata": {}, + "outputs": [], "source": [ "check_challenge_grid(\n", " project_root=PROJECT_ROOT,\n", @@ -425,7 +295,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "tb", "language": "python", "name": "python3" }, @@ -439,7 +309,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.15" + "version": "3.11.3" } }, "nbformat": 4, From a9ebb0c7d93b42d09fe4fd65105838e805482c9f Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 14:51:02 +0900 Subject: [PATCH 17/21] Change reapproximate setting to True --- configs/model/hypergraph/hypergraph_convolution.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/configs/model/hypergraph/hypergraph_convolution.yaml b/configs/model/hypergraph/hypergraph_convolution.yaml index 7664be064..a62e9366c 100644 --- a/configs/model/hypergraph/hypergraph_convolution.yaml +++ b/configs/model/hypergraph/hypergraph_convolution.yaml @@ -20,12 +20,8 @@ backbone: # False -> propagate with the raw incidence matrix (works only because the khop # lifting produces a square [N, N] incidence). # True -> build the actual HyperGCN Laplacian from the hyperedges each forward. - reapproximate: False + reapproximate: True cuda: 0 - # NOTE: do NOT add a `loss:` key here. configs/loss/default.yaml pulls - # `model.backbone.loss` into TBLoss.modules_losses and calls it as - # loss(model_out: dict, batch), so only AbstractLoss subclasses belong here. - # The task loss (cross-entropy / MSE) comes from dataset.parameters.loss_type. backbone_wrapper: _target_: topobench.nn.wrappers.HypergraphWrapper From 84d1e81c43afea4aca62fbac14cdbe3fb0c0e41c Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 16:37:51 +0900 Subject: [PATCH 18/21] Change device assignment for adjacency matrix A --- topobench/nn/backbones/hypergraph/hypergraph_convolution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index eb0f90968..7e18d629a 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -181,7 +181,7 @@ def forward(self, H, structure, m=True): else: A = structure - A = A.to(self.device) + A = A.to(H.device) # was: A.to(self.device) AHW = SparseMM.apply(A, HW) From 70c9a9813ee9e7f05bfb4b5786e95c7451b4d84d Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 16:42:20 +0900 Subject: [PATCH 19/21] Add hypergraph model to the test pipeline --- test/pipeline/test_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pipeline/test_pipeline.py b/test/pipeline/test_pipeline.py index a61165ae9..f0cbc7992 100644 --- a/test/pipeline/test_pipeline.py +++ b/test/pipeline/test_pipeline.py @@ -7,7 +7,7 @@ DATASET = "graph/MUTAG" # ADD YOUR DATASET HERE -MODELS = ["graph/gcn", "cell/topotune", "simplicial/topotune"] # ADD ONE OR SEVERAL MODELS +MODELS = ["graph/gcn", "cell/topotune", "simplicial/topotune","hypergraph/hypergraph_convolution"] # ADD ONE OR SEVERAL MODELS class TestPipeline: From 53b7775ad120cb79a1b19211ff1385b6a8e6c8a6 Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 16:50:08 +0900 Subject: [PATCH 20/21] Added results.json --- .../outputs/hhgconv_reapprox/results.json | 1240 +++++++++++++++++ 1 file changed, 1240 insertions(+) create mode 100644 2026_tdl_challenge/outputs/hhgconv_reapprox/results.json diff --git a/2026_tdl_challenge/outputs/hhgconv_reapprox/results.json b/2026_tdl_challenge/outputs/hhgconv_reapprox/results.json new file mode 100644 index 000000000..6092896b4 --- /dev/null +++ b/2026_tdl_challenge/outputs/hhgconv_reapprox/results.json @@ -0,0 +1,1240 @@ +{ + "metadata": { + "study_id": "hgconv_reapprox", + "model_config": "hypergraph/hypergraph_convolution", + "generated_at_utc": "2026-08-01T07:44:05.290422+00:00", + "n_runs": 72, + "train_seeds": [ + 42, + 43, + 44 + ], + "heatmap_note": "Cells show mean \u00b1 std over train_seeds (in-distribution test)." + }, + "results": [ + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 2.2220866680145264, + "test_best_rerun_accuracy": 0.3098403215408325, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 2.2163760662078857, + "test_best_rerun_accuracy": 0.30945831537246704, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 2.200658082962036, + "test_best_rerun_accuracy": 0.3153793215751648, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 106.1955337524414, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 101.48812866210938, + "test_triangles_total_structural": 1388.0, + "test_mse_by_total_triangles": 0.07311824831564076, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 100.56791687011719, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 95.9585189819336, + "test_triangles_total_structural": 1388.0, + "test_mse_by_total_triangles": 0.06913437966998097, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_lo__d_lo__pl_lo", + "test_loss": 88.70556640625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 89.3862533569336, + "test_triangles_total_structural": 1388.0, + "test_mse_by_total_triangles": 0.0643993179804997, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 2.2212162017822266, + "test_best_rerun_accuracy": 0.30877071619033813, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 2.2196223735809326, + "test_best_rerun_accuracy": 0.3080449104309082, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 2.219992160797119, + "test_best_rerun_accuracy": 0.3065169155597687, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_lo__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 3.6658568382263184, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 3.5184240341186523, + "test_triangles_total_structural": 190.0, + "test_mse_by_total_triangles": 0.018518021232203433, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 2.854748487472534, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 2.76094388961792, + "test_triangles_total_structural": 190.0, + "test_mse_by_total_triangles": 0.014531283629568, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_lo__d_lo__pl_hi", + "test_loss": 4.03803014755249, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 3.9579100608825684, + "test_triangles_total_structural": 190.0, + "test_mse_by_total_triangles": 0.020831105583592465, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_lo__pl_hi__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 2.1975533962249756, + "test_best_rerun_accuracy": 0.31476813554763794, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 2.1847939491271973, + "test_best_rerun_accuracy": 0.3177095353603363, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 2.1810123920440674, + "test_best_rerun_accuracy": 0.32091832160949707, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 4095.79248046875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 3908.0888671875, + "test_triangles_total_structural": 13185.0, + "test_mse_by_total_triangles": 0.2964041613339022, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 3932.098388671875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 3766.6103515625, + "test_triangles_total_structural": 13185.0, + "test_mse_by_total_triangles": 0.285673898487865, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_lo__d_hi__pl_lo", + "test_loss": 3875.919189453125, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 3809.2724609375, + "test_triangles_total_structural": 13185.0, + "test_mse_by_total_triangles": 0.2889095533513462, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 2.179140090942383, + "test_best_rerun_accuracy": 0.32034534215927124, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 2.196190357208252, + "test_best_rerun_accuracy": 0.3170219361782074, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 2.2067387104034424, + "test_best_rerun_accuracy": 0.31316372752189636, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_lo__d_hi__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 139.57333374023438, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 136.06581115722656, + "test_triangles_total_structural": 2967.0, + "test_mse_by_total_triangles": 0.04585972738699918, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 139.59112548828125, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 136.24752807617188, + "test_triangles_total_structural": 2967.0, + "test_mse_by_total_triangles": 0.045920973399451254, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0-0.1__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_lo", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_lo__d_hi__pl_hi", + "test_loss": 149.37551879882812, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 145.01759338378906, + "test_triangles_total_structural": 2967.0, + "test_mse_by_total_triangles": 0.048876843068348184, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_lo__d_hi__pl_hi__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 2.0954947471618652, + "test_best_rerun_accuracy": 0.3527389466762543, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 2.1056065559387207, + "test_best_rerun_accuracy": 0.3488425314426422, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 2.0978341102600098, + "test_best_rerun_accuracy": 0.35132554173469543, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 5498.6416015625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 5670.37646484375, + "test_triangles_total_structural": 7485.0, + "test_mse_by_total_triangles": 0.7575653259644288, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 5286.0498046875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 5465.728515625, + "test_triangles_total_structural": 7485.0, + "test_mse_by_total_triangles": 0.7302242505845024, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_mid__d_lo__pl_lo", + "test_loss": 5340.4443359375, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 5501.697265625, + "test_triangles_total_structural": 7485.0, + "test_mse_by_total_triangles": 0.7350296948062792, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 2.1086275577545166, + "test_best_rerun_accuracy": 0.3459393382072449, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 2.0953803062438965, + "test_best_rerun_accuracy": 0.34819313883781433, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 2.0850584506988525, + "test_best_rerun_accuracy": 0.35189855098724365, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_lo__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 143.88186645507812, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 151.5059051513672, + "test_triangles_total_structural": 1158.0, + "test_mse_by_total_triangles": 0.13083411498390948, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 139.2274932861328, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 146.42425537109375, + "test_triangles_total_structural": 1158.0, + "test_mse_by_total_triangles": 0.12644581638263708, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_mid__d_lo__pl_hi", + "test_loss": 152.0172576904297, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 159.37301635742188, + "test_triangles_total_structural": 1158.0, + "test_mse_by_total_triangles": 0.13762782068861992, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_lo__pl_hi__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 2.0919461250305176, + "test_best_rerun_accuracy": 0.35568034648895264, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 2.0909392833709717, + "test_best_rerun_accuracy": 0.35667353868484497, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 2.085005760192871, + "test_best_rerun_accuracy": 0.3577813506126404, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 113720.0625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 79835.0546875, + "test_triangles_total_structural": 43064.0, + "test_mse_by_total_triangles": 1.8538699305104032, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 113403.7890625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 79469.734375, + "test_triangles_total_structural": 43064.0, + "test_mse_by_total_triangles": 1.8453867354402749, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_mid__d_hi__pl_lo", + "test_loss": 113634.828125, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 79593.4140625, + "test_triangles_total_structural": 43064.0, + "test_mse_by_total_triangles": 1.848258732642114, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 2.042598009109497, + "test_best_rerun_accuracy": 0.36794254183769226, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 2.038547992706299, + "test_best_rerun_accuracy": 0.36969974637031555, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 2.086423635482788, + "test_best_rerun_accuracy": 0.3598441481590271, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_mid__d_hi__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 8585.7998046875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 8198.3779296875, + "test_triangles_total_structural": 14262.0, + "test_mse_by_total_triangles": 0.5748406906245618, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 8462.1533203125, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 8088.7001953125, + "test_triangles_total_structural": 14262.0, + "test_mse_by_total_triangles": 0.5671504834744425, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.4-0.6__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_mid", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_mid__d_hi__pl_hi", + "test_loss": 8372.935546875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 8005.818359375, + "test_triangles_total_structural": 14262.0, + "test_mse_by_total_triangles": 0.5613391080756556, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_mid__d_hi__pl_hi__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 1.8361661434173584, + "test_best_rerun_accuracy": 0.4446863830089569, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 1.8382230997085571, + "test_best_rerun_accuracy": 0.44556498527526855, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 1.858949899673462, + "test_best_rerun_accuracy": 0.440178781747818, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 27931.322265625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 28362.59375, + "test_triangles_total_structural": 19509.0, + "test_mse_by_total_triangles": 1.4538209928750834, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 27384.875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 27843.017578125, + "test_triangles_total_structural": 19509.0, + "test_mse_by_total_triangles": 1.4271883529717053, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_lo", + "run_slug": "h_hi__d_lo__pl_lo", + "test_loss": 27376.353515625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 27824.271484375, + "test_triangles_total_structural": 19509.0, + "test_mse_by_total_triangles": 1.4262274583205188, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 1.7885019779205322, + "test_best_rerun_accuracy": 0.4680647850036621, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 1.778948187828064, + "test_best_rerun_accuracy": 0.4677973985671997, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 1.7869094610214233, + "test_best_rerun_accuracy": 0.4663075804710388, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_lo__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 2653.28662109375, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 2811.577392578125, + "test_triangles_total_structural": 5625.0, + "test_mse_by_total_triangles": 0.49983598090277775, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 2617.212158203125, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 2767.001220703125, + "test_triangles_total_structural": 5625.0, + "test_mse_by_total_triangles": 0.491911328125, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_1-2.5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_lo", + "power_law": "pl_hi", + "run_slug": "h_hi__d_lo__pl_hi", + "test_loss": 2639.13623046875, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 2796.378662109375, + "test_triangles_total_structural": 5625.0, + "test_mse_by_total_triangles": 0.497133984375, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_lo__pl_hi__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 1.7479785680770874, + "test_best_rerun_accuracy": 0.48674458265304565, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_lo__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 1.752018928527832, + "test_best_rerun_accuracy": 0.484796404838562, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_lo__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 1.742499589920044, + "test_best_rerun_accuracy": 0.4888837933540344, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_lo__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 507176.0, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 326783.03125, + "test_triangles_total_structural": 88403.0, + "test_mse_by_total_triangles": 3.696515177652342, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_lo__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 505133.65625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 325649.96875, + "test_triangles_total_structural": 88403.0, + "test_mse_by_total_triangles": 3.683698163523862, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_lo__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_1.5-2__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_lo", + "run_slug": "h_hi__d_hi__pl_lo", + "test_loss": 508413.5, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 326733.25, + "test_triangles_total_structural": 88403.0, + "test_mse_by_total_triangles": 3.6959520604504372, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_lo__s44" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 1.6107715368270874, + "test_best_rerun_accuracy": 0.5439299941062927, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_hi__s42" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 1.634343147277832, + "test_best_rerun_accuracy": 0.5387347936630249, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_hi__s43" + }, + { + "experiment": "community_detection", + "wandb_project": "hgconv-cd", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 1.5953055620193481, + "test_best_rerun_accuracy": 0.5458782315254211, + "test_best_rerun_mse": null, + "test_triangles_total_structural": null, + "test_mse_by_total_triangles": null, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__community_detection__00__h_hi__d_hi__pl_hi__s44" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s42", + "train_seed": 42, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 115034.7265625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 110156.2109375, + "test_triangles_total_structural": 60093.0, + "test_mse_by_total_triangles": 1.8330955508545088, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_hi__s42" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s43", + "train_seed": 43, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 113723.4765625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 109443.5703125, + "test_triangles_total_structural": 60093.0, + "test_mse_by_total_triangles": 1.8212365884961643, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_hi__s43" + }, + { + "experiment": "triangle_counting", + "wandb_project": "hgconv-tri", + "wandb_run_name": "hypergraph_convolution_hom_0.9-1__deg_4-5__gamma_4-5__s44", + "train_seed": 44, + "homophily": "h_hi", + "avg_degree": "d_hi", + "power_law": "pl_hi", + "run_slug": "h_hi__d_hi__pl_hi", + "test_loss": 110779.6640625, + "test_best_rerun_accuracy": null, + "test_best_rerun_mse": 106560.75, + "test_triangles_total_structural": 60093.0, + "test_mse_by_total_triangles": 1.773263940891618, + "ood_test": {}, + "output_dir": "/mnt/gs21/scratch/f0101291/math/shuffle/topo/topobench_challenge/logs/train/runs/notebook_gu_grid_hgconv_reapprox__triangle_counting__00__h_hi__d_hi__pl_hi__s44" + } + ] +} From e09335d51f8b5b0f681384b412f17bb63fab09b3 Mon Sep 17 00:00:00 2001 From: Eric Rubiel Date: Sat, 1 Aug 2026 17:07:30 +0900 Subject: [PATCH 21/21] Test1 --- topobench/nn/backbones/hypergraph/hypergraph_convolution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py index 7e18d629a..9fe144db9 100644 --- a/topobench/nn/backbones/hypergraph/hypergraph_convolution.py +++ b/topobench/nn/backbones/hypergraph/hypergraph_convolution.py @@ -181,7 +181,7 @@ def forward(self, H, structure, m=True): else: A = structure - A = A.to(H.device) # was: A.to(self.device) + A = A.to(H.device) AHW = SparseMM.apply(A, HW)