大模型通识 / 大模型理论基础
12. 微调与 LoRA:什么时候值得改变模型本身
原文备份 · 第 13 / 20 篇 · 查看极客时间原知识库 ↗
本篇目录 · 13 节
来源:大模型理论基础
你的笔记助手已经能检索当前安排,并把依据交给模型。现在你希望它长期稳定地完成一项固定任务:提取目标章节的状态、时间和依据,遇到取消、冲突或缺失资料时也按同一规则处理。
你试过清楚的提示和少量示范,模型仍经常添加无关建议,或混淆“已取消”和“未安排”。有人建议:“把这些例子拿去微调。”另一个人说:“用 LoRA 就很便宜。”
这两个建议都还缺一步判断:问题是否真的需要改变模型?即使需要,要改变哪些参数,又怎样验证训练没有把事情弄得更糟?
本篇从复习助手出发,解释全量微调、LoRA、QLoRA 及其与提示、RAG 的分工。矩阵和数量均为教学构造,不代表实际训练效果;无需显卡、账号或训练环境。
一、微调改变模型,提示和检索改变本次输入
Fine-tuning,微调,是在已有模型基础上继续训练,使其适应某类任务或数据。它利用已有能力作为起点,不是从随机参数重新训练一个大模型。
在常见监督微调中,训练数据提供输入与期望输出。模型预测输出 Token,训练程序计算损失,再通过反向传播更新选定的可训练参数。第 06 篇讲过这条学习路径,本篇关注如何把它用于自己的任务。
把三种做法放在一起看:
| 做法 | 主要改变什么 | 复习助手里的例子 |
|---|---|---|
| 提示与上下文示范 | 本次指令、示例和输入条件 | 明确规定四种状态的定义 |
| RAG | 本次可见的外部证据 | 找到这周最新的安排 |
| 微调 | 参与模型计算的可训练参数 | 通过许多合格示范强化按规则提取的行为 |
三者可以组合。训练过的助手仍可以检索每周的新笔记,也仍需要当前问题和明确的输入格式。
常见经验是让 RAG 提供经常变化、需要追溯的事实,让微调适应反复出现的任务和表达方式。但不要把这句话理解成“微调绝对学不了知识”。继续训练也可能吸收领域知识和文本规律;例如领域继续预训练研究,在所考察的领域与分类任务上观察到了收益。《Don't Stop Pretraining》
区别在于,知识进入参数后,更新、逐条删除和定位来源通常不如外部记录直接。若第 2 章今天从周六改到周日,为这一条动态事实重新训练,往往不是个人项目最合适的第一步。
二、先把期望行为变成一致的训练样本
假设任务沿用第 09 篇的四种状态:已安排、未安排、已取消、待澄清。我们为教学重新约定输出字段:
status:四种状态之一。time:有明确当前安排时填原文时间,否则为null。evidence:支持判断的原文;资料未提及时写“未提及”。
null 在这里表示没有可填写的时间,是当前数据格式的约定。它与前面面向人的“未确定”表达同一类缺口,不是模型自动理解的通用标准。
一条监督样本可以这样表示:
输入
任务:提取目标章节的当前复习安排,按约定返回三个字段。
目标:第 2 章
笔记:第 2 章原定周五,现改为周六复习。
期望输出
{"status":"已安排","time":"周六","evidence":"第 2 章原定周五,现改为周六复习。"}
还应包含不同边界,而不是把“周六”重复几百遍:
| 输入笔记(提取目标均为第 2 章) | 状态 | 时间 | 依据 |
|---|---|---|---|
| 第 2 章周五复习已取消,暂无新安排。 | 已取消 | null | 对应原文 |
| 第 2 章尚未安排。 | 未安排 | null | 对应原文 |
| 只有第 1 章周二复习的记录。 | 未安排 | null | 未提及 |
| 两份无有效性说明的记录分别写周四、周日。 | 待澄清 | null | 两份冲突记录 |
表格用于审核标签,不是直接上传给某个训练接口的文件格式。实际样本应包含完整任务规则和原始笔记,并写出完整期望答案。
这里仍沿用课程约定:资料未提及也归为“未安排”,但依据写“未提及”;这不证明现实中没有安排。产品若需要区分两者,先改状态定义,再一致地修改样本。
给原始笔记和给示范答案,不是同一种训练
只提供一堆笔记并让模型继续预测文本,属于继续语言建模的一种做法;它不会自动知道你要三个 JSON 字段,也不会自动知道四种状态的业务边界。
监督微调需要把“收到什么输入时,应该怎样回答”展示清楚。对于对话数据,可以只对助手回答计算损失;训练器也可能按配置对其他位置计算损失。Hugging Face TRL 文档明确区分了只训练回答部分与全序列等设置。TRL:SFT Trainer
不对用户输入计算目标损失,不代表模型看不到用户输入。它仍作为条件参与计算。这里要防止的错误,是把训练对象、上下文和损失位置混为一谈。
样本审核比先调训练参数更重要:同一种情况是否用了相同标签?依据是否真的来自输入?有没有把“旧安排”标成当前安排?如果示范本身前后矛盾,训练会接收到互相冲突的信号。
三、全量微调与参数高效微调,差在更新范围
这里把作为训练起点的已有模型称为基座模型。它可以是预训练模型,也可以是已经做过指令训练的模型。
全量微调,full fine-tuning,通常让基座模型全部参数参与更新。模型里的权重可以整体调整,但训练还要容纳梯度、优化器状态和计算中间值等,成本不只是保存一份权重文件。
PEFT,Parameter-Efficient Fine-Tuning,参数高效微调,只训练相对少量的参数。LoRA,Low-Rank Adaptation,低秩适配,是其中一种方法,不是所有 PEFT 方法的统称。
对于标准 LoRA,我们保留已有权重不更新,另外训练表示增量的较小矩阵。这个增量参与前向计算,所以虽然基座权重保持不变,整个模型的输入—输出关系仍会改变。《LoRA: Low-Rank Adaptation of Large Language Models》
“冻结”指优化器不更新那部分参数,不是从计算图里删掉这部分模型。基座仍参与计算,训练通常也仍需要经过其中的计算来求可训练参数的梯度。
因此,LoRA 可以显著减少可训练参数及相关训练状态,却不意味着显存只剩两个小矩阵,也不意味着训练速度一定按参数减少比例提升。
四、LoRA:用两个小矩阵表达权重的增量
先看一个线性层。若输入向量长度为 n、输出长度为 m,它的权重矩阵 W₀ 有 m 行、n 列。暂时忽略偏置,原输出为:
原输出 = W₀ × x
标准 LoRA 为这个权重增加两个矩阵:A 为 r×n,B 为 m×r。新输出可以写成:
新输出 = W₀ × x + s × B × A × x
有效权重 = W₀ + s × B × A
其中 r 是选择的低秩维度,s 是缩放系数;标准形式常用 s=α/r,α 是配置的缩放参数。训练更新 A、B,W₀ 冻结。具体实现还有变体,本篇只解释这一基本形式。Hugging Face PEFT:LoRA
不用先掌握“秩”的全部线性代数定义。这里可以把它理解为:增量经过一个只有 r 个数的中间通道,能够表达的独立变化方向受到限制。BA 的秩最多是 r;这不表示原来的 W₀ 或整个语言模型也只有这么低的秩。
一个可以手算的例子
我们取 n=2、m=3、r=1、s=1,设某个教学状态下:
[1 0] [ 1]
W₀ = [0 1] A = [2 -1] B = [ 0] x = [3, 1]ᵀ
[1 1] [-1]
上标 T 表示把这两个数写成一列。先算原模型这条分支:
W₀x = [3, 1, 4]ᵀ
再算增量分支:
Ax = 2×3 - 1×1 = 5
B(Ax) = [5, 0, -5]ᵀ
两边相加:
新输出 = [3,1,4]ᵀ + [5,0,-5]ᵀ = [8,1,-1]ᵀ
W₀ 一个数字都没改,结果已经不同。这些数字仅演示线性层计算,不是概率、词义或训练效果;A、B 也不是推荐初始化。
你还可以把增量先乘出来检查:
[ 2 -1] [ 3 -1]
BA = [ 0 0] W₀+BA = [ 0 1]
[-2 1] [-1 2]
用右边矩阵乘 x,同样得到 [8,1,-1]ᵀ。这也说明,在线性代数层面可以把标准 LoRA 增量合并到原权重中。
为什么大矩阵下更省参数
全量更新这个 m×n 权重,需要训练 m×n 个参数。仅训练 LoRA 的 A、B,则需要:
r×n + m×r = r×(m+n)
假设 m=n=4096,r=8:
| 方法 | 可训练参数数目 |
|---|---|
| 全量更新该权重 | 4096×4096 = 16,777,216 |
| LoRA 的两组矩阵 | 8×4096 + 4096×8 = 65,536 |
后者是前者的 1/256,约 0.39%。若 r 改成 16,则为 131,072 个,数量翻倍。
注意,这只是一个被适配的权重矩阵的算例,不是整模型的比例。实际总量还取决于在哪些层、哪些投影上加入 LoRA,以及是否额外训练其他参数。
r 更大允许更丰富的增量,也增加开销;它不保证验证效果更好。数据有限或标签有噪声时,更强的适配能力也可能学到不该学的规律。
五、QLoRA:进一步减少基座权重的存储负担
LoRA 减少了可训练参数,基座权重仍然要存在。QLoRA 把低位宽量化与 LoRA 结合起来:以低位宽存储冻结的基座权重,训练附加的 LoRA 参数。原论文使用 4 位量化,并介绍了 NF4、量化常数的再次量化和分页优化器等节省内存的办法。《QLoRA: Efficient Finetuning of Quantized LLMs》
量化的基本意思,是用更有限的数值表示近似原有权重。详细方法会在第 14 篇展开,这里只区分两件事:
- 基座主要权重以多少位存储。
- 实际乘加、适配器训练和其他状态采用什么精度。
4 位存储不等于所有计算都用 4 位进行。计算时可以将量化权重解码到适合运算的表示,使用更高精度计算;这并不恢复量化前丢失的全部精度。PEFT 的官方量化示例就分别设置了 4 位加载与 bfloat16 计算。Hugging Face PEFT:Quantization
做一个只计算权重载荷的理想算例:假设有 80 亿个权重,全部用 16 位存储,需要 160 亿字节,也就是十进制 16 GB;全部按 4 位紧密存储,则为 40 亿字节,即 4 GB。
这不是“4 GB 显卡就能训练 80 亿模型”的结论。真实开销还包括量化元数据、未量化的部分、适配器、梯度、优化器状态、激活值和工作缓冲区等。序列长度、批量大小与实现都会影响内存。
QLoRA 降低了某些微调任务的资源门槛,没有把数据准备、评估和部署成本变成零,也不保证在任何任务上与全量微调完全等效。
六、训练完成后,你到底得到了什么
一次典型 LoRA 训练可以保存一个较小的适配器检查点,而不是再次保存完整基座。使用时需要把它与匹配的基座模型、配置组合起来。PEFT 的检查点格式专门记录适配器配置与基座信息。Hugging Face PEFT:Checkpoint format
这意味着,一个很小的 LoRA 文件通常不能独立回答问题。它也不是能装到任意同参数量模型上的通用插件:基座版本、层结构、目标模块和文本处理配置都要匹配。
对于标准 LoRA,有两种常见使用方式:保留基座与适配器分别加载,或者在支持的情况下合并权重。前面的矩阵算例演示了合并原理,但实际量化格式、部署后端和数值精度可能限制合并方式;合并后仍需复测。
原论文中避免额外推理分支的优势,与可合并的设计有关。不能据此承诺任何服务里单独加载适配器都绝无延迟开销。也不能把“合并”理解成模型被压缩成了适配器那么小;完整权重仍然需要保存或加载。
对于只提供 API 的模型,还要看服务商是否提供相应微调能力。能够调用聊天接口,不等于能下载它的权重或自行插入 LoRA。本篇解释原理,不把某家当前服务的支持范围当作通用能力。
七、决定训练之前,先准备一次公平的比较
对复习助手,可以按下面的顺序做判断:
flowchart TD
A[记录稳定出现的错误] --> B{缺少或弄错了资料吗}
B -->|是| C[先修数据与检索]
B -->|否| D[澄清规则并建立提示基线]
D --> E{仍有重复的任务适配问题吗}
E -->|否| F[保留当前方案]
E -->|是| G[审核示范并尝试小规模微调]
G --> H[在留出任务上比较效果与成本]
“小规模”不是固定多少条数据。任务差异很大,不能承诺凑够某个数字就成功。先收集能覆盖真实情况、且标签一致的样本,比盲目堆数量更有意义。
训练、验证、测试不能只是换了文件名
训练集用于更新参数;验证集用于选择训练轮次、LoRA 配置等;测试集留到方案确定后检查。来自同一份笔记的近似改写,应尽量放在同一组,避免训练和测试两边都出现几乎相同的例子。
可以为这项任务设计 30 个额外留出的教学检查案例:明确安排、明确更新、已取消、尚未安排、完全未提及、无法消解的冲突,每类 5 个。它是一个便于解释的检查方案,不是足以代表所有真实使用情况的标准规模。
不只检查 JSON 能不能解析,还要逐项看:状态是否正确、时间是否从有效记录中提取、依据是否支持判断、缺失时有没有补写事实。结构化输出与程序校验仍有作用,微调不能替代它们。
要隔离训练的影响,尽量固定同一批输入资料、提示、评分规则和可比的生成配置,比较基座与适配后的模型。如果同时换了检索器、提示和数据,就不能把所有改善都归因于 LoRA。
也可以另外比较各自优化后的完整方案,但应明确那是在比较两套应用方案,而不是单独测量训练效果。
训练损失下降,只说明训练目标更容易满足
如果训练样本几乎全是“已安排”,模型可能学会更频繁地输出这个标签,却在取消与冲突案例上变差。训练损失降低,并不能独立证明任务进步。
还应检查原来已经会做的事情有没有退步,例如正常改写笔记、处理其他章节、维持证据要求。微调可能产生过拟合或其他能力退化;保留原始模型、适配器版本和评估记录,才能比较与回退。
低训练成本只是决策的一部分。对于调用量很少的个人工具,整理训练数据、维护模型和部署服务的成本,可能超过短提示增加的调用成本。反过来,稳定的大批量任务若能通过微调降低错误或缩短输入,才有必要进一步核算整体收益。
八、理解检查
1. 第 2 章今天改了时间,应该立即训练一份新 LoRA 吗?
通常先更新记录与检索索引,让模型获得当前证据。微调不是动态事实更新的必经步骤。
2. W₀ 冻结,为什么 LoRA 仍会改变输出?
因为新增的 A、B 参与计算,输出从 W₀x 变成 W₀x+sBAx。冻结基座不等于整个模型没有可训练参数。
3. 手算例子中,Ax、W₀x 和最终输出分别是什么?
分别为 5、[3,1,4]ᵀ 和 [8,1,-1]ᵀ。增量分支是 [5,0,-5]ᵀ,与原分支相加。
4. 4096×4096 的权重采用 r=16 的 LoRA,需要多少适配器参数?
16×4096+4096×16=131,072,是 r=8 时的两倍。它只计算这一处 A、B,不代表整个模型只剩这些参数。
5. 理想计算得到 4 位权重只占 4 GB,是否说明总训练内存也是 4 GB?
不是。那只是忽略额外开销的权重载荷。训练还需要其他精度的参数或状态、激活、缓冲区等;低位存储也不等于全程低位计算。
6. 微调后训练样本全对,是否可以替换当前助手?
不能只据此决定。应检查独立案例、各类错误、原有能力和部署后的实际表现,并确认收益值得维护成本。训练成功运行与应用效果改善是两件事。
你现在可以把微调看成一种有数据、有更新范围、有验证成本的工程选择。提示表达任务,RAG 补充当前证据,微调通过训练适应任务;选择哪一种,要从已经定位的问题出发。
下一篇《稠密模型与 MoE:参数量究竟说明了什么》,将进一步区分模型一共保存多少参数、处理一个 Token 时用了多少,以及这些数字能告诉我们什么。
上一篇:RAG 与依据回答 · 返回第二部分大纲