Personalizzare un modello di intelligenza artificiale sui propri dati - per fargli adottare un tono, conoscere il proprio dominio o rispondere in un formato preciso - sembra roba da grandi laboratori con cluster di GPU. Non e' piu' cosi'. Con Unsloth e una sessione gratuita di Google Colab puoi fare il fine-tuning di un modello aperto da 4-8 miliardi di parametri in meno di un'ora, senza spendere nulla e senza installare niente sul tuo computer.

Questa guida e' pensata per chi sa programmare un minimo in Python e vuole un percorso concreto, dal primo comando fino al modello pronto da usare in locale con Ollama. Non serve hardware: gira tutto nel browser.

A chi serve e cosa otterrai

Il fine-tuning serve quando il prompt engineering non basta: vuoi che il modello risponda sempre in un certo stile, che padroneggi un gergo aziendale, che produca un formato rigido (per esempio JSON con campi fissi) o che imiti esempi specifici. Al termine avrai un "adattatore" LoRA - un piccolo file che modifica il comportamento del modello base - e saprai come fonderlo ed esportarlo per usarlo offline.

Prerequisiti reali: un account Google (per Colab), un account gratuito su Hugging Face (per scaricare i modelli e, volendo, caricare il tuo), qualche decina o centinaia di esempi di addestramento, e la voglia di leggere i messaggi d'errore. La GPU gratuita di Colab (di solito una T4 da 16 GB) basta per modelli fino a 7-8 miliardi di parametri in modalita' QLoRA.

Quale strumento usare e perche' Unsloth

Per il fine-tuning di LLM ci sono diverse opzioni. Unsloth e' la prima scelta per chi inizia: e' una libreria che ottimizza l'addestramento rendendolo circa due volte piu' veloce e usando molta meno memoria, il che e' decisivo sulla GPU gratuita di Colab. Supporta i modelli aperti piu' diffusi (Llama, Gemma, Qwen, Mistral, Phi) e offre notebook gia' pronti.

  • Unsloth - Pro: velocissimo, parco di memoria, notebook pronti, gratis. Contro: si concentra su una GPU alla volta.
  • Axolotl e LLaMA-Factory - Pro: molto configurabili, adatti a setup multi-GPU. Contro: piu' complessi da impostare.
  • PEFT + TRL "a mano" (le librerie di Hugging Face) - Pro: massimo controllo. Contro: piu' codice e meno ottimizzazioni automatiche.

Per un primo progetto su Colab, Unsloth e' il miglior equilibrio tra semplicita' e risultati.

Passo 1: prepara Colab e installa Unsloth

Vai su Google Colab, crea un nuovo notebook e imposta la GPU: menu Runtime > Cambia tipo di runtime > Acceleratore hardware > GPU. Poi installa la libreria nella prima cella:

!pip install unsloth

Passo 2: carica il modello base

Carichiamo un modello aperto in 4 bit (QLoRA) per risparmiare memoria. Qui usiamo una variante di Gemma gia' ottimizzata da Unsloth, ma puoi cambiare il nome con un altro modello presente su Hugging Face:

from unsloth import FastLanguageModel
import torch

max_seq_length = 2048

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "unsloth/gemma-3-4b-it-bnb-4bit",
    max_seq_length = max_seq_length,
    load_in_4bit = True,
)

Passo 3: aggiungi gli adattatori LoRA

Invece di riaddestrare tutti i miliardi di parametri (costoso e inutile), con LoRA ne addestriamo solo una piccola frazione. I valori sotto sono un buon punto di partenza:

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",
)

Passo 4: prepara il dataset

Il formato piu' comodo e' quello "chat": una lista di esempi con coppie utente/assistente. Puoi caricare un dataset da Hugging Face o crearne uno tuo. Ecco un mini esempio fatto a mano, utile per capire la struttura:

from datasets import Dataset

esempi = [
  {"conversations": [
     {"role": "user", "content": "Cos'e' un IBAN?"},
     {"role": "assistant", "content": "L'IBAN e' il codice internazionale che identifica un conto bancario..."},
  ]},
  # ...aggiungi decine o centinaia di esempi simili
]

