Ministral 3 là họ mô hình đa phương thức tối ưu cho thiết bị biên, có các kích thước 3B, 8B và 14B, mỗi kích cỡ đều cung cấp biến thể Base, Instruct và Reasoning với hỗ trợ thị giác đầy đủ.
Được thiết kế để mang lại hiệu năng tiệm cận nhóm dẫn đầu trong khi vẫn đủ gọn nhẹ cho triển khai cục bộ và riêng tư, Ministral 3 cân bằng giữa năng lực tiên tiến và ràng buộc phần cứng thực tế; mẫu chủ lực 14B Instruct chạy vừa 24GB VRAM ở FP8 và có thể sánh với các hệ lớn hơn như Mistral Small 3.2 24B. Mô hình có cửa sổ ngữ cảnh lớn 256k, bao phủ đa ngôn ngữ mạnh, gọi hàm gốc, tuân thủ system prompt tốt, và giấy phép mở Apache 2.0.
Trong hướng dẫn này, chúng ta sẽ tinh chỉnh mô hình Ministral 3 14B Instruct trên một tập dữ liệu X-quang gãy xương để cải thiện khả năng phát hiện và phân loại chính xác các nhóm gãy.
Bạn sẽ học cách:
Tải tập dữ liệu từ Kaggle.
Chuyển đổi sang tập dữ liệu Hugging Face.
Tạo prompt huấn luyện rõ ràng cho phân loại X-quang.
Thiết lập pipeline huấn luyện ngôn ngữ–thị giác với Ministral 3 14B.
Lưu ý: Hướng dẫn này minh họa quy trình tinh chỉnh kỹ thuật nhằm mục đích giáo dục. Mô hình tạo ra không dành cho mục đích y tế hay lâm sàng và không nên được sử dụng để chẩn đoán, ra quyết định hay chăm sóc bệnh nhân.
1. Thiết lập môi trường để tinh chỉnh mô hình ngôn ngữ–thị giác Ministral 3
Dù chúng ta tinh chỉnh mô hình 14B, huấn luyện ngôn ngữ–thị giác đòi hỏi bộ nhớ nhiều hơn đáng kể so với tinh chỉnh chỉ văn bản. Bộ mã hóa ảnh làm tăng tải GPU, nghĩa là chúng ta cần GPU A100 với 80 GB VRAM để chạy mượt mà.
Trong dự án này, tôi dùng Runpod và khởi chạy một pod A100.
Sau khi khởi chạy pod, tăng dung lượng lưu trữ container lên 50 GB. Sau đó thêm biến môi trường cho cả khóa API của Kaggle và Hugging Face.
Kaggle cho phép tải trực tiếp tập dữ liệu X-quang xương, còn Hugging Face cho phép đẩy adapter LoRA đã tinh chỉnh lên hub mô hình.
Tiếp theo, mở JupyterLab và tạo một notebook mới. Trước khi huấn luyện, chúng ta cần cài đặt tất cả các gói Python cần thiết.
Hãy đảm bảo thư viện Transformers được cập nhật lên phiên bản mới nhất, vì hỗ trợ Ministral 3 mới được bổ sung gần đây; các bản cũ sẽ không tải mô hình đúng cách.
Khi đã cài đặt xong, bạn sẵn sàng tải dữ liệu, chuẩn bị collator và bắt đầu tinh chỉnh.
2. Tải tập dữ liệu gãy xương từ Kaggle
Ở bước tiếp theo, chúng ta tạo thư mục gốc cho tập dữ liệu và dùng Kaggle Python API để tải bộ Bone Break Classification Image.
Bộ dữ liệu này chứa nhiều loại gãy xương ở định dạng X-quang và sẽ dùng để tinh chỉnh Ministral 3 cho nhiệm vụ phân loại hình ảnh.
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,)Được hỗ trợ bởi
Bạn có thể xem tập dữ liệu trên Kaggle tại đây:
Dataset URL: https://www.kaggle.com/datasets/pkdarabi/bone-break-classification-image-datasetĐược hỗ trợ bởi
3. Xây dựng tập dữ liệu Hugging Face
Tập dữ liệu đã tải không được tổ chức theo cấu trúc thông thường. Mỗi nhóm gãy xương chứa cả thư mục train và test ở bên trong.
Vì vậy trước tiên, ta cần phương thức duyệt qua từng thư mục lớp, tách hai phần train/test, rồi tạo một tập dữ liệu Hugging Face kết hợp với ánh xạ train và test gọn gàng.
Chúng ta có tổng cộng 10 loại phân loại, với 989 mẫu huấn luyện và 140 mẫu kiểm tra.
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:140Được hỗ trợ bởi
Giờ chúng ta sẽ mã hóa nhãn cho tập dữ liệu Hugging Face để mỗi lớp nhãn được coi là nhãn phân loại và mỗi ảnh là đặc trưng ảnh.
Chúng ta sẽ tạo hai tập: một cho huấn luyện và một cho kiểm tra. Cuối cùng, gộp chúng thành một tập duy nhất chứa cả hai phần.
# 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})
dataĐược hỗ trợ bởi
Trước khi tinh chỉnh, việc hiểu độ cân bằng của tập dữ liệu và đặc điểm ảnh là hữu ích. Chúng ta sẽ bắt đầu bằng cách kiểm tra số mẫu huấn luyện ở mỗi loại gãy xương.
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_namesĐược hỗ trợ bởi
Các nhóm tương đối cân bằng, dù tổng số mẫu là nhỏ cho một tác vụ phân loại thị giác phức tạp.
Trước mắt, chúng ta sẽ tiếp tục với tập này, nhưng cần diễn giải kết quả với kỳ vọng thực tế do số mẫu hạn chế.
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):74Được hỗ trợ bởi
Tiếp theo, hãy xem vài ảnh ngẫu nhiên để hiểu trực quan về tập dữ liệu.
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()Được hỗ trợ bởi
Quan sát các ảnh mẫu, có thể thấy sự khác biệt về kích thước, độ phân giải, hướng và chất lượng quét. Điều này không ảnh hưởng đến việc tinh chỉnh mô hình ngôn ngữ–thị giác, nhưng có thể tác động đến mức độ mô hình học nhất quán từng loại gãy.
Việc phát hiện gãy xương bằng quan sát có thể khá rõ ràng, nhưng phân loại vào một trong mười loại gãy y khoa tinh vi đòi hỏi dữ liệu có cấu trúc hơn so với những gì có ở đây.
5. Thiết kế prompt cho phân loại gãy xương
Tiếp theo, chúng ta cần quyết định cách mô hình sẽ ứng xử. Với tác vụ này, mục tiêu rất nghiêm ngặt: khi nhận một ảnh X-quang, mô hình phải xuất ra chính xác một tên lớp gãy xương và không có gì khác. Không giải thích, không markdown, không văn bản thừa.
Chúng ta sẽ viết một prompt chỉ dẫn rõ ràng rồi dùng nó để xây dựng cột messages trong tập dữ liệu.
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]Được hỗ trợ bởi
Điều này tạo ra cột messages trong đó mỗi bản ghi chứa một hội thoại nhỏ hoàn chỉnh: chỉ dẫn và lớp gãy xương đúng. Đây chính là những gì mô hình ngôn ngữ–thị giác sẽ thấy trong quá trình tinh chỉnh.
6. Tải mô hình ngôn ngữ–thị giác Ministral 3
Giờ chúng ta tải phiên bản BF16 của mô hình Ministral-3 14B Instruct từ Hugging Face Hub, kèm theo processor. Processor gộp tokenizer và pipeline tiền xử lý ảnh, vốn cần thiết cho đầu vào ngôn ngữ–thị giác.
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"Được hỗ trợ bởi
7. Thiết lập mẫu chat tùy chỉnh
Mẫu chat gốc do Mistral AI cung cấp được thiết kế cho các trường hợp hội thoại dài. Với dự án này, đó lại thành vấn đề. Mô hình bắt đầu tập trung vào các chỉ dẫn vai trò và văn bản hệ thống dài, bỏ qua mục tiêu thực sự là dự đoán một lớp gãy xương duy nhất từ ảnh X-quang.
Để khắc phục, chúng ta định nghĩa một mẫu ngôn ngữ–thị giác ngắn hơn, chỉ giữ phần quan trọng: chỉ dẫn của người dùng và câu trả lời của trợ lý. Điều này giảm nhiễu và giúp mô hình học ánh xạ sạch từ ảnh sang nhãn lớp.
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_TEMPLATEĐược hỗ trợ bởi
8. Kiểm thử Ministral 3 (trước tinh chỉnh)
Trước khi bắt đầu tinh chỉnh, việc kiểm thử mô hình Ministral 3 14B Instruct gốc để tạo đường cơ sở là hữu ích.
Đầu tiên, ta đưa cho mô hình một ảnh ngẫu nhiên từ tập dữ liệu và hỏi một câu chung chung, chỉ để xem nó hiểu nội dung X-quang như thế nào.
Vậy là mô hình làm đúng định dạng chỉ dẫn và sinh ra một tên lớp duy nhất, nhưng bản thân phân loại lại sai.
Đây chính là lý do cần tinh chỉnh. Mô hình gốc có khả năng hiểu thị giác mạnh, nhưng chưa được huấn luyện đặc thù để phân biệt các loại gãy xương chi tiết.
Ở các bước tiếp theo, chúng ta sẽ tinh chỉnh trên tập gãy xương để cải thiện hành vi đó.
9. Cấu hình LoRA để tinh chỉnh Ministral 3 hiệu quả
Tiếp theo, ta thiết lập LoRA để tinh chỉnh Ministral 3 một cách hiệu quả mà không cần cập nhật toàn bộ tham số. Cấu hình này nhắm vào các lớp attention chính và MLP projection được dùng trong mô hình ngôn ngữ–thị giác kiểu 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,)Được hỗ trợ bởi
Tiếp theo, chúng ta định nghĩa các tham số huấn luyện SFT (supervised fine-tuning).
Cấu hình này kiểm soát toàn bộ quá trình huấn luyện, bao gồm cách xử lý batch, tối ưu bộ nhớ, hành vi learning rate, logging, chiến lược lưu, và tích hợp với Hugging Face Hub.
10. Xây dựng data collator ngôn ngữ–thị giác cho huấn luyện
Để tinh chỉnh một mô hình ngôn ngữ–thị giác như Ministral 3, chúng ta cần một data collator tùy chỉnh có thể gom batch ảnh và văn bản dạng hội thoại theo định dạng nhất quán.
Collator dưới đây đảm nhiệm: thiết lập tokenizer và pad token, áp dụng mẫu chat, tokenize văn bản và ảnh cùng nhau, giới hạn độ dài chuỗi an toàn, và tạo nhãn trong đó padding và image token được che (-100) để không ảnh hưởng tới 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 batchĐược hỗ trợ bởi
11. Tinh chỉnh Ministral 3 bằng TRL
Với LoRA adapter, cấu hình huấn luyện và data collator đã sẵn sàng, giờ ta có thể nối tất cả vào SFTTrainer của trl.
Trainer này xử lý trọn vòng lặp tinh chỉnh có giám sát cho mô hình ngôn ngữ–thị giác Ministral 3 của chúng ta, sử dụng tập dữ liệu đã định dạng, cấu hình LoRA và hàm collate tùy chỉnh cho batch ảnh–văn bản.
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,)Được hỗ trợ bởi
Chạy đoạn mã dưới đây để bắt đầu quá trình huấn luyện.
Trong lần chạy của tôi, tinh chỉnh sử dụng khoảng 57 GB VRAM, và nhiều hơn một chút trong các bước đánh giá chạy sau vài vòng lặp. Thực tế, bạn có thể tinh chỉnh cấu hình này thoải mái trên phần cứng dưới 70 GB VRAM.
Toàn bộ huấn luyện mất khoảng nửa giờ, và training loss giảm đều theo thời gian, đây là dấu hiệu tốt cho thấy mô hình đang học từ tập dữ liệu.
Khi hoàn tất huấn luyện, chúng ta lưu mô hình đã thích ứng lên Hugging Face Hub. Điều này sẽ tạo một kho mới và đẩy tất cả tệp cần thiết để bạn có thể tải lại và chạy mô hình đã tinh chỉnh ở bất kỳ môi trường nào.
Giờ chúng ta tải mô hình và processor đã tinh chỉnh từ Hugging Face Hub. Bên dưới, thao tác này sẽ tải adapter LoRA đã lưu, tải checkpoint Ministral 3 gốc và gộp adapter vào mô hình gốc để sẵn sàng suy luận.
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"Được hỗ trợ bởi
Để so sánh công bằng, trước hết ta dùng lại cùng ảnh đã kiểm thử trước tinh chỉnh (chỉ số 200) và chạy qua pipeline suy luận với prompt phân loại nghiêm ngặt.
Một lần nữa, dự đoán chính xác và trùng khớp hoàn toàn với nhãn.
Với các kiểm tra này, có thể nói mô hình Ministral 3 14B của chúng ta đã được tinh chỉnh thành công trên tập X-quang gãy xương và hiện có thể tuân thủ prompt chỉ dẫn, đưa ra dự đoán một lớp chính xác cho các ví dụ này.
Suy ngẫm cuối
Tinh chỉnh mô hình Ministral 3 đòi hỏi kiên nhẫn và điều chỉnh dần dần. Tôi thực sự mất hai ngày để hiểu vì sao mô hình không huấn luyện như kỳ vọng và vì sao, dù tương đối nhỏ, nó vẫn khiến GPU của tôi tràn bộ nhớ.
Nguyên nhân chính rất đơn giản nhưng dễ bị bỏ qua. Đây không chỉ là mô hình ngôn ngữ. Nó là mô hình ngôn ngữ–thị giác, nghĩa là có bộ mã hóa ảnh làm tăng mức dùng bộ nhớ.
Độ phân giải ảnh lớn kéo theo mức tiêu thụ VRAM cao hơn trực tiếp. Giảm kích thước ảnh hoặc bắt đầu với batch nhỏ giúp quá trình huấn luyện ổn định hơn nhiều.
Một vấn đề khác tôi gặp phải là dùng mẫu chat mặc định. Nó quá dài và nặng cấu trúc cho kiểu tác vụ này. Mô hình tốn nhiều công sức để phù hợp định dạng mẫu hơn là học cách đọc ảnh và đưa ra phân loại gãy rõ ràng.
Khi tôi đơn giản hóa prompt thành chỉ dẫn trực tiếp, mô hình cuối cùng bắt đầu phản hồi đúng với đầu vào hình ảnh thay vì định dạng mọi câu trả lời như một phản hồi chat đầy đủ.
Tôi cũng từng cho rằng vì mô hình có khả năng thị giác mạnh nên sẽ tự nhiên làm tốt trên ảnh y khoa. Giả định đó làm tôi chậm lại. Gọi nó là “MedGemma” trong đầu không công bằng với mô hình hay quy trình. Nó không phải mô hình y khoa chuyên biệt ngay từ đầu, và kỳ vọng nó cư xử như vậy mà không được huấn luyện phù hợp là sai lầm của tôi.
Cuối cùng, tôi đã vượt qua từng trở ngại và biến những gì học được thành hướng dẫn này. Mục tiêu là giúp bạn tránh bối rối tương tự và đạt kết quả có ý nghĩa nhanh hơn.
“Với ảnh nhỏ hơn, prompt đơn giản hơn và kỳ vọng thực tế, Ministral 3 có thể được tinh chỉnh để hiểu X-quang mượt mà và tin cậy hơn nhiều.”
Là một nhà khoa học dữ liệu được chứng nhận, tôi đam mê tận dụng công nghệ tiên tiến để tạo ra các ứng dụng học máy đổi mới. Với nền tảng vững chắc về nhận dạng giọng nói, phân tích và báo cáo dữ liệu, MLOps, AI hội thoại và NLP, tôi đã rèn giũa kỹ năng phát triển các hệ thống thông minh có thể tạo ra tác động thực sự. Bên cạnh chuyên môn kỹ thuật, tôi cũng là một người truyền đạt tốt, có khả năng chắt lọc các khái niệm phức tạp thành ngôn ngữ rõ ràng, súc tích. Nhờ đó, tôi trở thành một blogger được nhiều người quan tâm trong lĩnh vực khoa học dữ liệu, chia sẻ góc nhìn và kinh nghiệm với cộng đồng các chuyên gia dữ liệu ngày càng lớn. Hiện tại, tôi tập trung vào sáng tạo và biên tập nội dung, làm việc với các mô hình ngôn ngữ lớn để phát triển nội dung mạnh mẽ và hấp dẫn, giúp doanh nghiệp và cá nhân tận dụng tối đa dữ liệu của mình.
Ministral 3 là họ mô hình đa phương thức tối ưu cho thiết bị biên, có các kích thước 3B, 8B và 14B, mỗi kích cỡ đều cung cấp biến thể Base, Instruct và Reasoning với hỗ trợ thị giác đầy đủ.
Được thiết kế để mang lại hiệu năng tiệm cận nhóm dẫn đầu trong khi vẫn đủ gọn nhẹ cho triển khai cục bộ và riêng tư, Ministral 3 cân bằng giữa năng lực tiên tiến và ràng buộc phần cứng thực tế; mẫu chủ lực 14B Instruct chạy vừa 24GB VRAM ở FP8 và có thể sánh với các hệ lớn hơn như Mistral Small 3.2 24B. Mô hình có cửa sổ ngữ cảnh lớn 256k, bao phủ đa ngôn ngữ mạnh, gọi hàm gốc, tuân thủ system prompt tốt, và giấy phép mở Apache 2.0.
Trong hướng dẫn này, chúng ta sẽ tinh chỉnh mô hình Ministral 3 14B Instruct trên một tập dữ liệu X-quang gãy xương để cải thiện khả năng phát hiện và phân loại chính xác các nhóm gãy.
Bạn sẽ học cách:
Nếu bạn muốn tìm hiểu thêm về các mô hình của Mistral AI, hãy tham khảo hướng dẫn Mistral 3 và hướng dẫn Mistral 3 Large.
Lưu ý: Hướng dẫn này minh họa quy trình tinh chỉnh kỹ thuật nhằm mục đích giáo dục. Mô hình tạo ra không dành cho mục đích y tế hay lâm sàng và không nên được sử dụng để chẩn đoán, ra quyết định hay chăm sóc bệnh nhân.
1. Thiết lập môi trường để tinh chỉnh mô hình ngôn ngữ–thị giác Ministral 3
Dù chúng ta tinh chỉnh mô hình 14B, huấn luyện ngôn ngữ–thị giác đòi hỏi bộ nhớ nhiều hơn đáng kể so với tinh chỉnh chỉ văn bản. Bộ mã hóa ảnh làm tăng tải GPU, nghĩa là chúng ta cần GPU A100 với 80 GB VRAM để chạy mượt mà.
Trong dự án này, tôi dùng Runpod và khởi chạy một pod A100.
Sau khi khởi chạy pod, tăng dung lượng lưu trữ container lên 50 GB. Sau đó thêm biến môi trường cho cả khóa API của Kaggle và Hugging Face.
Kaggle cho phép tải trực tiếp tập dữ liệu X-quang xương, còn Hugging Face cho phép đẩy adapter LoRA đã tinh chỉnh lên hub mô hình.
Tiếp theo, mở JupyterLab và tạo một notebook mới. Trước khi huấn luyện, chúng ta cần cài đặt tất cả các gói Python cần thiết.
Hãy đảm bảo thư viện Transformers được cập nhật lên phiên bản mới nhất, vì hỗ trợ Ministral 3 mới được bổ sung gần đây; các bản cũ sẽ không tải mô hình đúng cách.
Khi đã cài đặt xong, bạn sẵn sàng tải dữ liệu, chuẩn bị collator và bắt đầu tinh chỉnh.
2. Tải tập dữ liệu gãy xương từ Kaggle
Ở bước tiếp theo, chúng ta tạo thư mục gốc cho tập dữ liệu và dùng Kaggle Python API để tải bộ Bone Break Classification Image.
Bộ dữ liệu này chứa nhiều loại gãy xương ở định dạng X-quang và sẽ dùng để tinh chỉnh Ministral 3 cho nhiệm vụ phân loại hình ảnh.
Bạn có thể xem tập dữ liệu trên Kaggle tại đây:
3. Xây dựng tập dữ liệu Hugging Face
Tập dữ liệu đã tải không được tổ chức theo cấu trúc thông thường. Mỗi nhóm gãy xương chứa cả thư mục train và test ở bên trong.
Vì vậy trước tiên, ta cần phương thức duyệt qua từng thư mục lớp, tách hai phần train/test, rồi tạo một tập dữ liệu Hugging Face kết hợp với ánh xạ train và test gọn gàng.
Chúng ta có tổng cộng 10 loại phân loại, với 989 mẫu huấn luyện và 140 mẫu kiểm tra.
Giờ chúng ta sẽ mã hóa nhãn cho tập dữ liệu Hugging Face để mỗi lớp nhãn được coi là nhãn phân loại và mỗi ảnh là đặc trưng ảnh.
Chúng ta sẽ tạo hai tập: một cho huấn luyện và một cho kiểm tra. Cuối cùng, gộp chúng thành một tập duy nhất chứa cả hai phần.
Tổng quan tập dữ liệu như sau.
4. Khám phá phân bố lớp và xem mẫu ảnh X-quang
Trước khi tinh chỉnh, việc hiểu độ cân bằng của tập dữ liệu và đặc điểm ảnh là hữu ích. Chúng ta sẽ bắt đầu bằng cách kiểm tra số mẫu huấn luyện ở mỗi loại gãy xương.
Các nhóm tương đối cân bằng, dù tổng số mẫu là nhỏ cho một tác vụ phân loại thị giác phức tạp.
Trước mắt, chúng ta sẽ tiếp tục với tập này, nhưng cần diễn giải kết quả với kỳ vọng thực tế do số mẫu hạn chế.
Tiếp theo, hãy xem vài ảnh ngẫu nhiên để hiểu trực quan về tập dữ liệu.
Quan sát các ảnh mẫu, có thể thấy sự khác biệt về kích thước, độ phân giải, hướng và chất lượng quét. Điều này không ảnh hưởng đến việc tinh chỉnh mô hình ngôn ngữ–thị giác, nhưng có thể tác động đến mức độ mô hình học nhất quán từng loại gãy.
Việc phát hiện gãy xương bằng quan sát có thể khá rõ ràng, nhưng phân loại vào một trong mười loại gãy y khoa tinh vi đòi hỏi dữ liệu có cấu trúc hơn so với những gì có ở đây.
5. Thiết kế prompt cho phân loại gãy xương
Tiếp theo, chúng ta cần quyết định cách mô hình sẽ ứng xử. Với tác vụ này, mục tiêu rất nghiêm ngặt: khi nhận một ảnh X-quang, mô hình phải xuất ra chính xác một tên lớp gãy xương và không có gì khác. Không giải thích, không markdown, không văn bản thừa.
Chúng ta sẽ viết một prompt chỉ dẫn rõ ràng rồi dùng nó để xây dựng cột
messagestrong tập dữ liệu.Điều này tạo ra cột
messagestrong đó mỗi bản ghi chứa một hội thoại nhỏ hoàn chỉnh: chỉ dẫn và lớp gãy xương đúng. Đây chính là những gì mô hình ngôn ngữ–thị giác sẽ thấy trong quá trình tinh chỉnh.6. Tải mô hình ngôn ngữ–thị giác Ministral 3
Giờ chúng ta tải phiên bản BF16 của mô hình Ministral-3 14B Instruct từ Hugging Face Hub, kèm theo processor. Processor gộp tokenizer và pipeline tiền xử lý ảnh, vốn cần thiết cho đầu vào ngôn ngữ–thị giác.
7. Thiết lập mẫu chat tùy chỉnh
Mẫu chat gốc do Mistral AI cung cấp được thiết kế cho các trường hợp hội thoại dài. Với dự án này, đó lại thành vấn đề. Mô hình bắt đầu tập trung vào các chỉ dẫn vai trò và văn bản hệ thống dài, bỏ qua mục tiêu thực sự là dự đoán một lớp gãy xương duy nhất từ ảnh X-quang.
Để khắc phục, chúng ta định nghĩa một mẫu ngôn ngữ–thị giác ngắn hơn, chỉ giữ phần quan trọng: chỉ dẫn của người dùng và câu trả lời của trợ lý. Điều này giảm nhiễu và giúp mô hình học ánh xạ sạch từ ảnh sang nhãn lớp.
8. Kiểm thử Ministral 3 (trước tinh chỉnh)
Trước khi bắt đầu tinh chỉnh, việc kiểm thử mô hình Ministral 3 14B Instruct gốc để tạo đường cơ sở là hữu ích.
Đầu tiên, ta đưa cho mô hình một ảnh ngẫu nhiên từ tập dữ liệu và hỏi một câu chung chung, chỉ để xem nó hiểu nội dung X-quang như thế nào.
Kết quả là mô hình hiểu nội dung tổng quát của X-quang, nhưng sau đó trôi sang các mô tả không đáng tin cậy cho mục đích y khoa.
Tiếp theo, ta thử điều gần với mục tiêu cuối cùng hơn. Vẫn dùng ảnh đó, nhưng lần này dùng prompt phân loại gãy xương nghiêm ngặt thay vì câu hỏi mở.
Với mẫu này, mô hình trả lời:
Giờ kiểm tra nhãn sự thật cho cùng ảnh đó.
Kết quả trả về:
Vậy là mô hình làm đúng định dạng chỉ dẫn và sinh ra một tên lớp duy nhất, nhưng bản thân phân loại lại sai.
Đây chính là lý do cần tinh chỉnh. Mô hình gốc có khả năng hiểu thị giác mạnh, nhưng chưa được huấn luyện đặc thù để phân biệt các loại gãy xương chi tiết.
Ở các bước tiếp theo, chúng ta sẽ tinh chỉnh trên tập gãy xương để cải thiện hành vi đó.
9. Cấu hình LoRA để tinh chỉnh Ministral 3 hiệu quả
Tiếp theo, ta thiết lập LoRA để tinh chỉnh Ministral 3 một cách hiệu quả mà không cần cập nhật toàn bộ tham số. Cấu hình này nhắm vào các lớp attention chính và MLP projection được dùng trong mô hình ngôn ngữ–thị giác kiểu Mistral.
Tiếp theo, chúng ta định nghĩa các tham số huấn luyện SFT (supervised fine-tuning).
Cấu hình này kiểm soát toàn bộ quá trình huấn luyện, bao gồm cách xử lý batch, tối ưu bộ nhớ, hành vi learning rate, logging, chiến lược lưu, và tích hợp với Hugging Face Hub.
10. Xây dựng data collator ngôn ngữ–thị giác cho huấn luyện
Để tinh chỉnh một mô hình ngôn ngữ–thị giác như Ministral 3, chúng ta cần một data collator tùy chỉnh có thể gom batch ảnh và văn bản dạng hội thoại theo định dạng nhất quán.
Collator dưới đây đảm nhiệm: thiết lập tokenizer và pad token, áp dụng mẫu chat, tokenize văn bản và ảnh cùng nhau, giới hạn độ dài chuỗi an toàn, và tạo nhãn trong đó padding và image token được che (-100) để không ảnh hưởng tới loss.
11. Tinh chỉnh Ministral 3 bằng TRL
Với LoRA adapter, cấu hình huấn luyện và data collator đã sẵn sàng, giờ ta có thể nối tất cả vào SFTTrainer của trl.
Trainer này xử lý trọn vòng lặp tinh chỉnh có giám sát cho mô hình ngôn ngữ–thị giác Ministral 3 của chúng ta, sử dụng tập dữ liệu đã định dạng, cấu hình LoRA và hàm collate tùy chỉnh cho batch ảnh–văn bản.
Chạy đoạn mã dưới đây để bắt đầu quá trình huấn luyện.
Trong lần chạy của tôi, tinh chỉnh sử dụng khoảng 57 GB VRAM, và nhiều hơn một chút trong các bước đánh giá chạy sau vài vòng lặp. Thực tế, bạn có thể tinh chỉnh cấu hình này thoải mái trên phần cứng dưới 70 GB VRAM.
Toàn bộ huấn luyện mất khoảng nửa giờ, và training loss giảm đều theo thời gian, đây là dấu hiệu tốt cho thấy mô hình đang học từ tập dữ liệu.
Khi hoàn tất huấn luyện, chúng ta lưu mô hình đã thích ứng lên Hugging Face Hub. Điều này sẽ tạo một kho mới và đẩy tất cả tệp cần thiết để bạn có thể tải lại và chạy mô hình đã tinh chỉnh ở bất kỳ môi trường nào.
Bạn có thể xem mô hình tại kingabzpro/ministral-3-bone-fracture.
12. Đánh giá mô hình Ministral 3 đã tinh chỉnh
Giờ chúng ta tải mô hình và processor đã tinh chỉnh từ Hugging Face Hub. Bên dưới, thao tác này sẽ tải adapter LoRA đã lưu, tải checkpoint Ministral 3 gốc và gộp adapter vào mô hình gốc để sẵn sàng suy luận.
Để so sánh công bằng, trước hết ta dùng lại cùng ảnh đã kiểm thử trước tinh chỉnh (chỉ số 200) và chạy qua pipeline suy luận với prompt phân loại nghiêm ngặt.
Chúng ta đạt kết quả hoàn hảo. Không cần hậu xử lý thêm. Mô hình tuân thủ quy tắc prompt và sinh trực tiếp lớp đúng.
Tiếp theo, thử một mẫu ngẫu nhiên khác từ tập dữ liệu để xác nhận hành vi này không chỉ giới hạn ở một ví dụ.
Kết quả mô hình:
Nhãn sự thật:
Kết quả:
Một lần nữa, dự đoán chính xác và trùng khớp hoàn toàn với nhãn.
Với các kiểm tra này, có thể nói mô hình Ministral 3 14B của chúng ta đã được tinh chỉnh thành công trên tập X-quang gãy xương và hiện có thể tuân thủ prompt chỉ dẫn, đưa ra dự đoán một lớp chính xác cho các ví dụ này.
Suy ngẫm cuối
Tinh chỉnh mô hình Ministral 3 đòi hỏi kiên nhẫn và điều chỉnh dần dần. Tôi thực sự mất hai ngày để hiểu vì sao mô hình không huấn luyện như kỳ vọng và vì sao, dù tương đối nhỏ, nó vẫn khiến GPU của tôi tràn bộ nhớ.
Nguyên nhân chính rất đơn giản nhưng dễ bị bỏ qua. Đây không chỉ là mô hình ngôn ngữ. Nó là mô hình ngôn ngữ–thị giác, nghĩa là có bộ mã hóa ảnh làm tăng mức dùng bộ nhớ.
Độ phân giải ảnh lớn kéo theo mức tiêu thụ VRAM cao hơn trực tiếp. Giảm kích thước ảnh hoặc bắt đầu với batch nhỏ giúp quá trình huấn luyện ổn định hơn nhiều.
Một vấn đề khác tôi gặp phải là dùng mẫu chat mặc định. Nó quá dài và nặng cấu trúc cho kiểu tác vụ này. Mô hình tốn nhiều công sức để phù hợp định dạng mẫu hơn là học cách đọc ảnh và đưa ra phân loại gãy rõ ràng.
Khi tôi đơn giản hóa prompt thành chỉ dẫn trực tiếp, mô hình cuối cùng bắt đầu phản hồi đúng với đầu vào hình ảnh thay vì định dạng mọi câu trả lời như một phản hồi chat đầy đủ.
Tôi cũng từng cho rằng vì mô hình có khả năng thị giác mạnh nên sẽ tự nhiên làm tốt trên ảnh y khoa. Giả định đó làm tôi chậm lại. Gọi nó là “MedGemma” trong đầu không công bằng với mô hình hay quy trình. Nó không phải mô hình y khoa chuyên biệt ngay từ đầu, và kỳ vọng nó cư xử như vậy mà không được huấn luyện phù hợp là sai lầm của tôi.
Cuối cùng, tôi đã vượt qua từng trở ngại và biến những gì học được thành hướng dẫn này. Mục tiêu là giúp bạn tránh bối rối tương tự và đạt kết quả có ý nghĩa nhanh hơn.
“Với ảnh nhỏ hơn, prompt đơn giản hơn và kỳ vọng thực tế, Ministral 3 có thể được tinh chỉnh để hiểu X-quang mượt mà và tin cậy hơn nhiều.”
Nếu bạn muốn thực hành tinh chỉnh nhiều hơn, tôi gợi ý khóa học Fine-Tuning with Llama 3.