
从原理到调参,小白也能读懂的大模型微调LoRA,不懂线性代数也没问题 原创
身为一名AI工程师,我过去的工作主要集中在应用层开发,对算法的理解并不深入。然而,近期我开始对算法产生了浓厚的兴趣,并转向研究模型微调。在众多微调算法中,Lora以其普遍应用引起了我的关注,我计划在本文中对它进行详细介绍。将Lora仅仅视为一种算法可能并不准确,它更像是一种精妙的技巧或策略。下文将围绕几个核心问题,全面探讨和解析Lora技术,希望这些内容能为对模型微调感兴趣的你提供有用的参考和帮助。
Lora是什么
假设大模型的原始的权重矩阵w是:
全量微调需要更新 5 * 4 = 20个参数,假设微调后的参数是:
这个可以转化为:
其中ΔW 可以分解为
- 矩阵 ( A ):尺寸 ( 5 * 2 ),共10个参数
- 矩阵 ( B ):尺寸 ( 2 * 4 ),共8个参数
- LoRA总参数:( 10 + 8 = 18 ) 个
也就是说通过LoRA微调,调参对象从 W 变为 A、B,使得参数量从20个减少为18个,这是简化的例子。在实际案例中,参数量可以减少为0.01%~3%左右。
为什么需要LoRA
LoRA最早出现在2021年由微软研究院提出的一篇论文中(《LoRA: Low-Rank Adaptation of Large Language Models》),LoRA的核心思路是:与其每次都复制整个模型,不如只调整一小部分参数,把成本降下来。它的目标是解决大模型微调中的两大痛点:
- 资源消耗太大:大型语言模型动辄几亿甚至几千亿参数,全参数微调需要为每个新任务保存一份完整的模型副本。比如,一个10亿参数的模型,假设每个参数用4字节(float32),光存储就得4GB。多个任务下来,硬盘和显存都吃不消。
- 训练效率低下:全参数微调不仅占空间,还需要大量计算资源和时间。每次训练都得更新所有参数。
LoRA的核心亮点
- 参数少
- 在GPT-3上,
r = 8
的LoRA参数量占全微调的0.01%-0.1%,性能却达到全微调的95%-99%。 - 在GLUE任务(BERT),
r = 16
的LoRA用0.1%参数,平均得分仅比全微调低0.5-1分。 - 它只微调原始参数的1%甚至更少。
- 速度快
- 训练和部署都比全参数微调省时省力。
- 模块化
- 训练好的LoRA“插件”可以随时加载或卸载,不影响原始模型,特别适合多任务场景。
模块化设计的优点
- 避免灾难性遗忘
直接修改W
可能导致模型在新任务上表现良好,但在原始任务上性能下降(即“灾难性遗忘”)。LoRA通过冻结核心W
,保留了原始模型的能力。 - 存储高效
一个大模型可以搭配多个LoRA模块,每个模块只占用MB级空间,相比全模型微调动辄几GB,节省显著。 - 快速切换任务
任务切换只需加载不同LoRA文件,几秒钟搞定,不用重新训练。 - 兼容性强
原始模型完全不动,多个团队可以共享同一个基础模型,只开发自己的LoRA模块。
为什么可以对增量权重 ΔW 低秩分解?
低秩分解的核心思想是:矩阵里的信息往往不是均匀分布的,很多维度是冗余的,只需要抓住"主要方向"就够了。
1. 什么是矩阵的秩(Rank)?
在线性代数中,一个矩阵的秩(rank)是它的线性独立行或列的数量。如果一个矩阵是"低秩"的,意味着它的信息可以用少量独立方向表达,而不是需要完整的维度。
比如下述矩阵,第5行 [1, 2, 0, 3, 0]
是第1行 [1, 0, 0, 2, 0]
和第2行 [0, 2, 0, 1, 0]
的线性组合(第5行=第1行+第2行),第5行没有提供更多的信息,理论上这个矩阵有前4行就能提供所有信息了,因此矩阵的行秩为4(列秩也为4,第5列全为0,没有信息增量)。
2. 低秩分解的原理
奇异值分解(SVD)可以把任意矩阵分解成三个矩阵的乘积。对于一个形状 ( d * k ) 的矩阵 ( W ),SVD可以写成:
- ( U ) 是 ( d * d ) 的正交矩阵
- (Σ ) 是 ( d * k ) 的对角矩阵(奇异值按降序排列)
- ( V^T ) 是 ( k * k ) 的正交矩阵(( V ) 的转置)
其中 ( r ) 是矩阵的秩(非零奇异值的数量)。通过保留前 ( r ) 个最大的奇异值(低秩近似),可以用更少的参数近似原矩阵 ( W )。
任意矩阵(无论是实数还是复数、方阵还是非方阵、满秩还是不满秩)都可以通过奇异值分解(SVD)精确拆分为三个特定矩阵的乘积
举个例子,针对上述矩阵 ( S ) 的SVD分解(计算过程略):
如果只保留前三个奇异值(7.03, 3, 2.15),重构后的矩阵 ( S' ) 与原矩阵 ( S ) 几乎一致(三个矩阵分别取前三列,前三行&前三列,前三行):
结果对比原始矩阵和重构矩阵,直观上来看,基本保持一致,这就是说:如果只保留最大的几个奇异值,就能用更少的参数近似表示w。
3. 为什么可以对增量权重 ΔW 低秩分解?
研究发现:
- 信息集中性:微调后的权重变化 ( ΔW) 的奇异值分布中,前10-20个奇异值占据了90%以上的信息(LoRA论文在GPT-3上的实验结论)。
- 结构化特性:(ΔW ) 的变化不是随机的,而是集中在少数"任务相关方向"上(例如让模型学习法律术语只需调整少量语义方向)。
- 高效近似:直接用低秩矩阵 ( A * B ) 构造 (ΔW ),无需完整SVD计算,参数量从 ( d * k ) 降至 ( (d + k) * r )。
直观理解: 微调类似于让一个已学会"说话"的模型掌握某种"口音"。这种调整只需修改少数关键维度(如词汇选择),而非全部语言规则,因此低秩足够。
举个例子:
对一个 ( 512 * 512 ) 的权重矩阵(262,144参数):
- 全微调:更新全部262,144个参数。
- LoRA(( r=8 )):仅需 ( 512 * 8 + 8 * 512 = 8,192 ) 个参数,即可捕捉主要变化。
4. 对原始权重 ( W ) 可以低秩分解吗?
不行。预训练模型的权重 ( W ) 通常接近满秩(奇异值分布平滑),低秩分解会丢失关键信息。而 ( ΔW ) 的秩天然较低,适合分解。
LoRA是如何更新参数的
本质上,LoRA仍然使用反向传播算法进行参数更新,但仅针对新增的低秩矩阵 ( A ) 和 ( B ),而保持原始权重 ( W ) 冻结。
参数更新过程
(1)初始化
- ( W ) 使用预训练模型的权重,梯度计算被禁用(不更新)。
- ( A ) 用小的随机高斯分布初始化
- ( B ) 初始化为全零矩阵,确保训练开始时 ( ΔW = 0 ),避免干扰原始模型。
(2)前向传播
- 输入数据 ( X ) 通过调整后的权重计算输出
- 根据任务目标 计算损失函数 ( L )(如交叉熵损失)。
(3)反向传播
- 计算损失 ( L ) 对 ( A ) 和 ( B ) 的梯度
- 不计算( W ) 的梯度(因其被冻结)。
(4)参数更新
- 使用优化器(如Adam)更新
(5)迭代优化
- 重复步骤2-4,直到损失收敛或达到训练轮次。
- 训练完成后,( A ) 和 ( B ) 捕捉了任务特定的调整信息。
推理部署选项
- 合并权重:将 ( W' = W + A * B ) 合并为单一矩阵,直接用于推理(适合固定任务)。
- 动态加载:保持 ( W ) 和 ( A * B ) 分离,灵活切换不同任务的LoRA模块(适合多任务场景)。
关键特点
- 参数高效:仅训练 ( A ) 和 ( B ),参数量从 ( d * k ) 降至 ( (d + k) * r )。
- 内存节省:无需存储全参数微调的梯度,显存占用大幅降低。
- 兼容性:原始模型 ( W ) 保持不变,支持多任务共享。
LoRA可以用在Transformer的哪些层
LoRA是"好钢要用在刀刃上"。并非模型的所有参数都需要微调,选择关键层进行适配即可达到接近全参数微调的效果。LoRA目前主要可以应用在transformer中的以下两类层:
Transformer是谷歌在2017年推出的深度学习模型,专门处理序列数据。简单来说,序列数据就像排队的小朋友,每个小朋友都有自己的位置和信息,Transformer能把这些信息处理得明明白白。后面有空我会专门出一个系列讲解一下。
1. 注意力层(Self-Attention)
Transformer的核心是多头注意力机制,每个注意力头包含4个权重矩阵:
- ( W_q )(Query)
- ( W_k )(Key)
- ( W_v )(Value)
- ( W_o )(Output)
LoRA通常应用在:
- ( W_q ) 和 ( W_v )(最高优先级):
- 调整 ( W_q ) 可改变模型"关注哪些信息"。
- 调整 ( W_v ) 可影响"如何编码关注的信息"。
- ( W_o )(次优先级):
- 调整输出投影矩阵,但收益通常不如 ( W_q ) 和 ( W_v ) 显著。
实验结论(来自LoRA原论文):
- 仅微调 ( W_q ) 和 ( W_v ) 即可达到全参数微调效果的90%以上。
- 添加 ( W_o ) 的LoRA对性能提升有限(<2%),但会增加参数量。
2. 前馈网络层(FFN)
FFN包含两个线性变换:
- ( W_1 ):升维(通常放大4倍,如d_model → 4×d_model)
- ( W_2 ):降维(4×d_model → d_model)
适用场景:
- 大模型(如GPT-3):添加FFN层的LoRA可进一步提升性能。
- 复杂生成任务:调整FFN能增强任务特定的特征表达。
不推荐使用LoRA的层
(1)嵌入层(Embedding):
- 参数量大但微调收益低,冻结可节省资源。
(2)LayerNorm/Bias:
- 参数少,直接全参数微调成本低。
- LayerNorm的缩放因子和偏置本身具有低秩特性,无需LoRA。
实际配置建议
模型规模 | 推荐LoRA目标层 | 典型rank (r) |
小模型(如BERT) | 仅 ( W_q ), ( W_v ) | 8-16 |
大模型(如GPT-3) | ( W_q ), ( W_v ), FFN的 ( W_1 ) | 32-64 |
复杂生成任务 | 所有注意力矩阵 + FFN | 64+ |
模块化设计优势
- 任务切换:不同任务可独立配置LoRA模块(如翻译任务用( W_q ), ( W_v ),摘要任务额外启用FFN)。
- 资源分配:对关键层分配更高秩(如( r=32 )),次要层用低秩(如( r=8 ))。
LoRA训练时需要调整哪些超参数
以 LLaMA-Factory 的配置为例,说明 LoRA 的关键超参数及其调参策略:
核心参数表
参数名 | 类型/范围 | 含义 | 建议值 | 默认值 |
| | 微调类型选择 | 必须设为 | |
(r) | 正整数 | LoRA的秩,决定矩阵A/B的列数/行数 | 简单任务:8-16 | 8 |
(α) | 正整数 | 缩放系数,控制ΔW对原始权重W的影响强度 | 通常设为 | None |
| 0.0-1.0 | LoRA层的Dropout概率 | 大数据集:0.0 | 0.0 |
| 逗号分隔的字符串 | 应用LoRA的模块名称(需匹配模型层名) | 默认: | |
| 逗号分隔的字符串 | 额外扩展的LoRA目标模块(如FFN层) | 通常留空,大模型可加 | None |
调参技巧
- 秩(r)的选择
- 小数据集(<5K样本):r=8
- 大数据集(>50K样本):r=32+
- 从小开始:优先尝试r=8或16,逐步增加直至性能饱和。
- 数据量关联:
- 目标层选择策略
# 简单任务(如分类)
lora_target = "q_proj,v_proj"
# 复杂任务(如生成)
lora_target = "q_proj,k_proj,v_proj,o_proj,ffn.w1,ffn.w2"
3.改进技术的适用场景
- LoRA+:训练速度要求高时启用(设
lorapius_lr_ratio=8
)。 - DoRA:需要逼近全微调性能时开启(
use_dora=true
)。 - rsLoRA:当r≥32时更稳定(
use_rslora=true
)。
参数影响对比
超参数 | 参数量影响 | 训练速度 | 性能影响 |
↑ | 线性增加 | 略微下降 | 先升后平 |
↑ | 无影响 | 无影响 | 调节强度 |
| 增加约10% | 下降10%-20% | 提升1%-3% |
| 无影响 | 初始化耗时增加 | 收敛更快 |
经典配置示例
# GLUE任务(BERT-base)
lora_rank:16
lora_alpha:32
lora_target:"query,value"
lora_dropout:0.1
# GPT-3文本生成
lora_rank:64
lora_alpha:128
use_rslora:true
lora_target:"q_proj,v_proj,ffn.w1"
总结
LoRA是一种高效的大模型微调技术,它通过低秩矩阵分解显著地减少了参数量和计算资源的需求,同时又能保持接近全模型微调的性能。在接下来的文章中,我们将从实战角度出发,借由Llama-Factory来进行模型微调。我希望能帮助读者从零开始,全面掌握模型微调的知识和技巧。
本文转载自AI 博物院 作者:longyunfeigu