def formatta(ex):
    return {"text": tokenizer.apply_chat_template(
        ex["conversations"], tokenize=False, add_generation_prompt=False)}

dataset = Dataset.from_list(esempi).map(formatta)

La regola pratica: meglio pochi esempi puliti e coerenti che migliaia di esempi sciatti. Per uno stile o un formato, anche 100-300 esempi ben fatti danno risultati visibili.

Passo 5: configura e avvia l'addestramento

Usiamo l'SFTTrainer di TRL, che Unsloth integra. Per un primo test bastano poche decine di passi:

from trl import SFTTrainer, SFTConfig

trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    args = SFTConfig(
        per_device_train_batch_size = 2,
        gradient_accumulation_steps = 4,
        warmup_steps = 5,
        max_steps = 60,          # alza questo valore per dataset reali
        learning_rate = 2e-4,
        logging_steps = 1,
        output_dir = "outputs",
    ),
)

trainer.train()

Vedrai la loss (l'errore) scendere a ogni passo: e' il segno che il modello sta imparando. Su una T4, 60 passi richiedono pochi minuti.

Passo 6: prova il modello addestrato

FastLanguageModel.for_inference(model)

messaggi = [{"role": "user", "content": "Spiegami cos'e' un IBAN in una frase."}]
inputs = tokenizer.apply_chat_template(
    messaggi, tokenize=True, add_generation_prompt=True, return_tensors="pt"
).to("cuda")

out = model.generate(input_ids=inputs, max_new_tokens=128)
print(tokenizer.decode(out[0], skip_special_tokens=True))

Il risultato atteso e' una risposta nel tono e nel formato dei tuoi esempi di addestramento.

Passo 7: salva ed esporta in Ollama

Puoi salvare il solo adattatore LoRA (pochi MB) oppure esportare il modello completo in formato GGUF, pronto per girare in locale con Ollama o LM Studio:

# adattatore LoRA
model.save_pretrained("mio-adattatore")

# esporta in GGUF quantizzato (per Ollama / llama.cpp)
model.save_pretrained_gguf("mio-modello", tokenizer, quantization_method="q4_k_m")

# carica su Hugging Face (richiede il token)
# model.push_to_hub_gguf("tuo-utente/mio-modello", tokenizer, token="hf_...")

Scaricato il file GGUF, crei un Modelfile per Ollama con la riga FROM ./mio-modello.gguf e lanci ollama create mio-modello -f Modelfile: avrai il tuo modello personalizzato utilizzabile offline.

Errori comuni e come risolverli

  • "CUDA out of memory": riduci per_device_train_batch_size a 1, abbassa max_seq_length (es. 1024) e assicurati di usare load_in_4bit=True.
  • Il modello risponde in modo strano o ripetitivo: spesso e' un problema di chat template non applicato o dataset mal formattato. Verifica di usare apply_chat_template e che i ruoli (user/assistant) siano corretti.
  • Runtime disconnesso a meta': Colab gratuito stacca le sessioni inattive. Salva checkpoint frequenti e tieni la scheda attiva.
  • "gated model" / accesso negato: alcuni modelli richiedono di accettare la licenza su Hugging Face e un token. Usa le varianti gia' pronte di Unsloth per evitare il problema.

Varianti, casi avanzati e quando NON farlo

Per dataset reali, alza max_steps (o passa a contare le epoche) e monitora la loss per evitare l'overfitting. Per modelli piu' grandi serve Colab Pro o una GPU dedicata. Tecniche avanzate come la DPO permettono di allineare il modello alle preferenze, mentre lo scaling del RoPE estende il contesto.

Attenzione pero': il fine-tuning non e' sempre la risposta. Se ti serve dare al modello conoscenza aggiornata o documenti specifici, spesso conviene la RAG (recupero dei documenti al momento della domanda), piu' economica e aggiornabile. Se devi solo cambiare tono o formato in modo occasionale, basta un buon prompt di sistema. Usa il fine-tuning quando il comportamento desiderato e' stabile, ripetitivo e difficile da ottenere a colpi di prompt: e' li' che ripaga davvero lo sforzo.