本文是「GPT 训练分步学习路径」的又一篇番外。
GPT_teacher-3.37M-cn这个教学项目本身只讲「从 0 到 1 预训练」,并不涉及微调,但微调是把开源大模型用起来的第一步,值得单独讲清。本文只做一件事:把「微调」这件事从头捋一遍——它和从零训练差在哪、有哪些流派、产物长什么样、日常怎么组合用。看完你应该能分清「全量 / LoRA / QLoRA」和「SFT / RLHF / DPO」分别在说什么维度的事。
目录
- 一句话先讲清
- 微调和从零训练,到底差在哪
- 微调方法地图:两条正交的线
- 省参数的一条线:全量 vs PEFT 家族
- 用什么信号训的一条线:SFT / RLHF / DPO
- 微调产物长什么样
- 代码对照:从零 vs 微调,只差一行
- 微调 vs RAG:技能 vs 知识
- 为什么微调注入不了知识
- 知识到底怎么更新
- 继续预训练 vs 微调:机制一样,数据不同
- 速查总表
- 核心结论
1. 一句话先讲清
从零训练是把一张白纸练成模型;微调是拿别人已经练好的模型,用你自己的少量数据接着训一小段,让它学会某个具体任务或说话风格。
绝大多数人这辈子都不会「从零训练」一个大模型(太贵),但几乎都会用到「微调」——因为它便宜、快、数据量小。
2. 微调和从零训练,到底差在哪
有意思的是,用 HuggingFace 全家桶写出来,两者的代码骨架几乎一模一样,都是这四步:
1 | 建分词器 → 建模型 → 建数据 → Trainer.train() |
区别不在骨架,而在四步里各自填了什么:
| 步骤 | 从零训练 | 微调 | 为什么不同 |
|---|---|---|---|
| ① 分词器 | 自己造一份新词表 | 用基础模型自带的词表 | 要接着别人的权重训,词表必须和权重对得上 |
| ② 模型 | Model(config) 随机初始化 |
from_pretrained(...) 加载预训练权重 |
这是最本质的一行:白纸开始 vs 站在肩膀上 |
| ③ 数据 | prompt/completion 拼接分词 | 完全相同 | 数据处理不区分场景 |
| ④ 训练 | 学习率大(1e-3)、步数多 | 学习率小 100 倍(2e-5)、步数少 | 怕大改动冲垮模型已有知识(灾难性遗忘) |
只看第 ② 步就够了:
from_pretrained(加载权重)还是Model(config)(随机初始化),这一个函数调用就决定了它是「微调」还是「从零训练」。其余差异都是为配合第 ② 步做的连带调整。
3. 微调方法地图:两条正交的线
「微调有哪些方法」这个问题容易乱,是因为大家把两条不同维度的线混在一起说了:
1 | 微调 |
这两条线是正交的:你可以「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 | checkpoints/hf_finetune/ |
用时 from_pretrained("checkpoints/hf_finetune") 加载这一份即可,和原始基础模型再无关系。
6.2 LoRA 微调 → 只存一个小小的「外挂补丁」
1 | checkpoints/hf_finetune/ |
适配器离不开原始基础模型,用时要两份拼起来:
1 | base = AutoModelForCausalLM.from_pretrained(BASE_MODEL) # 原始大模型 |
由此带来两个好处:
| 好处 | 说明 |
|---|---|
| 省空间 | 7B 基础模型十几 GB,一个适配器几 MB;微调 10 个任务 = 1 份大模型 + 10 个小适配器 |
| 可热插拔 | 同一基础模型上随时换不同适配器切换「人格/任务」,不用重新加载大模型 |
7. 代码对照:从零 vs 微调,只差一行
用 HuggingFace 全家桶把「从零预训练」和「微调」并排写出来,四步骨架完全一样,差别几乎只在第 ② 步建模型这一行:
| 步骤 | 从零预训练 | 微调 |
|---|---|---|
| ① 分词器 | 自己造 / 用现成的 | 用基础模型自带的 |
| ② 建模型 | GPT2LMHeadModel(config) 随机初始化 |
AutoModelForCausalLM.from_pretrained(...) 加载权重 |
| ③ 数据 | 海量纯文本 | 少量任务样本 |
| ④ 训练 | Trainer.train(),学习率大档 |
Trainer.train(),学习率小档 |
微调若走 LoRA,只是在第 ② 步之后再套一层 peft(LoraConfig + get_peft_model),把可训练参数压到全量的 <1%,其余三步不变。可见「从零」和「微调」在工程上高度同源,理解一个就等于理解另一个。
8. 微调 vs RAG:技能 vs 知识
很多人对微调有个美好的误会:既然 LoRA 适配器能热插拔,那不就是「需要什么知识接入什么知识」?
热插拔这件事确实成立——同一基础模型上换不同适配器,就能切换律师/医生/客服等不同「人格」。但热插拔的是技能和风格,不是知识。这是最高频的一个坑:
| 你以为微调在装 | 微调实际擅长装 |
|---|---|
| 「2026 年的新闻」这类事实 | 「用律师口吻回答」这类风格 |
| 「产品手册第 3 章内容」 | 「按 JSON 格式输出」这类能力 |
| 「某个新 API 的用法」 | 「多做一步推理再回答」这类行为 |
真正「需要什么知识接入什么知识」的技术是 RAG(检索增强生成):
| 微调 / LoRA | RAG | |
|---|---|---|
| 装的是 | 技能、风格、行为 | 知识、事实、资料 |
| 怎么用 | 改模型参数 | 不改模型,临时把资料塞进提示词 |
| 更新知识 | 要重新训练 | 改数据库即可,实时生效 |
工业界最常见的组合:微调调性格 + RAG 供知识,两者分工,各干各的。
9. 为什么微调注入不了知识
微调不是绝对不能塞知识,而是代价高、效果差、副作用大,原因有四:
- 容量太小:LoRA 只训 <1% 的参数,像给厚书贴几张便利贴,写得下批注(风格),写不下整章新内容(海量事实)。
- 灾难性遗忘:知识分布式纠缠在几十亿参数里,为塞新事实去改参数,容易顺手破坏存旧知识的那部分——新的没记牢,老的先退化。
- 机制不对:微调是用梯度下降拟合「输入→输出」的规律,学的是「模式」;而记住孤立事实需要「存储 + 检索」,是另一回事。
- 爱编造:硬灌也常记串记错,还会加剧幻觉——学会了「自信作答」却没真记住,于是一本正经地编。
深层原因:为什么同样是梯度下降,预训练能记住、微调却遗忘?
关键不在机制(都一样),而在数据的覆盖面:
- 预训练:喂海量、包罗万象的数据,学新事实时旧知识 B/C/D 也一直在数据里反复出现,边学边复习,不会忘。
- 微调:只喂几百到几万条、主题单一的数据(比如全是医疗)。这段时间只见医疗,梯度只朝医疗方向推,那些没在数据里出现的旧知识被推偏却没数据「拉回来」——于是被覆盖遗忘。
决定「学新会不会忘旧」的是数据的「覆盖面」,不是单纯的「数量」。偏科练久了,别的科就忘了——不是机制的错,是数据太偏。学习率压到 2e-5 也是为了少推偏一点。
风格好学、知识难学的本质
- 风格/技能是「规律」:「凡这类问题都用这种腔调答」——几百个例子就能归纳,学得又快又稳。
- 知识是「一堆孤立的点」:各条事实之间毫无规律可循,让梯度下降去死记散点,它做不好。
打比方:微调像让学生总结解题套路(好学);而背「圆周率后 100 位」(孤立事实)不是「总结套路」擅长的事。
10. 知识到底怎么更新
既然微调塞不进知识,那商业大模型更新知识是不是得从零重训?几乎不是——从零重训(推倒重来)太贵,只留给换架构、做新一代模型。日常更新按成本从高到低有四种手段:
| 做法 | 干什么 | 成本 | 场景 |
|---|---|---|---|
| 继续预训练(增量预训练) | 在原模型上接着喂大批新语料继续训(不是从零) | 高,但远低于重训 | 大版本知识刷新、补整个新领域 |
| RAG | 不动模型,新知识放外部库,用时检索拼进提示词 | 极低、实时 | 绝大多数「知识要新」的需求 |
| 联网检索 / 工具调用 | 现场上网查、调 API | 低 | 时效性极强的信息 |
| 微调 | 调风格/技能,不适合塞知识 | 中 | 对齐、口吻、格式 |
大模型的知识其实分两层:
- 参数里的知识(模型「记得」的):靠预训练 / 继续预训练更新,有「知识截止日期」。
- 外挂的知识(模型「查得到」的):靠 RAG + 联网,实时更新,参数一个字不动。
所以一个「知识截止 2024 年」的模型,也能答今天的新闻——答案不来自参数,而来自联网检索外挂进来的。
11. 继续预训练 vs 微调:机制一样,数据不同
继续预训练和微调,运行逻辑(代码机制)几乎一样——都是「加载已有模型 → 喂数据 → 梯度下降」,核心差异全在数据:
| 维度 | 继续预训练 | 微调(SFT/LoRA) |
|---|---|---|
| 数据类型 | 海量无标注纯文本(像预训练那样”读书”) | 少量有结构的任务样本(问-答对) |
| 数据规模 | 大(几十亿~万亿 token) | 小(几百~几万条) |
| 数据覆盖面 | 广、全面(防遗忘的关键) | 窄、专一 |
| 算损失的范围 | 纯「预测下一个词」 | 常只在答案部分算损失 |
| 产物 | 一个新的基础模型(还能再微调) | 面向具体任务的成品 / 一个 LoRA 适配器 |
更精确地说,关键变量有两个:① 数据覆盖面(决定会不会遗忘,比「规模」更本质,且继续预训练常混入旧数据一起训来防遗忘);② 算损失的范围(纯预测下一词 vs 只在答案上算)。
三者关系一图串起:
1 | 从零预训练 → 继续预训练 → 微调(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 + 联网;微调只管风格技能,不参与知识更新。
- 三者机制相同、数据不同:从零预训练 / 继续预训练 / 微调都是「加载→喂数据→梯度下降」,差别全在数据的类型、规模、覆盖面与算损失的范围。
- 和本项目的关系:本项目只做「从零预训练」,微调是把开源模型用起来的后续步骤,本文作为番外系统梳理,代码层面它和从零训练高度同源、理解一个即通另一个。