Come Adattare LFM2 con QLoRA e DPO: Guida Pratica e Completa su Google Colab
Finire di allenare un modello linguistico su larga scala come LFM2 è diventato accessibile grazie a modelli open-source e ad algoritmi efficienti. In questo tutorial completo, mostreremo come personalizzare LFM2 (1.2B parametri) utilizzando QLoRA per addestrare solo una minuscola parte del modello e DPO (Direct Preference Optimization) per sintonizzare meglio le risposte. Si parte da un modello base, si aggiunge un dataset di chat, si allenano adattatori di tipo LoRA e si valutano i progressi con esempi pratici.
Prerequisiti e Configurazione
Per seguire questa guida, sarò necessario disporre di accesso a Google Colab con una GPU abilitata. Inizieremo installando tutti i pacchetti Python necessari usando i seguenti comandi:
- Transformers: per caricare e gestire il modello e il tokenizer.
- TRL: per applicare i metodi SFT (Supervised Fine-Tuning) e DPO.
- PEFT: per implementare QLoRA e salvare i risultati.
- BitsAndBytes e Datasets: per ottimizzare il carico GPU e preparare il dataset.
L’installazione si esegue con:
!pip install -q -U "transformers>=4.55" "trl>=0.12" "peft>=0.13" "datasets>=2.20" "accelerate>=0.34" bitsandbytes
Seguito da:
import torch, gc
from datasets import load_dataset, Dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, PeftModel, preparemodelforkbittraining
from trl import SFTConfig, SFTTrainer, DPOConfig, DPOTrainer
Configurazione Principale
Definiamo alcuni parametri fondamentali:
MODEL_ID = "LiquidAI/LFM2-1.2B"USE_4BIT = TrueRUN_DPO = TrueSFT_SAMPLES = 500SFT_STEPS = 60DPO_STEPS = 40MAX_LEN = 1024Inoltre, verifichiamo la presenza della GPU e selezioniamo la precisione più ottimale:
BF16 = torch.cuda.isavailable() and torch.cuda.isbf16-supported()DTYPE = torch.bfloat16 if BF16 else torch.float16assert torch.cuda.is_available(), "Nessuna GPU rilevata..."Caricare il Modello Base
Cominciamo caricando il modello base LFM2. Per risparmiare memoria GPU, possiamo utilizzare la quantizzazione 4-bit, che riduce notevolmente la quantità di dati caricati in GPU mantenendo un alto livello di performance.
Il carico avviene con:
model = loadbase(USE4BIT)
Dove load_base() è una funzione personalizzata per inizializzare il modello con la configurazione specificata. In parallelo, caricare e prepariamo il tokenizer per gestire il formato dei prompts.
Prova Iniziale
Prima di iniziare l’addestramento, testiamo il modello con un prompt specifico per confronto successivo:
PROBE = "Spiega cosa rende la struttura LFM2 ideale per l’AI su dispositivi, in due frasi."
print(chat(model, PROBE))
Il risultato serve come baseline per verificare i miglioramenti dopo la fine-tuning.
Addestramento Supervisionato (SFT)
Definizione del Dataset
Per il training supervisionato, utilizziamo un dataset in formato di chat, disponibile online. Eseguiamo:
sftds = loaddataset("HuggingFaceTB/smoltalk", "all", split=f"train[:{SFT_SAMPLES}]")
sftds = sftds.select_columns(["messages"])
Questo dataset ha 500 esempi, ciascuno con messaggi organizzati come dialoghi. Ne vengono selezionati solo i messaggi, per evitare dati ridondanti.
Configurazione LoRA
LoRA è un’ottimizzazione che permette di modificare solo una parte del modello, mantenendo l’originale. La configurazione per l’allenamento è:
lora_sft = LoraConfig(
r=16, loraalpha=32, loradropout=0.05, bias="none",
tasktype="CAUSALLM", target_modules="all-linear",
)
Questo settaggio indica che si addestreranno solo un piccolo subset di matrici rispetto al modello principale.
Configurazione del Training
Usiamo un SFTConfig con i seguenti iperparametri principali:
- learning_rate: 2e-5
- batches: 2 per dispositivo, con accumulazione 4
- massimo tokeni: 1024
- epoche: in totale 60
steps(non intere)
Una volta salvato in outputs/sft/lfm2_merged, possiamo eseguire:
sft_trainer.train()
Seguito da:
model = sft_trainer.model
print(chat(model, PROBE))
Per verificare miglioramenti dopo adattamento.
Unire Modello Principale e Adattatore
Dopo l’addestramento, per continuare al perfezionamento del modello (es. con DPO), dobbiamo unire il modello base alla variante ottenuta in SFT. Questo richiede di scaricare nuovamente il modello principale (in FP16 o BF16), caricare il LoRA, e unire in un unico modello con:
PeftModel.frompretrained(...).mergeand_unload()
Raffinamento con DPO
Per ottenere risposte più raffinate, DPO è un’ottimizzazione avanzata basata sui preferimenti (chosen/rejected). Gli esempi per addestrare il modello seguono lo schema:
pref_rows = [
{"prompt": [{"role": "user", "content": "Rispondi a un cliente che ha un ordine ritardato"}],
"chosen": [{"role": "assistant", "content": "Mi spiace che il suo ordine sia in ritardo..."}],
"rejected": [{"role": "assistant", "content": "Gli ordini sono spesso in ritardo. Attenda."}],
...
] * 20
Configurazione DPO
Impostiamo i parametri per DPO:
- learning_rate: 5e-6
- ← Torna alle news