Fine-tuning di Ministral 3: guida passo passo all’addestramento di un modello visione-linguaggio per la classificazione delle radiografie
Scopri come effettuare il fine-tuning del modello visione-linguaggio Ministral 3 per la classificazione di immagini a raggi X usando LoRA, strumenti Hugging Face, prompt personalizzati e TRL.
Ministral 3 è una nuova famiglia di modelli multimodali ottimizzati per l’edge, disponibili nelle dimensioni 3B, 8B e 14B, ciascuna con varianti Base, Instruct e Reasoning e pieno supporto alla visione.
Progettato per offrire prestazioni di frontiera restando al contempo abbastanza leggero per il deployment locale e privato, Ministral 3 unisce capacità avanzate a vincoli hardware pratici: il suo modello di punta 14B Instruct entra in 24 GB di VRAM in FP8 e rivaleggia con sistemi più grandi come Mistral Small 3.2 24B. Dispone di un ampio contesto da 256k, solida copertura multilingue, function calling nativo, forte aderenza al system prompt e licenza open Apache 2.0.
In questo tutorial, effettueremo il fine-tuning del modello Ministral 3 14B Instruct su un dataset di radiografie di fratture ossee per migliorarne la capacità di rilevare le fratture e classificarne correttamente le categorie.
Imparerai a:
Caricare il dataset da Kaggle.
Convertirlo in un dataset Hugging Face.
Creare un prompt di training chiaro per la classificazione delle radiografie.
Impostare la pipeline di training visione-linguaggio di Ministral 3 14B.
Effettuare il fine-tuning del modello e salvare il checkpoint.
Caricare l’adapter del modello addestrato per l’inferenza.
Confrontare i risultati prima e dopo il fine-tuning.
Disclaimer: questo tutorial illustra un processo tecnico di fine-tuning a solo scopo didattico. Il modello risultante non è destinato all’uso medico o clinico e non deve essere utilizzato per diagnosi, decisioni o assistenza ai pazienti.
1. Configurazione dell’ambiente per il fine-tuning visione-linguaggio di Ministral 3
Anche se stiamo effettuando il fine-tuning del modello 14B, l’addestramento visione-linguaggio richiede molta più memoria rispetto al solo testo. L’encoder di immagini aumenta il carico sulla GPU, quindi per eseguire il processo in modo fluido serve una GPU A100 con 80 GB di VRAM.
Per questo progetto utilizzo Runpod e avvio un pod A100.
Dopo l’avvio del pod, aumenta lo storage del container a 50 GB. Poi aggiungi le variabili d’ambiente per le API key di Kaggle e Hugging Face.
Kaggle ci permetterà di scaricare direttamente il dataset di radiografie ossee, mentre Hugging Face ci consentirà di caricare l’adapter LoRA fine-tunato sull’hub dei modelli.
Apri quindi l’istanza di JupyterLab e crea un nuovo notebook. Prima del training, dobbiamo installare tutti i pacchetti Python necessari.
Assicurati che la libreria Transformers sia aggiornata all’ultima versione, perché il supporto a Ministral 3 è stato aggiunto di recente e le build precedenti non caricheranno correttamente il modello.
Una volta installato tutto, sei pronto per caricare il dataset, preparare il collator e iniziare il fine-tuning.
2. Download del dataset di fratture ossee da Kaggle
Nel prossimo passaggio, impostiamo una cartella radice per il nostro dataset e usiamo la Python API di Kaggle per scaricare il dataset “Bone Break Classification Image”.
Questo dataset contiene varie categorie di fratture ossee in formato radiografico e sarà usato per il fine-tuning di Ministral 3 per la classificazione visiva.
import os
import glob
from kaggle.api.kaggle_api_extended import KaggleApi
DATA_ROOT ="/bone-break"
os.makedirs(DATA_ROOT, exist_ok=True)
kaggle_dataset ="pkdarabi/bone-break-classification-image-dataset"# Initialize and authenticate Kaggle API (it will read KAGGLE_USERNAME / KAGGLE_KEY)
api = KaggleApi()
api.authenticate()# Download and unzip the dataset using the Python API
api.dataset_download_files(
kaggle_dataset,
path=DATA_ROOT,
unzip=True,)Offerto da
Puoi visualizzare il dataset su Kaggle qui:
Dataset URL: https://www.kaggle.com/datasets/pkdarabi/bone-break-classification-image-datasetOfferto da
3. Creazione di un dataset Hugging Face
Il dataset scaricato non è organizzato nella struttura abituale. Ogni categoria di frattura contiene al suo interno sia una cartella di training sia una di test.
Quindi, per prima cosa, ci serve un metodo per iterare su ogni cartella di classe, separare i due split, e poi creare un dataset Hugging Face combinato con una mappatura pulita di train e test.
Abbiamo un totale di 10 classificazioni, con 989 campioni di training e 140 di test.
Classes:['Avulsion fracture','Comminuted fracture','Fracture Dislocation','Greenstick fracture','Hairline Fracture','Impacted fracture','Longitudinal fracture','Oblique fracture','Pathological fracture','Spiral Fracture']
Train samples:989
Test samples:140Offerto da
Ora codificheremo le etichette per il dataset Hugging Face in modo che ogni classe sia trattata come label di classe e ogni immagine come caratteristica immagine.
Creeremo due dataset: uno per il training e uno per il test. Infine li combineremo in un unico dataset che contiene entrambi i sottoinsiemi.
# Encode labels
classes =sorted(list(set(classes)))
label2id ={name: i for i, name inenumerate(classes)}for rec in train_records:
rec["label"]= label2id[rec["label_name"]]for rec in test_records:
rec["label"]= label2id[rec["label_name"]]
features = Features({"image": Image(),"label": ClassLabel(names=classes),})
train_ds = Dataset.from_list([{"image": r["image"],"label": r["label"]}for r in train_records],
features=features,)
test_ds = Dataset.from_list([{"image": r["image"],"label": r["label"]}for r in test_records],
features=features,)
data = DatasetDict({"train": train_ds,"test": test_ds})
dataOfferto da
Ecco una panoramica del dataset.
DatasetDict({
train: Dataset({
features:['image','label'],
num_rows:989})
test: Dataset({
features:['image','label'],
num_rows:140})})Offerto da
4. Esplorazione della distribuzione delle classi e di esempi di radiografie
Prima del fine-tuning, è utile capire quanto il dataset sia bilanciato e che aspetto abbiano le immagini. Inizieremo verificando quanti campioni di training esistono per ciascuna categoria di frattura.
from collections import Counter
label_names = data["train"].features["label"].names
label_ids = data["train"]["label"]
counts = Counter(label_ids)print("Training Class counts:")for lbl_id, cnt in counts.items():print(f"{lbl_id:2d} ({label_names[lbl_id]}): {cnt}")
FRACTURE_CLASSES = label_namesOfferto da
Le categorie sono piuttosto bilanciate, anche se la dimensione complessiva del campione è ridotta per un compito complesso di classificazione visiva.
Per ora procederemo con questo dataset, ma i risultati andrebbero interpretati con aspettative realistiche a causa del volume limitato di campioni.
Training Class counts:0(Avulsion fracture):1091(Comminuted fracture):1342(Fracture Dislocation):1373(Greenstick fracture):1064(Hairline Fracture):1015(Impacted fracture):756(Longitudinal fracture):687(Oblique fracture):698(Pathological fracture):1169(Spiral Fracture):74Offerto da
Successivamente, osserviamo alcune immagini casuali per comprendere meglio il dataset dal punto di vista visivo.
import matplotlib.pyplot as plt
from datasets import Image
# Cast the 'image' column to Hugging Face Image feature
dataset_images = data.cast_column("image", Image())# Select random samples from the training set
samples = dataset_images["train"].shuffle(seed=420).select(range(4))# Plot
fig, axes = plt.subplots(1,4, figsize=(16,5))for i, sample inenumerate(samples):
img_object = sample["image"]# PIL Image
label_id = sample["label"]# int
label_name = label_names[label_id]# string
axes[i].imshow(img_object)
axes[i].set_title(f"Label: {label_name}")
axes[i].axis("off")
plt.tight_layout()
plt.show()Offerto da
Guardando le immagini di esempio, si notano differenze in dimensione, risoluzione, orientamento e qualità della scansione. Questo non impedisce il fine-tuning di un modello visione-linguaggio, ma può influenzare la coerenza con cui il modello apprende ciascuna categoria di frattura.
Rilevare visivamente una frattura è spesso immediato, ma classificarla in uno dei dieci tipi medici sottilmente differenti richiede dati più strutturati rispetto a quelli forniti qui.
5. Progettazione del prompt per la classificazione delle fratture ossee
Dobbiamo ora decidere come vogliamo che il modello si comporti. Per questo compito, l’obiettivo è molto rigido: data un’immagine a raggi X, il modello deve restituire solo il nome di una classe di frattura e nient’altro. Niente spiegazioni, niente markdown, nessun testo extra.
Scriveremo un prompt di istruzioni chiaro e poi lo useremo per costruire una colonna messages nel dataset.
PROMPT =f"""
You are a radiology assistant specialised in bone fracture classification.
You must classify the X-ray image into exactly ONE of the following classes:
{", ".join(FRACTURE_CLASSES)}
Rules:
- Reply with ONLY the class name.
- No explanations, no extra words, no markdown, no punctuation.
- Output must be EXACTLY one of: {", ".join(FRACTURE_CLASSES)}
""".strip()from typing import Dict, Any
defconvert_to_conversation(example: Dict[str, Any])-> Dict[str, Any]:
conversation =[{"role":"user","content":[{"type":"text","text": PROMPT},{"type":"image"},# no image bytes here],},{"role":"assistant","content":[{"type":"text","text": FRACTURE_CLASSES[example["label"]]},],},]
example["messages"]= conversation
return example
formatted_data = data["train"].map(convert_to_conversation)
formatted_data["messages"][0]Offerto da
Questo crea una colonna messages in cui ogni record contiene una mini conversazione completa: l’istruzione e la classe di frattura corretta. È esattamente ciò che il modello visione-linguaggio vedrà durante il fine-tuning.
6. Caricamento del modello visione-linguaggio Ministral 3
Ora carichiamo la versione BF16 del modello Ministral-3 14B Instruct dall’Hugging Face Hub, insieme al processor. Il processor raggruppa il tokenizer e la pipeline di pre-processing delle immagini, necessaria per gli input visione-linguaggio.
import torch
from transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfig
model_id ="mistralai/Ministral-3-14B-Instruct-2512-BF16"
model_kwargs =dict(
attn_implementation="eager",
torch_dtype=torch.bfloat16,
device_map="auto",)
model = AutoModelForImageTextToText.from_pretrained(model_id,**model_kwargs)
processor = AutoProcessor.from_pretrained(model_id)# Use right padding to avoid issues during training
processor.tokenizer.padding_side ="right"Offerto da
7. Impostazione di un template chat personalizzato
Il template chat originale fornito da Mistral AI è pensato per casi d’uso conversazionali lunghi. Per questo progetto, è diventato un problema. Il modello ha iniziato a concentrarsi sulle lunghe istruzioni di ruolo e sul testo di sistema, ignorando l’obiettivo reale: prevedere una singola classe di frattura dall’immagine a raggi X.
Per risolvere, definiamo un template visione-linguaggio più corto che mantenga solo le parti importanti: l’istruzione dell’utente e la risposta dell’assistente. Questo riduce il rumore e aiuta il modello a imparare una mappatura pulita da immagine a etichetta di classe.
SHORT_VLM_TEMPLATE =r"""{{ bos_token }}[INST]
{% for message in messages if message['role'] == 'user' -%}
{%- for content in message['content'] -%}
{%- if content['type'] == 'text' -%}
{{ content['text'] }}
{%- elif content['type'] == 'image' -%}
[IMG]
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
[/INST]{% if not add_generation_prompt %}
{%- for message in messages if message['role'] == 'assistant' -%}
{{ message['content'][0]['text'] }}{{ eos_token }}
{%- endfor -%}
{%- endif %}"""# Attach to processor / tokenizer
processor.chat_template = SHORT_VLM_TEMPLATE
processor.tokenizer.chat_template = SHORT_VLM_TEMPLATEOfferto da
8. Test di Ministral 3 (pre-fine-tuning)
Prima di iniziare il fine-tuning, è utile testare il modello Ministral 3 14B Instruct originale per creare una baseline.
Per prima cosa, forniamo al modello un’immagine casuale dal dataset e poniamo una domanda generale, giusto per vedere come comprende il contenuto della radiografia.
Il modello ha compreso il contenuto generale della radiografia, ma poi è scivolato in descrizioni non affidabili per uso medico.
Poi proviamo qualcosa di più vicino al nostro obiettivo finale. Forniamo la stessa immagine, ma questa volta usiamo il nostro prompt rigoroso per la classificazione delle fratture invece di una domanda aperta.
Quindi, il modello ha seguito correttamente il formato dell’istruzione e prodotto un singolo nome di classe, ma la classificazione era errata.
Ed è proprio per questo che serve il fine-tuning. Il modello base ha una forte comprensione visiva, ma non è stato addestrato specificamente a distinguere tra i dettagliati tipi di fratture ossee.
Nei prossimi passaggi, lo fine-tuneremo sul nostro dataset di fratture per migliorare questo comportamento.
9. Configurazione di LoRA per un fine-tuning efficiente di Ministral 3
Ora impostiamo LoRA per effettuare il fine-tuning di Ministral 3 in modo efficiente senza aggiornare tutti i parametri. Questa configurazione prende di mira i principali strati di attenzione e proiezione MLP usati in un modello visione-linguaggio in stile Mistral.
from peft import LoraConfig, TaskType, get_peft_model
# LoRA config for a Mistral-style VLM used as a causal LM
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj",],
modules_to_save=None,)Offerto da
Poi definiamo gli argomenti di training per il supervised fine-tuning (SFT).
Questa configurazione controlla l’intero processo di training, inclusa la gestione dei batch, l’ottimizzazione della memoria, il comportamento del learning rate, il logging, la strategia di salvataggio e l’integrazione con l’Hugging Face Hub.
10. Creazione di un data collator visione-linguaggio per il training
Per il fine-tuning di un modello visione-linguaggio come Ministral 3, ci serve un data collator personalizzato che possa raggruppare immagini e testo in stile chat in un formato coerente.
Il collator seguente si occupa di: configurare tokenizer e token di padding, applicare il template chat, tokenizzare congiuntamente testo e immagini, imporre una lunghezza massima di sequenza sicura e creare le label in cui padding e token immagine sono mascherati (-100) così da non influenzare la loss.
from typing import Any, Dict, List
import torch
# --- One-time processor setup ---
tokenizer = processor.tokenizer
tokenizer.padding_side ="right"# Ensure we have a pad tokenif tokenizer.pad_token isNone:
tokenizer.add_special_tokens({"pad_token": tokenizer.eos_token})
pad_token_id = tokenizer.pad_token_id
image_token_id =getattr(processor,"image_token_id",None)# Hard cap for sequence length
MAX_SEQ_LEN =2048defcollate_fn(examples: List[Dict[str, Any]])-> Dict[str, torch.Tensor]:"""
Collate function for VLM fine-tuning.
Each example must contain:
- "image": a PIL image
- "messages": chat-style conversation (list[dict])
"""
images =[ex["image"]for ex in examples]
conversations =[ex["messages"]for ex in examples]# Build chat prompts for the whole batch
chat_texts = processor.apply_chat_template(
conversations,
add_generation_prompt=False,
tokenize=False,)# Tokenize + process images
batch = processor(
text=chat_texts,
images=images,
padding="longest",
truncation=True,
max_length=MAX_SEQ_LEN,
return_tensors="pt",)# Labels: same as input_ids but mask pad & image tokens
labels = batch["input_ids"].clone()if pad_token_id isnotNone:
labels[labels == pad_token_id]=-100if image_token_id isnotNoneand image_token_id != pad_token_id:
labels[labels == image_token_id]=-100
batch["labels"]= labels
return batchOfferto da
11. Fine-tuning di Ministral 3 con TRL
Con l’adapter LoRA, la configurazione di training e il data collator pronti, possiamo ora collegare tutto all’SFTTrainer di trl.
Questo trainer gestisce l’intero ciclo di supervised fine-tuning per il nostro modello visione-linguaggio Ministral 3, usando il dataset formattato, la config LoRA e la funzione di collate personalizzata per batch immagine–testo.
from trl import SFTTrainer
trainer = SFTTrainer(
model=model,
args=args,
train_dataset=formatted_data,
peft_config=peft_config,
processing_class=processor,
data_collator=collate_fn,)Offerto da
Esegui il codice seguente per avviare il processo di training.
Durante la mia esecuzione, il fine-tuning ha utilizzato circa 57 GB di VRAM, e un po’ di più durante gli step di valutazione che avvengono ogni poche iterazioni. In pratica, ciò significa che puoi effettuare il fine-tuning comodamente su hardware con meno di 70 GB di VRAM.
L’intero training è durato circa mezz’ora e la training loss è diminuita costantemente nel tempo, un buon segnale che il modello sta imparando dal dataset.
Una volta completato l’addestramento, salviamo il modello adattato su Hugging Face Hub. Questo creerà un nuovo repository e invierà tutti i file necessari affinché tu possa ricaricare ed eseguire il modello fine-tunato da qualsiasi ambiente.
12. Valutazione del modello Ministral 3 fine-tunato
Ora carichiamo il modello e il processor fine-tunati da Hugging Face Hub. Dietro le quinte, verrà scaricato l’adapter LoRA salvato, caricato il checkpoint base di Ministral 3 e unito l’adapter al modello base così da essere pronto per l’inferenza.
import torch
from transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfig
model_id ="kingabzpro/ministral-3-bone-fracture"
model_kwargs =dict(
attn_implementation="eager",
dtype=torch.bfloat16,
device_map="auto",)
model = AutoModelForImageTextToText.from_pretrained(model_id,**model_kwargs)
processor = AutoProcessor.from_pretrained(model_id)
processor.tokenizer.padding_side ="left"Offerto da
Per mantenere il confronto equo, riutilizziamo prima la stessa immagine testata prima del fine-tuning (indice 200) e la passiamo nella pipeline di inferenza con il nostro prompt di classificazione rigoroso.
Abbiamo ottenuto un risultato perfetto. Non è servito alcun post-processing aggiuntivo. Il modello ha seguito le regole del prompt e ha prodotto direttamente la classe corretta.
Anche in questo caso, la previsione è corretta e perfettamente allineata con l’etichetta.
Con queste verifiche, possiamo dire che il nostro modello Ministral 3 14B è stato fine-tunato con successo sul dataset di radiografie di fratture ossee ed è ora in grado di seguire il prompt di istruzioni e produrre previsioni accurate a singola classe per questi esempi.
Considerazioni finali
Il fine-tuning del modello Ministral 3 richiede pazienza e aggiustamenti graduali. Mi ci sono voluti davvero due giorni pieni per capire perché il modello non si addestrasse come mi aspettavo e perché, pur essendo relativamente piccolo, continuasse a mandare la GPU in out-of-memory.
La ragione principale era semplice, ma facile da trascurare. Non è solo un modello linguistico. È un modello visione-linguaggio, il che significa che incorpora un encoder di immagini che aggiunge ulteriore utilizzo di memoria.
Risoluzioni d’immagine più grandi portano direttamente a un maggiore consumo di VRAM. Ridurre la dimensione delle immagini o iniziare con batch più piccoli rende il processo di training molto più stabile.
Un altro problema che ho incontrato è stato l’uso del template chat predefinito. Era troppo lungo e strutturato per questo tipo di compito. Il modello impiegava più sforzi a seguire la formattazione del template invece di imparare a leggere le immagini e produrre una classificazione chiara della frattura.
Una volta semplificato il prompt in un formato di istruzione diretta, il modello ha finalmente iniziato a rispondere correttamente all’input visivo invece di modellare ogni risposta come una conversazione completa.
Davo anche per scontato che, poiché il modello ha forti capacità visive, si sarebbe comportato naturalmente bene sulle scansioni mediche. Questa supposizione mi ha rallentato. Chiamarlo “MedGemma” nella mia testa non è stato corretto né per il modello né per il processo. Non è un modello medico specializzato out-of-the-box, e aspettarmi che si comportasse come tale senza un adeguato training è stato un mio errore.
Alla fine, ho superato ogni ostacolo e ho trasformato ciò che ho imparato in questa guida. L’obiettivo è aiutarti a evitare la stessa confusione e arrivare più rapidamente a risultati significativi.
“Con immagini più piccole, prompt più semplici e aspettative realistiche, Ministral 3 può essere fine-tunato per la comprensione delle radiografie in modo molto più fluido e affidabile.”
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.
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.
Ministral 3 è una nuova famiglia di modelli multimodali ottimizzati per l’edge, disponibili nelle dimensioni 3B, 8B e 14B, ciascuna con varianti Base, Instruct e Reasoning e pieno supporto alla visione.
Progettato per offrire prestazioni di frontiera restando al contempo abbastanza leggero per il deployment locale e privato, Ministral 3 unisce capacità avanzate a vincoli hardware pratici: il suo modello di punta 14B Instruct entra in 24 GB di VRAM in FP8 e rivaleggia con sistemi più grandi come Mistral Small 3.2 24B. Dispone di un ampio contesto da 256k, solida copertura multilingue, function calling nativo, forte aderenza al system prompt e licenza open Apache 2.0.
In questo tutorial, effettueremo il fine-tuning del modello Ministral 3 14B Instruct su un dataset di radiografie di fratture ossee per migliorarne la capacità di rilevare le fratture e classificarne correttamente le categorie.
Imparerai a:
Se vuoi saperne di più sui modelli di Mistral AI, ti consiglio la nostra guida Mistral 3 e il tutorial Mistral 3 Large.
Disclaimer: questo tutorial illustra un processo tecnico di fine-tuning a solo scopo didattico. Il modello risultante non è destinato all’uso medico o clinico e non deve essere utilizzato per diagnosi, decisioni o assistenza ai pazienti.
1. Configurazione dell’ambiente per il fine-tuning visione-linguaggio di Ministral 3
Anche se stiamo effettuando il fine-tuning del modello 14B, l’addestramento visione-linguaggio richiede molta più memoria rispetto al solo testo. L’encoder di immagini aumenta il carico sulla GPU, quindi per eseguire il processo in modo fluido serve una GPU A100 con 80 GB di VRAM.
Per questo progetto utilizzo Runpod e avvio un pod A100.
Dopo l’avvio del pod, aumenta lo storage del container a 50 GB. Poi aggiungi le variabili d’ambiente per le API key di Kaggle e Hugging Face.
Kaggle ci permetterà di scaricare direttamente il dataset di radiografie ossee, mentre Hugging Face ci consentirà di caricare l’adapter LoRA fine-tunato sull’hub dei modelli.
Apri quindi l’istanza di JupyterLab e crea un nuovo notebook. Prima del training, dobbiamo installare tutti i pacchetti Python necessari.
Assicurati che la libreria Transformers sia aggiornata all’ultima versione, perché il supporto a Ministral 3 è stato aggiunto di recente e le build precedenti non caricheranno correttamente il modello.
Una volta installato tutto, sei pronto per caricare il dataset, preparare il collator e iniziare il fine-tuning.
2. Download del dataset di fratture ossee da Kaggle
Nel prossimo passaggio, impostiamo una cartella radice per il nostro dataset e usiamo la Python API di Kaggle per scaricare il dataset “Bone Break Classification Image”.
Questo dataset contiene varie categorie di fratture ossee in formato radiografico e sarà usato per il fine-tuning di Ministral 3 per la classificazione visiva.
Puoi visualizzare il dataset su Kaggle qui:
3. Creazione di un dataset Hugging Face
Il dataset scaricato non è organizzato nella struttura abituale. Ogni categoria di frattura contiene al suo interno sia una cartella di training sia una di test.
Quindi, per prima cosa, ci serve un metodo per iterare su ogni cartella di classe, separare i due split, e poi creare un dataset Hugging Face combinato con una mappatura pulita di train e test.
Abbiamo un totale di 10 classificazioni, con 989 campioni di training e 140 di test.
Ora codificheremo le etichette per il dataset Hugging Face in modo che ogni classe sia trattata come label di classe e ogni immagine come caratteristica immagine.
Creeremo due dataset: uno per il training e uno per il test. Infine li combineremo in un unico dataset che contiene entrambi i sottoinsiemi.
Ecco una panoramica del dataset.
4. Esplorazione della distribuzione delle classi e di esempi di radiografie
Prima del fine-tuning, è utile capire quanto il dataset sia bilanciato e che aspetto abbiano le immagini. Inizieremo verificando quanti campioni di training esistono per ciascuna categoria di frattura.
Le categorie sono piuttosto bilanciate, anche se la dimensione complessiva del campione è ridotta per un compito complesso di classificazione visiva.
Per ora procederemo con questo dataset, ma i risultati andrebbero interpretati con aspettative realistiche a causa del volume limitato di campioni.
Successivamente, osserviamo alcune immagini casuali per comprendere meglio il dataset dal punto di vista visivo.
Guardando le immagini di esempio, si notano differenze in dimensione, risoluzione, orientamento e qualità della scansione. Questo non impedisce il fine-tuning di un modello visione-linguaggio, ma può influenzare la coerenza con cui il modello apprende ciascuna categoria di frattura.
Rilevare visivamente una frattura è spesso immediato, ma classificarla in uno dei dieci tipi medici sottilmente differenti richiede dati più strutturati rispetto a quelli forniti qui.
5. Progettazione del prompt per la classificazione delle fratture ossee
Dobbiamo ora decidere come vogliamo che il modello si comporti. Per questo compito, l’obiettivo è molto rigido: data un’immagine a raggi X, il modello deve restituire solo il nome di una classe di frattura e nient’altro. Niente spiegazioni, niente markdown, nessun testo extra.
Scriveremo un prompt di istruzioni chiaro e poi lo useremo per costruire una colonna
messagesnel dataset.Questo crea una colonna
messagesin cui ogni record contiene una mini conversazione completa: l’istruzione e la classe di frattura corretta. È esattamente ciò che il modello visione-linguaggio vedrà durante il fine-tuning.6. Caricamento del modello visione-linguaggio Ministral 3
Ora carichiamo la versione BF16 del modello Ministral-3 14B Instruct dall’Hugging Face Hub, insieme al processor. Il processor raggruppa il tokenizer e la pipeline di pre-processing delle immagini, necessaria per gli input visione-linguaggio.
7. Impostazione di un template chat personalizzato
Il template chat originale fornito da Mistral AI è pensato per casi d’uso conversazionali lunghi. Per questo progetto, è diventato un problema. Il modello ha iniziato a concentrarsi sulle lunghe istruzioni di ruolo e sul testo di sistema, ignorando l’obiettivo reale: prevedere una singola classe di frattura dall’immagine a raggi X.
Per risolvere, definiamo un template visione-linguaggio più corto che mantenga solo le parti importanti: l’istruzione dell’utente e la risposta dell’assistente. Questo riduce il rumore e aiuta il modello a imparare una mappatura pulita da immagine a etichetta di classe.
8. Test di Ministral 3 (pre-fine-tuning)
Prima di iniziare il fine-tuning, è utile testare il modello Ministral 3 14B Instruct originale per creare una baseline.
Per prima cosa, forniamo al modello un’immagine casuale dal dataset e poniamo una domanda generale, giusto per vedere come comprende il contenuto della radiografia.
Il modello ha compreso il contenuto generale della radiografia, ma poi è scivolato in descrizioni non affidabili per uso medico.
Poi proviamo qualcosa di più vicino al nostro obiettivo finale. Forniamo la stessa immagine, ma questa volta usiamo il nostro prompt rigoroso per la classificazione delle fratture invece di una domanda aperta.
Per questo campione, il modello ha risposto con:
Ora controlliamo la ground truth per la stessa immagine.
Questo restituisce:
Quindi, il modello ha seguito correttamente il formato dell’istruzione e prodotto un singolo nome di classe, ma la classificazione era errata.
Ed è proprio per questo che serve il fine-tuning. Il modello base ha una forte comprensione visiva, ma non è stato addestrato specificamente a distinguere tra i dettagliati tipi di fratture ossee.
Nei prossimi passaggi, lo fine-tuneremo sul nostro dataset di fratture per migliorare questo comportamento.
9. Configurazione di LoRA per un fine-tuning efficiente di Ministral 3
Ora impostiamo LoRA per effettuare il fine-tuning di Ministral 3 in modo efficiente senza aggiornare tutti i parametri. Questa configurazione prende di mira i principali strati di attenzione e proiezione MLP usati in un modello visione-linguaggio in stile Mistral.
Poi definiamo gli argomenti di training per il supervised fine-tuning (SFT).
Questa configurazione controlla l’intero processo di training, inclusa la gestione dei batch, l’ottimizzazione della memoria, il comportamento del learning rate, il logging, la strategia di salvataggio e l’integrazione con l’Hugging Face Hub.
10. Creazione di un data collator visione-linguaggio per il training
Per il fine-tuning di un modello visione-linguaggio come Ministral 3, ci serve un data collator personalizzato che possa raggruppare immagini e testo in stile chat in un formato coerente.
Il collator seguente si occupa di: configurare tokenizer e token di padding, applicare il template chat, tokenizzare congiuntamente testo e immagini, imporre una lunghezza massima di sequenza sicura e creare le label in cui padding e token immagine sono mascherati (-100) così da non influenzare la loss.
11. Fine-tuning di Ministral 3 con TRL
Con l’adapter LoRA, la configurazione di training e il data collator pronti, possiamo ora collegare tutto all’SFTTrainer di trl.
Questo trainer gestisce l’intero ciclo di supervised fine-tuning per il nostro modello visione-linguaggio Ministral 3, usando il dataset formattato, la config LoRA e la funzione di collate personalizzata per batch immagine–testo.
Esegui il codice seguente per avviare il processo di training.
Durante la mia esecuzione, il fine-tuning ha utilizzato circa 57 GB di VRAM, e un po’ di più durante gli step di valutazione che avvengono ogni poche iterazioni. In pratica, ciò significa che puoi effettuare il fine-tuning comodamente su hardware con meno di 70 GB di VRAM.
L’intero training è durato circa mezz’ora e la training loss è diminuita costantemente nel tempo, un buon segnale che il modello sta imparando dal dataset.
Una volta completato l’addestramento, salviamo il modello adattato su Hugging Face Hub. Questo creerà un nuovo repository e invierà tutti i file necessari affinché tu possa ricaricare ed eseguire il modello fine-tunato da qualsiasi ambiente.
Puoi vedere il modello su kingabzpro/ministral-3-bone-fracture.
12. Valutazione del modello Ministral 3 fine-tunato
Ora carichiamo il modello e il processor fine-tunati da Hugging Face Hub. Dietro le quinte, verrà scaricato l’adapter LoRA salvato, caricato il checkpoint base di Ministral 3 e unito l’adapter al modello base così da essere pronto per l’inferenza.
Per mantenere il confronto equo, riutilizziamo prima la stessa immagine testata prima del fine-tuning (indice 200) e la passiamo nella pipeline di inferenza con il nostro prompt di classificazione rigoroso.
Abbiamo ottenuto un risultato perfetto. Non è servito alcun post-processing aggiuntivo. Il modello ha seguito le regole del prompt e ha prodotto direttamente la classe corretta.
Poi proviamo un altro campione casuale dal dataset per confermare che questo comportamento non sia limitato a un solo esempio.
Output del modello:
Ground truth:
Output:
Anche in questo caso, la previsione è corretta e perfettamente allineata con l’etichetta.
Con queste verifiche, possiamo dire che il nostro modello Ministral 3 14B è stato fine-tunato con successo sul dataset di radiografie di fratture ossee ed è ora in grado di seguire il prompt di istruzioni e produrre previsioni accurate a singola classe per questi esempi.
Considerazioni finali
Il fine-tuning del modello Ministral 3 richiede pazienza e aggiustamenti graduali. Mi ci sono voluti davvero due giorni pieni per capire perché il modello non si addestrasse come mi aspettavo e perché, pur essendo relativamente piccolo, continuasse a mandare la GPU in out-of-memory.
La ragione principale era semplice, ma facile da trascurare. Non è solo un modello linguistico. È un modello visione-linguaggio, il che significa che incorpora un encoder di immagini che aggiunge ulteriore utilizzo di memoria.
Risoluzioni d’immagine più grandi portano direttamente a un maggiore consumo di VRAM. Ridurre la dimensione delle immagini o iniziare con batch più piccoli rende il processo di training molto più stabile.
Un altro problema che ho incontrato è stato l’uso del template chat predefinito. Era troppo lungo e strutturato per questo tipo di compito. Il modello impiegava più sforzi a seguire la formattazione del template invece di imparare a leggere le immagini e produrre una classificazione chiara della frattura.
Una volta semplificato il prompt in un formato di istruzione diretta, il modello ha finalmente iniziato a rispondere correttamente all’input visivo invece di modellare ogni risposta come una conversazione completa.
Davo anche per scontato che, poiché il modello ha forti capacità visive, si sarebbe comportato naturalmente bene sulle scansioni mediche. Questa supposizione mi ha rallentato. Chiamarlo “MedGemma” nella mia testa non è stato corretto né per il modello né per il processo. Non è un modello medico specializzato out-of-the-box, e aspettarmi che si comportasse come tale senza un adeguato training è stato un mio errore.
Alla fine, ho superato ogni ostacolo e ho trasformato ciò che ho imparato in questa guida. L’obiettivo è aiutarti a evitare la stessa confusione e arrivare più rapidamente a risultati significativi.
“Con immagini più piccole, prompt più semplici e aspettative realistiche, Ministral 3 può essere fine-tunato per la comprensione delle radiografie in modo molto più fluido e affidabile.”
Se vuoi fare più pratica pratica con il fine-tuning, ti consiglio il corso Fine-tuning con Llama 3.