Vai al contenuto principale

Fine-tuning di Qwen3.5 Small con QLoRA per la classificazione di notizie

Scopri come effettuare il fine-tuning di Qwen3.5-0.8B con QLoRA usando una configurazione leggera che offre un forte incremento nelle prestazioni di classificazione delle notizie.
Aggiornato 29 set 2026  · 8 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

Qwen3.5 Small è un modello pratico per il fine-tuning leggero perché è pensato per il prototyping, l’adattamento specifico al compito e i flussi di lavoro di ricerca. Insieme a QLoRA, possiamo effettuare il fine-tuning partendo da un modello base quantizzato a 4 bit mantenuto congelato, rendendo il processo molto più efficiente in memoria e accessibile su hardware limitato.

In questo tutorial imposteremo l’ambiente, caricheremo il modello e il dataset AG News, valuteremo il modello base e poi faremo il fine-tuning di Qwen3.5 small per la classificazione delle notizie. Concluderemo confrontando i risultati prima e dopo l’addestramento, quindi salveremo e pubblicheremo l’adapter LoRA su Hugging Face per il riuso. 

Ti consiglio di seguire il percorso di competenze Hugging Face Fundamentals se non hai già familiarità con la piattaforma.

Che cos’è Qwen3.5 Small?

Prima di tuffarci nel codice, è utile capire il modello con cui lavoriamo. Qwen3.5 è una famiglia di foundation model, e la serie "Small" indica la linea più leggera, in particolare i modelli sotto i 10 miliardi di parametri. Per questo tutorial useremo la versione 0.8B.

Nonostante abbia solo 800 milioni di parametri, Qwen3.5-0.8B è molto capace ed estremamente efficiente. Caricato in precisione a 4 bit, richiede meno di 2 GB di VRAM. Questo lo rende ideale per laptop consumer, ambienti cloud gratuiti come Kaggle e deployment leggeri all’edge.

Inoltre, l’architettura Qwen3.5 supporta una finestra di contesto enorme da 262K e la multimodalità nativa. Anche se in questa guida ci concentriamo strettamente sulla classificazione di testo, i concetti di base trattati possono essere facilmente estesi a compiti di visione in seguito. Il modello offre anche una modalità di ragionamento ibrida, che però lasceremo disattivata per massimizzare la velocità di inferenza nel nostro semplice task di etichettatura.

Nel complesso, Qwen3.5-0.8B è un’opzione altamente pratica per il prototyping. Ci offre un modo rapido ed economico per testare i workflow di fine-tuning, garantendo comunque solidi risultati a valle.

1. Configura l’ambiente Kaggle

In questo tutorial useremo un notebook Kaggle come ambiente di training. Kaggle ci fornisce l’accesso alle GPU, rendendolo una piattaforma comoda per addestrare, effettuare il fine-tuning e valutare il nostro modello. Prima di eseguire il notebook, avvia un nuovo notebook Kaggle, apri le impostazioni della Sessione e seleziona GPU P100 come acceleratore. 

Successivamente, configureremo l’ambiente, aggiungeremo un token Hugging Face a Kaggle e importeremo le librerie Python utilizzate nel tutorial.

Crea un token di accesso Hugging Face

Prima di eseguire il notebook, crea un token di accesso Hugging Face dalle impostazioni del tuo account. Vai su Settings, apri Access Tokens e genera un nuovo token. Se vuoi pubblicare l’adapter LoRA fine-tunato su Hugging Face Hub alla fine del tutorial, assicurati che il token abbia i permessi di scrittura.

Hugging Face Access Token Page

Aggiungi il token ai secrets di Kaggle

Dopo aver generato il token, apri il tuo notebook Kaggle e aggiungilo come secret. Nell’editor del notebook, vai su Add-ons, poi Secrets, e crea un nuovo secret chiamato HUGGINGFACE_TOKEN. Incolla lì il valore del tuo token, così il notebook potrà accedervi in modo sicuro senza esporlo nel codice.

Kaggle Secrets setup

Installa le librerie necessarie

Ora possiamo installare le principali librerie necessarie per questo workflow. Questi pacchetti coprono il caricamento del modello, la quantizzazione, il fine-tuning efficiente in termini di parametri, la gestione dei dataset e la valutazione.

!pip install -q -U transformers accelerate
!pip install -q peft trl bitsandbytes datasets scikit-learn

Autenticati con Hugging Face

