Adattare un modello di intelligenza artificiale ai tuoi dati non richiede piu' un cluster di GPU da decine di migliaia di euro. Con Unsloth, una libreria open source che ottimizza l'addestramento, e la tecnica LoRA/QLoRA puoi fare il fine-tuning di un modello come Qwen3 o Llama 3.1 su una singola GPU gratuita di Google Colab, in meno di un'ora. In questa guida costruiamo passo passo un modello specializzato: partiamo da un modello base, lo addestriamo su un dataset di esempi e lo esportiamo per usarlo in locale con Ollama.
A chi serve questa guida e cosa otterrai
Il fine-tuning serve quando il prompt engineering non basta piu': vuoi che il modello risponda sempre in un certo formato, adotti il tono della tua azienda, conosca un dominio ristretto (assistenza clienti, terminologia medica, un manuale interno) o parli una lingua o un dialetto poco rappresentato. Non serve per aggiungere conoscenza aggiornata a un modello (per quello e' meglio il RAG): serve per modellarne il comportamento.
Al termine avrai: un modello fine-tuned salvato come adattatore LoRA, il file GGUF quantizzato pronto per l'uso locale, e una Modelfile per importarlo in Ollama. Tempo richiesto: circa 45-90 minuti, gran parte dei quali il computer lavora da solo.
Prerequisiti reali
- Un account Google (per Google Colab, gratuito).
- Un account Hugging Face gratuito e un token di accesso (Settings → Access Tokens) per scaricare alcuni modelli e, se vuoi, caricare il risultato.
- Conoscenza di base di Python: saper leggere una cella di codice e cambiare qualche parametro. Non serve essere esperti.
- Nessun hardware locale: il training gira sulla GPU T4 (16 GB) che Colab offre gratis. Per l'inferenza finale in locale basta un PC con 8-16 GB di RAM.
Cosa sono LoRA e QLoRA, spiegati semplice
Un modello linguistico ha miliardi di parametri (i "pesi"). Riaddestrarli tutti (full fine-tuning) richiede una quantita' enorme di memoria. LoRA (Low-Rank Adaptation) congela i pesi originali e aggiunge piccole matrici "adattatore" che vengono addestrate al posto loro: si allena meno dell'1% dei parametri, con risultati vicini al full fine-tuning. QLoRA aggiunge la quantizzazione a 4 bit del modello base: comprime i pesi in memoria, permettendo di addestrare modelli da 8-14 miliardi di parametri su una GPU da 16 GB.
Unsloth riscrive i passaggi piu' pesanti dell'addestramento con kernel ottimizzati: secondo la documentazione ufficiale il training risulta circa 2 volte piu' veloce e usa fino al 70% di VRAM in meno rispetto all'implementazione standard di Hugging Face, senza perdita di accuratezza. E' proprio questo che rende fattibile il tutto sul piano gratuito.
Quale strumento scegliere per il fine-tuning
Prima di partire, un confronto onesto tra le opzioni piu' usate nel 2026:
| Strumento | Pro | Contro | Costo |
|---|---|---|---|
| Unsloth (consigliato) | Velocissimo, poca VRAM, notebook pronti, esporta in GGUF/Ollama | Ottimizzato per una GPU sola | Gratis, open source |
| Hugging Face PEFT + TRL | Massima flessibilita', standard di settore | Piu' lento, piu' memoria, piu' configurazione | Gratis |
| Axolotl | Configurazione via YAML, multi-GPU | Curva di apprendimento ripida | Gratis |
| OpenAI fine-tuning API | Zero gestione infrastruttura | Modello chiuso, dati inviati a terzi, costo a token | A pagamento |
Prima scelta: Unsloth, perche' abbatte i requisiti hardware, mette a disposizione notebook Colab gia' pronti e, soprattutto, gestisce l'esportazione verso Ollama che ci serve alla fine. Se un domani ti serve addestrare su piu' GPU o con pipeline aziendali, passerai a PEFT o Axolotl.
Passo 1: aprire Colab e attivare la GPU
Vai su colab.research.google.com e crea un nuovo notebook. Poi attiva la GPU: menu Runtime → Change runtime type → Hardware accelerator → T4 GPU. Verifica che la GPU sia attiva con:
!nvidia-smi
Dovresti vedere una Tesla T4 con circa 15 GB di memoria. Se compare un errore o nessuna GPU, il piano gratuito potrebbe averti temporaneamente esaurito le risorse: riprova piu' tardi o riduci il carico.
Passo 2: installare Unsloth
Nella prima cella di codice installa la libreria. Unsloth pubblica su PyPI e gestisce da sola le dipendenze compatibili con Colab:
%%capture
!pip install unsloth
# aggiorna all'ultima versione dal repository ufficiale
!pip install --upgrade --no-cache-dir "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
Passo 3: caricare il modello base a 4 bit
Carichiamo un modello gia' quantizzato a 4 bit. Usiamo un modello della famiglia Qwen3 da 8 miliardi di parametri, un buon equilibrio tra qualita' e memoria sul T4. Puoi sostituirlo con unsloth/Meta-Llama-3.1-8B-bnb-4bit o un modello piu' piccolo se la memoria e' poca.
from unsloth import FastLanguageModel
import torch
max_seq_length = 2048 # lunghezza massima della sequenza
dtype = None # rilevata in automatico
load_in_4bit = True # quantizzazione 4 bit (QLoRA)
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Qwen3-8B-bnb-4bit",
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit,
)
Passo 4: aggiungere gli adattatori LoRA
Ora "avvolgiamo" il modello con gli adattatori LoRA. I parametri chiave sono r (il rango: piu' alto = piu' capacita' di apprendimento ma piu' memoria; 16 e' un ottimo default) e lora_alpha (fattore di scala, di solito uguale o doppio di r).
model = FastLanguageModel.get_peft_model(
model,
r = 16,
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 = "unsloth", # risparmia memoria
random_state = 3407,
)
Passo 5: preparare il dataset
La qualita' del risultato dipende dai dati, non dalla quantita'. Anche 300-1.000 esempi ben scritti bastano per cambiare in modo evidente il comportamento del modello. Il formato piu' comune e' il chat template con ruoli. Usiamo un dataset di esempio da Hugging Face, ma puoi caricare il tuo file JSON con lo stesso schema.
from datasets import load_dataset
dataset = load_dataset("mlabonne/FineTome-100k", split = "train[:2000]")
def formatting(examples):
convos = examples["conversations"]
texts = [tokenizer.apply_chat_template(c, tokenize=False,
add_generation_prompt=False) for c in convos]
return {"text": texts}
dataset = dataset.map(formatting, batched=True)
Per usare i tuoi dati, crea un file dati.json con una lista di conversazioni in questo formato e caricalo in Colab:
[
{"conversations": [
{"role": "user", "content": "Come richiedo un rimborso?"},
{"role": "assistant", "content": "Certo! Per richiedere un rimborso accedi all'area..."}
]}
]
Passo 6: lanciare l'addestramento
Configuriamo il SFTTrainer (Supervised Fine-Tuning). Per una prova rapida imposta max_steps = 60; per un training completo usa invece num_train_epochs = 1 (una passata sui dati) e commenta max_steps.
from trl import SFTTrainer
from transformers import TrainingArguments
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
max_seq_length = max_seq_length,
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
max_steps = 60,
learning_rate = 2e-4,
fp16 = not torch.cuda.is_bf16_supported(),
bf16 = torch.cuda.is_bf16_supported(),
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
output_dir = "outputs",
),
)
trainer_stats = trainer.train()
Durante il training osserva la colonna loss: deve scendere gradualmente. Se resta piatta, il learning rate e' troppo basso; se schizza a valori enormi o diventa nan, e' troppo alto: riduci learning_rate a 1e-4.
Passo 7: provare subito il modello
Prima di esportare, verifica che abbia imparato. Mettiamo il modello in modalita' inferenza e proviamo un prompt:
FastLanguageModel.for_inference(model)
messages = [{"role": "user", "content": "Come richiedo un rimborso?"}]
inputs = tokenizer.apply_chat_template(messages, tokenize=True,
add_generation_prompt=True, return_tensors="pt").to("cuda")
outputs = model.generate(input_ids=inputs, max_new_tokens=256,
temperature=0.7)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Il risultato atteso e' una risposta nel tono e nel formato dei tuoi esempi. Se il modello ignora ancora lo stile del dataset, aumenta il numero di step o di esempi.
Passo 8: esportare in GGUF e importare in Ollama
Ora salviamo il modello in formato GGUF quantizzato, il formato usato da Ollama e llama.cpp per l'esecuzione locale efficiente:
model.save_pretrained_gguf("modello_finetuned", tokenizer,
quantization_method = "q4_k_m")
Scarica la cartella generata sul tuo PC. Poi, con Ollama installato in locale, crea una Modelfile:
FROM ./modello_finetuned/unsloth.Q4_K_M.gguf
PARAMETER temperature 0.7
PARAMETER num_ctx 2048
E registra il modello con:
ollama create mio-assistente -f Modelfile
ollama run mio-assistente "Come richiedo un rimborso?"
Da questo momento hai un modello personalizzato che gira offline, gratis e privato sul tuo computer.
Errori comuni e come risolverli
CUDA out of memory: riduciper_device_train_batch_sizea 1, oppuremax_seq_lengtha 1024, o passa a un modello piu' piccolo (3-4B).- La loss non scende: dataset troppo piccolo o incoerente; aumenta gli esempi e assicurati che seguano tutti lo stesso formato.
- Il modello "dimentica" le competenze generali (catastrophic forgetting): stai addestrando troppo a lungo; riduci gli step o il learning rate.
- Runtime disconnesso su Colab: il piano gratuito ha limiti di tempo; salva spesso gli adattatori con
model.save_pretrained("lora")per non perdere il lavoro. - Errore di autenticazione Hugging Face: alcuni modelli richiedono di accettare la licenza sul sito e di fare login con
from huggingface_hub import login; login("hf_...").
Varianti, alternative e quando NON fare fine-tuning
Se ti serve dare al modello informazioni aggiornate o documenti specifici, non fare fine-tuning: usa il RAG, molto piu' economico da mantenere. Se ti basta cambiare tono o formato per poche richieste, prova prima un buon system prompt. Il fine-tuning conviene quando questi approcci non bastano e hai centinaia di esempi di qualita'.
Come varianti puoi: caricare il risultato su Hugging Face con model.push_to_hub_gguf(...) per condividerlo; usare r = 32 e piu' epoche per compiti complessi; oppure passare a modelli piu' grandi (14B) sfruttando le versioni a 4 bit. Per andare oltre, la documentazione di Unsloth offre notebook pronti per Llama, Qwen, Gemma, Mistral e Phi, e guide dedicate alla creazione dei dataset.
Nota di metodo: i comandi e i parametri di questa guida sono verificati sulla documentazione ufficiale di Unsloth e Hugging Face aggiornata al 2026. Le API delle librerie evolvono in fretta: se una cella restituisce un errore di versione, controlla i notebook ufficiali piu' recenti.




