微调是怎么回事——从全量到 LoRA,再到对齐(大模型番外)

本文是「GPT 训练分步学习路径」的又一篇番外。GPT_teacher-3.37M-cn 这个教学项目本身只讲「从 0 到 1 预训练」,并不涉及微调,但微调是把开源大模型用起来的第一步,值得单独讲清。本文只做一件事:把「微调」这件事从头捋一遍——它和从零训练差在哪、有哪些流派、产物长什么样、日常怎么组合用。看完你应该能分清「全量 / LoRA / QLoRA」和「SFT / RLHF / DPO」分别在说什么维度的事。


目录

  1. 一句话先讲清
  2. 微调和从零训练,到底差在哪
  3. 微调方法地图:两条正交的线
  4. 省参数的一条线:全量 vs PEFT 家族
  5. 用什么信号训的一条线:SFT / RLHF / DPO
  6. 微调产物长什么样
  7. 代码对照:从零 vs 微调,只差一行
  8. 微调 vs RAG:技能 vs 知识
  9. 为什么微调注入不了知识
  10. 知识到底怎么更新
  11. 继续预训练 vs 微调:机制一样,数据不同
  12. 速查总表
  13. 核心结论

1. 一句话先讲清

从零训练是把一张白纸练成模型;微调是拿别人已经练好的模型,用你自己的少量数据接着训一小段,让它学会某个具体任务或说话风格。

绝大多数人这辈子都不会「从零训练」一个大模型(太贵),但几乎都会用到「微调」——因为它便宜、快、数据量小。


2. 微调和从零训练,到底差在哪

有意思的是,用 HuggingFace 全家桶写出来,两者的代码骨架几乎一模一样,都是这四步:

1
建分词器 → 建模型 → 建数据 → Trainer.train()

区别不在骨架,而在四步里各自填了什么

步骤 从零训练 微调 为什么不同
① 分词器 自己造一份新词表 基础模型自带的词表 要接着别人的权重训,词表必须和权重对得上
② 模型 Model(config) 随机初始化 from_pretrained(...) 加载预训练权重 这是最本质的一行:白纸开始 vs 站在肩膀上
③ 数据 prompt/completion 拼接分词 完全相同 数据处理不区分场景
④ 训练 学习率大(1e-3)、步数多 学习率小 100 倍(2e-5)、步数少 怕大改动冲垮模型已有知识(灾难性遗忘)

只看第 ② 步就够了from_pretrained(加载权重)还是 Model(config)(随机初始化),这一个函数调用就决定了它是「微调」还是「从零训练」。其余差异都是为配合第 ② 步做的连带调整。


3. 微调方法地图:两条正交的线

「微调有哪些方法」这个问题容易乱,是因为大家把两条不同维度的线混在一起说了:

1
2
3
4
5
6
7
8
9
10
11
12
微调
├── 按「动多少参数」(省不省钱)
│ ├── 全量微调 ← 全改,最贵
│ └── PEFT(参数高效)
│ ├── LoRA / QLoRA ← 旁挂低秩矩阵(最主流)
│ ├── Adapter ← 插入小模块
│ ├── Prefix/Prompt-Tuning ← 学软提示向量
│ └── (IA)³
└── 按「用什么信号训」(教什么)
├── SFT ← 问答对直接教(本项目示例在做的)
├── RLHF ← 人类偏好 + 强化学习
└── DPO ← 好坏答案成对优化(RLHF 平替)

这两条线是正交的:你可以「LoRA + SFT」,也可以「QLoRA + DPO」。LoRA 回答的是「改多少参数」,SFT/DPO 回答的是「拿什么数据、优化什么目标」,两者不冲突,日常都是组合用。


4. 省参数的一条线:全量 vs PEFT 家族

4.1 全量微调(Full Fine-tuning)

更新模型全部参数。效果上限最高,但显存、存储都最贵——每微调一个任务,就得存一整个大模型。

4.2 PEFT:只动一小撮参数