Successivamente, carichiamo il token Hugging Face dai secrets di Kaggle e lo usiamo per l’autenticazione. Questo dà al notebook accesso al modello e ci permette di caricare l’adapter addestrato in seguito.

from huggingface_hub import login
from kaggle_secrets import UserSecretsClient

user_secrets = UserSecretsClient()
login(token=user_secrets.get_secret("HUGGINGFACE_TOKEN"))

Importa le librerie Python

Infine, importiamo le librerie Python usate nel tutorial per il caricamento del modello, l’addestramento, l’elaborazione del dataset e la valutazione.

import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer, SFTConfig
from transformers import TrainingArguments
from sklearn.metrics import accuracy_score, f1_score
from tqdm.notebook import tqdm

2. Carica il modello Qwen3.5 e il dataset AG News

Ora che l’ambiente è pronto, possiamo caricare il modello base e preparare il dataset per il fine-tuning. 

In questa sezione caricheremo Qwen3.5-0.8B in precisione a 4 bit per rendere l’addestramento più efficiente in memoria, imposteremo il tokenizer e caricheremo un piccolo sottoinsieme del dataset AG News per training e valutazione.

Carica Qwen3.5-0.8B con quantizzazione a 4 bit

Iniziamo caricando Qwen3.5-0.8B con quantizzazione a 4 bit usando BitsAndBytes. Questo riduce l’uso di memoria e rende il modello più pratico da usare in un notebook Kaggle.

model_id = "Qwen/Qwen3.5-0.8B"

bnb_config = BitsAndBytesConfig(
  load_in_4bit=True,
  bnb_4bit_quant_type="nf4",
  bnb_4bit_compute_dtype=torch.bfloat16
)

model = AutoModelForCausalLM.from_pretrained(
  model_id,
  quantization_config=bnb_config,
  device_map="auto",
  dtype=torch.bfloat16
)

Carica il tokenizer

Poi carichiamo il tokenizer per lo stesso modello. Impostiamo anche il token di padding come token di fine sequenza, così il modello gestisce correttamente gli input con padding durante training e generazione.

tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token

model.config.pad_token_id = tokenizer.eos_token_id
model.generation_config.pad_token_id = tokenizer.eos_token_id

Carica il dataset AG News

Infine, carichiamo il dataset AG News e creiamo split di training e test più piccoli per questo tutorial. Usare un sottoinsieme mantiene il workflow più veloce, pur fornendo abbastanza dati per valutare l’effetto del fine-tuning.

dataset = load_dataset("ag_news")

train_dataset = dataset["train"].select(range(2500))
test_dataset = dataset["test"].select(range(200))

3. Formattazione del prompt e valutazione di baseline

Prima del fine-tuning, dobbiamo definire come il modello vedrà il compito e misurare come si comporta nella sua forma originale. 

In questa sezione creeremo un prompt in stile istruzioni per la classificazione delle notizie, estrarremo le previsioni dall’output del modello, eseguiremo un’inferenza di esempio e valuteremo il modello base sul set di test prima dell’addestramento.

Crea il prompt di istruzioni

Iniziamo definendo i nomi delle etichette e costruendo un prompt che chieda al modello di classificare un articolo di notizie. Il prompt è scritto affinché il modello restituisca solo l’etichetta numerica, semplificando l’analisi dell’output in fase di valutazione.

labels = ['World','Sports','Business','Sci/Tech']

def build_prompt(text):

    return f"""
Classify the news article.

Article:
{text}

Return ONLY the number of the correct label.

0 = World
1 = Sports
2 = Business
3 = Sci/Tech

Answer:
"""

Estrai le previsioni dall’output del modello

Creiamo quindi una piccola funzione di supporto per estrarre l’etichetta prevista dal testo generato. Questa funzione rimuove eventuali token di ragionamento extra e restituisce l’etichetta finale come intero.

import re

def extract_label(text):

   text = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL)
   matches = re.findall(r"[0-3]", text)

   if matches:
       return int(matches[-1])

   return -1

Esegui un’inferenza di esempio

Prima di valutare il modello sull’intero set di test, proviamolo su un singolo esempio. Questo ci aiuta a ispezionare l’articolo, verificare l’etichetta corretta e vedere cosa prevede il modello prima del fine-tuning.

sample = train_dataset[10]

sample_text = sample["text"]
sample_label = sample["label"]

print("Ground truth label:", sample_label)
print("Sample text:")
print(sample_text[:300])

L’output mostra che la vera etichetta è 2, che corrisponde a Business.

