大模型微调(Fine-tuning)是指在预训练模型的基础上,使用特定任务或领域的数据继续训练,让模型更好地适应具体应用场景。下面是微调的完整过程,包括主流方法和关键步骤。


一、微调的核心思想

预训练模型已经学习了通用的语言知识(语法、推理、常识等),微调相当于把通才变为专才——用少量高质量任务数据调整模型参数,使其在特定任务(如情感分析、法律问答、医疗诊断)上表现更优。

微调的两种常见模式:

  • 全量微调:更新模型所有参数,效果好但计算开销大。

  • 参数高效微调 (PEFT):只更新少量额外参数(如 LoRA、Adapter),在保持效果的同时大幅降低显存需求。


二、微调的完整流程

步骤1:明确任务与数据准备

  • 确定任务类型:文本分类、指令跟随、代码生成、对话摘要等。

  • 收集/标注数据:需要输入-输出对。例如情感分析数据 (文本, 标签),对话数据 (用户消息, 助手回复)

  • 数据质量要求

    • 干净、一致、无噪声(去除错误标注、重复、无关内容)。

    • 规模:几百到几十万条不等,取决于任务难度和模型大小(通常几千条已能看到明显效果)。

    • 分布:覆盖实际部署场景的边界情况。

  • 数据集划分:训练集、验证集、测试集(例如 8:1:1)。

步骤2:预处理与格式化

  • 模板化:将原始数据构造成模型能理解的对话/指令格式。例如,微调 Llama 2 时常用:

    text

    [INST] {用户问题} [/INST] {期望回答}
  • 分词:将文本转换为令牌 ID,同时填充/截断到统一长度(例如 2048 tokens)。

  • 遮蔽:自回归训练时,需要因果掩码(causal mask)确保模型只能看到前面的 token。

  • 处理标签:对于生成任务,通常将输入部分的标签设为 -100(忽略损失),只计算输出部分的损失。

步骤3:选择微调方法

方法 更新参数量 显存需求 效果 适用场景
全量微调 100% 极高 最好 数据量大、有充足计算资源
LoRA 0.1%~1% 媲美全量 绝大多数场景
QLoRA ~0.1% 极低(4-bit量化) 接近全量 单卡微调7B~70B模型
Adapter ~1% 较低 中等 较旧的技术,现较少用
Prefix Tuning 很少 中等 生成任务

LoRA 原理:冻结原始权重,在旁支插入低秩矩阵(A和B),训练时只更新这两个小矩阵,最后与原始权重合并。

步骤4:设置训练超参数

关键超参数及其典型值(以 LoRA 微调 7B 模型为例):

参数 全量微调 LoRA 说明
学习率 5e-6 ~ 5e-5 1e-4 ~ 5e-4 LoRA 通常需要更高学习率
批次大小 4~32 4~16 受限于显存
训练轮次 2~5 3~10 小数据集可多轮,防止过拟合
优化器 AdamW / AdamW AdamW 常用
梯度累积步数 1~8 1~4 等效增大 batch size
学习率调度 余弦退火 / 线性衰减 余弦退火
预热步数 0~100 0~200
最大序列长度 512~4096 与基座一致

LoRA 特有参数

  • r(秩):通常 8, 16, 32。越大能力越强,但参数增多。

  • alpha:缩放因子,通常设为 2r 或与 r 相等。

  • dropout:0~0.1,防过拟合。

步骤5:执行训练

硬件要求

  • 7B 模型全量微调:至少 1 张 80G A100 或 2~4 张 40G A100。

  • 7B LoRA/QLoRA:1 张 24G 显卡(RTX 3090/4090)足够。

  • 13B QLoRA:24G 勉强可跑;33B 需要 2×24G 或 A100 40G。

常见工具

  • Hugging Face Transformers + PEFT + TRL:最通用,支持 SFTTrainer。

  • LLaMA-Factory:WebUI 操作,低代码。

  • Axolotl:配置化微调,适合生产。

  • Unsloth:专门优化 Llama/Mistral 微调速度,快 2~5 倍。

训练循环示意(伪代码)

python

for epoch in range(num_epochs):
    for batch in dataloader:
        # 前向:输入 batch 得到 logits
        outputs = model(input_ids=batch["input_ids"], labels=batch["labels"])
        loss = outputs.loss
        # 反向传播
        loss.backward()
        # 梯度裁剪(防止爆炸)
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
        # 更新参数
        optimizer.step()
        scheduler.step()
        optimizer.zero_grad()
        # 记录损失,在验证集上评估

步骤6:评估与验证

  • 验证集损失:判断是否过拟合(训练损失持续降,验证损失上升 → 停止)。

  • 任务具体指标

    • 分类:准确率、F1。

    • 生成:ROUGE-L、BLEU(参考答案)、人工评分或 GPT-4 评估。

  • 对抗测试:检查是否产生有害内容、幻觉、格式错误。

步骤7:合并与部署

  • LoRA 权重合并:可将 adapter 合并回基座模型,得到一个完整的新模型文件。

  • 量化:若需降低部署成本,可再量化到 int8 或 int4(GPTQ、AWQ)。

  • 部署格式:导出为 HuggingFace 格式,或转换为 vLLM、TGI 能加载的格式。

  • 提供服务:用 FastAPI 封装模型推理接口,或使用推理引擎加速。


三、微调中的常见陷阱与建议

问题 原因 解决方案
模型只重复输入 模板错误 / 标签遮蔽不当 检查 labels 中是否将输入部分设为 -100
灾难性遗忘 学习率过高 / 训练过久 降低学习率,添加少量原始预训练数据混合训练
过拟合 数据太少或轮次太多 增加正则(dropout,权重衰减),早停,收集更多数据
效果不如提示工程 微调数据质量差或任务简单 先尝试 few-shot 提示,不行再微调
显存不足 模型大,序列长 使用 LoRA + 梯度检查点 + 4-bit 量化

四、一个最小的微调示例(使用 LLaMA-Factory)

bash

# 安装 LLaMA-Factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .

# 准备数据:data/medical.json (格式示例)
[
  {"instruction": "什么是高血压?", "output": "高血压是指..."},
  ...
]

# 启动微调命令行
llamafactory-cli train \
    --model_name_or_path meta-llama/Llama-2-7b-hf \
    --stage sft \
    --dataset medical \
    --template llama2 \
    --finetuning_type lora \
    --lora_rank 8 \
    --output_dir ./lora_medical \
    --per_device_train_batch_size 4 \
    --learning_rate 1e-4 \
    --num_train_epochs 5

五、总结

大模型微调的关键不在于复杂的代码,而在于高质量的数据 + 合适的微调方法 + 正确的超参数。对于大多数开发者,推荐 LoRA/QLoRA + Hugging Face PEFT + 小型专用数据集,可以在消费级显卡上快速得到效果不错的垂直领域模型。如果追求极致效果且资源充足,才考虑全量微调。

如果需要更深入解释某个环节(例如数据构造细节、LoRA 原理、评估方法等),可以继续问我。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