Fare fine-tuning significa prendere un modello aperto gia' addestrato e continuarne l'addestramento sui tuoi dati, per specializzarlo su un compito, uno stile o un dominio. La buona notizia e' che oggi non servono cluster da migliaia di euro: con la tecnica LoRA e la libreria Unsloth puoi personalizzare un modello da 8 miliardi di parametri gratis, sulla GPU offerta da Google Colab. Questa guida ti porta dall'inizio alla fine, con codice pronto.
A chi serve e cosa otterrai
E' una guida di livello intermedio-avanzato, per chi conosce Python e vuole un modello che risponda «a modo suo»: con il tono della propria azienda, in un formato fisso, o esperto di un argomento di nicchia. Al termine avrai un modello personalizzato salvato e pronto da usare in locale con Ollama.
Quando NON farlo. Il fine-tuning non serve per aggiungere conoscenza aggiornata (per quella conviene il RAG, cioe' dare i documenti al modello al momento della domanda) ne' per piccoli aggiustamenti ottenibili con un buon prompt. Ha senso quando vuoi cambiare comportamento e stile in modo stabile, o insegnare un formato che il prompt da solo non garantisce.
Cos'e' LoRA (in breve)
Addestrare tutti i parametri di un modello e' costosissimo. LoRA (Low-Rank Adaptation) aggira il problema: congela il modello originale e addestra solo piccole matrici aggiuntive, gli «adattatori», che pesano pochi megabyte. Il risultato e' quasi identico a un fine-tuning completo, ma con una frazione della memoria e del tempo. Unsloth ottimizza ulteriormente il processo, rendendolo fino a 2 volte piu' veloce e con meno consumo di memoria.
Prerequisiti
- Un account Google (per usare Google Colab).
- Un notebook Colab con GPU attiva: menu Runtime → Change runtime type → T4 GPU (gratuita).
- I tuoi dati di addestramento in formato istruzione-risposta (bastano 100-1.000 esempi di qualita').
1. Installazione
pip install unsloth
2. Caricare il modello in 4 bit
Carichiamo un modello aperto gia' pronto per Unsloth, quantizzato a 4 bit per entrare nella memoria della T4:
from unsloth import FastLanguageModel
import torch
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/llama-3.1-8b-instruct-bnb-4bit",
max_seq_length = 2048,
load_in_4bit = True,
)
3. Aggiungere gli adattatori LoRA
model = FastLanguageModel.get_peft_model(
model,
r = 16, # «capacita'» dell'adattatore
lora_alpha = 16,
lora_dropout = 0,
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
use_gradient_checkpointing = "unsloth",
)
Il parametro r regola quanto «spazio» ha il modello per imparare: valori tra 8 e 32 sono un buon punto di partenza. Piu' alto non e' sempre meglio: rischia il sovradattamento su pochi dati.
4. Preparare i dati
Serve un dataset di esempi. Puoi partire da un file JSON con coppie istruzione/risposta e trasformarlo nel formato di chat del modello:
from datasets import load_dataset
# Esempio: un tuo file locale con campi 'istruzione' e 'risposta'
dataset = load_dataset("json", data_files="miei_dati.json", split="train")
def formatta(esempio):
msgs = [
{"role": "user", "content": esempio["istruzione"]},
{"role": "assistant", "content": esempio["risposta"]},
]
return {"text": tokenizer.apply_chat_template(msgs, tokenize=False)}
dataset = dataset.map(formatta)
Consiglio: la qualita' batte la quantita'. 300 esempi puliti e coerenti valgono piu' di 5.000 rumorosi. Includi anche casi limite e il modo in cui vuoi che il modello dica «non lo so».
Che aspetto ha un file di dati? Ecco tre righe di esempio per un assistente che deve rispondere sempre in tono formale e conciso, nello stile di un'azienda:
[
{"istruzione": "Il pacco non e' arrivato, cosa faccio?",
"risposta": "Ci scusiamo per il disagio. Puo' indicarci il numero d'ordine? Verificheremo subito lo stato della spedizione e le forniremo un aggiornamento entro 24 ore."},
{"istruzione": "Posso avere uno sconto?",
"risposta": "Al momento non sono attive promozioni sul suo profilo. La invitiamo a iscriversi alla newsletter per ricevere in anteprima le offerte dedicate."},
{"istruzione": "Che ore sono?",
"risposta": "Non dispongo dell'orario in tempo reale. Posso pero' aiutarla con informazioni su ordini, spedizioni e resi."}
]
Nota come la terza riga insegna esplicitamente al modello a rifiutare in modo elegante cio' che non sa fare: e' uno degli usi piu' preziosi del fine-tuning, perche' definisce i confini del comportamento.
5. Addestrare
from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
args = SFTConfig(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
max_steps = 60, # aumenta con dataset piu' grandi
learning_rate = 2e-4,
logging_steps = 1,
output_dir = "outputs",
),
)
trainer.train()
Su una T4 gratuita, 60 passi su qualche centinaio di esempi richiedono pochi minuti. Osserva la loss nei log: deve scendere in modo graduale. Se crolla a zero subito, probabilmente il modello sta memorizzando (sovradattamento): riduci i passi o aumenta i dati.
6. Provare il modello personalizzato
FastLanguageModel.for_inference(model)
msgs = [{"role": "user", "content": "La tua domanda di prova"}]
inputs = tokenizer.apply_chat_template(msgs, return_tensors="pt",
add_generation_prompt=True).to("cuda")
out = model.generate(input_ids=inputs, max_new_tokens=200)
print(tokenizer.decode(out[0], skip_special_tokens=True))
7. Salvare ed esportare per Ollama
Puoi salvare solo gli adattatori LoRA (pochi MB) oppure esportare direttamente in formato GGUF per usarlo con Ollama in locale:
# Solo adattatori
model.save_pretrained("mio_modello_lora")
# Esportazione in GGUF quantizzato, pronto per Ollama
model.save_pretrained_gguf("mio_modello_gguf", tokenizer,
quantization_method = "q4_k_m")
Poi, sul tuo PC, crea un Modelfile che punta al file GGUF e registralo:
ollama create mio-modello -f Modelfile
ollama run mio-modello
Errori comuni
- «CUDA out of memory»: riduci
max_seq_length(es. 1024), abbassaper_device_train_batch_sizea 1, o usa un modello piu' piccolo. - Il modello ripete o «impazzisce»: learning rate troppo alto o troppi passi. Prova
learning_rate = 1e-4e meno step. - Risposte identiche agli esempi: sovradattamento. Aumenta i dati, riduci
re i passi. - Colab si disconnette: la GPU gratuita ha limiti di tempo; salva spesso su Google Drive e riprendi.
Come capire se ha funzionato
Non fidarti di una singola prova andata bene. Prepara in anticipo una decina di domande di test che non compaiono nel dataset di addestramento e confronta le risposte del modello prima e dopo il fine-tuning. Valuta tre cose: se lo stile e' quello desiderato, se il formato e' rispettato e se il modello ha perso capacita' generali (un effetto collaterale chiamato «oblio catastrofico», tipico quando si addestra troppo su pochi dati). Se noti che il modello personalizzato risponde peggio a domande comuni rispetto all'originale, hai esagerato: riduci i passi di addestramento o mescola nel dataset anche qualche esempio di conversazione generica, cosi' il modello non «dimentica» cio' che gia' sapeva.
Varianti e come proseguire
Puoi applicare lo stesso schema ad altri modelli aperti (Qwen, Mistral, Gemma, Nemotron) cambiando il model_name. Per dataset grandi conviene passare a una GPU piu' potente (Colab Pro o un servizio cloud). Se il tuo obiettivo e' aggiungere conoscenza aggiornabile, affianca al modello un sistema RAG sui tuoi documenti: fine-tuning per lo stile e il comportamento, RAG per i fatti. La documentazione di Unsloth e quella della libreria TRL di Hugging Face sono i riferimenti per approfondire parametri e tecniche piu' avanzate come il DPO.