PEFT(Parameter-Efficient Fine-Tuning)是一个大家族,共同点是:冻结原始大模型,只训练极少量新增参数。LoRA 只是其中最火的一个。

方法 一句话原理 特点
LoRA 冻结原权重,旁挂两个低秩矩阵 A·B 学「增量」 最主流,效果接近全量
QLoRA LoRA + 把基础模型 4bit 量化再训 单张消费级显卡就能微调 65B,省显存王者
Adapter 在每层中间插入小模块,只训这些小模块 LoRA 的前辈,会增加一点推理延迟
Prefix-Tuning 每层注意力前拼一段可学习的前缀向量 不改模型本体
Prompt/P-Tuning 只学一小段软提示词向量(连续 embedding) 参数最少
(IA)³ 学几个缩放系数去乘激活值 比 LoRA 还省

LoRA 为什么能只学「增量」?直觉是:微调相对预训练的改动量很小,这个「小改动矩阵」可以用两个瘦长矩阵(低秩)近似表示,于是不用改原始的大方阵,只训这两个小的即可。秩 r 越小越省、越大越接近全量。


5. 用什么信号训的一条线:SFT / RLHF / DPO

上面讲「动多少参数」,这一节讲另一条正交的线——拿什么数据、优化什么目标,这在「对齐」大模型时更常听到。

方法 用什么数据 干什么
SFT(监督微调) 「问-答」对 直接照着标准答案教,最基础,本项目示例就是它
RLHF 人类对多个回答的偏好排序 训一个奖励模型,再用强化学习对齐(ChatGPT 成名的那套,复杂)
DPO 「好答案 vs 坏答案」成对数据 跳过奖励模型,直接优化偏好,比 RLHF 简单,现在很流行

一个真实大模型的养成顺序通常是:预训练(从零) → SFT(学会听话) → RLHF/DPO(对齐人类偏好)。本项目只覆盖第一步,微调对应的是后面两步。


6. 微调产物长什么样

很多人第一个疑问:微调完,参数存哪?分两种:

6.1 全量微调 → 存一整个新模型

1
2
3
4
checkpoints/hf_finetune/
├── model.safetensors # 全部权重(完整模型,自给自足)
├── config.json
└── tokenizer.json ...

用时 from_pretrained("checkpoints/hf_finetune") 加载这一份即可,和原始基础模型再无关系。

6.2 LoRA 微调 → 只存一个小小的「外挂补丁」

1
2
3
checkpoints/hf_finetune/
├── adapter_model.safetensors # 只有 LoRA 那点参数,通常几 MB
└── adapter_config.json # 记录:我基于哪个基础模型

适配器离不开原始基础模型,用时要两份拼起来:

1
2
base = AutoModelForCausalLM.from_pretrained(BASE_MODEL)          # 原始大模型
model = PeftModel.from_pretrained(base, "checkpoints/hf_finetune") # 套上适配器

由此带来两个好处:

好处 说明
省空间 7B 基础模型十几 GB,一个适配器几 MB;微调 10 个任务 = 1 份大模型 + 10 个小适配器
可热插拔 同一基础模型上随时换不同适配器切换「人格/任务」,不用重新加载大模型

7. 代码对照:从零 vs 微调,只差一行

用 HuggingFace 全家桶把「从零预训练」和「微调」并排写出来,四步骨架完全一样,差别几乎只在第 ② 步建模型这一行:

步骤 从零预训练 微调
① 分词器 自己造 / 用现成的 用基础模型自带的
建模型 GPT2LMHeadModel(config) 随机初始化 AutoModelForCausalLM.from_pretrained(...) 加载权重
③ 数据 海量纯文本 少量任务样本
④ 训练 Trainer.train(),学习率大档 Trainer.train(),学习率小档

微调若走 LoRA,只是在第 ② 步之后再套一层 peftLoraConfig + get_peft_model),把可训练参数压到全量的 <1%,其余三步不变。可见「从零」和「微调」在工程上高度同源,理解一个就等于理解另一个。


8. 微调 vs RAG:技能 vs 知识

