Gemma 4 微调教程:LoRA 一步步教你

2026/04/07

Gemma 4 开箱即用已经很强了,但如果你想让它说你们品牌的话、按你的格式输出、或者在某个垂直领域表现更好,微调就是必走的路。

好消息是:现在不需要一堆 A100 了。用 LoRA 加一个叫 Unsloth 的工具,一张消费级显卡就能在一小时内完成微调。

什么时候该微调?

先别急着动手,确认一下微调是不是真正需要的:

场景建议方案
模型不懂你的行业术语用行业数据微调
模型总是不按格式输出用格式示例微调
模型需要最新信息用 RAG,不需要微调
模型太啰嗦或太简短先试试调 prompt
模型偶尔回答错误先试试 few-shot

如果 prompt 工程和 RAG 都搞不定,再上微调。动手之前先试试最佳 Gemma 4 提示词,说不定调 prompt 就能解决。想先了解 Gemma 4 能干什么,可以看看使用场景指南

LoRA 和 QLoRA 到底是什么?

LoRA(低秩适配)不改动原始模型的权重,而是在模型上面训练一组很小的适配器权重。打个比方就像给相机装个滤镜,而不是重新造一台相机。

  • 基础模型:冻结,完全不动
  • 适配器:很小,通常只有基础模型的 1-5%
  • 效果:接近全参数微调,但成本低得多

QLoRA 更进一步——它把基础模型用 4-bit 量化加载,显存占用直接砍半。质量大概是 LoRA 的 90% 以上,但能在小得多的显卡上跑。

方法显存需求 (E4B)显存需求 (26B)质量
全参数微调32GB+100GB+最好
LoRA16GB48GB约 98%
QLoRA8GB24GB约 95%

安装 Unsloth

Unsloth 是微调 Gemma 4 最快的工具,比原版 HuggingFace 快 2 倍,省 60% 显存。

# 创建虚拟环境
python -m venv gemma4-finetune
source gemma4-finetune/bin/activate

# 安装 Unsloth(包含所有依赖)
pip install unsloth

# 如果要用 QLoRA,还需要:
pip install bitsandbytes

检查环境是否就绪:

import torch
print(f"CUDA 可用: {torch.cuda.is_available()}")
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"显存: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB")

准备训练数据

训练数据用 JSONL 格式,每行是一段对话:

{"messages": [{"role": "user", "content": "退货政策是什么?"}, {"role": "assistant", "content": "我们支持30天内凭原始收据退货。"}]}
{"messages": [{"role": "user", "content": "发国际快递吗?"}, {"role": "assistant", "content": "支持,覆盖45个国家,通常7-14个工作日到达。"}]}
{"messages": [{"role": "system", "content": "你是一个医疗编码助手。"}, {"role": "user", "content": "编码:患者出现急性支气管炎"}, {"role": "assistant", "content": "ICD-10: J20.9 - 急性支气管炎,未特指"}]}

数据质量要点:

  • 500-1000 条是大多数任务的甜区
  • 质量比数量重要——500 条高质量数据碾压 5000 条水数据
  • 要包含边界情况和反例
  • 回答的格式和语气要保持一致
  • 训练前先验证数据:
import json

def validate_jsonl(filepath):
    valid = 0
    errors = 0
    with open(filepath, 'r') as f:
        for i, line in enumerate(f, 1):
            try:
                data = json.loads(line)
                assert "messages" in data, "缺少 'messages' 字段"
                assert len(data["messages"]) >= 2, "至少需要2条消息"
                valid += 1
            except (json.JSONDecodeError, AssertionError) as e:
                print(f"第 {i} 行: {e}")
                errors += 1
    print(f"\n有效: {valid}, 错误: {errors}")

validate_jsonl("training_data.jsonl")

训练配置

完整的训练脚本:

from unsloth import FastLanguageModel
import torch

# 加载模型(QLoRA 4-bit)
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="google/gemma-4-e4b",
    max_seq_length=4096,
    dtype=None,           # 自动检测
    load_in_4bit=True,    # QLoRA
)

# 添加 LoRA 适配器
model = FastLanguageModel.get_peft_model(
    model,
    r=16,                  # 秩——越高容量越大,显存也越多
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    lora_alpha=16,
    lora_dropout=0,        # Unsloth 优化过,保持 0
    bias="none",
    use_gradient_checkpointing="unsloth",
)

# 加载训练数据
from datasets import load_dataset
dataset = load_dataset("json", data_files="training_data.jsonl", split="train")

# 训练参数
from trl import SFTTrainer
from transformers import TrainingArguments

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    max_seq_length=4096,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=10,
        num_train_epochs=3,
        learning_rate=2e-4,
        fp16=not torch.cuda.is_bf16_supported(),
        bf16=torch.cuda.is_bf16_supported(),
        logging_steps=10,
        output_dir="outputs",
        optim="adamw_8bit",
        seed=42,
    ),
)

# 开始训练
trainer.train()

# 保存 LoRA 适配器
model.save_pretrained("gemma4-finetuned-lora")
tokenizer.save_pretrained("gemma4-finetuned-lora")

关键参数调整建议:

  • r=16:LoRA 秩。先用 16,效果不够再加到 32 或 64
  • num_train_epochs=3:一般 2-5 就够。注意观察是否过拟合
  • learning_rate=2e-4:默认值通常够用。训练不稳定就降到 1e-4
  • per_device_train_batch_size=2:显存够的话可以加大

导出 GGUF 格式

训练好的适配器要跑在 Ollama 上,需要先转成 GGUF。各种量化选项的详细对比看 GGUF 量化指南

# 合并适配器并导出 GGUF(Q4_K_M 量化)
model.save_pretrained_gguf(
    "gemma4-finetuned-gguf",
    tokenizer,
    quantization_method="q4_k_m",
)

# 也可以导出多个量化等级
for method in ["q4_k_m", "q5_k_m", "q8_0"]:
    model.save_pretrained_gguf(
        f"gemma4-finetuned-{method}",
        tokenizer,
        quantization_method=method,
    )
量化方式文件大小 (E4B)质量损失适合场景
Q4_K_M~2.5 GB很小大多数用户
Q5_K_M~3.2 GB更小追求质量
Q8_0~4.8 GB几乎没有显存充足时

用 Ollama 部署

创建一个 Modelfile 把微调好的模型导入 Ollama:

# Modelfile
FROM ./gemma4-finetuned-gguf/gemma4-finetuned-q4_k_m.gguf

PARAMETER temperature 0.7
PARAMETER top_p 0.9

SYSTEM "你是一个专门为客户服务优化过的助手。"

然后构建并运行:

# 创建自定义模型
ollama create my-gemma4 -f Modelfile

# 测试
ollama run my-gemma4 "退货政策是什么?"

# 确认模型已创建
ollama list

微调后的模型现在跟普通 Ollama 模型一样使用。可以通过 Ollama API 调用,在上面做开发,或者分享给团队。

常见问题

训练时显存不够:per_device_train_batch_size 降到 1,打开 gradient_checkpointing,或者换更小的基础模型。

微调后模型输出乱码: 数据格式可能有问题,或者训练轮次太多了。减少 epochs,重新检查 JSONL 数据。

GGUF 导出失败: 确保磁盘空间充足(转换过程需要模型大小的 3-5 倍),Unsloth 版本也要是最新的。

训练 loss 不下降: 学习率可能太低,试试 5e-4。同时检查数据里是否真的包含了你想让模型学习的模式。

下一步

Gemma 4 AI

Gemma 4 AI

相关教程