Track: Track1; Team name: SweetLesson; Model: TopoPolynormer#353
Open
AaravG42 wants to merge 3 commits into
Open
Track: Track1; Team name: SweetLesson; Model: TopoPolynormer#353AaravG42 wants to merge 3 commits into
AaravG42 wants to merge 3 commits into
Conversation
A Polynormer graph transformer augmented with a per-node topological substructure encoding that restores the 1-WL blind spot: standard message passing provably cannot count triangles (Chen et al., NeurIPS 2020), so we give each node — computed from edge_index inside the backbone — its degree, triangle count, local clustering coefficient, and random-walk return probabilities at steps 2/3/4. A triangle is a 2-simplex, so this is the minimal bridge from a graph to topology (the challenge theme). Adding substructure counts provably exceeds 1-WL (GSN, Bouritsas et al.). - topobench/nn/backbones/graph/topo_polynormer.py: `TopoPolynormer` + `structural_encoding` (batch-aware; injected after the input projection to bypass the encoder GraphNorm so the absolute triangle-count scale survives). - configs/model/graph/topo_polynormer.yaml: reuses GNNWrapper + NoReadOut; one config serves both GraphUniverse tasks. - test/nn/backbones/graph/test_topo_polynormer.py: 100% backbone coverage, including triangle-count correctness vs networkx, the sum=3x-total-triangles property, and batch isolation. - test/pipeline/test_pipeline.py: add graph/topo_polynormer. - tutorials/tutorial_topo_polynormer.ipynb: walkthrough of the idea. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
results.json from the official challenge pipeline (run_challenge_grid + save_challenge_artifacts), 72 runs (12 settings x 2 tasks x 3 seeds) with in-distribution and OOD metrics. vs the Polynormer baseline (PR geometric-intelligence#345): triangle-counting MSE/triangles drops ~98% in-distribution (0.872 -> 0.015) and ~97% OOD (35.1 -> 1.0); community-detection in-distribution accuracy improves (0.455 -> 0.477, gains at mid/high homophily). Generated offline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
Address the concern that injecting the raw per-node triangle count trivialises the graph-level triangle-counting task (its sum equals 3x the label, which the sum-pool readout recovers near-linearly). The default encoding is now purely degree-normalized and contains no raw count: log1p(degree), local clustering coefficient, and random-walk return probabilities at steps 2/3/4 (GraphGPS-style RWSE). The model must learn to estimate higher-order structure rather than being handed it. The raw triangle count remains available as an explicit, off-by-default ablation (use_triangle_count, default False) for the expressivity demonstration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist
Description
Track 1 (GNNs) submission — Team
SweetLesson— Model: TopoPolynormer. Companion to our faithful Polynormer submission (#345); same team, different architecture.The idea in one sentence. Message passing is a whispering game along edges, so it can never learn whether two of your neighbours are also neighbours of each other — i.e. whether you sit on a triangle. TopoPolynormer gives each node a small structural fingerprint of the local higher-order structure it lives in.
This is the canonical expressivity gap, not a hack: message-passing GNNs are bounded by the 1-Weisfeiler-Leman test, which provably cannot count triangles (Chen et al., NeurIPS 2020); structural features that encode local cohesion provably lift a model beyond 1-WL (Graph Substructure Networks, Bouritsas et al.). A triangle is a 2-simplex, so this is the minimal, literal bridge from a graph (edges = 1-simplices) to topology (triangles = 2-simplices) — directly the challenge's "Bridging the Gap" theme.
The model. Polynormer (local GAT-style attention + global linear attention) augmented with a per-node structural encoding computed from
edge_indexinside the backbone. By default the encoding is degree-normalised and contains no raw count:[log1p(degree), local clustering coefficient, random-walk return probabilities at steps 2/3/4](the latter being GraphGPS-style RWSE — a 3-step return is only possible around a triangle, so it is a multi-scale fingerprint of local cycle structure). It is injected after the input projection, bypassing the feature encoder'sGraphNorm, and is batch-aware (per graph segment). It adds ~512 parameters.Crucially, none of the default channels is the answer to any task — their sum is not the triangle-counting target — so the model must learn to estimate higher-order structure from structural cues rather than being handed it. (The raw per-node triangle count is available as an explicit, off-by-default ablation,
use_triangle_count; we keep it off precisely because injecting it would make sum-pooled triangle counting a near-linear readout and trivialise the task.)Results vs the Polynormer baseline (#345), full GraphUniverse grid (12 settings × 2 tasks × 3 seeds, in-distribution + OOD)
Triangle-counting error drops ~95–96% — the model learns to count from the degree-normalised structural signal (the 3-step random-walk return correlates ~0.85 with triangle participation), rather than being handed it; the credible non-zero result (0.045, not ~0) reflects genuine learning. Community detection improves in-distribution (mid/high homophily, where triangles signal community cohesion) at no OOD cost. For transparency: an explicit-count ablation (
use_triangle_count=True) reaches ~0.015 in-dist MSE, but we deliberately do not submit that, as it trivialises the counting task.What's added
topobench/nn/backbones/graph/topo_polynormer.py—TopoPolynormer+structural_encoding(NumPy docstrings cite Polynormer, Chen et al., GSN, and GraphGPS/RWSE).configs/model/graph/topo_polynormer.yaml— reusesGNNWrapper+NoReadOut; one config for both tasks;use_triangle_count: false.test/nn/backbones/graph/test_topo_polynormer.py— 100% backbone coverage, incl. clustering range, the random-walk/triangle correlation, the ablation's exactness, and batch isolation.test/pipeline/test_pipeline.py— addgraph/topo_polynormer.tutorials/tutorial_topo_polynormer.ipynb— the idea, the normalised-vs-explicit distinction, and an end-to-end run.2026_tdl_challenge/outputs/<study>/results.json— the full grid for the submitted (default) model.Adaptations (correctness notes)
The structural encoding and the global attention are both batch-aware (per graph segment); the paper's task heads are replaced by a single output projection (the TopoBench readout produces logits); local+global are trained jointly (
global_layers=0recovers local-only;use_struct=falserecovers plain Polynormer).Note on
results.jsongenerationOn upstream
main,2026_tdl_challenge/run_evaluation.ipynbcarries a self-integrity hash (expected_hash = f87b2c…) that does not match the hash of its own shipped cells (hash_remaining_cells(...) → 3c1d78…), so the guard cell raisesValueErrorbefore any work, for the unmodified notebook. Results were therefore generated by the notebook's own backend —run_challenge_grid(...)+save_challenge_artifacts(...)from2026_tdl_challenge/utils.py(identical pipeline), withWANDB_MODE=offline. Happy to open an issue to refresh the stored hash.Issue
Submission to the TDL Challenge 2026, Track 1 (GNNs). No existing PR uses structural/positional encodings; the field is concentrated on sheaf/diffusion methods.
Additional context
Tested with the project environment (Python 3.11, torch 2.3.0+cu121). Unit tests (100% backbone coverage), the pipeline test, the tutorial notebook, and a GraphUniverse sanity over all settings pass locally.