Building a Shape-Checked GNN Experiment Skeleton with TGraphX
A good experiment skeleton does three things before the first forward pass
runs: it records the environment, seeds randomness, validates the data
structure, and puts the model on the right device. This tutorial builds a
concrete, working skeleton using TGraphX's utilities, layer stack, and logging
infrastructure. Every step is grounded in the library's actual API.
Why a Skeleton Matters
Ad-hoc experiment scripts accumulate technical debt quickly. They lack
reproducibility (no seed), lack introspection (no env_report), and fail
mysteriously when moved to a different machine or batch size. A skeleton is a
starting template that enforces good practices from the first commit.
Step 1: Environment Report
Before anything else, record what you're running on:
from tgraphx.performance import env_report
info = env_report(include_hardware=True)
print(info)
# Returns: python version, PyTorch version, TGraphX version,
# CUDA availability, GPU name if present
This call is cheap and should be the first line of any experiment script.
Store the output in your experiment log so you can reproduce conditions later.
Step 2: Reproducibility
from tgraphx.reproducibility import set_seed
set_seed(42, deterministic=True)
# Sets Python random, NumPy random, and PyTorch random seeds.
# deterministic=True enables PyTorch's deterministic algorithm mode.
# Note: deterministic mode may reduce throughput.
set_seed is available from Beta v0.4.1. Call it before constructing data,
before building the model, and before the training loop.
Step 3: Device Selection
from tgraphx.performance import recommended_device
import torch
device = recommended_device()
# Returns 'cuda' if torch.cuda.is_available(), else 'cpu'
print(f"Using device: {device}")
Step 4: Graph Construction with Validation
Construct your Graph object with explicit shape assertions. The constructor
validates shapes and devices, but adding your own assertions documents your
intent:
import torch
from tgraphx import Graph
from tgraphx.graph_builders import build_knn_graph
# Example: 64 nodes, each with a [32]-dim feature vector
N = 64
node_features = torch.randn(N, 32) # [N, d]
node_labels = torch.randint(0, 4, (N,)) # [N]
# Build edges
edge_index = build_knn_graph(node_features, k=5) # [2, E]
E = edge_index.shape[1]
edge_features = torch.randn(E, 16) # [E, d_e]
# Document expected shapes
assert node_features.shape == (N, 32), f"Unexpected: {node_features.shape}"
assert edge_index.shape[0] == 2, f"edge_index must be [2, E]"
assert edge_features.shape[0] == E, "edge_features/edge_index mismatch"
g = Graph(
node_features=node_features,
edge_index=edge_index,
edge_features=edge_features,
node_labels=node_labels,
).to(device)
print(f"Graph: {N} nodes, {E} edges, on {device}")
Step 5: Build the Model
TGraphX provides several layers. For node classification, a two-layer GNN with
TensorGraphSAGELayer is a common starting point:
import torch.nn as nn
from tgraphx.layers import TensorGraphSAGELayer
class SimpleGNN(nn.Module):
def __init__(self, in_dim, hidden_dim, out_dim):
super().__init__()
self.layer1 = TensorGraphSAGELayer(in_dim, hidden_dim)
self.layer2 = TensorGraphSAGELayer(hidden_dim, out_dim)
self.relu = nn.ReLU()
def forward(self, g):
x = self.layer1(g)
x = self.relu(x)
# For layer2, update g.node_features with x
# (exact API depends on layer's forward signature)
return x
model = SimpleGNN(in_dim=32, hidden_dim=64, out_dim=4).to(device)
Step 6: Shape Check the Model Output
After building the model, run a single forward pass before the training loop
to verify shapes end-to-end:
model.eval()
with torch.no_grad():
out = model(g)
# Verify output shape matches expectation
expected_shape = (N, 4) # [num_nodes, num_classes]
assert out.shape == expected_shape, (
f"Model output shape {out.shape} does not match expected {expected_shape}"
)
print(f"Shape check passed: {out.shape}")
This smoke test catches layer configuration errors before you waste time
training.
Step 7: Logging Setup
TGraphX exports three loggers:
from tgraphx import CSVLogger, TensorBoardLogger, MLflowLogger
# CSVLogger: lightweight, no external dependencies
logger = CSVLogger(log_dir="./logs", experiment_name="skeleton_run")
# TensorBoardLogger: if tensorboard is installed
# logger = TensorBoardLogger(log_dir="./logs/tb")
# MLflowLogger: if mlflow is installed
# logger = MLflowLogger(tracking_uri="./mlruns")
For a first skeleton, CSVLogger is the lowest-friction choice.
Step 8: Write Experiment Config
Before training starts, write out your configuration:
from tgraphx import write_experiment_config
config = {
"seed": 42,
"device": device,
"num_nodes": N,
"num_edges": E,
"hidden_dim": 64,
"num_classes": 4,
"epochs": 50,
"lr": 0.01,
"model": "SimpleGNN",
}
write_experiment_config(config, path="./logs/experiment_config.json")
Step 9: Training Loop with Logging
import torch.optim as optim
optimizer = optim.Adam(model.parameters(), lr=config["lr"])
criterion = nn.CrossEntropyLoss()
model.train()
for epoch in range(config["epochs"]):
optimizer.zero_grad()
out = model(g)
loss = criterion(out, g.node_labels)
loss.backward()
optimizer.step()
logger.log({"epoch": epoch, "loss": loss.item()})
if epoch % 10 == 0:
print(f"Epoch {epoch:3d} | Loss: {loss.item():.4f}")
Step 10: Hardware Report
After training, write a hardware report alongside your results:
from tgraphx import write_hardware_report
write_hardware_report(path="./logs/hardware_report.json")
The Complete Skeleton Structure
experiment/
├── skeleton.py ← your script
└── logs/
├── experiment_config.json ← write_experiment_config
├── hardware_report.json ← write_hardware_report
├── metrics.csv ← CSVLogger output
└── graph_stats.json ← write_graph_stats (optional)
Common Mistakes This Skeleton Prevents
| Mistake | How the Skeleton Prevents It |
|---|---|
| Forgetting to seed randomness | set_seed() called first |
| Wrong device for model vs data | recommended_device() + g.to(device) |
| Silent shape mismatch | Graph constructor + explicit assertions |
| Model output shape wrong | Shape check before training loop |
| No record of Python/PyTorch ver | env_report() at startup |
| No experiment config saved | write_experiment_config() before training |
| No hardware context for results | write_hardware_report() after training |
Notes on Beta Status
TGraphX is Beta software. The skeleton above may need small adjustments if API
details change between versions. Pin your version in requirements.txt:
tgraphx==1.4.2
Check the changelog when upgrading. The experiment infrastructure — loggers,
write_* functions, set_seed, env_report — is the most likely to remain stable,
as it has fewer dependencies on the core graph computation machinery.