Ground truth label: 2
Sample text:
Oil and Economy Cloud Stocks' Outlook  NEW YORK (Reuters) - Soaring crude prices plus worries  about the economy 
and the outlook for earnings are expected to  hang over the stock market next week during the depth of the  summer doldrums.

Poi formattiamo il prompt, lo passiamo al modello e generiamo una previsione.

prompt = build_prompt(sample_text)

inputs = tokenizer(prompt, return_tensors="pt").to("cuda")

with torch.inference_mode():
    outputs = model.generate(
        **inputs,
        max_new_tokens=5,
        do_sample=False,
        pad_token_id=tokenizer.eos_token_id
    )

prediction = tokenizer.decode(outputs[0], skip_special_tokens=True)

print("Model prediction (before training):")
print(extract_label(prediction))

Il modello prevede anche 2, quindi classifica correttamente questo esempio. Questo ci dà una verifica rapida che il formato del prompt e la pipeline di previsione funzionano come previsto.

Model prediction (before training):
2

Valuta il modello base prima del fine-tuning

Ora valutiamo il modello base sul set di test per stabilire una baseline. Questo ci fornisce un punto di riferimento per confrontare le prestazioni prima e dopo il fine-tuning.

def evaluate_model(dataset):

    preds = []
    refs = []

    model.eval()

    for example in tqdm(dataset):

        text = example["text"]
        label = example["label"]

        prompt = build_prompt(text)

        inputs = tokenizer(prompt, return_tensors="pt", truncation=True)
        inputs = {k: v.to("cuda") for k, v in inputs.items()}

        with torch.inference_mode():

            outputs = model.generate(
                **inputs,
                max_new_tokens=5,
                do_sample=False,
                pad_token_id=tokenizer.eos_token_id
            )

        prediction = tokenizer.decode(outputs[0], skip_special_tokens=True)

        pred_label = extract_label(prediction)

        preds.append(pred_label)
        refs.append(label)

    acc = accuracy_score(refs, preds)
    f1 = f1_score(refs, preds, average="weighted")

    print("Accuracy:", acc)
    print("F1:", f1)


print('Pre-fine-tuning evaluation')
evaluate_model(test_dataset)

L’output riporta un’accuratezza di 0.52 e un F1 score pesato di 0.4589. Questi risultati di baseline mostrano che il modello ha già una certa capacità di svolgere il compito, pur lasciando ampio margine di miglioramento tramite fine-tuning.

Pre-fine-tuning evaluation
Accuracy: 0.52
F1: 0.45889163289429247

4. Fine-tuning di Qwen3.5 con QLoRA

Ora che abbiamo stabilito una baseline, possiamo fare il fine-tuning del modello sul task di classificazione delle notizie. In questa sezione formatteremo i dati di training, configureremo gli adapter LoRA, definiremo le impostazioni di training, alleneremo il modello e salveremo l’adapter finale per usi futuri.

Prepara i dati di training

Per prima cosa, formattiamo ogni esempio di training in modo che corrisponda alla stessa struttura di prompt usata in inferenza. Aggiungiamo l’etichetta corretta alla fine del prompt, così il modello può imparare a generare la risposta giusta durante il fine-tuning.

def format_train(example):
    prompt = build_prompt(example['text'])
    answer = str(example['label'])
    return {'text': prompt + ' ' + answer}

train_dataset = train_dataset.map(format_train)

Configura gli adapter LoRA

Successivamente definiamo la configurazione di LoRA. Questo indica al modello quali layer adattare durante il fine-tuning, permettendoci di addestrare un piccolo set di parametri aggiuntivi invece di aggiornare l’intero modello.

lora_config = LoraConfig(
    r=16,
    lora_alpha=16,
    lora_dropout=0,
    bias='none',
    task_type='CAUSAL_LM',
    target_modules=[
        'q_proj','k_proj','v_proj','o_proj',
        'gate_proj','up_proj','down_proj'
    ]
)

Definisci la configurazione di training

Impostiamo quindi gli argomenti di training per il supervised fine-tuning. Queste impostazioni controllano quante istanze vengono elaborate alla volta, come si accumulano i gradienti, quanto dura l’addestramento e dove salvare i file di output.

training_args = SFTConfig(
    output_dir="./qwen35-lora",
    per_device_train_batch_size=8,
    gradient_accumulation_steps=2,
    learning_rate=2e-4,
    num_train_epochs=1,
    logging_steps=10,
    bf16=True,
    dataset_text_field="text",
    packing=False,
)

Allena il modello

