Il fine-tuning serve quando un modello generico non basta: vuoi che risponda con un certo stile, conosca la terminologia della tua azienda o segua un formato preciso. La buona notizia e' che oggi non servono GPU costose: con la tecnica LoRA e la libreria Unsloth puoi addestrare un modello open su un tuo dataset gratis, su una GPU di Google Colab, in meno di un'ora. Questa guida ti porta dall'inizio alla fine, con comandi reali.

A chi serve e cosa otterrai

Questa guida e' pensata per chi ha gia' un minimo di dimestichezza con Python e vuole personalizzare un modello linguistico senza spendere. Al termine avrai: un modello open (ad esempio della famiglia Llama o Qwen) addestrato sul tuo dataset, salvato come adattatore LoRA, e una versione esportata in formato GGUF pronta da eseguire in locale con Ollama o LM Studio.

Prerequisiti reali: un account Google (per Colab), facoltativamente un account Hugging Face (gratuito) se vuoi usare modelli che richiedono accettazione della licenza o pubblicare il risultato, e un dataset anche piccolo (bastano qualche centinaio di esempi ben fatti). La GPU gratuita di Colab e' tipicamente una NVIDIA T4 con circa 15 GB di memoria: sufficiente per modelli da 7-8 miliardi di parametri in 4 bit.

Perche' LoRA e Unsloth (e quando NON farlo)

LoRA (Low-Rank Adaptation) non riaddestra tutto il modello, ma inserisce piccole matrici aggiuntive ("adattatori") che imparano il tuo compito. Si addestra solo l'1% circa dei parametri: molto piu' veloce ed economico, e il risultato e' un file di pochi MB. QLoRA aggiunge la quantizzazione a 4 bit per ridurre ancora la memoria. Unsloth e' una libreria che ottimizza questo processo, rendendolo fino a 2 volte piu' veloce e con meno consumo di memoria rispetto agli strumenti standard.

Prima di iniziare, una domanda onesta: ti serve davvero il fine-tuning? In molti casi no. Se il tuo problema e' "il modello non conosce i miei documenti", la soluzione giusta e' il RAG (recupero delle informazioni dai tuoi file). Se e' "il modello non risponde come voglio", spesso basta un buon prompt di sistema. Il fine-tuning conviene quando vuoi cambiare in modo stabile lo stile, il formato o il comportamento del modello su molti esempi.

Passo 1: preparare Colab e installare Unsloth

Apri Google Colab e crea un nuovo notebook. Imposta la GPU: menu Runtime > Cambia tipo di runtime > Acceleratore hardware: GPU. Poi, nella prima cella, installa Unsloth:

!pip install unsloth

Verifica che la GPU sia disponibile:

import torch
print(torch.cuda.get_device_name(0))  # es. "Tesla T4"

Passo 2: caricare il modello base in 4 bit

Carichiamo un modello open quantizzato a 4 bit. Unsloth offre versioni gia' pronte. Sostituisci il nome con il modello che preferisci tra quelli supportati nella documentazione.

from unsloth import FastLanguageModel
import torch

max_seq_length = 2048

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "unsloth/llama-3.1-8b-bnb-4bit",  # vedi i nomi sulla doc Unsloth
    max_seq_length = max_seq_length,
    load_in_4bit = True,
)

Passo 3: aggiungere gli adattatori LoRA

Ora trasformiamo il modello in un modello addestrabile con LoRA, scegliendo il rango (r) e i moduli da adattare:

model = FastLanguageModel.get_peft_model(
    model,
    r = 16,                       # rango: 8-32 e' un buon intervallo
    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",
    random_state = 3407,
)

Passo 4: preparare il dataset

Il formato piu' semplice e' una lista di esempi con istruzione e risposta. Puoi caricare un file JSON tuo oppure un dataset da Hugging Face. Quello che conta e' costruire un campo di testo unico con un template di chat coerente. Esempio minimale:

from datasets import load_dataset

# Esempio con un dataset pubblico; in produzione usa il tuo file JSON
dataset = load_dataset("yahma/alpaca-cleaned", split = "train[:500]")

def formatta(esempio):
    istr = esempio["instruction"]
    inp  = esempio.get("input", "")
    out  = esempio["output"]
    prompt = f"### Istruzione:\n{istr}\n\n### Input:\n{inp}\n\n### Risposta:\n{out}"
    return {"text": prompt}

dataset = dataset.map(formatta)

Per usare i tuoi dati, basta un file dati.json con campi simili e load_dataset("json", data_files="dati.json"). Regola d'oro: pochi esempi ma puliti e coerenti valgono piu' di tanti esempi sciatti.

Passo 5: addestrare

Usiamo l'SFTTrainer della libreria TRL di Hugging Face, integrato con Unsloth:

from trl import SFTTrainer, SFTConfig

trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    dataset_text_field = "text",
    max_seq_length = max_seq_length,
    args = SFTConfig(
        per_device_train_batch_size = 2,
        gradient_accumulation_steps = 4,
        warmup_steps = 5,
        max_steps = 60,            # per una prova; aumenta per dataset reali
        learning_rate = 2e-4,
        logging_steps = 1,
        optim = "adamw_8bit",
        output_dir = "outputs",
    ),
)

trainer.train()

Sulla T4 gratuita, 60 step su poche centinaia di esempi richiedono pochi minuti. Vedrai la "loss" scendere passo dopo passo: e' il segnale che il modello sta imparando.

Passo 6: provare il modello addestrato

FastLanguageModel.for_inference(model)

prompt = "### Istruzione:\nSpiega in una frase cos'e' LoRA.\n\n### Risposta:\n"
inputs = tokenizer(prompt, return_tensors = "pt").to("cuda")
out = model.generate(**inputs, max_new_tokens = 128)
print(tokenizer.decode(out[0], skip_special_tokens = True))

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

Passo 7: salvare ed esportare per Ollama

Salva l'adattatore LoRA (pochi MB) e, se vuoi eseguirlo in locale, esporta direttamente in GGUF quantizzato:

# Solo gli adattatori LoRA
model.save_pretrained("lora_model")
tokenizer.save_pretrained("lora_model")

# Esportazione in GGUF (per Ollama / LM Studio)
model.save_pretrained_gguf("modello_gguf", tokenizer, quantization_method = "q4_k_m")

Scarica la cartella risultante. Per eseguirlo con Ollama, crea un file Modelfile con FROM ./modello.gguf e poi:

ollama create mio-modello -f Modelfile
ollama run mio-modello

Errori comuni e soluzioni

  • "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.
  • La sessione di Colab si disconnette: la versione gratuita ha limiti di tempo e puo' interrompersi. Salva spesso e tieni il numero di step basso per le prove.
  • "403" o accesso negato al modello: alcuni modelli richiedono di accettare la licenza su Hugging Face e un token di accesso. Effettua il login con huggingface_hub.login().
  • Risposte incoerenti dopo l'addestramento: spesso il dataset e' troppo piccolo o male formattato, oppure il template di chat usato in addestramento e in inferenza non coincide. Allinea i due template.

Varianti, alternative e come proseguire

Se non vuoi scrivere codice, strumenti come LM Studio permettono di eseguire i modelli GGUF con interfaccia grafica, mentre per l'addestramento esistono alternative gestite a pagamento. Per dataset piu' grandi conviene aumentare gli step e valutare una GPU piu' potente (Colab Pro o servizi cloud). Ricorda infine il principio guida: prima di addestrare, chiediti se RAG o un buon prompt non risolvano gia' il problema con meno fatica. Quando il fine-tuning serve davvero, LoRA e Unsloth lo rendono finalmente alla portata di tutti.