Graph Neural Networks (PyG). Classificação de nós/grafos, predição de links, GCN, GAT, GraphSAGE, grafos heterogêneos, predição de propriedades moleculares, para deep learning geométrico.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add artubss/SKILLS-CLAUDE-CODE --skill torch_geometric --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Torch Geometric?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/artubss-torch-geometric)More formats (shields.io, HTML) on the badges page.
---
name: torch-geometric
description: "Graph Neural Networks (PyG). Classificação de nós/grafos, predição de links, GCN, GAT, GraphSAGE, grafos heterogêneos, predição de propriedades moleculares, para deep learning geométrico."
---
# PyTorch Geometric (PyG)
## Visão Geral
PyTorch Geometric é uma biblioteca construída sobre PyTorch para desenvolvimento e treinamento de Graph Neural Networks (GNNs). Use esta skill para deep learning em grafos e estruturas irregulares, incluindo processamento em mini-batch, treinamento multi-GPU e aplicações de deep learning geométrico.
## Quando Usar Esta Skill
Esta skill deve ser usada ao trabalhar com:
- **Machine learning baseado em grafos**: Classificação de nós, classificação de grafos, predição de links
- **Predição de propriedades moleculares**: Descoberta de fármacos, predição de propriedades químicas
- **Análise de redes sociais**: Detecção de comunidades, predição de influência
- **Redes de citação**: Classificação de papers, sistemas de recomendação
- **Dados geométricos 3D**: Point clouds, malhas, estruturas moleculares
- **Grafos heterogêneos**: Nós e arestas de múltiplos tipos (ex: knowledge graphs)
- **Aprendizado em grafos em larga escala**: Amostragem de vizinhos, treinamento distribuído
## Início Rápido
### Instalação
```bash
uv pip install torch_geometric
```
Para dependências adicionais (operações esparsas, clustering):
```bash
uv pip install pyg_lib torch_scatter torch_sparse torch_cluster torch_spline_conv -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html
```
### Criação Básica de Grafos
```python
import torch
from torch_geometric.data import Data
# Create a simple graph with 3 nodes
edge_index = torch.tensor([[0, 1, 1, 2], # source nodes
[1, 0, 2, 1]], dtype=torch.long) # target nodes
x = torch.tensor([[-1], [0], [1]], dtype=torch.float) # node features
data = Data(x=x, edge_index=edge_index)
print(f"Nodes: {data.num_nodes}, Edges: {data.num_edges}")
```
### Carregamento de Dataset de Benchmark
```python
from torch_geometric.datasets import Planetoid
# Load Cora citation network
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0] # Get the first (and only) graph
print(f"Dataset: {dataset}")
print(f"Nodes: {data.num_nodes}, Edges: {data.num_edges}")
print(f"Features: {data.num_node_features}, Classes: {dataset.num_classes}")
```
## Conceitos Principais
### Estrutura de Dados
PyG representa grafos usando a classe `torch_geometric.data.Data` com estes atributos principais:
- **`data.x`**: Matriz de features de nós `[num_nodes, num_node_features]`
- **`data.edge_index`**: Conectividade do grafo em formato COO `[2, num_edges]`
- **`data.edge_attr`**: Matriz de features de arestas `[num_edges, num_edge_features]` (opcional)
- **`data.y`**: Labels alvo para nós ou grafos
- **`data.pos`**: Posições espaciais dos nós `[num_nodes, num_dimensions]` (opcional)
- **Atributos customizados**: Você pode adicionar qualquer atributo (ex: `data.train_mask`, `data.batch`)
**Importante**: Esses atributos não são obrigatórios—estenda objetos Data com atributos customizados conforme necessário.
### Formato de Edge Index
Arestas são armazenadas em formato COO (coordinate) como um tensor `[2, num_edges]`:
- Primeira linha: índices dos nós de origem
- Segunda linha: índices dos nós de destino
```python
# Edge list: (0→1), (1→0), (1→2), (2→1)
edge_index = torch.tensor([[0, 1, 1, 2],
[1, 0, 2, 1]], dtype=torch.long)
```
### Processamento em Mini-Batch
PyG lida com batching criando matrizes de adjacência block-diagonais, concatenando múltiplos grafos em um grande grafo desconectado:
- Matrizes de adjacência são empilhadas diagonalmente
- Features de nós são concatenadas ao longo da dimensão do nó
- Um vetor `batch` mapeia cada nó ao seu grafo de origem
- Sem necessidade de padding—computacionalmente eficiente
```python
from torch_geometric.loader import DataLoader
loader = DataLoader(dataset, batch_size=32, shuffle=True)
for batch in loader:
print(f"Batch size: {batch.num_graphs}")
print(f"Total nodes: {batch.num_nodes}")
# batch.batch maps nodes to graphs
```
## Construindo Graph Neural Networks
### Paradigma de Message Passing
GNNs em PyG seguem um esquema de agregação de vizinhança:
1. Transformar features de nós
2. Propagar mensagens ao longo das arestas
3. Agregar mensagens dos vizinhos
4. Atualizar representações de nós
### Usando Camadas Pré-Construídas
PyG fornece 40+ camadas convolucionais. As mais comuns incluem:
**GCNConv** (Graph Convolutional Network):
```python
from torch_geometric.nn import GCNConv
import torch.nn.functional as F
class GCN(torch.nn.Module):
def __init__(self, num_features, num_classes):
super().__init__()
self.conv1 = GCNConv(num_features, 16)
self.conv2 = GCNConv(16, num_classes)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
```
**GATConv** (Graph Attention Network):
```python
from torch_geometric.nn import GATConv
class GAT(torch.nn.Module):
def __init__(self, num_features, num_classes):
super().__init__()
self.conv1 = GATConv(num_features, 8, heads=8, dropout=0.6)
self.conv2 = GATConv(8 * 8, num_classes, heads=1, concat=False, dropout=0.6)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = F.dropout(x, p=0.6, training=self.training)
x = F.elu(self.conv1(x, edge_index))
x = F.dropout(x, p=0.6, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
```
**GraphSAGE**:
```python
from torch_geometric.nn import SAGEConv
class GraphSAGE(torch.nn.Module):
def __init__(self, num_features, num_classes):
super().__init__()
self.conv1 = SAGEConv(num_features, 64)
self.conv2 = SAGEConv(64, num_classes)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
```
### Camadas de Message Passing Customizadas
Para camadas customizadas, herde de `MessagePassing`:
```python
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degree
class CustomConv(MessagePassing):
def __init__(self, in_channels, out_channels):
super().__init__(aggr='add') # "add", "mean", or "max"
self.lin = torch.nn.Linear(in_channels, out_channels)
def forward(self, x, edge_index):
# Add self-loops to adjacency matrix
edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))
# Transform node features
x = self.lin(x)
# Compute normalization
row, col = edge_index
deg = degree(col, x.size(0), dtype=x.dtype)
deg_inv_sqrt = deg.pow(-0.5)
norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]
# Propagate messages
return self.propagate(edge_index, x=x, norm=norm)
def message(self, x_j, norm):
# x_j: features of source nodes
return norm.view(-1, 1) * x_j
```
Métodos principais:
- **`forward()`**: Ponto de entrada principal
- **`message()`**: Constrói mensagens dos nós de origem para os de destino
- **`aggregate()`**: Agrega mensagens (geralmente não sobrescreva—defina o parâmetro `aggr`)
- **`update()`**: Atualiza embeddings de nós após agregação
**Convenção de nomenclatura**: Adicionar `_i` ou `_j` aos nomes de tensores mapeia automaticamente para nós de destino ou de origem.
## Trabalhando com Datasets
### Carregando Datasets Incorporados
PyG fornece datasets de benchmark extensivos:
```python
# Citation networks (node classification)
from torch_geometric.datasets import Planetoid
dataset = Planetoid(root='/tmp/Cora', name='Cora') # or 'CiteSeer', 'PubMed'
# Graph classification
from torch_geometric.datasets import TUDataset
dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES')
# Molecular datasets
from torch_geometric.datasets import QM9
dataset = QM9(root='/tmp/QM9')
# Large-scale datasets
from torch_geometric.datasets import Reddit
dataset = Reddit(root='/tmp/Reddit')
```
Verifique `references/datasets_reference.md` para uma lista abrangente.
### Criando Datasets Customizados
Para datasets que cabem em memória, herde de `InMemoryDataset`:
```python
from torch_geometric.data import InMemoryDataset, Data
import torch
class MyOwnDataset(InMemoryDataset):
def __init__(self, root, transform=None, pre_transform=None):
super().__init__(root, transform, pre_transform)
self.load(self.processed_paths[0])
@property
def raw_file_names(self):
return ['my_data.csv'] # Files needed in raw_dir
@property
def processed_file_names(self):
return ['data.pt'] # Files in processed_dir
def download(self):
# Download raw data to self.raw_dir
pass
def process(self):
# Read data, create Data objects
data_list = []
# Example: Create a simple graph
edge_index = torch.tensor([[0, 1], [1, 0]], dtype=torch.long)
x = torch.randn(2, 16)
y = torch.tensor([0], dtype=torch.long)
data = Data(x=x, edge_index=edge_index, y=y)
data_list.append(data)
# Apply pre_filter and pre_transform
if self.pre_filter is not None:
data_list = [d for d in data_list if self.pre_filter(d)]
if self.pre_transform is not None:
data_list = [self.pre_transform(d) for d in data_list]
# Save processed data
self.save(data_list, self.processed_paths[0])
```
Para datasets grandes que não cabem em memória, herde de `Dataset` e implemente `len()` e `get(idx)`.
### Carregando Grafos de CSV
```python
import pandas as pd
import torch
from torch_geometric.data import HeteroData
# Load nodes
nodes_df = pd.read_csv('nodes.csv')
x = torch.tensor(nodes_df[['feat1', 'feat2']].values, dtype=torch.float)
# Load edges
edges_df = pd.read_csv('edges.csv')
edge_index = torch.tensor([edges_df['source'].values,
edges_df['target'].values], dtype=torch.long)
data = Data(x=x, edge_index=edge_index)
```
## Workflows de Treinamento
### Classificação de Nós (Grafo Único)
```python
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
# Load dataset
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# Create model
model = GCN(dataset.num_features, dataset.num_classes)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
# Training
model.train()
for epoch in range(200):
optimizer.zero_grad()
out = model(data)
loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
if epoch % 10 == 0:
print(f'Epoch {epoch}, Loss: {loss.item():.4f}')
# Evaluation
model.eval()
pred = model(data).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}')
```
### Classificação de Grafos (Múltiplos Grafos)
```python
from torch_geometric.datasets import TUDataset
from torch_geometric.loader import DataLoader
from torch_geometric.nn import global_mean_pool
class GraphClassifier(torch.nn.Module):
def __init__(self, num_features, num_classes):
super().__init__()
self.conv1 = GCNConv(num_features, 64)
self.conv2 = GCNConv(64, 64)
self.lin = torch.nn.Linear(64, num_classes)
def forward(self, data):
x, edge_index, batch = data.x, data.edge_index, data.batch
x = self.conv1(x, edge_index)
x = F.relu(x)
x = self.conv2(x, edge_index)
x = F.relu(x)
# Global pooling (aggregate node features to graph-level)
x = global_mean_pool(x, batch)
x = self.lin(x)
return F.log_softmax(x, dim=1)
# Load dataset
dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES')
loader = DataLoader(dataset, batch_size=32, shuffle=True)
model = GraphClassifier(dataset.num_features, dataset.num_classes)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# Training
model.train()
for epoch in range(100):
total_loss = 0
for batch in loader:
optimizer.zero_grad()
out = model(batch)
loss = F.nll_loss(out, batch.y)
loss.backward()
optimizer.step()
total_loss += loss.item()
if epoch % 10 == 0:
print(f'Epoch {epoch}, Loss: {total_loss / len(loader):.4f}')
```
### Grafos em Larga Escala com Amostragem de Vizinhos
Para grafos grandes, use `NeighborLoader` para amostrar subgrafos:
```python
from torch_geometric.loader import NeighborLoader
# Create a neighbor sampler
train_loader = NeighborLoader(
data,
num_neighbors=[25, 10], # Sample 25 neighbors for 1st hop, 10 for 2nd hop
batch_size=128,
input_nodes=data.train_mask,
)
# Training
model.train()
for batch in train_loader:
optimizer.zero_grad()
out = model(batch)
# Only compute loss on seed nodes (first batch_size nodes)
loss = F.nll_loss(out[:batch.batch_size], batch.y[:batch.batch_size])
loss.backward()
optimizer.step()
```
**Importante**:
- Subgrafos de saída são direcionados
- Índices de nós são renomeados (0 a batch.num_nodes - 1)
- Use apenas predições de nós seed para computar a perda
- Amostragem além de 2-3 saltos geralmente não é viável
## Funcionalidades Avançadas
### Grafos Heterogêneos
Para grafos com múltiplos tipos de nós e arestas, use `HeteroData`:
```python
from torch_geometric.data import HeteroData
data = HeteroData()
# Add node features for different types
data['paper'].x = torch.randn(100, 128) # 100 papers with 128 features
data['author'].x = torch.randn(200, 64) # 200 authors with 64 features
# Add edges for different types (source_type, edge_type, target_type)
data['author', 'writes', 'paper'].edge_index = torch.randint(0, 200, (2, 500))
data['paper', 'cites', 'paper'].edge_index = torch.randint(0, 100, (2, 300))
print(data)
```
Converta modelos homogêneos para heterogêneos:
```python
from torch_geometric.nn import to_hetero
# Define homogeneous model
model = GNN(...)
# Convert to heterogeneous
model = to_hetero(model, data.metadata(), aggr='sum')
# Use as normal
out = model(data.x_dict, data.edge_index_dict)
```
Ou use `HeteroConv` para operações customizadas específicas do tipo de aresta:
```python
from torch_geometric.nn import HeteroConv, GCNConv, SAGEConv
class HeteroGNN(torch.nn.Module):
def __init__(self, metadata):
super().__init__()
self.conv1 = HeteroConv({
('paper', 'cites', 'paper'): GCNConv(-1, 64),
('author', 'writes', 'paper'): SAGEConv((-1, -1), 64),
}, aggr='sum')
self.conv2 = HeteroConv({
('paper', 'cites', 'paper'): GCNConv(64, 32),
('author', 'writes', 'paper'): SAGEConv((64, 64), 32),
}, aggr='sum')
def forward(self, x_dict, edge_index_dict):
x_dict = self.conv1(x_dict, edge_index_dict)
x_dict = {key: F.relu(x) for key, x in x_dict.items()}
x_dict = self.conv2(x_dict, edge_index_dict)
return x_dict
```
### Transforms
Aplique transforms para modificar estrutura ou features do grafo:
```python
from torch_geometric.transforms import NormalizeFeatures, AddSelfLoops, Compose
# Single transform
transform = NormalizeFeatures()
dataset = Planetoid(root='/tmp/Cora', name='Cora', transform=transform)
# Compose multiple transforms
transform = Compose([
AddSelfLoops(),
NormalizeFeatures(),
])
dataset = Planetoid(root='/tmp/Cora', name='Cora', transform=transform)
```
Transforms comuns:
- **Estrutura**: `ToUndirected`, `AddSelfLoops`, `RemoveSelfLoops`, `KNNGraph`, `RadiusGraph`
- **Features**: `NormalizeFeatures`, `NormalizeScale`, `Center`
- **Amostragem**: `RandomNodeSplit`, `RandomLinkSplit`
- **Positional Encoding**: `AddLaplacianEigenvectorPE`, `AddRandomWalkPE`
Veja `references/transforms_reference.md` para a lista completa.
### Explicabilidade de Modelo
PyG fornece ferramentas de explicabilidade para entender predições do modelo:
```python
from torch_geometric.explain import Explainer, GNNExplainer
# Create explainer
explainer = Explainer(
model=model,
algorithm=GNNExplainer(epochs=200),
explanation_type='model', # or 'phenomenon'
node_mask_type='attributes',
edge_mask_type='object',
model_config=dict(
mode='multiclass_classification',
task_level='node',
return_type='log_probs',
),
)
# Generate explanation for a specific node
node_idx = 10
explanation = explainer(data.x, data.edge_index, index=node_idx)
# Visualize
print(f'Node {node_idx} explanation:')
print(f'Important edges: {explanation.edge_mask.topk(5).indices}')
print(f'Important features: {explanation.node_mask[node_idx].topk(5).indices}')
```
### Operações de Pooling
Para representações hierárquicas de grafos:
```python
from torch_geometric.nn import TopKPooling, global_mean_pool
class HierarchicalGNN(torch.nn.Module):
def __init__(self, num_features, num_classes):
super().__init__()
self.conv1 = GCNConv(num_features, 64)
self.pool1 = TopKPooling(64, ratio=0.8)
self.conv2 = GCNConv(64, 64)
self.pool2 = TopKPooling(64, ratio=0.8)
self.lin = torch.nn.Linear(64, num_classes)
def forward(self, data):
x, edge_index, batch = data.x, data.edge_index, data.batch
x = F.relu(self.conv1(x, edge_index))
x, edge_index, _, batch, _, _ = self.pool1(x, edge_index, None, batch)
x = F.relu(self.conv2(x, edge_index))
x, edge_index, _, batch, _, _ = self.pool2(x, edge_index, None, batch)
x = global_mean_pool(x, batch)
x = self.lin(x)
return F.log_softmax(x, dim=1)
```
## Padrões Comuns e Melhores Práticas
### Verificar Propriedades do Grafo
```python
# Undirected check
from torch_geometric.utils import is_undirected
print(f"Is undirected: {is_undirected(data.edge_index)}")
# Connected components
from torch_geometric.utils import connected_components
print(f"Connected components: {connected_components(data.edge_index)}")
# Contains self-loops
from torch_geometric.utils import contains_self_loops
print(f"Has self-loops: {contains_self_loops(data.edge_index)}")
```
### Treinamento em GPU
```python
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
data = data.to(device)
# For DataLoader
for batch in loader:
batch = batch.to(device)
# Train...
```
### Salvar e Carregar Modelos
```python
# Save
torch.save(model.state_dict(), 'model.pth')
# Load
model = GCN(num_features, num_classes)
model.load_state_dict(torch.load('model.pth'))
model.eval()
```
### Capacidades de Camadas
Ao escolher camadas, considere essas capacidades:
- **SparseTensor**: Suporta operações eficientes com matrizes esparsas
- **edge_weight**: Lida com pesos de arestas unidimensionais
- **edge_attr**: Processa features de arestas multidimensionais
- **Bipartite**: Funciona com grafos bipartidos (dimensões diferentes de origem/destino)
- **Lazy**: Habilita inicialização sem especificar dimensões de entrada
Veja o cheatsheet de GNN em `references/layer_capabilities.md`.
## Recursos
### Referências Incluídas
Esta skill inclui documentação de referência detalhada:
- **`references/layers_reference.md`**: Listagem completa de todos os 40+ layers de GNN com descrições e capacidades
- **`references/datasets_reference.md`**: Catálogo abrangente de datasets organizado por categoria
- **`references/transforms_reference.md`**: Todos os transforms disponíveis e seus casos de uso
- **`references/api_patterns.md`**: Padrões comuns de API e exemplos de código
### Scripts
Scripts de utilidade são fornecidos em `scripts/`:
- **`scripts/visualize_graph.py`**: Visualiza estrutura do grafo usando networkx e matplotlib
- **`scripts/create_gnn_template.py`**: Gera código boilerplate para arquiteturas GNN comuns
- **`scripts/benchmark_model.py`**: Benchmarks de desempenho do modelo em datasets padrão
Execute scripts diretamente ou leia-os para padrões de implementação.
### Recursos Oficiais
- **Documentação**: https://pytorch-geometric.readthedocs.io/
- **GitHub**: https://github.com/pyg-team/pytorch_geometric
- **Tutorials**: https://pytorch-geometric.readthedocs.io/en/latest/get_started/introduction.html
- **Examples**: https://github.com/pyg-team/pytorch_geometric/tree/master/examplesIs this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!