Ora inizializziamo il trainer con il modello, il dataset, la configurazione LoRA, le impostazioni di training e il tokenizer. Poi avviamo il fine-tuning del modello sul training set formattato di AG News.

trainer = SFTTrainer(
    model=model,
    train_dataset=train_dataset,
    peft_config=lora_config,
    args=training_args,
    processing_class=tokenizer
)
trainer.train()

Output: 

TrainOutput(global_step=157, training_loss=1.9094241804378047, metrics={'train_runtime': 616.477, 'train_samples_per_second': 4.055, 'train_steps_per_second': 0.255, 'total_flos': 1041693973114368.0, 'train_loss': 1.9094241804378047})

Salva l’adapter addestrato

Al termine dell’addestramento, salviamo l’adapter LoRA e il tokenizer. In questo modo possiamo ricaricare l’adapter fine-tunato in seguito per valutazione, condivisione o pubblicazione su Hugging Face.

trainer.model.save_pretrained("qwen35-small-news-class")
tokenizer.save_pretrained("qwen35-small-news-class")

5. Valuta il modello fine-tunato

Dopo l’addestramento, ricarichiamo il modello base e colleghiamo l’adapter LoRA salvato. Questo ci consente di eseguire la valutazione usando i pesi fine-tunati e confrontare i risultati con la baseline precedente.

Ricarica il modello base e collega l’adapter LoRA

Per prima cosa carichiamo di nuovo il modello Qwen3.5 base, quindi colleghiamo l’adapter LoRA fine-tunato salvato nella working directory di Kaggle. Dopo, passiamo il modello in modalità valutazione e ispezioniamo il riepilogo dei parametri addestrabili.

from transformers import AutoModelForCausalLM
base_model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    dtype=torch.bfloat16
)


from peft import PeftModel

model = PeftModel.from_pretrained(
    base_model,
    "/kaggle/working/qwen35-small-news-class"
)

model.eval()
model.print_trainable_parameters()

L’output mostra che in questa fase non ci sono parametri addestrabili perché l’addestramento è terminato e ora stiamo usando l’adapter salvato per inferenza e valutazione.

trainable params: 0 || all params: 758,782,784 || trainable%: 0.0000

Valuta il modello fine-tunato

Ora eseguiamo di nuovo la stessa funzione di valutazione sul set di test. Questo ci permette di misurare quanto il modello è migliorato dopo il fine-tuning.

print('Post-fine-tuning evaluation')
evaluate_model(test_dataset)

L’output riporta un’accuratezza di 0.865 e un F1 score pesato di 0.8661. Rispetto ai risultati di baseline, questo mostra un grande miglioramento dopo il fine-tuning.

Post-fine-tuning evaluation
Accuracy: 0.865
F1: 0.8660926258753361

Confronta i risultati

Ora possiamo confrontare le prestazioni del modello prima e dopo il fine-tuning. Sia l’accuratezza sia l’F1 score migliorano in modo sostanziale, mostrando che il fine-tuning con QLoRA aiuta il modello ad adattarsi bene al task di classificazione delle notizie.

Metrica

Prima del training

Dopo il training

Accuracy

0.52

0.865

F1 Score

0.4589

0.866

Come possiamo vedere, il fine-tuning di Qwen3.5 Small con QLoRA migliora significativamente le prestazioni di classificazione.

6. Pubblica il modello su Hugging Face

Una volta completata la valutazione, possiamo caricare l’adapter fine-tunato e il tokenizer su Hugging Face. Questo rende il modello più semplice da riutilizzare, condividere e caricare in progetti futuri senza ripetere l’intero processo di training.

model.push_to_hub("kingabzpro/qwen35-small-news-class")
tokenizer.push_to_hub("kingabzpro/qwen35-small-news-class")

Dopo il caricamento, il modello sarà disponibile qui:

Model:
https://huggingface.co/kingabzpro/qwen35-small-news-class

Fine-tuned Qwen 3.5 LoRA on Hugging Face

Fonte: kingabzpro/qwen35-small-news-class

È disponibile anche il notebook Kaggle per questo tutorial. Ti consiglio di usarlo solo se incontri problemi nel riprodurre i passaggi sopra. Puoi anche clonare il notebook ed eseguirlo sul tuo sistema, ma ricordati di aggiornare username e token di Hugging Face in base al tuo account.

7. Conclusione

In questo tutorial, abbiamo effettuato il fine-tuning di Qwen3.5-0.8B con QLoRA per la classificazione di notizie e abbiamo ottenuto un risultato solido con una configurazione molto leggera. Dopo una sola epoca su un piccolo sottoinsieme di dati, l’accuratezza è passata da 0.52 a 0.865 e l’F1 pesato da 0.4589 a 0.8661. 

