GNN-DR learns a single GNN model that maps high-dimensional CLIP embeddings to 2D visualizations. Unlike t-SNE or UMAP, the trained model generalizes to unseen datasets without per-dataset optimization.
- Inductive DR: Train once, apply to any CLIP-embedded dataset
- GRU-based GNN: Iterative message passing with edge-weighted convolutions
- UMAP-style loss: Fuzzy simplicial set weights with attraction/repulsion objective
- Multi-dataset training: Train on multiple datasets simultaneously with weighted sampling
- GPU-optimized: KNN graph construction, edge weight computation, and replay buffer all on GPU
- Comprehensive evaluation: 14 DR quality metrics via tf-projection-qm
conda create -n gnn-dr python=3.10 -y
conda activate gnn-drPyTorch and PyG extensions (torch-scatter, torch-sparse, torch-cluster) must be installed with matching versions. Choose one of the following:
CPU only:
pip install torch==2.4.1 torchvision==0.19.1 --index-url https://download.pytorch.org/whl/cpu
pip install torch-geometric torch-scatter torch-sparse torch-cluster \
-f https://data.pyg.org/whl/torch-2.4.0+cpu.htmlCUDA 11.8:
pip install torch==2.4.1 torchvision==0.19.1 --index-url https://download.pytorch.org/whl/cu118
pip install torch-geometric torch-scatter torch-sparse torch-cluster \
-f https://data.pyg.org/whl/torch-2.4.0+cu118.htmlCUDA 12.1:
pip install torch==2.4.1 torchvision==0.19.1 --index-url https://download.pytorch.org/whl/cu121
pip install torch-geometric torch-scatter torch-sparse torch-cluster \
-f https://data.pyg.org/whl/torch-2.4.0+cu121.htmlFor other PyTorch/CUDA combinations, see the PyG installation guide.
# From the gnn-dr/ directory
pip install -e .This installs all remaining dependencies (pytorch-lightning, wandb, transformers, scikit-learn, etc.).
For comprehensive DR quality metrics using tf-projection-qm:
pip install -e ".[metrics]"python -c "from gnn_dr.network.lightning_module import CoReGDLightningModule; print('OK')"
python scripts/train.py --helppython scripts/train.py --config configs/default.yamlThis trains on MNIST, CIFAR-10, and Fashion-MNIST simultaneously (multi-dataset mode). Training progress is logged to Weights & Biases.
Override config options from the command line:
python scripts/train.py --config configs/default.yaml --epochs 100 --lr 0.001 --device 0Resume from a checkpoint:
python scripts/train.py --config configs/default.yaml --resume_from last
python scripts/train.py --config configs/default.yaml --resume_from models/my_model_best_val.ckptKey config options (in configs/default.yaml):
| Config key | Description | Default |
|---|---|---|
dataset.train_datasets |
Datasets to train on | CIFAR-10, MNIST, Fashion-MNIST |
dimensionality_reduction.knn_k |
Number of KNN neighbors | 15 |
dimensionality_reduction.umap_repulsion_weight |
Repulsion weight (gamma) | 5.0 |
model.conv |
Convolution type (gru or gin) |
gru |
model.hidden_dimension |
Hidden dimension | 64 |
model.num_layers |
Number of GNN iterations | 12 |
training.lr |
Learning rate | 0.001 |
training.epochs |
Number of training epochs | 200 |
Evaluate a trained model on multiple datasets with tf-projection-qm metrics:
python scripts/evaluate.py \
--checkpoint models/last.ckpt \
--datasets mnist_clip cifar10_clip food101_clip \
--output results/gnn_results.csvOptions:
python scripts/evaluate.py --help| Flag | Description | Default |
|---|---|---|
--checkpoint |
Path to .ckpt file (required) | - |
--config |
Config YAML (uses checkpoint config if omitted) | None |
--datasets |
Datasets to evaluate (space-separated) | all |
--rounds |
Number of GNN message passing rounds | 10 |
--k |
KNN neighbors for graph construction | 15 |
--max-samples |
Max samples per dataset | 10000 |
--output |
Output CSV path | results/gnn_results.csv |
--compile |
Use torch.compile for faster inference | off |
Run PCA, t-SNE, UMAP, and Parametric UMAP on all datasets:
python scripts/run_baselines.py --output results/baselines.csvRun on specific datasets:
python scripts/run_baselines.py \
--datasets mnist_clip cifar10_clip fashion_mnist_clip \
--output results/baselines.csvTrain a Parametric UMAP encoder on the same training data as CoRe-DR (MNIST + Fashion-MNIST + CIFAR-10), then evaluate on all datasets:
python scripts/evaluate_parametric_umap.py \
--output results/pumap.csv \
--checkpoint models/pumap.pt \
--device cudaEvaluate using a previously trained checkpoint:
python scripts/evaluate_parametric_umap.py \
--eval-only \
--checkpoint models/pumap.pt \
--output results/pumap.csvCompare GNN-DR projections against baselines visually:
python scripts/generate_scatter_plots.py \
--checkpoint models/last.ckpt \
--datasets mnist_clip cifar10_clip food101_clip \
--output figures/scatter_comparison.pdfInclude Parametric UMAP in the comparison:
python scripts/generate_scatter_plots.py \
--checkpoint models/last.ckpt \
--pumap-checkpoint models/pumap.pt \
--datasets mnist_clip fashion_mnist_clip cifar10_clip kmnist_clip food101_clip \
--output figures/scatter_comparison.pdfGenerate a comparison table (console + LaTeX):
python scripts/analyze_results.py \
--baselines results/baselines.csv \
--gnn results/gnn_results.csv \
--pumap results/pumap.csv \
--latex --latex-out results/table.texGenerate a full-metric appendix table:
python scripts/analyze_results.py \
--baselines results/baselines.csv \
--gnn results/gnn_results.csv \
--pumap results/pumap.csv \
--appendix --appendix-out results/appendix_table.texEvaluate how metrics change with the number of GNN message passing rounds:
python scripts/sweep_iterations.py \
--checkpoint models/last.ckpt \
--max-iterations 20 \
--output results/iteration_sweep.csvPlot the results:
python scripts/plot_iterations.py \
--input results/iteration_sweep.csv \
--output figures/iteration_sweep.pdfGenerate the main TikZ-based architecture figure (requires CLIP model download):
python scripts/generate_figure.py --output-dir figure_assets
pdflatex figure_main.texExport raw data for TikZ plotting:
python scripts/export_data_for_tikz.py --output-dir tikz_data
python scripts/generate_scatter.py --input-dir tikz_dataThe following commands reproduce all results, tables, and figures from the paper.
All scripts should be run from the gnn-dr/ directory. Evaluation requires a GPU
(NVIDIA A6000 or similar) for reasonable runtimes.
python scripts/train.py --config configs/default.yaml --device 0Training runs for 200 epochs on MNIST, CIFAR-10, and Fashion-MNIST. Checkpoints
are saved to models/. Training progress is logged to W&B.
python scripts/run_baselines.py \
--datasets mnist_clip fashion_mnist_clip cifar10_clip \
kmnist_clip fgvc_aircraft_clip oxford_pets_clip food101_clip \
--output results/baselines.csvpython scripts/evaluate_parametric_umap.py \
--output results/pumap.csv \
--checkpoint models/pumap.pt \
--device cudapython scripts/evaluate.py \
--checkpoint models/last.ckpt \
--datasets mnist_clip fashion_mnist_clip cifar10_clip \
kmnist_clip fgvc_aircraft_clip oxford_pets_clip food101_clip \
--output results/gnn_results.csvMain results table (Table 1):
python scripts/analyze_results.py \
--baselines results/baselines.csv \
--gnn results/gnn_results.csv \
--pumap results/pumap.csv \
--latex --latex-out results/table.texFull metrics appendix table:
python scripts/analyze_results.py \
--baselines results/baselines.csv \
--gnn results/gnn_results.csv \
--pumap results/pumap.csv \
--appendix --appendix-out results/appendix_table.texScatter plot comparison:
python scripts/generate_scatter_plots.py \
--checkpoint models/last.ckpt \
--pumap-checkpoint models/pumap.pt \
--datasets mnist_clip fashion_mnist_clip cifar10_clip \
kmnist_clip fgvc_aircraft_clip oxford_pets_clip food101_clip \
--output figures/scatter_comparison.pdfIteration sweep plot:
python scripts/sweep_iterations.py \
--checkpoint models/last.ckpt \
--max-iterations 20 \
--output results/iteration_sweep.csv
python scripts/plot_iterations.py \
--input results/iteration_sweep.csv \
--output figures/iteration_sweep.pdfArchitecture figure:
python scripts/generate_figure.py --output-dir figure_assets
pdflatex figure_main.texA Containerfile is provided for reproducible GPU-accelerated training and evaluation.
cd gnn-dr/
podman build -t gnn-dr .podman run --rm gnn-dr -c "from gnn_dr.network.lightning_module import CoReGDLightningModule; print('OK')"Requires the NVIDIA Container Toolkit (CDI):
podman run --rm --device nvidia.com/gpu=all \
-v ./data:/app/data \
-v ./models:/app/models \
-v ./results:/app/results \
gnn-dr scripts/train.py --config configs/default.yaml --device 0podman run --rm --device nvidia.com/gpu=all \
-v ./data:/app/data \
-v ./models:/app/models \
-v ./results:/app/results \
gnn-dr scripts/evaluate.py \
--checkpoint models/last.ckpt \
--datasets mnist_clip cifar10_clip food101_clip \
--output results/gnn_results.csvpodman run --rm --device nvidia.com/gpu=all \
-v ./data:/app/data \
-v ./results:/app/results \
gnn-dr scripts/run_baselines.py --output results/baselines.csvNote: Replace
podmanwithdockerif using Docker. For Docker GPU support, use--gpus allinstead of--device nvidia.com/gpu=all.
All datasets use CLIP (ViT-B/32) embeddings, extracted and cached automatically on first use.
Training (default): MNIST, CIFAR-10, Fashion-MNIST
Evaluation: KMNIST, Flowers-102, FGVC Aircraft, Oxford Pets, Food-101, STL-10, SVHN, EMNIST, CIFAR-100, Caltech-101, Stanford Cars, DTD
Dataset names for CLI arguments: mnist_clip, cifar10_clip, fashion_mnist_clip, cifar100_clip, svhn_clip, stl10_clip, emnist_clip, kmnist_clip, flowers102_clip, fgvc_aircraft_clip, oxford_pets_clip, food101_clip, dtd_clip, caltech101_clip, stanford_cars_clip
- Preprocessing: Extract CLIP embeddings, build KNN graph, compute UMAP fuzzy simplicial set weights
- Input features: PCA projection of CLIP embeddings (configurable)
- GNN: Encoder MLP -> Iterative GRU convolutions with edge weights -> Decoder MLP -> 2D output
- Loss: UMAP cross-entropy with attraction (positive edges) and repulsion (negative sampling)
- Training: Dynamic graph generation with GPU replay buffer for stability
gnn-dr/
├── pyproject.toml # Package configuration
├── configs/
│ └── default.yaml # Default training configuration
├── gnn_dr/
│ ├── config/ # Configuration dataclasses and loading
│ ├── network/ # Model, loss, training loop, callbacks
│ │ ├── model.py # CoReGD model with GRU/GIN convolutions
│ │ ├── losses.py # UMAP attraction/repulsion loss
│ │ ├── lightning_module.py # PyTorch Lightning training module
│ │ ├── lightning_datamodule.py # Data loading and preprocessing
│ │ ├── convolutions.py # GRUEdgeConv, GINEdgeConv layers
│ │ ├── replay_buffer.py # GPU replay buffer for training stability
│ │ └── *_callback.py # Evaluation callbacks
│ ├── datasets/ # CLIP dataset loading and graph construction
│ │ ├── clip_dr_base.py # Base class for GPU-accelerated CLIP datasets
│ │ ├── loaders.py # Dataset loading functions
│ │ └── *_dr.py # Per-dataset implementations (15 datasets)
│ ├── baselines/ # PCA, t-SNE, UMAP, Parametric UMAP
│ ├── evaluation/ # Model evaluation and metrics
│ │ ├── evaluate_model.py # Evaluate GNN checkpoints
│ │ ├── evaluate_parametric_umap.py # Train + evaluate Parametric UMAP
│ │ ├── run_full_evaluation.py # Run all baselines
│ │ └── show_metric_table.py # Display results
│ └── utils/ # Edge weights, logging, visualization
│ ├── umap_weights.py # UMAP + t-SNE edge weight computation
│ └── logging.py # W&B logging utilities
└── scripts/
├── train.py # Training entry point
├── evaluate.py # Evaluate a trained GNN checkpoint
├── run_baselines.py # Run PCA, t-SNE, UMAP baselines
├── evaluate_parametric_umap.py # Train + evaluate Parametric UMAP
├── generate_scatter_plots.py # Multi-method scatter plot comparison
├── analyze_results.py # Generate comparison tables (+ LaTeX)
├── sweep_iterations.py # Sweep GNN iteration counts
├── plot_iterations.py # Plot metrics vs. iterations
├── generate_figure.py # Generate TikZ paper figure
├── export_data_for_tikz.py # Export data for TikZ plotting
└── generate_scatter.py # Standalone scatter plot from exported data