QLoRA

Description of the image

QLoRA是在LoRA的基础上对冻结部分权重进行量化

特性介绍

LoRA

模型中的线性层通常是将激活值xx与权重矩阵的转置WTW^T进行矩阵乘运算,并加上biasbias

y=xWT+biasy = xW^T + bias

矩阵的(Rank)揭示了这个矩阵的“信息量”,预训练模型中的这些线性层的权重矩阵通常是满秩的。

对于预训练的权重矩阵W0∈Rn×mW_0\in \mathbb{R}^{n\times m},可以认为它在微调阶段更新后变成了W0+ΔW=W0+ABW_0 + \Delta W = W_0 + AB,其中A∈Rn×r,B∈Rr×mA\in \mathbb{R}^{n\times r}, B\in \mathbb{R}^{r\times m},那么矩阵ΔW=AB∈Rn×m\Delta W = AB\in \mathbb{R}^{n\times m},且rank(ΔW)∈[0,min(n,m,r)]rank(\Delta W)\in[0, min(n, m, r)],我们选取r≪min(n,m)r\ll min(n, m),所以rank(ΔW)∈[0,r]rank(\Delta W)\in[0, r]

这样冻结W0W_0部分权重,仅更新参数量极少的旁路矩阵A,BA,B的训练是非常高效的,很大程度上减少了低秩矩阵中的冗余信息占用的空间和计算量。

在前向传播时,增加了LoRA的线性层(矩阵部分)变成了计算:

y=xW0T+xBTATy = xW_0^T + x B^T A^T

反向传播的输入是Loss对当前层的输出 yy 的梯度 ∂L∂y\frac{\partial \mathcal{L}}{\partial y},需要更新旁路矩阵 A,BA, B 的参数,所以需要计算 A,BA, B 的梯度 ∂L∂A,∂L∂B\frac{\partial \mathcal{L}}{\partial A}, \frac{\partial \mathcal{L}}{\partial B},仅对AABB求偏导可以将 xW0TxW_0^T 看做常数项,这个过程不涉及W0W_0,但为了继续反向传播,当前层还需要返回 L\mathcal{L} 对输入的的梯度:

∂L∂x=∂L∂y∂y∂x=∂L∂yW0+∂L∂yAB\frac{\partial \mathcal{L}}{\partial x}=\frac{\partial \mathcal{L}}{\partial y} \frac{\partial y}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} W_0 + \frac{\partial \mathcal{L}}{\partial y} AB

因此,W0W_0的参数不需要更新,但是仍需要在前向和反向时各参与一次矩阵乘运算。

QLoRA

线性层量化

量化(Quantization)技术可以压缩模型大小的同时保持较高的精度,无校准集的仅权重量化可以使

ϕ(W−Q−1(Q(W)))\phi \big(W - Q^{-1}(Q(W))\big)

尽可能小,误差在可以接受的范围内,其中WW表示浮点权重,Q(∗)Q(*)Q−1(∗)Q^{-1}(*)分别代表量化和反量化函数,ϕ\phi代表某种损失函数比如平均绝对误差等。

我们使用NF4量化来进行权重量化,这也是开源社区流行的QLoRA量化方式,该量化算法被实现在bitsandbytes,它在开源社区广受欢迎。

我们已经将支持NPU硬件的NF4量化功能贡献到bitsandbytes多硬件后端重构分支,但由于bitsandbytes官方还未正式将该分支在PyPi上发布,本仓库暂使用NPU版本的bitsandbytes,可以通过pip3 install bitsandbytes-npu-beta来安装。

NF4是一种查找表量化,NF4表接近高斯分布下的数据的最佳表示方式,我们可以在QLoRA微调前先对权重W0W_0进行量化:

W0NF4=Q(W0)W_0^{NF4} = Q(W_0)

然后在微调阶段每次需要W0W_0参与运算时对其进行反量化,即在前向传播中计算:

y=x(Q−1(W0NF4))T+xATBTy = x\big(Q^{-1}(W_0^{NF4})\big)^T + x A^T B^T

在反向传播中计算:

∂L∂x=∂L∂yQ−1(W0NF4)+∂L∂yBA\frac{\partial \mathcal{L}}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} Q^{-1}(W_0^{NF4}) + \frac{\partial \mathcal{L}}{\partial y} BA

QLoRA在LoRA的基础上,对主干部分的权重进行量化,大幅降低了LoRA微调时的显存占用。

使用方法

1、权重转换

将原精度的hf权重转换为mg权重时,可以通过增加--qlora-nf4选项开启QLoRA的NF4量化,会得到量化压缩后的mg权重,目前不支持其它量化方式。

(新版本问题修复中,暂不推荐开启该特性)目前QLoRA特性支持开启 --moe-grouped-gemm GMM算子以及 --moe-alltoall-overlap-comm 特性。

2、QLoRA微调

在微调时,增加--qlora开启QLoRA微调,开启时请确保配置的权重路径是NF4量化后的mg权重。

3、LoRA权重合并到主干模型(可选)

默认QLoRA微调后保存的权重仍然是量化后的权重,无法与浮点的LoRA部分直接合并,如果需要浮点的反量化权重,即上文中的Q−1(W0NF4)Q^{-1}(W_0^{NF4}),可以在微调阶段开启保存时反量化选项--qlora-save-dequantize,合并权重、推理的方式与LoRA相同。

使用效果

由于仅对线性层的权重矩阵进行量化,激活值、梯度、优化器状态等仍然保持原精度,因此使用QLoRA可以给整体带来的内存收益比例会受到batch size、数据序列长度等因素的影响。

作为参考,我们在Llama-2-70b和Mixtral-8x7b上进行量化测试:

模型 原始权重大小 NF4量化后权重大小 节省内存
Llama-2-70b 129GB 35GB 94GB
Mixtral-8x7b 87GB 24GB 63GB

均可使用64GB单卡进行QLoRA微调,实测Llama-2-70b单batch微调过程中NPU内存占用约50GB左右,建议使用双卡以免数据集中较长的序列导致OOM。

注意:QLoRA是量化模型权重的LoRA算法,必然会对模型效果和精度产生影响,用户充分评估特性后方可使用。

使用限制

  • QLoRA 暂不支持 lora-fusion 特性,开启时无性能收益。

(新版本问题修复中,暂不推荐开启该特性)目前QLoRA特性支持开启 --moe-grouped-gemm GMM算子以及 --moe-alltoall-overlap-comm 特性。

目前QLoRA微调必须加载权重,暂不支持随机初始化权重。

QLoRA支持分布式LoRA、PP、TP、VPP、CP、SP、重计算等LoRA支持的特性,并且精度正常,更多特性的亲和性还在补充验证中。