T

Torch Geometric Engine

Battle-tested skill for graph, neural, networks, node. Includes structured workflows, validation checks, and reusable patterns for scientific.

SkillClipticsscientificv1.0.0MIT
0 views0 copies

Torch Geometric Engine

Build and train Graph Neural Networks (GNNs) using PyTorch Geometric (PyG), a library for deep learning on graphs and irregular structures. This skill covers graph construction, message passing layers, node/edge/graph classification, link prediction, graph generation, and scaling to large graphs.

When to Use This Skill

Choose Torch Geometric Engine when you need to:

  • Train GNNs for node classification, link prediction, or graph-level tasks
  • Process molecular graphs, social networks, or knowledge graphs with neural networks
  • Implement custom message passing schemes and graph transformations
  • Scale graph learning to large datasets with mini-batching and sampling

Consider alternatives when:

  • You need graph analysis without neural networks (use NetworkX)
  • You need drug discovery with specialized molecular models (use TorchDrug)
  • You need static graph algorithms and analytics (use igraph or graph-tool)

Quick Start

pip install torch torch-geometric
import torch import torch.nn.functional as F from torch_geometric.datasets import Planetoid from torch_geometric.nn import GCNConv # Load Cora citation network dataset = Planetoid(root='/tmp/Cora', name='Cora') data = dataset[0] print(f"Nodes: {data.num_nodes}, Edges: {data.num_edges}") print(f"Features: {data.num_node_features}, Classes: {dataset.num_classes}") # Define GCN model class GCN(torch.nn.Module): def __init__(self, in_channels, hidden_channels, out_channels): super().__init__() self.conv1 = GCNConv(in_channels, hidden_channels) self.conv2 = GCNConv(hidden_channels, out_channels) def forward(self, x, edge_index): x = self.conv1(x, edge_index) x = F.relu(x) x = F.dropout(x, p=0.5, training=self.training) x = self.conv2(x, edge_index) return x # Train device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = GCN(dataset.num_features, 16, dataset.num_classes).to(device) data = data.to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4) model.train() for epoch in range(200): optimizer.zero_grad() out = model(data.x, data.edge_index) loss = F.cross_entropy(out[data.train_mask], data.y[data.train_mask]) loss.backward() optimizer.step() # Evaluate model.eval() pred = model(data.x, data.edge_index).argmax(dim=1) correct = (pred[data.test_mask] == data.y[data.test_mask]).sum() acc = int(correct) / int(data.test_mask.sum()) print(f"Test accuracy: {acc:.4f}")

Core Concepts

GNN Layer Types

LayerClassMechanismBest For
GCNGCNConvSpectral convolutionHomogeneous graphs
GATGATConvAttention-weighted aggregationVariable-importance neighbors
GraphSAGESAGEConvSampling + aggregationLarge graphs, inductive
GINGINConvSum aggregation (WL-test powerful)Graph classification
EdgeConvEdgeConvDynamic graph constructionPoint clouds
TransformerConvTransformerConvMulti-head attention on graphsHeterogeneous features

Graph Classification with Pooling

import torch import torch.nn.functional as F from torch_geometric.datasets import TUDataset from torch_geometric.loader import DataLoader from torch_geometric.nn import GINConv, global_mean_pool, global_add_pool from torch.nn import Linear, Sequential, ReLU, BatchNorm1d # Load molecular dataset dataset = TUDataset(root='/tmp/MUTAG', name='MUTAG') print(f"Graphs: {len(dataset)}, Classes: {dataset.num_classes}") # Split train_dataset = dataset[:150] test_dataset = dataset[150:] train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=32) class GINClassifier(torch.nn.Module): def __init__(self, in_channels, hidden, out_channels, num_layers=3): super().__init__() self.convs = torch.nn.ModuleList() self.bns = torch.nn.ModuleList() for i in range(num_layers): in_ch = in_channels if i == 0 else hidden mlp = Sequential( Linear(in_ch, hidden), BatchNorm1d(hidden), ReLU(), Linear(hidden, hidden), ReLU() ) self.convs.append(GINConv(mlp)) self.bns.append(BatchNorm1d(hidden)) self.classifier = Sequential( Linear(hidden, hidden), ReLU(), Linear(hidden, out_channels) ) def forward(self, x, edge_index, batch): for conv, bn in zip(self.convs, self.bns): x = conv(x, edge_index) x = bn(x) x = F.relu(x) x = global_add_pool(x, batch) # Graph-level readout return self.classifier(x) device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = GINClassifier(dataset.num_features, 64, dataset.num_classes).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.01) for epoch in range(100): model.train() total_loss = 0 for batch in train_loader: batch = batch.to(device) optimizer.zero_grad() out = model(batch.x, batch.edge_index, batch.batch) loss = F.cross_entropy(out, batch.y) loss.backward() optimizer.step() total_loss += loss.item() model.eval() correct = 0 total = 0 for batch in test_loader: batch = batch.to(device) pred = model(batch.x, batch.edge_index, batch.batch).argmax(dim=1) correct += (pred == batch.y).sum().item() total += batch.y.size(0) print(f"Test accuracy: {correct/total:.4f}")

Configuration

ParameterDescriptionDefault
hidden_channelsHidden layer dimensionality64
num_layersNumber of GNN layers3
dropoutDropout rate0.5
learning_rateOptimizer learning rate0.01
weight_decayL2 regularization5e-4
batch_sizeMini-batch size for graph-level tasks32
headsNumber of attention heads (GAT)8
aggrAggregation function (add, mean, max)"add"

Best Practices

  1. Start with 2-3 GNN layers, rarely go beyond 5 — GNNs suffer from over-smoothing: too many layers make all node embeddings converge to the same value. For most tasks, 2-3 layers capture sufficient neighborhood information. Add skip connections (residual) if you need deeper models.

  2. Use mini-batching for graph-level tasks — PyG's DataLoader batches multiple graphs into a single disconnected graph using the batch tensor. Always pass batch to pooling functions (global_mean_pool, global_add_pool) — without it, the model treats all graphs as one.

  3. Choose the aggregation function based on your task — sum aggregation (GIN) is most expressive for graph isomorphism tasks. mean aggregation (GCN, GraphSAGE) normalizes by degree and works better for node-level predictions. max aggregation captures the most extreme neighbor feature.

  4. Normalize node features before training — GNN performance is sensitive to feature scale. Standardize continuous features and use one-hot encoding for categorical node attributes. Without normalization, high-magnitude features dominate message passing.

  5. Use NeighborLoader for large-graph training — Full-batch training on graphs with millions of nodes exhausts GPU memory. NeighborLoader samples a fixed number of neighbors per layer, enabling mini-batch training on arbitrarily large graphs with constant memory usage.

Common Issues

Out of memory on large graphs — Full-batch GCN on a million-node graph requires storing the full adjacency and feature matrix. Use NeighborLoader or ClusterLoader for mini-batch training. Reduce hidden_channels and num_layers as a quick fix while debugging.

Node classification accuracy is random (~1/num_classes) — Check that data.train_mask is not empty and properly selects training nodes. Also verify that edge_index contains valid edges — missing or corrupted edges means nodes receive no neighbor information. Print data to inspect all attributes.

Custom dataset fails with "Data object has no attribute 'x'" — PyG expects specific attribute names: x for node features, edge_index for edges (shape [2, num_edges]), y for labels, edge_attr for edge features. When building custom Data objects, ensure edge_index is a LongTensor and is 0-indexed.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates