Hai provato a usare un LLM per il tuo caso specifico e non funziona benissimo. ChatGPT non conosce il gergo del tuo settore. Llama risponde in modo troppo generico. La tentazione è forte: "facciamo fine-tuning!". Prima di buttarti, facciamo un passo indietro.
Prima Domanda: Ti Serve Davvero Fine-tuning?
Il fine-tuning è diventato quasi una moda. Ma nella mia esperienza, l'80% delle volte non serve. Ci sono alternative più semplici che dovresti provare prima.
Prompt engineering. Sembra banale, ma prompt migliori risolvono molti problemi. Esempi nel prompt (few-shot), istruzioni più precise, formati di output specificati. Prima di trainare qualsiasi cosa, spendi qualche ora a ottimizzare il prompt.
RAG (Retrieval Augmented Generation). Se il problema è che il modello non conosce i tuoi dati, RAG è quasi sempre la risposta giusta. Indicizzi i tuoi documenti, recuperi quelli rilevanti, li passi nel contesto. Il modello usa le sue capacità di ragionamento sui tuoi dati senza bisogno di training.
Context injection. Simile a RAG ma più semplice. Metti le informazioni rilevanti direttamente nel prompt. Con context window da 128K-1M token, puoi passare un sacco di informazioni.
Fine-tuning ha senso quando:
- Vuoi cambiare lo stile delle risposte (tono, formato, lunghezza)
- Il modello deve imparare task specifici che non sa fare
- Hai bisogno di performance migliori su un dominio ristretto
- Vuoi ridurre la latenza evitando prompt lunghi
- Devi far girare il modello localmente e vuoi uno piccolo che funzioni bene
Fine-tuning NON serve per:
- Aggiungere conoscenza fattuale (usa RAG)
- Fare cose che un buon prompt già risolve
- "Migliorare" il modello genericamente
Tipi di Fine-tuning
Non tutto il fine-tuning è uguale. Ci sono approcci diversi con costi e risultati diversi.
Full fine-tuning. Aggiorni tutti i pesi del modello. È l'approccio classico e dà i migliori risultati, ma richiede GPU mostruose. Per un modello da 7B parametri servono almeno 80GB di VRAM. Per 70B, centinaia di GB. Impraticabile per la maggior parte di noi.
LoRA (Low-Rank Adaptation). L'idea geniale che ha democratizzato il fine-tuning. Invece di aggiornare tutti i pesi, aggiungi piccole matrici "adapter" che vengono trainate. Il modello originale resta congelato. Risultato: puoi fare fine-tuning di un modello 7B con 24GB di VRAM, o anche meno.
QLoRA. LoRA su un modello quantizzato a 4-bit. Ancora meno memoria, risultati quasi comparabili a LoRA standard. Con una RTX 5090 e i suoi 32GB di VRAM puoi fare fine-tuning anche di modelli 13B senza problemi. È quello che uso più spesso.
Prefix tuning / Prompt tuning. Invece di modificare il modello, traina dei "soft prompt" che vengono prepended all'input. Ancora più leggero di LoRA ma risultati generalmente peggiori. Lo uso raramente.
Setup Pratico per QLoRA
Vediamo come fare fine-tuning in pratica. Uso QLoRA perché è l'approccio più accessibile e i risultati sono ottimi.
Hardware
Per fare fine-tuning con QLoRA, hai bisogno di una GPU con abbastanza VRAM. La RTX 5090 con i suoi 32GB di GDDR7 è perfetta: gestisce comodamente modelli da 7-8B, e con qualche ottimizzazione anche modelli più grossi come i 13B.
Se non hai una GPU adatta, il nostro servizio di GPU renting ti dà accesso a una workstation con RTX 5090 32GB + Threadripper 9960X, con ambiente già configurato (CUDA, PyTorch, vLLM preinstallati). Paghi solo le ore che usi, senza sbatterti con setup e driver.
Software Stack
# Ambiente base
pip install torch transformers accelerate
pip install bitsandbytes # Per quantizzazione
pip install peft # Per LoRA
pip install trl # Per training con SFT
pip install datasets # Per gestire dataset
Oppure usa unsloth, che wrappa tutto e ottimizza per velocità:
pip install unsloth
Il Codice
Ecco un esempio completo di fine-tuning con QLoRA su Llama:
from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset
# Carica modello con quantizzazione 4-bit
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/llama-3-8b-bnb-4bit",
max_seq_length=2048,
load_in_4bit=True,
)
# Configura LoRA
model = FastLanguageModel.get_peft_model(
model,
r=16, # Rank delle matrici LoRA
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_alpha=16,
lora_dropout=0,
bias="none",
use_gradient_checkpointing=True,
)
# Carica dataset
dataset = load_dataset("json", data_files="training_data.jsonl")
# Training
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset["train"],
dataset_text_field="text",
max_seq_length=2048,
args=TrainingArguments(
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
warmup_steps=10,
max_steps=100, # Aumenta per training più lungo
learning_rate=2e-4,
fp16=True,
logging_steps=10,
output_dir="outputs",
),
)
trainer.train()
# Salva
model.save_pretrained("fine_tuned_model")
tokenizer.save_pretrained("fine_tuned_model")
Questo codice funziona tranquillamente su una RTX 5090 con un modello da 8B parametri. I 32GB di VRAM ti danno margine per batch size più grandi e sequence length più lunghe. Tempo di training: circa 1 ora per 1000 esempi.
Preparare i Dati
La qualità dei dati è tutto. Garbage in, garbage out. Non c'è fine-tuning che salvi dati cattivi.
Formato Standard
Il formato più comune è conversazionale:
{"messages": [
{"role": "system", "content": "Sei un assistente esperto di..."},
{"role": "user", "content": "Domanda dell'utente"},
{"role": "assistant", "content": "Risposta che vuoi che il modello impari"}
]}
Per instruction tuning più semplice:
{"instruction": "Riassumi questo testo", "input": "Testo da riassumere...", "output": "Riassunto..."}
Quanti Dati Servono?
Dipende dal task. Per cambiare lo stile o il formato delle risposte, bastano 100-500 esempi di qualità. Per task più complessi o domini specializzati, 1000-5000 esempi. Oltre i 10000, i rendimenti decrescono rapidamente.
La qualità batte la quantità. 500 esempi perfetti battono 5000 esempi mediocri. Investi tempo nella curation dei dati.
Come Creare un Dataset
Tre approcci:
Manuale. Scrivi tu gli esempi. È noioso ma dà i risultati migliori perché controlli tutto. Funziona per dataset piccoli.
Semi-automatico. Usa un modello più potente (GPT-4, Claude) per generare esempi, poi fai review manuale e correggi. Velocizza molto il processo.
Da dati esistenti. Se hai log di conversazioni, documentazione, Q&A esistenti, puoi convertirli in formato training. Attenzione: filtra gli esempi cattivi.
Iperparametri Che Contano
Non tutti gli iperparametri sono uguali. Questi sono quelli su cui concentrarti:
Learning rate. Per LoRA, 1e-4 a 3e-4 funziona quasi sempre. Inizia con 2e-4. Se il training è instabile (loss che salta), abbassa.
LoRA rank (r). Controlla la "capacità" degli adapter. r=8 è conservativo, r=16 è standard, r=32+ per task complessi. Rank più alto = più parametri trainabili = serve più VRAM e più dati.
Epochs. Per dataset piccoli, 3-5 epochs. Per dataset grandi, spesso basta 1 epoch. Occhio all'overfitting: se la loss di validation sale mentre quella di training scende, stai overfittando.
Batch size. Più grande possibile senza esaurire VRAM. Usa gradient accumulation per simulare batch più grandi.
Valutare il Risultato
Training finito, loss bella bassa. Il modello è buono? Forse. La loss non ti dice tutto.
Test manuale. Prova il modello con prompt reali. È il test più importante. Come si comporta sui casi che ti interessano?
Test set held-out. Tieni da parte il 10-20% dei dati e valuta su quelli. Se hai metriche automatiche per il tuo task, usale.
Confronto A/B. Metti il modello fine-tuned e quello base side by side. Per ogni prompt, quale risposta è migliore? Fai valutare a qualcun altro per evitare bias.
Test di regressione. Il fine-tuning può "rompere" capacità che il modello aveva. Verifica che non abbia perso abilità importanti.
Problemi Comuni e Soluzioni
Il modello ripete la stessa frase. Succede con dataset piccoli o poca varietà. Soluzione: più dati diversificati, temperature più alta in inference, penalità di ripetizione.
Il modello è peggiorato. Overfitting o dati di training cattivi. Riduci epochs, aumenta dropout, rivedi i dati.
Il training è instabile (loss che salta). Learning rate troppo alto. Abbassalo. Prova warmup più lungo.
Out of memory. Riduci batch size, usa gradient checkpointing, riduci sequence length, quantizza di più.
Il modello non segue le istruzioni. Probabilmente i dati di training non hanno il formato giusto. Il modello impara quello che vede: se i tuoi esempi non dimostrano il comportamento che vuoi, non lo imparerà.
Servire il Modello Fine-tuned
Dopo il training, vuoi usare il modello. Diverse opzioni:
Con gli adapter LoRA separati. Carichi il modello base, carichi gli adapter, li "fondi". Utile se hai più versioni fine-tuned dello stesso modello base.
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("base_model")
model = PeftModel.from_pretrained(base_model, "lora_adapter_path")
model = model.merge_and_unload() # Fonde gli adapter nel modello
Modello merged. Fondi gli adapter e salva il modello completo. Più semplice da deployare ma occupa più spazio.
Per inference veloce. Esporta in GGUF per llama.cpp, o usa vLLM. Performance molto migliori del naive PyTorch inference.
Caso Studio: Fine-tuning per Codice Aziendale
Racconto un caso reale (anonimizzato).
Un cliente aveva un codebase legacy con convenzioni particolari. Volevano un assistente che generasse codice nello stile giusto. GPT-4 era troppo generico.
Step 1: Estratto 2000 esempi di codice "buono" dal repo, con commenti che spiegavano cosa faceva.
Step 2: Generato coppie istruzione-codice usando GPT-4 per creare le istruzioni a partire dal codice.
Step 3: Review manuale, scartato il 30% degli esempi che non erano buoni.
Step 4: Fine-tuning di CodeLlama 7B con QLoRA. Circa 3 ore su RTX 5090.
Risultato: Il modello fine-tuned generava codice molto più allineato alle convenzioni aziendali. Non perfetto, ma significativamente meglio del base.
Costo totale: Poche ore di GPU + qualche giorno di lavoro per preparare i dati. Se non hai hardware, con il nostro servizio GPU renting il compute costa una frazione rispetto ai big cloud provider.
Quando Non Ne Vale la Pena
Sii onesto: a volte fine-tuning non è la risposta.
- Se RAG risolve il problema, usa RAG. È più semplice e mantenerlo aggiornato è banale. Se hai bisogno di aiuto per implementare RAG, offriamo anche servizi AI custom.
- Se il problema è la qualità dei dati, fine-tuning non aiuta.
- Se non hai risorse per mantenere il modello nel tempo, meglio usare API.
- Se hai bisogno di risultati domani, fine-tuning richiede tempo.
Conclusione
Fine-tuning è uno strumento potente ma non è magia. Funziona quando:
- Hai un task specifico ben definito
- Hai dati di qualità che mostrano il comportamento desiderato
- Le alternative più semplici non bastano
Grazie a LoRA e QLoRA, è diventato accessibile a chiunque abbia una GPU decente — e se non ce l'hai, possiamo aiutarti. Ma "accessibile" non significa "facile". La parte difficile non è il training, sono i dati e sapere cosa vuoi ottenere.
Il mio consiglio: inizia con prompt engineering e RAG. Se non bastano, allora considera fine-tuning. E quando lo fai, investi più tempo nei dati che nel codice di training. È lì che si vince o si perde.
Il modello migliore è quello che risolve il tuo problema, non quello con più parametri o il training più sofisticato.