Introduzione al rank sweep con LoRA
Le ultime release di Hugging Face, PEFT v0.21.3 e TRL v1.18.0, costituiscono lo stack di base per la maggior parte dei lavori di fine‑tuning LoRA. Un rank sweep costruito su queste librerie testa esattamente la configurazione che verrà poi messa in produzione. Il laboratorio qui presentato addestra lo stesso adapter a cinque diversi rank su una singola GPU, valuta ogni esecuzione su un set di test riservato e infine fonde il modello vincente in un modello autonomo.
Molti tutorial LoRA si fermano al primo training e a un risultato fortunato, lasciando aperte domande cruciali che incidono sui costi: il rank 64 supera davvero il rank 8? L’alpha ha un impatto significativo? L’adapter ha realmente appreso il compito o ha semplicemente memorizzato i template? Il sweep fornisce risposte numeriche basate sul proprio hardware in circa 90 minuti.
Perché LoRA resta la scelta vincente a novembre 2026
LoRA congela tutti i pesi del modello di base e aggiunge due piccole matrici accanto a ciascun layer adattato. Il prodotto di queste matrici funge da correzione appresa al peso originale. Poiché solo le piccole matrici ricevono gradienti, lo stato dell’ottimizzatore si riduce da miliardi a pochi milioni di valori, e l’artifact salvato è un file che si può inviare via email anziché un checkpoint da 15 GB.
QLoRA aggiunge un passaggio: il modello di base viene caricato in precisione a 4 bit, mentre l’adapter si addestra in precisione più alta sopra di esso. La documentazione di Hugging Face indica un risparmio di memoria fino a quattro volte rispetto a un caricamento LoRA standard, consentendo di far girare il lavoro su una scheda da 24 GB che altrimenti non basterebbe.
Il metodo scala ancora. Il 29 ottobre 2026 Hugging Face ha annunciato il supporto “day‑zero” di TRL per Mistral Large 4, invitando gli utenti ad aggiornare transformers, trl e peft. Le note di rilascio di TRL v1.18.0 includono un esempio di fine‑tuning supervisionato LoRA per Mistral Large 4 su un singolo nodo con otto GPU B300 in FP8. La stessa versione aggiunge supporto per le varianti Gemma 4 e le revisioni Qwen3.8, coprendo così modelli da 1,5 B a un trilione di parametri con lo stesso oggetto LoraConfig.
La domanda è reale: il “Stack Overflow Developer Survey 2025” ha rilevato che l’84 % degli sviluppatori usa o prevede di usare strumenti AI. Le squadre che già gestiscono modelli open‑weight vogliono adattarli a compiti privati, e LoRA è il metodo più economico per farlo.
Confronto di LoRA con altre tecniche di adattamento
Tabella comparativa
- Prompting: nessuna modifica al modello, memoria nulla, ideale per compiti con istruzioni brevi e pochi esempi.
- Retrieval (RAG): utilizza la finestra di contesto, consumo di memoria basso, adatto quando la risposta proviene da documenti che cambiano frequentemente.
- LoRA: aggiunge piccole matrici adapter, consumo di memoria moderato, consigliato per formati di output fissi, toni specifici o abilità ristrette.
- QLoRA: adapter su modello base a 4 bit, consumo fino a quattro volte inferiore rispetto a LoRA, necessario quando il modello base fatica a entrare in GPU a 16 bit.
- Full fine‑tuning: modifica tutti i pesi, consumo di memoria massimo, riservato a dataset molto grandi, più GPU e quando gli adapter non bastano.
Fine‑tuning non sostituisce il retrieval: insegna comportamenti, non fatti. Un classificatore di ticket che deve sempre restituire JSON è un classico caso d’uso LoRA; un chatbot che deve citare il listino prezzi della settimana corrente richiede retrieval.
Come rank, alpha e dropout influenzano un run LoRA
Ogni impostazione LoRA si riduce a quattro numeri e una lista:
- Rank (r): numero di colonne delle matrici adapter, limita la capacità espressiva.
- Alpha (lora_alpha): scala l’output dell’adapter; il moltiplicatore effettivo è alpha / rank.
- Dropout: azzera casualmente le attivazioni dell’adapter per ridurre l’overfitting.
- Learning rate: intensità di ogni passo di aggiornamento.
- target_modules: lista dei layer a cui applicare gli adapter.
Il numero di parametri addestrabili cresce linearmente con il rank. Per una matrice di peso con din ingressi e dout uscite, l’adapter aggiunge r * (din + dout) valori. Raddoppiare il rank raddoppia il costo su tutti i layer target, per questo il sweep stampa il conteggio dei parametri accanto a ogni punteggio. Un rank che guadagna mezzo punto ma triplica la dimensione del file difficilmente merita di essere distribuito.
L’alpha può confondere i neofiti: poiché il moltiplicatore è alpha / rank, aumentare il rank mantenendo alpha fisso riduce l’influenza dell’adapter. Il sweep mantiene costante il rapporto impostando alpha pari a due volte il rank, una convenzione ampiamente usata. PEFT offre anche lo scaling stabilizzato per rank (use_rslora=True) che divide per la radice quadrata del rank; è una seconda sperimentazione, non parte del primo sweep.
Per il dropout, lo strumento Hugging Face usa 0.05 di default, con un range tipico 0.05‑0.1. Un compito molto strutturato, come quello del laboratorio, ha poco da sovra‑adattare a rank bassi, quindi il valore di default è adeguato. È importante verificare la licenza del modello prima di addestrare: la tabella di comparazione delle licenze per sei famiglie di modelli open‑weight indica quali consentono adapter derivati in prodotti commerciali.
Valori di partenza e intervalli di sweep consigliati
| Impostazione | Valore di partenza | Intervallo di sweep | Cosa monitorare |
|---|---|---|---|
| Rank (r) | 16 | 4, 8, 16, 32, 64 | Guadagno di punteggio per parametro addestrabile extra |
| Alpha | 2 × rank | Fisso rapporto iniziale | Possibili divergenze se il rapporto è troppo alto |
| Dropout | 0.05 | 0.0 – 0.1 | Gap tra loss di training e punteggio di valutazione |
| Learning rate | 2e‑4 | 1e‑4 – 3e‑4 | Picchi di loss nei primi 50 step |
| Target modules | all‑linear | Attenzione‑only vs all | Qualità vs dimensione dell’adapter |
| Epochs | 2 | 1 – 3 | Punteggio di valutazione che cala mentre la loss continua a scendere |
I valori di partenza sono quelli più comuni nella community, non raccomandazioni ufficiali di Hugging Face. Il sweep serve a sostituirli con valori misurati per il proprio compito.
Prerequisiti hardware, software e versioni pinneate
Il laboratorio è stato testato su una singola GPU NVIDIA sotto Linux o WSL2. Una scheda da 16 GB gestisce il modello di default da 1,5 B in bfloat16 senza quantizzazione. Passando a modelli da 7‑8 B con il flag --q4, il consumo di VRAM si aggira tra 8 e 12 GB, poiché i pesi a 4 bit occupano circa 4‑5 GB e il resto è destinato a attivazioni, stato dell’adapter e overhead del framework.
Le variabili più influenti sulla memoria sono la lunghezza della sequenza e la dimensione del batch. Chi vuole dimensionare l’hardware per modelli più grandi può consultare la tabella di memoria nella guida locale Qwen3.8‑27B.
Versioni consigliate
- Python: 3.11 o superiore
- PyTorch: ultima build stabile compatibile con il driver CUDA
- Transformers: 5.23.0 (unifica sei nuove famiglie di modelli, rilasciata 13 novembre 2026)
- PEFT: 0.21.3 (fix per salvataggio di adapter DTensor tensor‑parallel)
- TRL: 1.18.0 (introduce
AsyncGRPOTrainerstabile) - bitsandbytes: ultima release (necessaria per
--q4) - datasets, accelerate: ultime release, nessun pin speciale
Due note di versione semplificano il debug: PEFT v0.21.2 ha risolto problemi con modelli encoder‑decoder abbinati a Transformers 5.18.0 o successive; i checkpoint FP8 richiedono Transformers 5.0.0 o superiore, importante se si intende passare a release più grandi.
È necessario disporre di circa 20 GB di spazio libero su disco per la cache dei modelli, le cartelle dei run e i file di merge.
Procedura passo‑passo del rank sweep
1. Preparazione dell’ambiente
Creare un virtual environment, installare le versioni pinneate con pip install torch transformers==5.23.0 peft==0.21.3 trl==1.18.0 bitsandbytes datasets accelerate. Verificare che la GPU sia riconosciuta con torch.cuda.is_available().
2. Scaricare il modello di base
Usare from transformers import AutoModelForCausalLM per caricare il modello desiderato (es. “mistral-large-4”). Se si vuole usare la quantizzazione 4‑bit, aggiungere il flag loadin4bit=True.
3. Definire la configurazione LoRA
Creare un oggetto LoraConfig con i parametri di partenza (rank = 16, loraalpha = 32, dropout = 0.05, targetmodules=“all‑linear”).
4. Preparare i dataset
Dividere i dati in training e validation, mantenendo un set di test separato per la valutazione finale. Utilizzare datasets.load_dataset e accelerate per il batching.
5. Loop di sweep sui rank
Per ogni rank nella lista (4, 8, 16, 32, 64):
- Aggiornare
LoraConfig(rank=R, lora_alpha=2*R). - Avviare il training con
TraineroAsyncGRPOTrainerper 2 epoch. - Salvare il modello adapter e registrare il numero di parametri addestrabili.
- Valutare sul set di test e memorizzare il punteggio.
6. Analisi dei risultati
Confrontare i punteggi con il conteggio dei parametri. Un rank che migliora di < 0.2 punti ma raddoppia la dimensione non è conveniente. Se più di un rank è competitivo, scegliere quello con il miglior rapporto “punteggio per milione di parametri”.
7. Merge del modello vincente
Usare peft.mergeandunload per incorporare l’adapter nel modello base, ottenendo un checkpoint stand‑alone pronto per il deployment.
Conclusioni e consigli pratici
Il rank sweep dimostra che LoRA rimane la strategia più efficiente per adattare grandi modelli a compiti specifici, soprattutto quando le risorse GPU sono limitate. QLoRA estende la fattibilità a modelli ancora più grandi grazie alla quantizzazione 4‑bit, mentre TRL fornisce strumenti di training avanzati come l’AsyncGRPOTrainer.
Le chiavi del successo sono:
- Testare più rank con un rapporto alpha costante per isolare l’effetto della capacità.
- Monitorare sia la loss di training sia il punteggio di valutazione per evitare overfitting.
- Verificare le licenze dei modelli open‑weight prima di distribuire gli adapter commercialmente.
- Mantenere le tre librerie (Transformers, PEFT, TRL) allineate alle versioni più recenti per evitare incompatibilità.
Seguendo questi passaggi, è possibile trasformare un semplice esperimento LoRA in un processo di ottimizzazione misurato, pronto per la produzione in circa 90 minuti su una singola GPU.
