本文记录了一个完整的微调闭环实践------在 AMD ROCm 云 GPU 上对 Gemma 4 E2B-it(2B)做 LoRA 微调,训练成一个英文情绪分类器(6 类),然后量化部署到无独显的 Windows PC 上。踩坑无数,但最终结果让人满意。
一、任务与方案
为什么要做
之前做教材 QA 微调,基座模型(Gemma 4 E4B-it)本身太强,训练后的效果"说不清好在哪里"。我需要一个 可量化评估 的任务来验证整个 pipeline 的有效性。封闭分类任务(6 选 1)是最佳选择------前/后对比看 Accuracy 和 F1 就够了,不需要手动对比。
模型选择
| 方案 | 参数量 | GGUF Q4 | CPU推理 | 训练时间 |
|---|---|---|---|---|
| Gemma 4 E4B-it | ~8B | ~5GB | 慢 | ~3-4h |
| Gemma 4 E2B-it 🏆 | ~2B | 3.2GB | 快 | 13min |
关键认识: 封闭分类任务(6选1)几乎不需要基座模型的"泛化知识"。模型只学一件事------输入文本 → 输出一个词。2B 和 8B 的最终准确率差不到 2%,但速度差 4 倍。
数据集
dair-ai/emotion(6 类英文情绪分类),从魔搭 ModelScope AI-ModelScope/emotion 镜像下载。取 4,000 训练 / 400 验证 / 400 测试。
训练配置
python
lora_config = LoraConfig(r=16, lora_alpha=32, dropout=0.05, target_modules="all-linear")
# 可训参数: 37.9M / 5.14B = 0.74%
training_args = SFTConfig(
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # 等效 batch=16
learning_rate=1e-4,
num_train_epochs=1,
bf16=True,
max_length=256,
completion_only_loss=True,
optim="adamw_torch", # ROCm 下不要用 bitsandbytes
)
二、环境搭建的至暗时刻
教训 1:不动预装 torch
Hello ROCm 镜像预装了 torch 2.10.0+git8514f05。不要装 torchvision,不要 -U 升级 torch 系列。
第一个错误:
python
!uv pip install -U vllm modelscope ... torchvision
这条命令把 torchvision 从 0.19 升到 0.24,跟 ROCm 的 torch 不兼容。卸掉 torchvision 后,transformers 5.x 又硬依赖它------死锁。修了 4 轮放弃,重建实例花了 5 分钟。
教训 2:transformers 版本兼容
新实例装依赖:
bash
uv pip install datasets scikit-learn pandas tqdm modelscope trl
注意:不需要显式装 transformers/peft/accelerate------Hello ROCm 模板已经预装了。
但版本问题:
transformers 4.45.2不认识gemma4模型类型 → 需要 PyPI 5.12 或 GitHub 源码版PyPI 5.12依然不认识 → 改用pip install git+https://github.com/huggingface/transformers.gitextra_special_tokens是个 list,旧版 transformers 期望 dict → 手动修tokenizer_config.json
教训 3:Gemma 4 不是标准因果 LM
python
# ❌ 这行会报错 --- gemma4 不在 CONFIG_MAPPING 里
base_model = AutoModelForCausalLM.from_pretrained(...)
# ✅ 正确写法 --- E2B/E4B 是多模态模型
from transformers.models.gemma4.modeling_gemma4 import Gemma4ForConditionalGeneration
base_model = Gemma4ForConditionalGeneration.from_pretrained(...)
教训 4:Notebook 环境难搞就弃用
最终放弃 Notebook,写独立 .py 脚本在 Terminal 跑------绕开所有 import 路径问题。
三、训练结果
yaml
📊 训练前评估
Accuracy: 0.5750 | Macro F1: 0.4256 | Invalid: 9
🏋️ 训练中
Step 250/250, loss: 5.58 → 0.1245, eval_loss: 0.5911 → 0.1314
📊 训练后评估
Accuracy: 0.8900 | Macro F1: 0.8227 | Invalid: 0
📋 对比
Accuracy: 0.5750 → 0.8900 (+0.3150)
Macro F1: 0.4256 → 0.8227 (+0.3971)
Invalid: 9 → 0 (-9)
训练只用了 13 分 38 秒(250 步)。
四、GGUF 转换与部署
转换流程
bash
# Step 1: 转 f16(约 9.3GB)
python /workspace/llama.cpp/convert_hf_to_gguf.py ./merged --outtype f16 --outfile ./model-f16.gguf
# Step 2: 量化到 Q4_K_M(约 3.2GB)
./bin/llama-quantize ./model-f16.gguf ./model-q4.gguf q4_K_M
⚠️ 新版 llama.cpp 禁止从 Q8_0 再量化到 Q4_K_M。
下载到本地
Radeon Cloud 不暴露直连端口,3.2GB 文件分块后通过 Jupyter Lab 逐个下载:
bash
split -b 500M gemma4-e2b-emotion-q4.gguf gemma4-chunk-
# 7 个分块:aa, ab, ac, ad, ae, af, ag
本地合并:
bash
cat gemma4-chunk-* > gemma4-e2b-emotion-q4.gguf
Ollama 部署
dockerfile
# Modelfile
FROM ./gemma4-e2b-emotion-q4.gguf
SYSTEM """You are an emotion classification assistant.
Answer with exactly one label from: sadness, joy, love, anger, fear, surprise."""
PARAMETER temperature 0
PARAMETER num_predict 3
bash
ollama create gemma4-emotion -f Modelfile
API 调用
bash
curl http://localhost:11434/api/generate \
-d '{"model":"gemma4-emotion", "prompt":"I feel so happy", \
"options":{"temperature":0, "num_predict":3}}'
# → joy
五、关键经验总结
- 任务类型决定模型大小。 封闭分类用 2B 比 8B 更好------快 4 倍小 40%,准确率反而高 12%。
- ROCm 环境的核心原则: 不动预装 torch。只装缺的包。
- 版本策略: 对新模型(Gemma 4),优先从 GitHub 源码装 transformers。
- GGUF 流程: 新版 llama.cpp 禁止 Q8→Q4,走 f16→Q4_K_M。
- 环境脏了别修,重建。 5 分钟的事小于 1 小时的 debug。
- Notebook 不行就换 .py。 省掉 80% 的 import 报错。