3、LoRA参数组成:Adapter矩阵A和B、缩放因子alpha、Dropout率、初始化策略
聊到LoRA的参数,很多人第一反应就是「不就是两个低秩矩阵嘛」。嗯,这话没错,但实际用起来,里面的门道可不少。我最早接触LoRA时也踩过坑,总觉得参数随便设设就行,结果模型要么不收敛,要么训完跟没训一样。今天咱们就把这几个核心参数掰开揉碎了讲清楚。
3.1 Adapter矩阵A和B:LoRA的骨架
LoRA的核心思想,说白了就是给预训练权重矩阵W加一个低秩的增量。这个增量由两个矩阵相乘得到:A和B。
假设原始权重W的维度是d×k,我们想给它加一个更新量ΔW。ΔW的秩r远小于d和k,于是我们把它拆成:
ΔW = B × A
其中:
- A 的维度:r × k(从输入映射到低秩空间)
- B 的维度:d × r(从低秩空间映射回输出空间)
- r 是秩,通常取 1、2、4、8、16 等小值
我个人习惯把A叫做「压缩矩阵」,把B叫做「恢复矩阵」。你想想看,A先把高维输入压缩到低维空间,B再把它恢复成高维输出。这个过程中,真正学到的就是低维空间里的那点「精华」。
关键点:训练时,原始权重W被冻结,只有A和B参与梯度更新。推理时,我们可以把B×A合并到W中,完全不影响推理速度。
我在项目中遇到过一个问题:当r设得太大时,A和B的参数量会急剧增加。比如d=4096、k=4096时,r=64的参数量是r=4的16倍。所以别贪心,r不是越大越好。
3.2 缩放因子alpha:控制更新强度
光有A和B还不够,我们还需要一个缩放因子α来控制更新量的强度。LoRA的前向传播公式是:
h = Wx + (α / r) × B × A × x
这里的α/r就是缩放系数。为什么要有这个系数?
说白了,就是怕更新量太大,直接把预训练模型学到的知识给冲没了。我刚开始做LoRA微调时,把α设得跟r一样大,结果模型训了没几步就开始发散。后来才明白,α相当于一个学习率调节器。
| α取值 | 效果 | 适用场景 |
|---|---|---|
| α = r | 缩放系数为1,更新量直接叠加 | 任务与预训练分布差异较大时 |
| α = r/2 | 缩放系数为0.5,更新量减半 | 大多数通用场景 |
| α = r/4 | 缩放系数为0.25,更新量较小 | 任务与预训练分布接近时 |
我的经验:α通常设为r的1到2倍。如果你不确定,先从α=r开始,观察loss曲线。如果loss震荡剧烈,就把α调小;如果收敛太慢,就适当调大。
3.3 Dropout率:防止过拟合的利器
LoRA虽然参数量少,但照样会过拟合。尤其是当训练数据量不大时,A和B很容易记住那些噪声。这时候Dropout就派上用场了。
LoRA中的Dropout通常加在A矩阵的输出上,也就是低秩空间的表示上。这样做的好处是:
- 只对低维空间做正则化,计算量小
- 不影响原始预训练权重的表达
- 能有效防止A和B过度耦合
我记得有一次做文本分类任务,训练集只有500条样本。一开始没加Dropout,验证集准确率只有82%。后来加了0.1的Dropout,直接飙到89%。你想想看,这差距有多大。
避坑指南:我曾经把Dropout率设到0.5,结果模型根本学不动。LoRA的参数量本来就少,Dropout率建议控制在0.05到0.2之间。超过0.3基本就废了。
3.4 初始化策略:好的开始是成功的一半
A和B的初始化方式,直接决定了训练初期的稳定性。目前主流做法是:
- 矩阵A:使用Kaiming均匀初始化或高斯初始化
- 矩阵B:初始化为全零矩阵
为什么B要初始化为零?因为这样一开始ΔW = B×A = 0,相当于模型什么都没改。随着训练进行,B逐渐学到非零值,更新量才慢慢出现。这种「从零开始」的策略,能保证训练初期模型行为不突变。
我见过有人把A和B都随机初始化,结果模型一开始就输出乱七八糟的东西,loss直接飞到天上。嗯,这种坑踩过一次就记住了。
推荐配置:
- A矩阵:Kaiming均匀初始化,均值为0,方差为1/r
- B矩阵:全零初始化
- 这样能保证ΔW的初始方差约为0,训练稳定
3.5 参数间的协同效应
这几个参数不是孤立的,它们之间会相互影响。我画了一张图,帮你理清它们的关系:
从这张图你能看到,整个LoRA的流程是:输入x先经过A压缩,再经过Dropout正则化,然后由B恢复维度,最后用α缩放后加到原始输出上。每一步的参数都会影响最终效果。
实用建议:调参时先固定r和α,把Dropout率调好,再回头微调r和α。别一上来就四个参数一起调,那样你根本分不清是哪个参数的问题。
好了,关于LoRA的参数组成就聊到这儿。这几个参数看着简单,但组合起来能玩出很多花样。下次你跑LoRA时,不妨试试不同的参数组合,感受一下它们对模型行为的影响。