很多人对微调有个美好的误会:既然 LoRA 适配器能热插拔,那不就是「需要什么知识接入什么知识」?

热插拔这件事确实成立——同一基础模型上换不同适配器,就能切换律师/医生/客服等不同「人格」。但热插拔的是技能和风格,不是知识。这是最高频的一个坑:

你以为微调在装 微调实际擅长装
「2026 年的新闻」这类事实 「用律师口吻回答」这类风格
「产品手册第 3 章内容」 「按 JSON 格式输出」这类能力
「某个新 API 的用法」 「多做一步推理再回答」这类行为

真正「需要什么知识接入什么知识」的技术是 RAG(检索增强生成)

微调 / LoRA RAG
装的是 技能、风格、行为 知识、事实、资料
怎么用 改模型参数 不改模型,临时把资料塞进提示词
更新知识 要重新训练 改数据库即可,实时生效

工业界最常见的组合:微调调性格 + RAG 供知识,两者分工,各干各的。


9. 为什么微调注入不了知识

微调不是绝对不能塞知识,而是代价高、效果差、副作用大,原因有四:

  1. 容量太小:LoRA 只训 <1% 的参数,像给厚书贴几张便利贴,写得下批注(风格),写不下整章新内容(海量事实)。
  2. 灾难性遗忘:知识分布式纠缠在几十亿参数里,为塞新事实去改参数,容易顺手破坏存旧知识的那部分——新的没记牢,老的先退化。
  3. 机制不对:微调是用梯度下降拟合「输入→输出」的规律,学的是「模式」;而记住孤立事实需要「存储 + 检索」,是另一回事。
  4. 爱编造:硬灌也常记串记错,还会加剧幻觉——学会了「自信作答」却没真记住,于是一本正经地编。

深层原因:为什么同样是梯度下降,预训练能记住、微调却遗忘?

关键不在机制(都一样),而在数据的覆盖面

  • 预训练:喂海量、包罗万象的数据,学新事实时旧知识 B/C/D 也一直在数据里反复出现,边学边复习,不会忘。
  • 微调:只喂几百到几万条、主题单一的数据(比如全是医疗)。这段时间只见医疗,梯度只朝医疗方向推,那些没在数据里出现的旧知识被推偏却没数据「拉回来」——于是被覆盖遗忘。

决定「学新会不会忘旧」的是数据的「覆盖面」,不是单纯的「数量」。偏科练久了,别的科就忘了——不是机制的错,是数据太偏。学习率压到 2e-5 也是为了少推偏一点。

风格好学、知识难学的本质

  • 风格/技能是「规律」:「凡这类问题都用这种腔调答」——几百个例子就能归纳,学得又快又稳。
  • 知识是「一堆孤立的点」:各条事实之间毫无规律可循,让梯度下降去死记散点,它做不好。

打比方:微调像让学生总结解题套路(好学);而背「圆周率后 100 位」(孤立事实)不是「总结套路」擅长的事。


10. 知识到底怎么更新

既然微调塞不进知识,那商业大模型更新知识是不是得从零重训?几乎不是——从零重训(推倒重来)太贵,只留给换架构、做新一代模型。日常更新按成本从高到低有四种手段:

做法 干什么 成本 场景
继续预训练(增量预训练) 在原模型上接着喂大批新语料继续训(不是从零) 高,但远低于重训 大版本知识刷新、补整个新领域
RAG 不动模型,新知识放外部库,用时检索拼进提示词 极低、实时 绝大多数「知识要新」的需求
联网检索 / 工具调用 现场上网查、调 API 时效性极强的信息
微调 调风格/技能,不适合塞知识 对齐、口吻、格式

大模型的知识其实分两层:

  • 参数里的知识(模型「记得」的):靠预训练 / 继续预训练更新,有「知识截止日期」。
  • 外挂的知识(模型「查得到」的):靠 RAG + 联网,实时更新,参数一个字不动。

所以一个「知识截止 2024 年」的模型,也能答今天的新闻——答案不来自参数,而来自联网检索外挂进来的。


