如何选择合适的 LLMs fine-tuning 方法?
先用 SFT 配合 LoRA 建立基线,再根据评估结果调整
如果已有经过审核的“输入与理想输出”数据,可以先尝试监督微调(SFT)配合 LoRA;显存受限时,再考虑 QLoRA。是否采用全参数微调,要结合数据规模、训练预算和对照实验结果判断。
选择训练方案时,需要区分两个问题:
- SFT、持续预训练、DPO 等方法,决定模型从什么训练信号中学习。
- LoRA、QLoRA、全参数微调,决定训练哪些参数,以及如何控制资源开销。
两者可以组合,例如“用 LoRA 做 SFT”。任何组合都不能自动保证模型能处理边界情况或实现跨领域泛化,这些能力仍需通过数据设计和独立测试验证。
根据当前问题选择训练方法
| 当前主要问题 | 优先考虑 | 适用前提与限制 |
|---|---|---|
| 输出格式不稳定、任务流程不符合要求 | SFT | 有一致、可靠的输入与目标输出 |
| 显存有限,希望先验证微调是否有效 | LoRA;资源更紧张时考虑 QLoRA | LoRA 冻结基础权重并训练低秩适配器;QLoRA 在量化基础模型上训练适配器 |
| 有大量领域文本,但缺少问答标注 | 持续预训练,再按需要做 SFT | 可以帮助模型适应领域文本分布,但不直接教会它按任务要求作答 |
| 模型已能完成任务,但回答质量或偏好不理想 | DPO 等偏好优化方法 | 需要可信的优选与劣选回答对,不能代替事实核查 |
| 需要回答经常变化、可追溯的业务知识 | 先评估 RAG | 可与微调组合;检索质量仍会影响回答 |
| 适配器实验未达目标,且数据和算力充足 | 对照测试全参数微调 | 训练开销更高,也需要检查原有能力是否退化 |
先看模型实际错在哪里。知识缺失造成的错误,未必能靠增加训练轮数解决;数据中的答案互相矛盾,换用更大的模型也解决不了标注问题。
先把数据和评估设计好
1. 按真实使用场景划分数据
先划分训练集、验证集和测试集,再做数据增强。划分时要检查近重复内容,避免把同一文档的段落、同一用户的相似对话,或同一题目的改写版本分到不同集合。
具体怎么划分,取决于想验证什么能力:
- 验证对新客户的适应能力,按客户或组织分组。
- 验证对未来数据的适应能力,按时间留出数据。
- 验证跨领域泛化,留出训练中未出现的领域。
- 验证跨任务泛化,留出整个任务类型,仅留出同一任务中的部分样本不足以验证这项能力。
随机切分得到的分数,通常不足以证明模型能够处理新领域或新任务。
2. 为边界情况标注正确行为
根据基线模型的失败样例整理错误类别,例如信息不足、条件冲突、异常格式、超长输入,以及超出任务范围的请求。
每类数据都要明确模型该怎么做。信息不足时,是追问、返回空值,还是说明无法判断?标注中的处理方式必须一致。
可以适当提高少见但重要样例的采样比例,同时保留接近真实分布的普通样例。反复使用少量边界样例,可能让模型记住措辞,或在正常输入上频繁拒答。
使用合成数据时,要检查答案是否正确,并与测试数据隔离。如果样本只改了措辞,没有引入新条件或新错误类型,对覆盖边界情况的帮助就有限。
3. 控制多任务和多领域数据的比例
直接拼接不同领域的数据,容易让样本最多的领域主导训练。应根据目标场景设置采样比例,并分别观察各任务、各领域的结果。
如果希望保留模型已有能力,可以混入经过审核、使用权限明确的通用任务数据。具体混入多少,要通过实验判断;这样做也不能保证完全消除灾难性遗忘。
用小规模实验决定后续投入
先记录未微调模型在固定提示词下的表现,再训练第一个 LoRA 基线。比较时,保持测试集、提示模板和生成参数一致。
根据实际用途选择评估指标:
| 任务 | 可以观察的指标 |
|---|---|
| 分类 | Macro-F1、各类别召回率、混淆矩阵 |
| 信息抽取 | 字段级准确率、缺失率、格式合法率 |
| 问答或生成 | 正确性、指令遵循情况,以及人工抽样审核 |
| 边界情况 | 各错误类型的通过率、误拒答率 |
| 泛化能力 | 未见领域、未见任务上的独立结果 |
普通样例、边界样例和领域外样例的结果应分别报告,避免总体平均分掩盖局部退化。
实验中要控制变量:
- 固定数据和基础模型,建立可复现的基线。
- 分别调整学习率、训练步数、LoRA rank 或数据比例。
- 定期检查验证结果,保存业务指标更好的 checkpoint。
- 确定方案后,再用测试集做最终评估。
学习率、训练轮数和 LoRA rank 都没有通用的最优值。训练损失持续下降时,泛化能力也可能下降。如果验证表现变差,应检查是否存在过拟合、数据重复、标注噪声或训练分布偏移。
代码示例:为因果语言模型接入 LoRA
使用 Hugging Face Transformers 和 PEFT 接入 LoRA,需要本地已有兼容的模型文件。这个最小示例还要求模型注意力层包含名为 q_proj 和 v_proj 的模块。
from transformers import AutoModelForCausalLM
from peft import LoraConfig, TaskType, get_peft_model
model_path = "/path/to/local/model"
model = AutoModelForCausalLM.from_pretrained(
model_path,
local_files_only=True,
)
target_modules = ["q_proj", "v_proj"]
module_names = {
name.rsplit(".", 1)[-1]
for name, _ in model.named_modules()
}
missing = set(target_modules) - module_names
if missing:
raise ValueError(f"Target modules not found: {sorted(missing)}")
# 示例配置,不代表适合所有模型或数据集。
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8,
lora_alpha=16,
lora_dropout=0.05,
target_modules=target_modules,
bias="none",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
不同架构的模块名称可能不同,需要先检查 model.named_modules(),再确定适配位置。示例参数只是实验起点,这段代码只接入了适配器,尚未执行训练。运行前,还需确认所安装的库与模型实现兼容。
对话 SFT 数据可以保留角色结构,例如:
{
"messages": [
{"role": "user", "content": "请提取订单编号;缺失时返回 null。"},
{"role": "assistant", "content": "{\"order_id\": null}"}
]
}
训练前,需要用与模型匹配的 chat template 将数据序列化。如果只监督 assistant 回答,应将其他位置以及 padding 对应的 labels 设为 -100,让损失函数忽略这些位置。训练框架是否自动处理这一步,取决于具体配置,不能仅凭数据中有 messages 字段判断。
训练和部署时容易遗漏的细节
- 检查截断后的样本。目标回答被截断,或输入中的关键条件丢失,都会改变训练含义。
- 保持训练与推理时的角色标记、提示模板和特殊 token 一致。
- QLoRA 需要正确配置量化加载、计算精度及训练准备流程。仅把权重转成低精度,还没有完成 QLoRA 所需的配置。
- 保存数据版本、基础模型标识、随机种子和训练配置。部署适配器时,使用匹配的基础模型。
- 对指标接近的候选方案重复实验,判断收益是否稳定。最终方案应同时满足任务质量、边界情况表现和资源约束。
如果跨领域或跨任务测试出现退化,应先分析具体失败类别,再调整数据覆盖和采样比例。增加参数量或延长训练时间,都不能替代对失败原因的分析。
备注:内容仅供参考。
