Lora

提出对于预训练的参数矩阵
W
0
∈
R
m
×
n
W_0 \in \mathbb{R}^{m\times n}
W0∈Rm×n,我们不去直接微调
W
0
W_0
W0,而是对增量做低秩分解假设:
W
=
W
0
+
B
A
,
B
∈
R
m
×
r
,
A
∈
R
r
×
n
W = W_0+BA, \qquad B \in \mathbb{R}^{m\times r}, A \in \mathbb{R}^{r \times n}
W=W0+BA,B∈Rm×r,A∈Rr×n
其中
B
B
B,
A
A
A 之一用全零初始化,
W
0
W_0
W0 固定不变,优化器只优化
B
B
B,
A
A
A。
LoRA 文中指出,预训练模型通常是过参数化的 (the learned over-parametrized models in fact reside on a low intrinsic dimension),在对这些模型进行微调时,参数的更新主要在低维子空间中,高维子空间的参数在微调前后没有变化。因此微调所学的 Δ W \Delta W ΔW 不需要那么高的维度(秩),所以 r r r 可以取得很小,很多时候甚至可以直接取 1。所以说,LoRA 是一种参数高效的微调方法,至少 被优化的参数量大大降低了。
如果参数的更新也会大量发生在高维子空间中,此时进行低秩分解会遗漏信息,导致 LoRA 失效
为什么矩阵 B B B 被初始化为 0,而矩阵 A A A 正常高斯初始化
- 如果 B B B, A A A 全都初始化为 0,那么缺点与深度网络全 0 初始化一样,很容易导致梯度消失(因为此时初始所有神经元的功能都是等价的)。
- 如果 B B B, A A A 全部高斯初始化,那么在网络训练刚开始就会有概率为得到一个过大的偏移值 Δ W \Delta W ΔW 从而引入太多噪声,导致难以收敛。
因此,一部分初始为 0,一部分正常初始化是为了在训练开始时维持网络的原有输出(初始偏移为 0),但同时也保证在真正开始学习后能够更好的收敛。
LoRA 最终被插入在网络的哪些地方
只加在了 Self Attention 层 的 W q W_q Wq, W k W_k Wk, W v W_v Wv, W o W_o Wo 矩阵上 ( W q W_q Wq, W k W_k Wk, W v W_v Wv, W o W_o Wo 分别指代 self-attention 模块中的 query/key/value/output 投影矩阵)。其余部分诸如 MLP 等位置则没有添加。当然,后续也有一些实验表明,在其他任务中只添加在 Q 和 K 上会更好。

LoRA 与 Adapter 的区别
Adapter
- 插入位置:LoRA 是以残差连接的形式 “并联” 在 Transformer 的 W q W_q Wq, W k W_k Wk, W v W_v Wv, W o W_o Wo 矩阵上,而 Adapter 是插入在 Feed-forward Layer 后面。
- 推理延迟:LoRA 在训练完后其参数可以与原有预训练模型直接合并,变回单分支结构,不会引入额外的延迟;而 Adapter 由于引入了额外的串联网络层,因此会带来额外的延迟。
- 参数存储:使用 LoRA 进行微调,在训练完毕后只需要保存 LoRA 本身的参数;而使用 Adapter 则要保存整个原有模型的参数
LoRA 训练实际上只是 降低了显存需求,并没有降低计算量:
观察
U
U
U,
V
V
V 的梯度:
∂
L
∂
U
=
∂
L
∂
W
V
T
∂
L
∂
V
=
U
T
∂
L
∂
W
\frac{\partial \mathcal{L}}{\partial U} =\frac{\partial \mathcal{L}}{\partial W}V^T \\\\ \frac{\partial \mathcal{L}}{\partial V} = U^T \frac{\partial \mathcal{L}}{\partial W}
∂U∂L=∂W∂LVT∂V∂L=UT∂W∂L
这里
L
\mathcal{L}
L 是损失函数,并且约定参数的 shape 跟其梯度的 shape 一致。在训练过程中,求模型梯度是主要的计算量,如果全量更新,那么所用的梯度是
∂
L
∂
W
\frac{\partial \mathcal{L}}{\partial W}
∂W∂L,而 LoRA 所用的梯度则是
∂
L
∂
U
\frac{\partial \mathcal{L}}{\partial U}
∂U∂L 和
∂
L
∂
U
\frac{\partial \mathcal{L}}{\partial U}
∂U∂L ,它们是建立在全量更新的梯度
∂
L
∂
W
\frac{\partial \mathcal{L}}{\partial W}
∂W∂L 基础上的,所以理论上 LoRA 的计算量比全量更新还大。
LoRA 的训练速度变快的原因:
1、只更新了部分参数:比如 LoRA 原论文就选择只更新 Self Attention 的参数,实际使用时我们还可以选择只更新部分层的参数;
2、减少了通信时间:由于更新的参数量变少了,所以(尤其是多卡训练时)要传输的数据量也变少了,从而减少了传输时间;
3、采用了各种低精度加速技术,如 FP16、FP8 或者 INT8 量化等。
- LoRA 的优点 是它的低秩分解很直观,在不少场景下跟全量微调的效果一致,以及在推理阶段可以直接把 W 0 W_0 W0, U U U, V V V 合并成单个矩阵从而不增加推理成本