{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Online edge inference via auxiliary regression (Tier 0+)\n", "\n", "This notebook demonstrates **online** function → function edge inference during GSNN training using `MagnitudeEdgeRegressor`.\n", "\n", "Instead of a post-hoc correlation pass (`MagnitudeEdgeInferer`), we fit a shared **(N, N)** weight matrix `W` as an auxiliary linear regression: activation magnitudes at layer *n−1* predict gradient magnitudes at layer *n*. Held-out edges are split into validation (early-stopping) and test sets.\n", "\n", "Same converging-tier DAG setup as notebook 13, scaled to **12 inputs → 24 function nodes → 12 outputs** with **16 held-out** function-function edges." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import networkx as nx\n", "import torch\n", "\n", "from gsnn.models.GSNN import GSNN\n", "from gsnn.simulate.nx2pyg import nx2pyg\n", "from gsnn.simulate.simulate import simulate\n", "from gsnn.optim.MagnitudeEdgeInferer import MagnitudeEdgeInferer\n", "from gsnn.optim.MagnitudeEdgeRegressor import MagnitudeEdgeRegressor\n", "\n", "from sklearn.metrics import r2_score, roc_auc_score, roc_curve\n", "\n", "torch.manual_seed(0)\n", "np.random.seed(0)\n", "\n", "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", "\n", "%load_ext autoreload\n", "%autoreload 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build ground-truth graph G*\n", "\n", "Same converging-tier DAG as notebook 13 (scaled 4×). Held-out edges are removed when building `G_partial`; we try to recover them online during training." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tier-A width: 25\n", "inputs: 25 | functions: 50 | outputs: 25\n", "Function-function edges: 72\n", "Held-out edges: 35 | kept in G_partial: 37\n", "Is DAG: True\n" ] } ], "source": [ "def build_convergence_graph(n_tier_a=6):\n", " n = n_tier_a\n", " G = nx.DiGraph()\n", " func_func_edges_TRUE = []\n", "\n", " input_nodes = [f'in{i}' for i in range(n)]\n", " tier_a = [f'f{i}' for i in range(n)]\n", " tier_b = [f'f{n + k}' for k in range(n - 1)]\n", " tier_c = [f'f{2 * n - 1}']\n", " function_nodes = tier_a + tier_b + tier_c\n", " output_nodes = [f'o{k}' for k in range(n)]\n", "\n", " for i, u in enumerate(input_nodes):\n", " G.add_edge(u, tier_a[i])\n", "\n", " for k in range(n - 1):\n", " b = tier_b[k]\n", " for parent in (tier_a[k], tier_a[k + 1]):\n", " e = (parent, b)\n", " G.add_edge(*e)\n", " func_func_edges_TRUE.append(e)\n", "\n", " sink = tier_c[0]\n", " for b in tier_b:\n", " e = (b, sink)\n", " G.add_edge(*e)\n", " func_func_edges_TRUE.append(e)\n", "\n", " for k, b in enumerate(tier_b):\n", " G.add_edge(b, output_nodes[k])\n", " G.add_edge(sink, output_nodes[n - 1])\n", "\n", " pos = {}\n", " x_spread = max(n - 1, 1)\n", " for i, u in enumerate(input_nodes):\n", " pos[u] = (i * 2 * x_spread / max(n - 1, 1) - x_spread, 4.0)\n", " for i, f in enumerate(tier_a):\n", " pos[f] = (i * 2 * x_spread / max(n - 1, 1) - x_spread, 3.0)\n", " for k, f in enumerate(tier_b):\n", " pos[f] = ((k + 0.5) * 2 * x_spread / max(n - 2, 1) - x_spread, 2.0)\n", " pos[sink] = (0.0, 1.0)\n", " for k, o in enumerate(output_nodes):\n", " pos[o] = (k * 2 * x_spread / max(n - 1, 1) - x_spread, 0.0)\n", "\n", " return G, pos, input_nodes, function_nodes, output_nodes, func_func_edges_TRUE\n", "\n", "\n", "def default_held_out_edges(n_tier_a, b2sink_stride=2):\n", " n = n_tier_a\n", " sink = f'f{2 * n - 1}'\n", " held = [(f'f{k}', f'f{n + k}') for k in range(1, n - 1)]\n", " held += [(f'f{n + k}', sink) for k in range(0, n - 1, b2sink_stride)]\n", " return held\n", "\n", "\n", "N_TIER_A = 25\n", "G, pos, input_nodes, function_nodes, output_nodes, func_func_edges_TRUE = build_convergence_graph(\n", " n_tier_a=N_TIER_A,\n", ")\n", "N_FUNC = len(function_nodes)\n", "\n", "HELD_OUT_EDGES = default_held_out_edges(N_TIER_A, b2sink_stride=2)\n", "held_out_set = set(HELD_OUT_EDGES)\n", "kept_ff_set = set(func_func_edges_TRUE) - held_out_set\n", "\n", "assert all(G.has_edge(*e) for e in HELD_OUT_EDGES)\n", "assert len(held_out_set & kept_ff_set) == 0\n", "\n", "print(f'Tier-A width: {N_TIER_A}')\n", "print(f'inputs: {len(input_nodes)} | functions: {N_FUNC} | outputs: {len(output_nodes)}')\n", "print(f'Function-function edges: {len(func_func_edges_TRUE)}')\n", "print(f'Held-out edges: {len(HELD_OUT_EDGES)} | kept in G_partial: {len(kept_ff_set)}')\n", "print(f'Is DAG: {nx.is_directed_acyclic_graph(G)}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulate data" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "train: torch.Size([2000, 25]) torch.Size([2000, 25])\n", "test: torch.Size([500, 25]) torch.Size([500, 25])\n" ] } ], "source": [ "N_TRAIN = 2000\n", "N_TEST = 500\n", "\n", "x_train, x_test, y_train, y_test = simulate(\n", " G,\n", " n_train=N_TRAIN,\n", " n_test=N_TEST,\n", " input_nodes=input_nodes,\n", " output_nodes=output_nodes,\n", " noise_scale=0.15,\n", " special_functions=None,\n", ")\n", "\n", "x_train = torch.tensor(x_train, dtype=torch.float32).to(device)\n", "x_test = torch.tensor(x_test, dtype=torch.float32).to(device)\n", "y_train = torch.tensor(y_train, dtype=torch.float32).to(device)\n", "y_test = torch.tensor(y_test, dtype=torch.float32).to(device)\n", "\n", "y_mu = y_train.mean(0)\n", "y_std = y_train.std(0)\n", "y_train = (y_train - y_mu) / (y_std + 1e-8)\n", "y_test = (y_test - y_mu) / (y_std + 1e-8)\n", "\n", "print('train:', x_train.shape, y_train.shape)\n", "print('test:', x_test.shape, y_test.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build partial graph G_partial\n", "\n", "Remove held-out function-function edges. Split held-out edges into **validation** (early-stopping) and **test** sets, stratified by structural role." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Held-out function-function edges: 35\n", " val: 17 | test: 18\n", "Kept function-function edges: 37\n", "Non-edges (true negatives): 2378\n", "G_partial edges: 87\n" ] } ], "source": [ "held_out_edges = HELD_OUT_EDGES\n", "held_out_set = set(held_out_edges)\n", "\n", "kept_edges = [e for e in func_func_edges_TRUE if e not in held_out_set]\n", "true_ff_set = set(func_func_edges_TRUE)\n", "\n", "G_partial = G.copy()\n", "G_partial.remove_edges_from(held_out_edges)\n", "data = nx2pyg(G_partial, input_nodes, function_nodes, output_nodes)\n", "\n", "n_non_edges = N_FUNC * (N_FUNC - 1) - len(true_ff_set)\n", "\n", "# Stratified val/test split by structural role\n", "sink = f'f{2 * N_TIER_A - 1}'\n", "left_merge = [e for e in held_out_edges if e[1] != sink]\n", "b2sink = [e for e in held_out_edges if e[1] == sink]\n", "\n", "rng = np.random.default_rng(0)\n", "rng.shuffle(left_merge)\n", "rng.shuffle(b2sink)\n", "\n", "def half_split(edges):\n", " n = len(edges)\n", " return edges[: n // 2], edges[n // 2 :]\n", "\n", "edges_val_lm, edges_test_lm = half_split(left_merge)\n", "edges_val_sink, edges_test_sink = half_split(b2sink)\n", "\n", "edges_val = edges_val_lm + edges_val_sink\n", "edges_test = edges_test_lm + edges_test_sink\n", "\n", "print(f'Held-out function-function edges: {len(held_out_edges)}')\n", "print(f' val: {len(edges_val)} | test: {len(edges_test)}')\n", "print(f'Kept function-function edges: {len(kept_edges)}')\n", "print(f'Non-edges (true negatives): {n_non_edges}')\n", "print(f'G_partial edges: {G_partial.number_of_edges()}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Train GSNN + online MagnitudeEdgeRegressor\n", "\n", "Joint training loop: GSNN forward/backward, then auxiliary regression step on detached magnitudes. Validation AUC on `edges_val` selects the best checkpoint." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "GSNN params: 13980\n", "Regressor params: 16480\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "epoch 1/30 | train loss: 0.9980 | val AUC: 0.788 | MRR: 0.198\n", "epoch 2/30 | train loss: 0.9965 | val AUC: 0.904 | MRR: 0.365\n", "epoch 3/30 | train loss: 0.9929 | val AUC: 0.893 | MRR: 0.407\n", "epoch 4/30 | train loss: 0.9890 | val AUC: 0.912 | MRR: 0.410\n", "epoch 5/30 | train loss: 0.9857 | val AUC: 0.886 | MRR: 0.417\n", "epoch 6/30 | train loss: 0.9793 | val AUC: 0.922 | MRR: 0.416\n", "epoch 7/30 | train loss: 0.9733 | val AUC: 0.922 | MRR: 0.484\n", "epoch 8/30 | train loss: 0.9628 | val AUC: 0.881 | MRR: 0.482\n", "epoch 9/30 | train loss: 0.9512 | val AUC: 0.862 | MRR: 0.570\n", "epoch 10/30 | train loss: 0.9360 | val AUC: 0.913 | MRR: 0.571\n", "epoch 11/30 | train loss: 0.9194 | val AUC: 0.913 | MRR: 0.602\n", "epoch 12/30 | train loss: 0.8986 | val AUC: 0.899 | MRR: 0.601\n", "epoch 13/30 | train loss: 0.8746 | val AUC: 0.882 | MRR: 0.630\n", "epoch 14/30 | train loss: 0.8482 | val AUC: 0.880 | MRR: 0.630\n", "epoch 15/30 | train loss: 0.8183 | val AUC: 0.892 | MRR: 0.630\n", "epoch 16/30 | train loss: 0.7856 | val AUC: 0.870 | MRR: 0.630\n", "epoch 17/30 | train loss: 0.7538 | val AUC: 0.864 | MRR: 0.660\n", "epoch 18/30 | train loss: 0.7176 | val AUC: 0.877 | MRR: 0.661\n", "epoch 19/30 | train loss: 0.6823 | val AUC: 0.877 | MRR: 0.662\n", "epoch 20/30 | train loss: 0.6499 | val AUC: 0.934 | MRR: 0.663\n", "epoch 21/30 | train loss: 0.6205 | val AUC: 0.927 | MRR: 0.661\n", "epoch 22/30 | train loss: 0.5925 | val AUC: 0.919 | MRR: 0.663\n", "epoch 23/30 | train loss: 0.5698 | val AUC: 0.892 | MRR: 0.663\n", "epoch 24/30 | train loss: 0.5558 | val AUC: 0.920 | MRR: 0.665\n", "epoch 25/30 | train loss: 0.5410 | val AUC: 0.935 | MRR: 0.666\n", "epoch 26/30 | train loss: 0.5329 | val AUC: 0.917 | MRR: 0.667\n", "epoch 27/30 | train loss: 0.5282 | val AUC: 0.919 | MRR: 0.667\n", "epoch 28/30 | train loss: 0.5251 | val AUC: 0.907 | MRR: 0.669\n", "epoch 29/30 | train loss: 0.5223 | val AUC: 0.905 | MRR: 0.668\n", "epoch 30/30 | train loss: 0.5239 | val AUC: 0.919 | MRR: 0.667\n", "test loss: 0.4999 | test r2: 0.487\n", "best val-AUC epoch: 25\n" ] } ], "source": [ "BATCH_SIZE = 64\n", "\n", "model_kwargs = {\n", " 'channels': 8,\n", " 'layers': 6,\n", " 'share_layers': False,\n", " 'bias': True,\n", " 'add_function_self_edges': True,\n", " 'norm': 'none',\n", " 'dropout': 0.2,\n", " 'nonlin': torch.nn.ELU,\n", " 'node_mlp': False,\n", " 'checkpoint': False,\n", "}\n", "\n", "model = GSNN(\n", " data.edge_index_dict,\n", " data.node_names_dict,\n", " **model_kwargs,\n", ").to(device)\n", "\n", "regressor = MagnitudeEdgeRegressor(\n", " model, data,\n", " aggregators=('sum', 'max'),\n", " lr=1e-3,\n", " weight_decay=1e-4,\n", " ridge=1e-2,\n", " dropout=0.2,\n", ").to(device)\n", "\n", "print('GSNN params:', sum(p.numel() for p in model.parameters()))\n", "print('Regressor params:', sum(p.numel() for p in regressor.parameters()))\n", "\n", "train_loader = torch.utils.data.DataLoader(\n", " torch.utils.data.TensorDataset(x_train, y_train),\n", " batch_size=BATCH_SIZE,\n", " shuffle=True,\n", " drop_last=True,\n", ")\n", "\n", "gsnn_optim = torch.optim.AdamW(model.parameters(), lr=1e-4, weight_decay=0)\n", "crit = torch.nn.MSELoss()\n", "\n", "n_epochs = 30\n", "val_auc_history = []\n", "best_epoch = None\n", "\n", "for epoch in range(n_epochs):\n", " model.train()\n", " regressor.train()\n", " epoch_losses = []\n", "\n", " for x_batch, y_batch in train_loader:\n", " regressor.pre_forward()\n", " yhat = model(x_batch)\n", " loss = crit(yhat, y_batch)\n", "\n", " regressor.arm_retained_grads()\n", " gsnn_optim.zero_grad()\n", " loss.backward()\n", " regressor.aux_step()\n", " gsnn_optim.step()\n", "\n", " epoch_losses.append(loss.item())\n", "\n", " val_metrics = regressor.evaluate_against(edges_val)\n", " val_auc = val_metrics['auc']\n", " val_auc_history.append(val_auc)\n", "\n", " if regressor.maybe_save_best(val_auc):\n", " best_epoch = epoch + 1\n", "\n", " if epoch == 0 or (epoch + 1) % 1 == 0 or epoch == n_epochs - 1:\n", " print(\n", " f'epoch {epoch + 1:2d}/{n_epochs} | train loss: {np.mean(epoch_losses):.4f} '\n", " f'| val AUC: {val_auc:.3f} | MRR: {val_metrics[\"mrr\"]:.3f}'\n", " )\n", "\n", "model.eval()\n", "with torch.inference_mode():\n", " yhat_test = model(x_test)\n", "loss_test = crit(y_test, yhat_test)\n", "r2_test = r2_score(y_test.detach().cpu().numpy(), yhat_test.detach().cpu().numpy())\n", "print(f'test loss: {loss_test.item():.4f} | test r2: {r2_test:.3f}')\n", "print(f'best val-AUC epoch: {best_epoch}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Validation AUC vs epoch" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(7, 4))\n", "ax.plot(range(1, n_epochs + 1), val_auc_history, marker='o', ms=4)\n", "if best_epoch is not None:\n", " ax.axvline(best_epoch, color='C1', ls='--', label=f'best epoch ({best_epoch})')\n", "ax.axhline(0.5, color='k', ls=':', alpha=0.5, label='random')\n", "ax.set_xlabel('epoch')\n", "ax.set_ylabel('val AUC (held-out vs non-edge)')\n", "ax.set_title('Online regressor: validation edge recovery during training')\n", "ax.legend()\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Compare regressor (best checkpoint) vs post-hoc MagnitudeEdgeInferer\n", "\n", "Load the best regressor checkpoint, then run post-hoc `MagnitudeEdgeInferer` on the final GSNN for head-to-head comparison on **test** held-out edges." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Top 10 regressor scores:\n", " src_func dst_func score has_edge q_value\n", "0 f1 f26 0.461439 False 0.527687\n", "1 f22 f47 0.400908 False 0.527687\n", "2 f16 f41 0.400895 False 0.527687\n", "3 f6 f31 0.398516 False 0.527687\n", "4 f23 f48 0.397042 False 0.527687\n", "5 f2 f27 0.395549 False 0.527687\n", "6 f12 f37 0.394976 False 0.527687\n", "7 f18 f43 0.392816 False 0.527687\n", "8 f14 f39 0.390867 False 0.527687\n", "9 f8 f33 0.388819 False 0.527687\n" ] } ], "source": [ "regressor.load_best()\n", "res_reg = regressor.evaluate()\n", "\n", "# Post-hoc MEI on final model\n", "MEI = MagnitudeEdgeInferer(model, data, reduction='l1')\n", "infer_loader = torch.utils.data.DataLoader(\n", " torch.utils.data.TensorDataset(x_train, y_train),\n", " batch_size=BATCH_SIZE,\n", " shuffle=False,\n", " drop_last=True,\n", ")\n", "MEI.fit(infer_loader, crit=crit, device=device, verbose=False)\n", "res_corr = MEI.evaluate(layer_agg='max', score='corr')\n", "res_partial = MEI.evaluate(layer_agg='max', score='partial')\n", "\n", "print('Top 10 regressor scores:')\n", "print(res_reg[['src_func', 'dst_func', 'score', 'has_edge', 'q_value']].head(10).to_string())" ] }, { "cell_type": "code", "execution_count": 13, "id": "5ec9b108", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " src_func dst_func score has_edge q_value\n", "2440 f7 f36 0.000032 False 0.527687\n", "2441 f17 f23 0.000031 False 0.527687\n", "2442 f31 f29 0.000030 False 0.527687\n", "2443 f5 f7 0.000025 False 0.527687\n", "2444 f38 f44 0.000020 False 0.527687\n", "2445 f44 f34 0.000015 False 0.527687\n", "2446 f0 f18 0.000008 False 0.527687\n", "2447 f25 f19 0.000003 False 0.527687\n", "2448 f45 f2 0.000003 False 0.527687\n", "2449 f31 f39 0.000002 False 0.527687\n" ] } ], "source": [ "print(res_reg[['src_func', 'dst_func', 'score', 'has_edge', 'q_value']].tail(10).to_string())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Test-set ROC comparison" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test-set ROC-AUC (held-out test vs non-edges):\n", " regressor (best) : AUC = 0.961\n", " MEI corr : AUC = 0.969\n", " MEI partial : AUC = 0.970\n", "\n", "=== regressor (best) ===\n", " MRR: 0.687 top@1: 0.667 top@3: 0.667\n", "=== MEI corr ===\n", " MRR: 0.707 top@1: 0.667 top@3: 0.667\n", "=== MEI partial ===\n", " MRR: 0.707 top@1: 0.667 top@3: 0.667\n" ] } ], "source": [ "def roc_auc_for_edges(res_df, positive_edges, score_col='score'):\n", " pos_set = set(positive_edges)\n", " pos = res_df[res_df.apply(lambda r: (r['src_func'], r['dst_func']) in pos_set, axis=1)][score_col].dropna().values\n", " neg = res_df[~res_df.apply(lambda r: (r['src_func'], r['dst_func']) in pos_set, axis=1)]\n", " neg = neg[neg.apply(lambda r: (r['src_func'], r['dst_func']) not in kept_ff_set, axis=1)][score_col].dropna().values\n", " if len(pos) == 0 or len(neg) == 0:\n", " return float('nan')\n", " y_true = np.concatenate([np.ones(len(pos)), np.zeros(len(neg))])\n", " y_score = np.concatenate([pos, neg])\n", " return roc_auc_score(y_true, y_score)\n", "\n", "\n", "def print_target_ranking(label, res_df, positive_edges):\n", " detail, summary = MagnitudeEdgeRegressor.evaluate_target_ranking(\n", " res_df, positive_edges=positive_edges, score_col='score' if 'score' in res_df.columns else 'corr',\n", " )\n", " print(f'=== {label} ===')\n", " print(f\" MRR: {summary['mrr']:.3f} top@1: {summary['top@1']:.3f} top@3: {summary['top@3']:.3f}\")\n", " return summary\n", "\n", "kept_set = set(kept_edges)\n", "\n", "results = {\n", " 'regressor (best)': (res_reg, 'score'),\n", " 'MEI corr': (res_corr, 'corr'),\n", " 'MEI partial': (res_partial, 'corr'),\n", "}\n", "\n", "print('Test-set ROC-AUC (held-out test vs non-edges):')\n", "for name, (df, col) in results.items():\n", " auc = roc_auc_for_edges(df, edges_test, score_col=col)\n", " print(f' {name:20s}: AUC = {auc:.3f}')\n", "\n", "print()\n", "for name, (df, col) in results.items():\n", " if col != 'score':\n", " df = df.rename(columns={'corr': 'score'})\n", " print_target_ranking(name, df, edges_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ROC curves on test held-out edges" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(7, 5))\n", "\n", "for name, (df, col) in results.items():\n", " pos_set = set(edges_test)\n", " pos = df[df.apply(lambda r: (r['src_func'], r['dst_func']) in pos_set, axis=1)][col].dropna().values\n", " neg = df[~df.apply(lambda r: (r['src_func'], r['dst_func']) in pos_set, axis=1)]\n", " neg = neg[neg.apply(lambda r: (r['src_func'], r['dst_func']) not in kept_ff_set, axis=1)][col].dropna().values\n", " if len(pos) == 0 or len(neg) == 0:\n", " continue\n", " y_true = np.concatenate([np.ones(len(pos)), np.zeros(len(neg))])\n", " y_score = np.concatenate([pos, neg])\n", " auc = roc_auc_score(y_true, y_score)\n", " fpr, tpr, _ = roc_curve(y_true, y_score)\n", " ax.plot(fpr, tpr, label=f'{name} (AUC={auc:.3f})')\n", "\n", "ax.plot([0, 1], [0, 1], 'k--', alpha=0.5)\n", "ax.set_xlabel('FPR')\n", "ax.set_ylabel('TPR')\n", "ax.set_title('ROC: test held-out edges vs non-edges')\n", "ax.legend()\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Discussion\n", "\n", "`MagnitudeEdgeRegressor` trains a shared **(N, N)** weight matrix online during GSNN training. Unlike post-hoc correlation (`MagnitudeEdgeInferer`), it:\n", "\n", "1. **Reuses the training forward/backward** — no extra pass over the data.\n", "2. **Multivariate regression** — each target gradient magnitude is predicted from all source activations, conditioning on other sources automatically (partial-correlation-like).\n", "3. **Validation early-stopping** — held-out edges drive checkpoint selection, mitigating **gradient absorption** at equilibrium (see `docs/notes/edge_inference_notes.md` §4.5 / §7.1).\n", "\n", "The val-AUC vs epoch plot should show a peak **before** full convergence, when missing edges still produce informative gradient signal." ] }, { "cell_type": "markdown", "id": "441a6204", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": "gsnn", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 }