Per un modello così piccolo, questa è onestamente la parte più sorprendente: non servono un modello enorme, un dataset gigantesco o un addestramento lungo per ottenere buoni risultati a valle.

Ciò che rende il tutto ancora più utile è la praticità della configurazione. Qwen descrive il modello da 0.8B come adatto a prototyping e fine-tuning specifico per il task, e QLoRA mantiene basso l’uso di memoria addestrando adapter sopra un modello base a 4 bit congelato. Questo significa che non è solo un workflow da notebook nel cloud: è realistico anche per test su GPU consumer e laptop più piccole.

Un altro motivo per cui trovo questo modello interessante è che la famiglia Qwen3.5 supporta sia il fine-tuning su testo che su visione. Quindi, anche se qui lo abbiamo usato per la classificazione di testo, la stessa idea può estendersi a classificazione di immagini, image-to-text e text-to-text. Questo rende un modello piccolo come questo un’opzione davvero pratica quando vuoi testare rapidamente idee, fare fine-tuning a basso costo e mantenere il deployment leggero.

Ti consiglio anche di dare un’occhiata alle nostre altre risorse, tra cui la guida a Qwen3.5 e il nostro tutorial su come eseguire Qwen3.5 in locale su una singola GPU.

FAQs

Perché usare QLoRA (quantizzazione a 4 bit) invece del fine-tuning completo per un modello da 0.8B?

Anche se 0.8B è considerato "small" secondo gli standard degli LLM, aggiornare completamente tutti gli 800 milioni di parametri richiede comunque molta VRAM e potenza di calcolo. QLoRA congela il modello base in precisione a 4 bit e allena solo un piccolo set di nuovi pesi di adapter sopra di esso. Questo riduce drasticamente l’impronta in memoria, permettendoti di addestrare comodamente su una GPU P100 gratuita di Kaggle o su un normale laptop consumer senza esaurire la memoria.

Qwen3.5 supporta una nuova modalità "thinking". Dovrei usarla per i task di classificazione?

Qwen3.5-0.8B supporta nativamente il ragionamento ibrido ma opera in modalità "non-thinking" per impostazione predefinita. Anche se puoi abilitare le sue capacità di ragionamento, compiti semplici di classificazione come AG News non richiedono logiche complesse passo dopo passo. Tenere disabilitata la thinking mode è molto più veloce e più efficiente in termini di token per un’etichettatura diretta.

In che modo la finestra di contesto enorme da 262K di Qwen3.5 influisce su questo script di fine-tuning?

Sebbene il modello base supporti nativamente fino a 262.144 token, il fine-tuning su documenti enormi esaurirà rapidamente la memoria della GPU su Kaggle. Per la classificazione di notizie, i testi sono brevi, quindi non è un problema. Se vuoi adattare questo script a task su documenti lunghi (come riassumere interi libri), dovrai abilitare il gradient checkpointing e ridurre la dimensione del batch.


Abid Ali Awan's photo
Author
Abid Ali Awan
LinkedIn
Twitter

In quanto data scientist certificato, sono appassionato di sfruttare tecnologie all’avanguardia per creare applicazioni di machine learning innovative. Con una solida esperienza in riconoscimento vocale, analisi e reportistica dei dati, MLOps, AI conversazionale e NLP, ho affinato le mie competenze nello sviluppo di sistemi intelligenti in grado di avere un impatto concreto. Oltre alla mia expertise tecnica, sono anche un comunicatore efficace, con il talento di rendere chiari e sintetici concetti complessi. Di conseguenza, sono diventato un blogger molto seguito in ambito data science, condividendo idee ed esperienze con una community in crescita di professionisti dei dati. Attualmente mi concentro sulla creazione e sull’editing di contenuti, lavorando con large language model per sviluppare contenuti potenti e coinvolgenti che possano aiutare aziende e singoli a valorizzare al meglio i propri dati.

Argomenti
Intelligenza artificiale

I migliori corsi DataCamp

Corso

Fine-tuning con Llama 3

2 ore
4.1K
Ottimizza Llama per attività personalizzate usando TorchTune e scopri tecniche per una messa a punto efficiente, come la quantizzazione.
Vedi i dettagliRight Arrow
Inizia Il Corso
Mostra altroRight Arrow
Correlato

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

Mostra AltroMostra Altro