Skip to content

feat: use PyG SAGEConv on native graph_sampler mini-batches - #7

Merged
sathariels merged 2 commits into
mainfrom
cursor/phase6-pyg-sageconv-8999
Sep 14, 2026
Merged

sathariels merged 2 commits into
mainfrom
cursor/phase6-pyg-sageconv-8999

Conversation

@sathariels

@sathariels sathariels commented Sep 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

Phase 6 closes the project-requirements gap (“Use PyTorch and PyTorch Geometric”) without giving up the systems story: C++ CSR + seeded ADR-005 sampling is still what GraphSAGE consumes.

Owner decision (ADR-006): PyG production path — torch_geometric.nn.SAGEConv (mean aggregation) for message passing; neighborhoods must still come from native graph_sampler via sagerec_minibatch / NativeMinibatchSampler. Primary experiments do not use NeighborLoader, ClusterLoader, or any PyG sampler.

What changed

  • GraphSAGE conv stack in python/sagerec_graphsage.py now uses PyG SAGEConv instead of in-repo Linear(concat(self, mean(neighbors))) layers.
  • Thin adapter neighborhood_hop_to_edge_index converts one native NeighborhoodBatch hop into the PyG edge_index form SAGEConv expects. It does not sample.
  • CPU-friendly pins in python/requirements-train.txt: torch==2.6.0 and torch-geometric==2.6.1. Mean SAGEConv does not need torch-scatter / torch-sparse / pyg-lib.
  • CI installs that PyG pin after the CPU PyTorch wheel.
  • Tests prove native sample_neighbors is still on the path, assert SAGEConv is the conv stack, and reject NeighborLoader / ClusterLoader on the primary path.

What stayed native

  • python/sagerec_minibatch.py / graph_sampler.BipartiteCSR.sample_neighbors remain the only neighborhood expansion path.
  • Pair scoring (PairScorer), ADR-003 split, ADR-005 without-replacement sampling, and the train-only CSR contract are unchanged.
  • Native C++ stays free of PyTorch and PyG.

Honesty

  • Stored MovieLens 100K metrics (results/graphsage_movielens_100k.json, results/gnn_vs_mf_*) are not retconned. They were measured with the Phase 5 in-repo mean layers. This PR does not invent a new 100K table.
  • Tiny synthetic GraphSAGE metrics remain protocol smoke, not 100K quality.

Test plan

  • Release CMake + CTest: 17/17 passed locally (python_binding_smoke included)
  • python3 -m unittest for test_graphsage_train.py, test_minibatch_native.py, test_gnn_vs_mf_compare.py (39 tests)
  • Native sample_neighbors spy still fires; NeighborLoader/ClusterLoader are never constructed
  • scripts/run_graphsage_synthetic_smoke.py (protocol smoke only; not stored as 100K)
  • GitHub Actions native CI green on 748618d (CPU PyTorch + torch-geometric==2.6.1; no CUDA wheels, no MovieLens download)
Open in Web Open in Cursor 

cursoragent and others added 2 commits September 14, 2026 16:16
Switch GraphSAGE message passing to torch_geometric.nn.SAGEConv while
keeping neighborhood expansion on graph_sampler via sagerec_minibatch
(ADR-006). Add an edge_index adapter, harness tests that spy native
sample_neighbors and forbid NeighborLoader, and CPU-friendly PyG pins.
Do not retcon stored MovieLens 100K quality numbers.

Co-authored-by: Nithilan Kumaran <sathariels@users.noreply.github.com>
The mini-batch helper still documents that it must not fall back to a
PyG NeighborLoader. Assert against imports and constructor calls instead
of the bare class name.

Co-authored-by: Nithilan Kumaran <sathariels@users.noreply.github.com>
@sathariels
sathariels marked this pull request as ready for review September 14, 2026 16:18
@sathariels
sathariels merged commit 305c3a6 into main Sep 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants