Logo VRAMfarm VRAMfarm
IT
Registrati

12 novembre 2026 · Team VRAMfarm

Training multi-GPU: DDP, FSDP e ZeRO su una macchina a noleggio con 2–8 GPU

Quattro GPU in un server collegate da linee di dati, con i pezzi del modello distribuiti tra loro: le basi del training multi-GPU con DDP, FSDP e ZeRO

Quattro schede noleggiate, lo script lanciato con python train.py, e nvidia-smi mostra una scheda al 100% e tre allo 0%. Non c’è niente di rotto. Uno script di training usa una sola GPU, a meno che non venga avviato da un launcher che esegue un processo per scheda, e il lavoro va diviso in un modo adatto al tuo modello. I modi per dividerlo sono due: dare a ogni scheda una copia del modello e una parte dei dati, oppure tagliare il modello stesso in pezzi. Quale ti serve dipende dal fatto che il modello stia o no su una scheda.

Prima di tutto: ti serve davvero più di una scheda?

I motivi per usare più GPU sono solo due: il lavoro non ci sta nella memoria di una scheda, oppure su una scheda ci mette troppo. Prima di passare a una macchina multi-GPU, controlla se una sola scheda più grande risolve il problema. Una scheda è sempre più semplice: niente launcher, niente comunicazione tra schede, niente errori di NCCL.

Lavoro Una scheda che basta Quando più schede hanno senso
LoRA o QLoRA su un modello fino a 70B 24–80 GB, vedi la guida alla VRAM Di rado; per addestrare più in fretta su un dataset grande
Fine-tuning completo di un modello da 7–8B Una scheda da 80 GB con ottimizzatore a 8 bit, o una H200 (141 GB) Per usare l’ottimizzatore standard, sequenze più lunghe o un training più breve
Fine-tuning completo di un modello da 13–70B Nessuna con l’ottimizzatore standard; un 13B sta su una scheda da 141–192 GB solo con ottimizzatore a 8 bit Quasi sempre: 4–8 schede con FSDP o ZeRO-3
Addestrare un modello piccolo su tanti dati Qualsiasi scheda che lo contenga Per portare un training da 40 ore a 10
Servire un modello da 70B in fp8 H200 2 × H100 con vLLM, vedi H200 o H100

Le schede singole più grandi del catalogo sono la B200 con 192 GB, la H200 con 141 GB e la RTX PRO 6000 con 96 GB. Se una di queste contiene il tuo lavoro, parti da lì.

Data parallel: lo stesso modello su ogni scheda

Il training data parallel (PyTorch DDP) esegue un processo per GPU. Ogni processo tiene una copia completa del modello, prende una fetta diversa di ogni batch, calcola i suoi gradienti, e poi tutte le schede fanno la media dei gradienti prima dello step dell’ottimizzatore. Le schede restano identiche, e N schede elaborano N volte più dati per step.

Serve una sola condizione: modello, gradienti, stati dell’ottimizzatore e attivazioni devono stare su una scheda. Se ci stanno, DDP è il modo più semplice per andare più veloce. Lanci lo script con un launcher invece che con python:

torchrun --nproc_per_node=4 train.py        # PyTorch puro, Hugging Face Trainer
accelerate launch --num_processes 4 train.py  # Hugging Face Accelerate

L’Hugging Face Trainer e la maggior parte degli strumenti di fine-tuning (Axolotl, LLaMA-Factory, torchtune) passano a DDP da soli quando li avvii così. In PyTorch puro avvolgi il modello in DistributedDataParallel e aggiungi un DistributedSampler.

Il prezzo è la comunicazione: dopo ogni step le schede si scambiano una copia dei gradienti. Per un modello da 1B in bf16 sono circa 2 GB per step, che il PCIe gestisce mentre il backward pass è ancora in corso. Aspettati che due schede rendano circa 1,7–1,9 volte la velocità di una e quattro schede circa 3–3,7 volte, meno per modelli più grandi su macchine senza NVLink.

Quando il modello non ci sta: FSDP e DeepSpeed ZeRO

Con l’ottimizzatore AdamW standard in mixed precision, ogni parametro costa circa 16 byte: 2 per i pesi bf16, 2 per i gradienti e 12 per l’ottimizzatore (una copia master in fp32 e due stime dei momenti). Per un modello da 8B fanno 128 GB prima delle attivazioni, più di qualsiasi scheda singola da 80 GB.

Lo sharding distribuisce quei 16 byte tra le schede invece di copiarli. DeepSpeed lo chiama ZeRO e ha tre stadi; FSDP di PyTorch fa la stessa cosa con nomi diversi. Per un modello da 8B:

Metodo Cosa tiene ogni scheda Per scheda, 4 schede Per scheda, 8 schede
DDP Tutto 128 GB 128 GB
ZeRO-1 Pesi, gradienti, 1/N dell’ottimizzatore 56 GB 44 GB
ZeRO-2, FSDP SHARD_GRAD_OP Pesi, 1/N di gradienti e ottimizzatore 44 GB 30 GB
ZeRO-3, FSDP FULL_SHARD 1/N di tutto 32 GB 16 GB

Le attivazioni si aggiungono sopra, da pochi GB a decine di GB per scheda a seconda della lunghezza delle sequenze e del batch size; il gradient checkpointing le riduce al prezzo di circa un terzo di calcolo in più. Come leggere la tabella: 4 schede da 80 GB gestiscono comodamente un fine-tuning completo di un 8B con ZeRO-2 o ZeRO-3, 4 schede da 48 GB con ZeRO-3, e le schede da 24 GB solo se sono 8, oppure con l’offload dell’ottimizzatore sulla RAM della CPU.

FSDP fa parte di PyTorch; DeepSpeed si configura con un file JSON. L’Hugging Face Trainer e Accelerate li supportano entrambi. Il CPU offload (ZeRO-Offload, FSDP cpu_offload) sposta gli stati dell’ottimizzatore nella RAM di sistema e permette a schede piccole di addestrare modelli grandi, lentamente, e solo se la macchina ha la RAM.

ZeRO-3 ha un costo che sulle macchine a noleggio pesa: a ogni step sono i pesi stessi a viaggiare tra le schede. Per un modello da 8B su quattro schede sono circa 35–50 GB per scheda per step. Via NVLink su una macchina H100 basta una frazione di secondo; via PCIe possono servire secondi, e le schede aspettano. Per questo il tipo di collegamento conta.

Tensor e pipeline parallel, e cosa si usa per l’inferenza

Il tensor parallel taglia ogni matrice di pesi in fette, una per scheda, e scambia dati a ogni layer, quindi funziona bene solo via NVLink. Il pipeline parallel mette layer diversi su schede diverse, con meno traffico ma con schede ferme mentre la pipeline si riempie. I framework di pre-training come Megatron li combinano; per il fine-tuning di solito bastano FSDP o ZeRO.

Per l’inferenza il quadro è più semplice. vLLM divide un modello con --tensor-parallel-size 2 (o 4, 8), mentre llama.cpp e Ollama distribuiscono i layer sulle schede da soli. L’inferenza manda pochi dati tra le schede, quindi gira in modo accettabile anche via PCIe.

Una trappola: device_map="auto" in Hugging Face Transformers distribuisce i layer sulle schede e li esegue uno dopo l’altro. Il modello ci sta, ma in ogni momento lavora una sola scheda. Va bene per provare un modello grande, non per la velocità di training.

Collegamento Velocità tra le schede, circa Dove lo trovi
PCIe 4.0 x16 25–32 GB/s per direzione RTX 3090, RTX 4090, A6000, la maggior parte delle schede PCIe
PCIe 5.0 x16 50–64 GB/s per direzione RTX 5090, RTX PRO 6000, server più recenti
Bridge NVLink, RTX 3090 circa 112 GB/s Raro sulle macchine a noleggio
NVLink, A100 SXM 600 GB/s Schede madri A100 SXM da 4 e 8 schede
NVLink, H100 / H200 SXM 900 GB/s Schede madri SXM da 4 e 8 schede

