A comparative study of Graph Neural Networks (GNNs) operating in three different geometric spaces: Euclidean, spherical, and hyperbolic. Includes a real-time web dashboard for running experiments and visualizing results.
GNN layers perform two operations at each step: aggregate neighbor features, then transform the result. The geometry determines what "transform" means. A Euclidean GNN applies a plain linear map. A spherical GNN normalizes embeddings onto the unit sphere after each transformation. A hyperbolic GNN maps to the tangent space at the origin via the logarithmic map, applies a linear transformation there, then maps back to the Poincaré ball via the exponential map.
This project compares these three architectures on synthetic node classification tasks where the node features are constructed to be compatible with each geometry by design. This makes the experiment a sanity check rather than a discovery: the matching geometry is expected to win. The value of the project is in the implementation, not the result.
All three experiments share the same underlying graph. A Watts–Strogatz random graph
where
The node features
Sample
Apply a random orthogonal transformation (via QR decomposition), center, then expand to 128 dimensions via a random projection
Place nodes along latitude
then normalize
Use BFS from node 0 to assign each node a depth
Labels encode depth:
Each variant is a 2-layer GNN with 256 hidden dimensions, ReLU activation, dropout rate 0.3, trained for 500 epochs with the Adam optimizer.
Euclidean layer: standard graph convolution
Spherical layer: normalize inputs onto
Hyperbolic layer: map from the Poincaré ball to the tangent space at the origin via the logarithmic map
Python 3.8+, PyTorch, NetworkX, NumPy, Matplotlib, scikit-learn, Flask, Flask-SocketIO.
CPU only:
pip install torch numpy networkx matplotlib scikit-learn flask flask-socketioGPU (NVIDIA CUDA):
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install numpy networkx matplotlib scikit-learn flask flask-socketioVerify CUDA:
python -c "import torch; print(torch.cuda.is_available())"# Multiple runs, auto-detect GPU
python gnn.py --test euclidean --runs 5
# Single run with fixed seed
python gnn.py --test hyperbolic --seed 42
# Force GPU (fails if CUDA unavailable)
python gnn.py --test spherical --device cuda --runs 3
# Force CPU
python gnn.py --test spherical --device cpuOptions:
--test: test geometry (euclidean,spherical,hyperbolic)--runs: number of experimental runs (default: 3)--seed: random seed for reproducibility--device:cpu,cuda, orauto(default:auto)--no-save: disable saving outputs--quiet: suppress verbose output
python app.pyNavigate to http://localhost:5000. The dashboard streams training logs in real time via SocketIO and renders embedding visualizations and summary plots on completion.
Results are saved in timestamped directories results_{geometry}_{device}_{timestamp}/ containing:
{model_geom}_GNN-{test_geom}_test-{run}.png: 2D PCA projections of learned embeddingsmulti_run_results.png: accuracy and runtime summary (mean ± std)results_summary.jsonorsingle_run_results.json: numerical results
