11.3 全参数微调、LoRA 与领域适配:可训练参数少,不等于风险和显存都按比例缩小
阿花的基础模型能续写通用文本,却不懂模型工坊的任务格式。团队有三种选择:继续用领域语料训练、用标注指令改变行为,或冻结大部分权重只接入小型 adapters。
微调不是“喂几百条样本就学会新任务”。它改变的是特定 data/objective 下的参数;数据质量、覆盖、遗忘和验证协议决定结果。
本课目标
- 区分 continued pretraining、task fine-tuning 与 instruction tuning;
- 比较 head-only、full fine-tuning 和 PEFT;
- 推导 LoRA 的低秩 update 与 trainable parameter count;
- 正确构造 chat labels、split 与 evaluation;
- 版本化 base、adapter、tokenizer 与 serving composition。
1. 先选适配目标
Continued pretraining / Domain-adaptive pretraining
继续用 causal/MLM 等 self-supervised objective 训练领域原文,改善术语/分布建模。它不直接教会 instruction format,也可能增加领域偏见或遗忘通用能力。
Task supervised fine-tuning
使用 input–label pairs 训练分类、抽取、生成等明确任务。可以加 task head 或用 text-to-text/causal loss。
Instruction tuning / SFT
用 system/user/assistant 或 instruction–response examples 训练模型按对话/任务格式回应。它提高行为拟合,不保证 response 事实正确或安全。
Preference/alignment post-training
用 comparisons/rewards 改变偏好与策略,放到第 12 章讨论。不要把 SFT、RLHF 和 LoRA 混成同一维度:SFT 是 objective/data,LoRA 是参数更新方式。
2. 三种 Parameter Update 范围
Head-only / Feature extraction
冻结 backbone,只训练 classification/projection head。成本低、遗忘少,但 representation 无法适配深层 domain mismatch。
Full fine-tuning
更新全部 weights,容量最大,也需要 optimizer states、gradients 和 activations,checkpoint/serving 管理更重。小数据/大学习率容易过拟合或破坏原能力。
PEFT
冻结多数 base weights,训练 adapters、prompt/prefix parameters 或 low-rank updates。减少 trainable parameters 和 optimizer/gradient memory,但 forward/backward 仍经过 base model,activation 与 base-weight memory 不会按 trainable ratio 消失。
3. LoRA 把 Update 限制为低秩
对冻结权重 $W_0\in\mathbb R^{d_{out}\times d_{in}}$:
$$ W=W_0+\Delta W,qquad \Delta W=sBA, $$
其中:
$$ A\in\mathbb R^{r\times d_{in}},\qquad B\in\mathbb R^{d_{out}\times r}, $$
$r\ll\min(d_{in},d_{out})$,$s$ 常由 lora_alpha/r 或变体决定。Trainable parameter 从 $d_{out}d_{in}$ 变为:
$$ r(d_{in}+d_{out}). $$
低秩是对任务 update 的结构假设。Rank 太低可能欠拟合,太高增加成本;target modules、scaling、dropout 和哪些 bias 可训练都需要验证。
4. LoRA 接到哪里比“用了 LoRA”更重要
可 target attention Q/K/V/O projections、FFN layers、embedding/head 等。Module names 随架构不同,错误 pattern 可能:
- 没有匹配任何 layer;
- 只训练少数意外层;
- 包含不希望更新的 output head;
- 在 tensor-parallel/quantized wrapper 下名称变化。
训练前打印 trainable parameter names/counts,并对一次 backward 检查 frozen .grad is None、adapter gradients finite/nonzero。
5. 一个 PEFT 构造骨架
from peft import LoraConfig, TaskType, get_peft_model
# base_model 已按固定 revision 加载,并与 tokenizer 匹配。
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=["q_proj", "v_proj"], # 必须按具体架构核对
bias="none",
)
model = get_peft_model(base_model, config)
model.print_trainable_parameters()这是构造 adapter,不是完整训练方案。Package/API 变化快,项目要固定 transformers/peft/accelerate 版本和 base revision,保存 resolved config。
6. Quantized Base + LoRA
QLoRA 类方案以低精度/量化形式保存冻结 base weights,并训练 LoRA,以进一步降低 weight memory。仍需处理:
- compute dtype 与 accumulation precision;
- quantization scheme/block statistics;
- 哪些 modules 保持高精度;
- optimizer/activation memory;
- hardware/kernel support;
- merge/dequantize 后质量与内存;
- training–serving quantization 是否一致。
“4-bit 微调”不表示所有 tensors、计算和 checkpoint 都是 4-bit,也不保证与 full fine-tune 等价。
7. SFT Formatting 与 Label Mask
Chat sample 是消息结构,不只是拼接字符串。使用 checkpoint 的 chat template 生成 control tokens,并明确 loss positions。
一种 assistant-only loss:
<system> ... </system> labels = ignore
<user> ... </user> labels = ignore
<assistant> response ... labels = token IDs也有模型在完整对话所有非-padding tokens 上训练。选择要与 objective 一致。
高危错误:
- 训练 template 与 serving template 不同;
- 重复 BOS/EOS;
- response 截断后只剩 prompt;
- prompt tokens 未 mask 却误称 assistant-only;
- packed examples 跨边界相互 attend;
- padding label 没设 ignore index。
写 unit test 解码 input/labels,逐 token 可视化 supervision mask。
8. 数据质量比样本数口号重要
检查:
- instruction 是否明确且可完成;
- response 是否正确、来源可靠、格式一致;
- 同一输入是否有冲突答案;
- model-generated data 是否经过验证;
- safety refusal 与正常帮助是否平衡;
- 语言、长度、领域、难度覆盖;
- PII、license、consent 与删除 lineage;
- near-duplicate 与 benchmark contamination。
“几百到几千条足够”没有通用保证。任务复杂度、base capability、噪声和验收门槛决定样本需求;用 learning curve 和 error taxonomy 决策。
9. Split 要按来源和模板去重
同一文档生成十条 QA 后按行随机 split,train/test 会共享 source facts/style。Template 只换实体名也会近重复。
按 document/source/user/time/task family 分组切分,并 near-dedup instructions/responses。若目标是未来知识/新客户,使用 temporal/domain holdout。
保留:
- in-domain validation:调参;
- held-out task/templates:组合泛化;
- safety/adversarial sets;
- base capability regression suite;
- 最终 blind/private test。
10. Catastrophic Forgetting 与 Trade-off
微调可能改善目标任务却损害:
- 通用语言/多语言;
- calibration 与 uncertainty expression;
- safety refusal;
- formatting/tool calling;
- 长上下文;
- 原先专业领域。
缓解候选:更小 LR/steps、regularization、replay/mixed data、adapter isolation、multi-task training、selective layers。它们不能替代 regression evaluation。
Adapter 便于任务隔离和切换,但多个 adapters 组合/merge 的相互作用也需测试。
11. 训练诊断
- train/validation token loss,按 response/source 分层;
- supervised token count,而不只 example count;
- truncation/empty-label rate;
- gradient/adapter update norm;
- base vs tuned outputs on fixed prompts;
- exact/semantic/task metrics 与 human rubric;
- memorization/copy rate;
- throughput、peak memory、checkpoint size。
Loss 下降不代表 instruction following 或 factuality 改善。Generation metrics 必须用冻结 decoding config,并记录多 seed/sample variability。
12. 部署与 Version Contract
Adapter artifact 必须引用:
- exact base model ID/revision/hash;
- tokenizer/chat template revision;
- PEFT config/target modules/rank/scaling;
- merge 状态与 dtype/quantization;
- training data/version/metrics;
- license 与使用限制。
Unmerged adapter serving 可能增加 module management/少量 latency;merged weights 减少切换灵活性,并需要重新生成/验证完整 checkpoint。Merge 前后 logits 在容差内比较。
常见误区
- LoRA 是一种训练目标:它是参数化/update 方法。
- Trainable parameters 1% 就只需 1% 显存:base weights/activations 仍占资源。
- 量化 LoRA 全程都是 4-bit:compute、adapter、optimizer 可能更高精度。
- 微调只会增加能力:会产生遗忘和安全/校准回归。
- Adapter 可加载到同名任意 base:必须匹配具体 revision/架构。
练习
- 为 continued pretraining、SFT、LoRA 分别说明 data/objective/update 范围。
- 计算一个 $4096\times4096$ projection 在 rank 8/16/64 下的 LoRA 参数量。
- 打印并验证实际 target modules 与 gradient。
- 解码一条 SFT sample,逐 token 标出 loss mask。
- 比较 base/full FT/LoRA 的目标任务与 regression suite。
小结
适配基础模型先选 objective,再选参数更新范围。Full fine-tuning 提供最大自由度,LoRA 用低秩假设减少 trainable parameters,量化进一步压缩 base memory;它们都不能省略数据治理、split、回归评估和版本契约。
下一课先不改权重:prompt 与 in-context examples 通过输入序列改变条件分布。它部署快,也更依赖模板、上下文、生成配置与持续评估。