Le schede consumer aggiungono un altro limite: la RTX 4090 non supporta i trasferimenti diretti peer-to-peer, quindi i dati tra le schede passano dalla memoria di sistema. Le macchine con più 4090 vanno bene per l’inferenza e per DDP su modelli piccoli, male per ZeRO-3 su modelli grandi.

Il catalogo mostra il nome della scheda prima dell’avvio. “SXM” o “SXM4” vuol dire che le schede stanno su una scheda madre pensata per NVLink; le schede PCIe possono avere i bridge oppure no. Il filtro “PCIe” del catalogo indica la velocità del bus tra CPU e GPU. Conta per caricare dati e modelli (una scheda su uno slot stretto x4 carica lentamente), ma non dice niente sui collegamenti tra le schede. Per quelli, lancia questo subito dopo l’avvio:

nvidia-smi topo -m

NV4, NV12 o NV18 tra due schede significa NVLink. PIX e PXB indicano uno switch PCIe, PHB il bridge PCIe della CPU, e NODE o SYS un percorso che attraversa la CPU, il più lento.

Noleggiare una macchina multi-GPU su VRAMfarm

  1. Scegli la macchina. Nel catalogo dei server, imposta “Schede per macchina” su 2×, 4× o 8×. Il prezzo è orario per l’intera macchina, più o meno il numero di schede per il prezzo di una: da 2,36 € all’ora per 4 × RTX 4090, da 31,20 € per 8 × H100. Ogni riga mostra nome della scheda, core CPU, RAM, disco, driver, versione CUDA e paese.
  2. Usa i filtri che contano per il training. VRAM per macchina, RAM (almeno pari alla VRAM totale), core CPU (4–8 per scheda), disco libero (un checkpoint completo di un modello da 8B con gli stati dell’ottimizzatore supera i 100 GB) e “Durata del noleggio”, cioè per quanti giorni di fila puoi tenere la macchina. Per i training lunghi lascia un margine.
  3. Scegli un server vuoto. PyTorch con Jupyter, oppure una tua immagine Docker. Per avviare, il credito deve coprire un’ora dell’intera macchina; è un controllo, non un addebito, e la fatturazione è al minuto.
  4. Controlla la macchina nei primi minuti. Lancia nvidia-smi, nvidia-smi topo -m e python -c "import torch; print(torch.cuda.device_count())". Se qualcosa non va, ferma il server: paghi il minimo di 15 minuti, non l’ora.
  5. Fai un breve test di comunicazione prima del lavoro vero:
# nccl_check.py: avvialo con  torchrun --nproc_per_node=4 nccl_check.py
import os, time, torch, torch.distributed as dist
rank = int(os.environ["LOCAL_RANK"]); torch.cuda.set_device(rank)
dist.init_process_group("nccl")
x = torch.ones(512 * 1024**2, dtype=torch.bfloat16, device="cuda")  # 1 GiB
for _ in range(3): dist.all_reduce(x)
torch.cuda.synchronize(); t = time.time()
for _ in range(10): dist.all_reduce(x)
torch.cuda.synchronize()
if rank == 0: print(f"{10 / (time.time() - t):.1f} all-reduces of 1 GiB per second")
dist.destroy_process_group()

Se stampa un numero, le schede si parlano; una macchina con NVLink dovrebbe essere molte volte più veloce di una PCIe. Se si blocca, guarda il primo problema dell’elenco qui sotto.

L’API accetta il numero di schede come count, quindi uno script può avviare una macchina da 8 schede per un lavoro notturno e fermarla quando ha finito.

