markdown
# MedGemma 27B (unsloth/medgemma-27b-it) Fine-tune 完整指南
**任务**:皮肤肿物 **6分类**(图像 + 病史文本)
**模型**:`unsloth/medgemma-27b-it`(多模态版本)
**方法**:QLoRA(4bit + LoRA),最小化修改
**硬件**:NVIDIA A100 + 64GB RAM
**目标**:训完后导出 GGUF 回 LM Studio 使用
---
## 整体目标
- 用你的皮肤肿物**图像 + 病史**数据,做 **LoRA 微调**,让模型更好地做**6分类**任务。
- 只改必要部分(LoRA),不全参数训练。
- 训完导出 GGUF 回 LM Studio 使用。
- **成功标准**:测试集 accuracy/F1 比 zero-shot 提升明显,输出格式稳定(Class + Confidence + Reasoning)。
---
## 阶段 0:前置确认(必须先做)
- A100 VRAM( 80GB)→ 影响 batch size。
- Hugging Face 账号登录 + 接受 gated 模型权限(`unsloth/medgemma-27b-it`)。
- 数据集准备:至少 200+ 条(图像 + 病史文本 + 对应 6 类标签),分成 train/test。图像保持原始大小,格式 JPG/PNG。
- 全新 conda 环境 Python 3.11。
```python
# 终端命令
conda create -n medgemma-ft python=3.11
conda activate medgemma-ft
nvidia-smi # 确认 A100 可见
阶段 1:环境搭建
- 创建并激活 conda 环境。
- 安装 torch(CUDA 对应版本) + Unsloth(最新版) + 必要库。
- 测试 GPU 可见。
python
# 终端执行
pip install --upgrade pip
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
pip install --upgrade --force-reinstall --no-cache-dir unsloth unsloth_zoo
pip install trl peft accelerate bitsandbytes datasets pillow pandas scikit-learn
验证环境:
python
import torch
import unsloth
print("Torch CUDA:", torch.cuda.is_available())
print("GPU:", torch.cuda.get_device_name(0))
print("Unsloth version:", unsloth.__version__)
成功标准:GPU 显示 A100,无报错。
阶段 2:加载模型(使用 Unsloth 优化版)
- 模型名称:
"unsloth/medgemma-27b-it" - 加载方式:4bit 量化 + FastLanguageModel。
- 开启 gradient checkpointing 省显存。
python
from unsloth import FastLanguageModel
import torch
from PIL import Image
model_name = "unsloth/medgemma-27b-it"
model, tokenizer = FastLanguageModel.from_pretrained(
model_name=model_name,
dtype=None, # A100 自动 bf16
load_in_4bit=True, # QLoRA 核心
max_seq_length=8192,
use_gradient_checkpointing="unsloth",
token=True, # HF token
)
print("模型加载完成!")
成功标准:模型加载成功,能做一次带图像的普通推理(不训练),确认多模态输入正常。
阶段 3:数据准备与格式化(最关键)
- 把每条数据转成 chat 格式:
- System:专家皮肤科医生提示。
- User:病史 + 明确"从以下6类中选一个"的指令 + 图像。
- Assistant:标准答案(你希望的输出格式)。
- 使用 datasets 库加载(jsonl)。
python
from datasets import load_dataset
from PIL import Image
dataset = load_dataset("json", data_files="train.jsonl", split="train")
def format_for_training(example):
classes_str = "Melanoma, Basal Cell Carcinoma, Squamous Cell Carcinoma, Benign Keratosis, Actinic Keratosis, Dermatofibroma" # ← 替换成你的6个类别
user_text = f"""Patient history: {example['history']}
Classify this skin lesion image into exactly ONE of the 6 classes.
Classes: {classes_str}
Output strictly: Class: XXX\nConfidence: XX%\nReasoning: ..."""
messages = [
{"role": "system", "content": "You are an expert dermatologist specializing in skin lesion classification."},
{"role": "user", "content": [
{"type": "text", "text": user_text},
{"type": "image", "image": Image.open(example["image_path"]).convert("RGB")}
]},
{"role": "assistant", "content": example["standard_output"]}
]
return {"messages": messages}
dataset = dataset.map(format_for_training, num_proc=4)
dataset = dataset.shuffle(seed=3407)
print("数据集准备完成,样本数:", len(dataset))
成功标准 :能打印 dataset[0],图像和文本对应正确,Assistant 输出严格符合格式。
阶段 4:添加 LoRA + 开始训练
- 只对关键层加 LoRA(r=8~32,先从小 r 开始)。
- 训练参数(外科式):小 batch + gradient accumulation + bf16。
python
model = FastLanguageModel.get_peft_model(
model,
r=16, # 可调 8~32
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_alpha=16,
lora_dropout=0,
bias="none",
use_gradient_checkpointing="unsloth",
random_state=3407,
)
from trl import SFTTrainer
from transformers import TrainingArguments
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
dataset_text_field="messages",
max_seq_length=8192,
packing=False,
args=TrainingArguments(
per_device_train_batch_size=1, # A100 40GB 安全
gradient_accumulation_steps=8, # 有效 batch ≈8
warmup_steps=10,
max_steps=300, # 先小步测试
learning_rate=2e-4,
bf16=True,
logging_steps=10,
output_dir="medgemma-27b-skin-lora",
optim="adamw_8bit",
save_strategy="steps",
save_steps=100,
report_to="none",
),
)
trainer.train()
model.save_pretrained("medgemma-27b-skin-lora")
tokenizer.save_pretrained("medgemma-27b-skin-lora")
成功标准:loss 稳定下降,无 OOM,checkpoint 可正常保存。
阶段 5:验证与评估
- 用 hold-out 测试集跑推理。
- 计算 Accuracy、F1,对比 zero-shot baseline。
python
model = FastLanguageModel.for_inference(model) # 切换推理模式
# 使用测试集(简化版示例)
test_dataset = load_dataset("json", data_files="test.jsonl", split="train")
# ... 调用 classify 函数批量预测,收集 pred_labels 和 true_labels
from sklearn.metrics import accuracy_score, f1_score, classification_report
print("Accuracy:", accuracy_score(true_labels, pred_labels))
print(classification_report(true_labels, pred_labels))
成功标准:指标明显提升 + 输出格式一致。如果不理想 → 调整数据/prompt 或 LoRA rank,再训。
阶段 6:保存与导出到 LM Studio
- 保存 LoRA 权重。
- 导出 GGUF(推荐 Q5_K_M)。
python
# 导出 GGUF
model.save_pretrained_gguf(
"medgemma-27b-skin-gguf",
tokenizer,
quantization_method="q5_k_m" # 或 q4_k_m
)
print("GGUF 导出完成!文件夹内文件可直接拖入 LM Studio")
成功标准:在 LM Studio 中能上传皮肤图像 + 输入病史,正确按 6 类输出。
时间与资源预期(单 A100)
- 准备 + 小测试:半天。
- 完整训练(500-1000 条数据,1 epoch):几小时到 1-2 天(4bit + LoRA 下 40GB 基本可行,80GB 更轻松)。
- OOM 时:降低 r、增大 accumulation steps,或先用 4B 版验证流程。
风险与最小化建议
- 多模态训练比纯文本稍耗资源,先用少量数据验证流程。
- 优先提升数据质量而非改超参数。
- 迭代原则:小步验证 → 发现问题立即停,调整数据/prompt 而不是改模型架构。
完整执行顺序:0 → 1 → 2 → 3 → 4(小步测试) → 5 → 4(继续训练) → 6