F FisherHub Docs

模型微调

为什么需要微调

微调(Fine-tuning)是在预训练模型基础上用特定数据集继续训练,使其适配特定任务或领域。与 RAG 相比,微调的优势在于:

  • 模型真正”学会”了领域知识,推理时无需外部检索
  • 可以改变模型的行为风格和输出格式
  • 适合需要深度理解专业术语的场景

参数高效微调(PEFT)

传统全参数微调需要更新模型的所有权重,对计算资源要求极高。参数高效微调通过在模型中插入少量可训练参数,以极小代价实现接近全参数微调的效果。

LoRA(Low-Rank Adaptation)

LoRA 是 PEFT 中最主流的方法。其原理是在 Transformer 的注意力层权重矩阵旁插入低秩分解矩阵,训练时只更新这些低秩矩阵。

from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B")

lora_config = LoraConfig(
    r=16,              # 秩(rank),越大学习能力越强
    lora_alpha=32,     # 缩放系数
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, lora_config)
print(f"可训练参数占比:{model.num_parameters(only_trainable=True) / model.num_parameters():.2%}")

常见 LoRA 参数配置:

场景rlora_alphatarget_modules
聊天风格调整816q_proj, v_proj
代码任务1632所有注意力层
领域知识注入3264所有线性层
数学推理1632qkv + gate/up/down

QLoRA(量化 LoRA)

QLoRA 在 LoRA 的基础上引入 4-bit 量化,可以将 7B 模型的微调显存需求从 ~56GB 降低到 ~16GB,使单卡消费级 GPU 也能微调大模型。

from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True
)

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B",
    quantization_config=bnb_config,
    device_map="auto"
)

数据集准备

微调数据的质量直接决定最终效果。常见的数据格式:

对话格式(ChatML)

[
  {
    "conversations": [
      {"role": "system", "content": "你是一个资深的金融分析师。"},
      {"role": "user", "content": "解释一下什么是 IRR?"},
      {"role": "assistant", "content": "内部收益率(IRR)是使项目净现值为零的贴现率..."}
    ]
  }
]

指令格式

[
  {
    "instruction": "翻译以下句子为英文",
    "input": "机器学习正在改变世界。",
    "output": "Machine learning is changing the world."
  }
]

数据质量要求

  1. 多样性:覆盖目标场景的不同子任务
  2. 正确性:每条数据经过人工审核
  3. 一致性:风格和格式统一
  4. 平衡性:各类别数据量大致平衡
  5. 去重:删除完全重复或高度相似的样本

训练脚本

from transformers import TrainingArguments, Trainer
from datasets import load_dataset

dataset = load_dataset("json", data_files="train.jsonl")

training_args = TrainingArguments(
    output_dir="./qwen-lora",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=8,
    learning_rate=2e-4,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_strategy="steps",
    save_steps=200,
    fp16=True,
    gradient_checkpointing=True,
    report_to="wandb"
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    tokenizer=tokenizer,
    data_collator=data_collator
)

trainer.train()

关键训练参数建议:

  • 学习率:LoRA 通常用 1e-4 到 5e-4,比全参数微调高一个数量级
  • Epoch 数:3-5 个 epoch 通常足够,过多会导致灾难性遗忘
  • Batch size:在显存允许的范围内尽量大,或用梯度累积模拟
  • Warmup:前 3% 的 step 做 warmup,稳定训练过程

模型评估

微调后的评估应当从多个维度展开:

自动化评估

from datasets import load_metric

# 在标准基准上测试
bleu = load_metric("bleu")
rouge = load_metric("rouge")

predictions = generate_predictions(model, test_dataset)
result = rouge.compute(
    predictions=predictions,
    references=test_dataset["output"]
)

人工评估

自动化指标无法完全反映生成质量。建议建立包括以下维度的人工评估体系:

  • 正确性:是否存在事实错误
  • 相关性:回答是否针对用户问题
  • 流畅性:语言是否自然
  • 指令遵循:是否遵守了格式要求
  • 安全性:是否有有害内容

对比测试

微调后务必在原始能力的通用 benchmark(如 MMLU、GSM8K)上测试,确保没有灾难性遗忘。

微调 vs RAG

维度微调RAG
知识时效性依赖训练数据可实时更新
幻觉控制可能记忆错误有检索支撑
推理成本无额外检索开销每次都要检索
适用场景深度领域适配知识密集型问答