Hai già scritto codice che funziona, ma quando provi a costruire una rete neurale con PyTorch ti perdi tra tensori, autograd e moduli. Non sei il primo. Il framework è potente, ma la curva di apprendimento è verticale se arrivi da stack tradizionali. Noi, di Meteora Web, lo usiamo quotidianamente per progetti di machine learning applicato a clienti reali. Come per ogni strumento, il trucco è capire i fondamenti prima di scrivere una riga di codice. Questa guida ti porta direttamente al punto: creare, addestrare e valutare una rete neurale con PyTorch, senza fronzoli.
Perché PyTorch?
PyTorch è diventato lo standard de facto per la ricerca e la produzione nel deep learning per un motivo: unisce flessibilità e controllo. A differenza di framework come TensorFlow (nella sua versione 1.x), PyTorch usa un grafo computazionale dinamico: puoi eseguire codice Python normale, fare debug con print() e modificare la struttura della rete al volo. Se vieni dallo sviluppo web, puoi pensarlo come un ambiente in cui la logica di rete è scritta con lo stesso linguaggio del resto dell’applicazione.
Dinamico vs Statico
In un grafo statico (TensorFlow 1.x), definisci prima il grafo, poi lo esegui. Con PyTorch il grafo viene costruito al volo durante la forward pass. Questo significa che puoi usare condizioni, cicli e funzioni Python senza trucchi. Per uno sviluppatore, è una manna: il codice riflette esattamente ciò che accade.
Sponsored Protocol
Integrazione Python
PyTorch è una libreria Python pura (con runtime C++ sotto). Tensori, autograd, moduli: tutto è accessibile da Python. Non c’è un linguaggio di template separato, nessun file di configurazione astratto. Se sai Python, sai già metà di PyTorch.
Azioni immediate per te: apri un terminale e installa PyTorch con pip install torch torchvision. Poi verifica con python -c "import torch; print(torch.__version__)".
I mattoni fondamentali: Tensori, Autograd e nn.Module
Tensori: il nuovo array
Il tensore è l’equivalente PyTorch di un array NumPy, ma con supporto GPU e tracciamento automatico delle derivate. Ogni dato che entra in una rete neurale deve essere convertito in un tensore.
import torch
# Tensore da lista
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print(x.shape) # torch.Size([2, 2])
# Tensore da numpy
import numpy as np
np_array = np.array([1, 2, 3])
x_tensor = torch.from_numpy(np_array)
# Tensore su GPU (se disponibile)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x_gpu = x.to(device)
Errore comune: dimenticare di convertire i dati in float32. PyTorch richiede float32 per default nelle reti neurali. np.float64 o int64 causano errori silenziosi o di tipo.
Autograd: le derivate automatiche
Ogni tensore con requires_grad=True registra le operazioni eseguite su di esso. Alla chiusa .backward(), PyTorch calcola i gradienti rispetto a quel tensore. È il cuore del training.
Sponsored Protocol
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x[0]2 + x[1]3
y.backward()
print(x.grad) # tensor([4., 27.]) -> derivate: 2*x[0], 3*x[1]^2
Attenzione: i gradienti si accumulano. Dopo ogni passo di ottimizzazione, azzerali con optimizer.zero_grad() o manualmente.
nn.Module: la classe base per ogni rete
Tutti i modelli in PyTorch ereditano da torch.nn.Module. Definisci i layer in __init__ e la forward pass in forward.
import torch.nn as nn
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(10, 50)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(50, 2)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
return self.fc2(x)
Costruire una rete neurale completa: passo dopo passo
Prendiamo un problema concreto: classificazione binaria su dati bidimensionali (es. separare due cluster).
1. Generiamo dati di esempio
import torch
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
X, y = make_moons(n_samples=1000, noise=0.1, random_state=42)
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.long) # CrossEntropyLoss vuole long
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
2. Definiamo il modello
class BinaryClassifier(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(2, 16),
nn.ReLU(),
nn.Linear(16, 16),
nn.ReLU(),
nn.Linear(16, 2) # output logits per 2 classi
)
def forward(self, x):
return self.net(x)
model = BinaryClassifier()
3. Loss e ottimizzatore
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
4. Training loop
epochs = 100
batch_size = 32
for epoch in range(epochs):
# Mescoliamo i dati
perm = torch.randperm(len(X_train))
X_train_shuffled = X_train[perm]
y_train_shuffled = y_train[perm]
for i in range(0, len(X_train), batch_size):
X_batch = X_train_shuffled[i:i+batch_size]
y_batch = y_train_shuffled[i:i+batch_size]
# Forward
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
# Backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch+1) % 10 == 0:
with torch.no_grad():
val_outputs = model(X_val)
val_loss = criterion(val_outputs, y_val)
_, predicted = torch.max(val_outputs, 1)
acc = (predicted == y_val).float().mean()
print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}, Val Loss: {val_loss.item():.4f}, Acc: {acc.item():.2f}')
Nota: stai costruendo il loop a mano. In produzione usa DataLoader per batching automatico (vedi sezione best practice).
Sponsored Protocol
Spostare su GPU: accelerazione reale
Il vero potere di PyTorch è la GPU. Basta spostare modello e dati sul device corretto.
Sponsored Protocol
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
# Nel loop:
X_batch = X_batch.to(device)
y_batch = y_batch.to(device)
Errore comune: dimenticare di spostare anche i target. I gradienti non si propagano se i tensori sono su device diversi. Controlla sempre con tensor.device.
Best practice per sviluppatori che passano alla produzione
Usare DataLoader
Invece di gestire manualmente i batch, usa torch.utils.data.DataLoader. Offre shuffling, parallelismo e mini-batch automatico.
from torch.utils.data import TensorDataset, DataLoader
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
for X_batch, y_batch in train_loader:
# già pronti
pass
Salvare e caricare il modello
Salva solo i state_dict (pesi) per flessibilità e sicurezza. Mai l’intero oggetto.
# Salvare
torch.save(model.state_dict(), 'model.pth')
# Caricare
model = BinaryClassifier()
model.load_state_dict(torch.load('model.pth', map_location=device))
model.eval()
Modalità evaluation
Prima di fare predizioni, chiama model.eval(). Disabilita dropout e batch normalization. Dopo il training, rimetti model.train() se riprendi.
Sponsored Protocol
Tracciamento con TensorBoard
Usa torch.utils.tensorboard per loggare loss, metriche e grafi. È uno strumento che abbiamo integrato in diverse piattaforme per i nostri clienti.
In sintesi — cosa fare adesso
- Installa PyTorch sul tuo ambiente di sviluppo (
pip install torch torchvision). - Copia il codice sopra per la classificazione binaria e fallo girare. Sperimenta con più layer, attivazioni diverse (ReLU, Tanh, GELU).
- Passa a un dataset reale: carica MNIST o CIFAR-10 con
torchvision.datasetse adatta la rete (input dimensioni, output). - Aggiungi GPU se disponi di una scheda NVIDIA. Nota la differenza di velocità.
- Leggi la documentazione ufficiale: PyTorch Docs è chiara e completa.
Noi, di Meteora Web, abbiamo costruito modelli PyTorch per clienti che vanno dal riconoscimento di documenti alla previsione di vendite. Il framework è incredibilmente potente se lo tratti come un'estensione di Python — non come una scatola nera. Inizia con questi fondamentali e il resto verrà da sé.
Per approfondire l'uso dell'AI nel lavoro quotidiano, leggi la nostra guida su Prompt per sviluppatori.