11. 继续预训练 vs 微调:机制一样,数据不同

继续预训练和微调,运行逻辑(代码机制)几乎一样——都是「加载已有模型 → 喂数据 → 梯度下降」,核心差异全在数据

维度 继续预训练 微调(SFT/LoRA)
数据类型 海量无标注纯文本(像预训练那样”读书”) 少量有结构的任务样本(问-答对)
数据规模 大(几十亿~万亿 token) 小(几百~几万条)
数据覆盖面 广、全面(防遗忘的关键) 窄、专一
算损失的范围 纯「预测下一个词」 常只在答案部分算损失
产物 一个新的基础模型(还能再微调) 面向具体任务的成品 / 一个 LoRA 适配器

更精确地说,关键变量有两个:① 数据覆盖面(决定会不会遗忘,比「规模」更本质,且继续预训练常混入旧数据一起训来防遗忘);② 算损失的范围(纯预测下一词 vs 只在答案上算)。

三者关系一图串起:

1
2
3
4
5
6
7
从零预训练  →  继续预训练  →  微调(SFT/对齐)
(随机初始化) (换更全面的 (换少量任务数据,
海量新语料, 调风格/技能,
补知识、防遗忘) 不补知识)

机制都一样:加载 → 喂数据 → 梯度下降
差别全在:数据的「类型 / 规模 / 覆盖面」+ 算损失的范围

12. 速查总表

术语 属于哪条线 一句话
全量微调 动多少参数 全改,效果上限高但最贵
LoRA 动多少参数 旁挂低秩矩阵,最主流的省参数法
QLoRA 动多少参数 LoRA + 4bit 量化,单卡微调大模型
Adapter 动多少参数 插入小模块,只训它
Prefix/Prompt-Tuning 动多少参数 只学一段软提示向量
SFT 用什么信号训 问答对直接教
RLHF 用什么信号训 人类偏好 + 强化学习
DPO 用什么信号训 好坏答案成对优化,RLHF 平替
灾难性遗忘 现象 学习率太大冲垮模型已有知识
PEFT 类别 参数高效微调家族的统称
RAG 知识注入 不改模型,检索资料拼进提示词,实时更新
继续预训练 知识更新 在原模型上接着喂海量新语料,非从零
知识截止日期 概念 参数里的知识只到预训练语料的时间点

13. 核心结论

  • 微调 vs 从零:代码骨架几乎一样,本质差别只在一行——from_pretrained(加载权重)还是 Model(config)(随机初始化)。
  • 两条正交的线别混:「动多少参数」(全量 / PEFT)和「用什么信号训」(SFT / RLHF / DPO)是两个维度,日常组合用(如 QLoRA + DPO)。
  • PEFT 家族:LoRA、QLoRA、Adapter、Prefix/Prompt-Tuning、(IA)³,共同点是冻结原模型、只训一小撮新参数。
  • 产物:全量微调存一整个模型;LoRA 只存一个几 MB 的适配器,用时和基础模型拼起来,可热插拔。
  • 技能 vs 知识:微调热插拔的是「技能/风格」,「需要什么知识接入什么知识」是 RAG 的活;微调塞不进知识,因为它擅长拟合「规律」而非死记「散点」。
  • 遗忘的根源是数据太偏:微调只喂单一主题、没数据复习旧知识才遗忘;预训练/继续预训练靠海量全面数据边学边复习,所以不忘——关键是「覆盖面」而非「数量」。
  • 知识怎么更新:参数级知识靠继续预训练(非从零重训),时效性知识靠 RAG + 联网;微调只管风格技能,不参与知识更新。
  • 三者机制相同、数据不同:从零预训练 / 继续预训练 / 微调都是「加载→喂数据→梯度下降」,差别全在数据的类型、规模、覆盖面与算损失的范围。
  • 和本项目的关系:本项目只做「从零预训练」,微调是把开源模型用起来的后续步骤,本文作为番外系统梳理,代码层面它和从零训练高度同源、理解一个即通另一个。