Problemi comuni

  • NCCL si blocca o dà “unhandled system error”. Avvia con NCCL_DEBUG=INFO per vedere dove si ferma. Sulle schede consumer, NCCL_P2P_DISABLE=1 spesso risolve i blocchi. Se un processo è andato in crash, gli altri lo aspettano fino al timeout, quindi cerca il primo errore nel log, non l’ultimo.
  • Memoria condivisa troppo piccola. Dentro i container, /dev/shm a volte è di poche decine di megabyte, e questo manda in errore NCCL e i data loader con “bus error”. Controlla con df -h /dev/shm; abbassa num_workers o prova NCCL_SHM_DISABLE=1.
  • Il batch size è cambiato senza che te ne accorgessi. Batch globale = batch per scheda × numero di schede × step di gradient accumulation. Passando da 1 a 4 schede con la stessa configurazione, il batch diventa quattro volte più grande e l’epoca quattro volte più corta in step. Abbassa gli step di accumulation per tenere fisso il batch globale, oppure alza il learning rate: più o meno in modo lineare per SGD, con più cautela (radice quadrata) per Adam, con un warm-up.
  • Ogni scheda vede gli stessi dati. Senza un DistributedSampler tutte le schede si addestrano su batch identici; senza sampler.set_epoch(epoch) ogni epoca ha lo stesso ordine. L’Hugging Face Trainer gestisce entrambe le cose.
  • Quattro copie di ogni log e checkpoint. Scrivi i file solo sul rank 0. Un checkpoint FSDP completo viene raccolto nella RAM di un solo processo; i checkpoint sharded lo evitano.
  • “System not yet initialized” su una macchina SXM da 8 schede. Dipende dal fabric NVLink dell’host, non dal tuo codice. Ferma il server, scegli un’altra macchina e avvisa l’assistenza.

I training lunghi chiedono due abitudini. Avvia il training dentro tmux, così sopravvive anche se chiudi il portatile. Salva i checkpoint ogni 30–60 minuti in /workspace, tieni solo gli ultimi due e, per i training di più di un giorno, copiali fuori dalla macchina: il disco del server viene cancellato allo stop, a meno che tu non salvi la cartella (cosa succede ai tuoi file). Finché le GPU lavorano, il rilevamento dell’inattività lascia stare il server. Quando il training finisce, inizia a contare: dopo 2 ore senza carico sulla GPU né connessioni SSH o Jupyter ricevi un’email, e un’ora dopo la cartella viene salvata e il server si ferma. Puoi disattivarlo, e i server avviati da una tua immagine Docker non si fermano in automatico. Un’alternativa più economica è un’ultima riga nello script che ferma il server tramite l’API.

Parti con due schede e un training breve, misura il tempo per step, poi passa a quattro o otto. Se due schede non sono vicine al doppio della velocità, più schede non risolveranno il problema; guarda prima il collegamento tra loro.

Domande sull’argomento

Posso mescolare GPU diverse nella stessa macchina?

No. Ogni macchina del catalogo ha schede di un solo modello, indicate per esempio come «4× RTX 4090». Ed è proprio quello che ti serve: nel training data parallel, a ogni step tutte le schede aspettano la più lenta.

ComfyUI o Ollama usano tutte le schede?

Ollama, llama.cpp e vLLM possono distribuire un modello linguistico su più schede. ComfyUI esegue un workflow su una sola scheda, quindi su una macchina con 4 GPU avvieresti quattro istanze di ComfyUI, ognuna sulla sua scheda con CUDA_VISIBLE_DEVICES, per generare quattro batch in parallelo.

Quanti core CPU e quanta RAM servono per GPU?

Come regola pratica, 4–8 core CPU per GPU, così il caricamento dei dati tiene il passo, e almeno tanta RAM di sistema quanta è la VRAM totale della macchina. Il CPU offload in DeepSpeed o FSDP ne chiede molta di più: il solo offload dell'ottimizzatore di un modello da 8B occupa circa 100 GB di RAM.

Cosa succede al mio training se la macchina si guasta?

La fatturazione si ferma dal momento in cui la macchina è sparita e ricevi una notifica, ma il disco del server se ne va con lei. Per i training più lunghi di qualche ora, copia regolarmente i checkpoint fuori dalla macchina, per esempio in un repository privato su Hugging Face o in un tuo bucket S3.

Trova la GPU in cui entra il tuo modello

Scegli un modello e vedi la scheda più economica con VRAM sufficiente, con fatturazione al minuto in euro.