LoRA 微调 LLaMA 类模型:原理与实战指南
低秩自适应(LoRA)是一种高效的参数微调技术,通过冻结预训练权重并引入可训练的低秩分解矩阵,大幅减少下游任务的可训练参数量。 LoRA 的原理、秩的选择策略及其在 LLaMA 模型上的实战效果。实验表明,LoRA 能在单卡 GPU 上以较低资源消耗实现接近全量微调的性能,且推理时无额外开销,适合资源受限场景下的指令微调。

低秩自适应(LoRA)是一种高效的参数微调技术,通过冻结预训练权重并引入可训练的低秩分解矩阵,大幅减少下游任务的可训练参数量。 LoRA 的原理、秩的选择策略及其在 LLaMA 模型上的实战效果。实验表明,LoRA 能在单卡 GPU 上以较低资源消耗实现接近全量微调的性能,且推理时无额外开销,适合资源受限场景下的指令微调。

低秩自适应(Low-Rank Adaptation,简称 LoRA)随着大语言模型(LLM)的兴起而受到广泛关注。近期,ChatGPT 等一系列大模型的相继出现,导致算力需求日益紧缺。虽然构建专属大模型的需求强烈,但能够负担上亿参数模型全量训练的机构寥寥无几。在人工智能快速发展的背景下,以高效、有效的方式使用大型语言模型变得尤为重要。
LoRA 作为微调 LLM 的一种流行技术,通过引入可训练的低秩分解矩阵,同时固定预训练权重,大幅减少了下游任务的可训练参数量。本文将深入探讨如何以高效的方式利用 LoRA 来微调 LLM。
预训练大语言模型通常被称为基础模型,因为它们在各种任务中表现良好,可作为目标任务微调的基础。然而,大模型的计算成本可能非常昂贵——模型越大,更新其网络层的成本越高。如果不想更新网络中的所有层,可以使用前缀微调、适配器(Adapter)等高效调参方法。目前,Hu 等人提出的低秩自适应(LoRA)是一种更为流行的微调技术。
本文旨在回答以下问题:什么是 LoRA?它是如何工作的?它与其他流行的微调方法相比有何优劣?
![图:LoRA 微调概念示意图]
论文《LoRA: Low-Rank Adaptation of Large Language Models》提出将权重变化 ΔW 分解为秩较低的表示。LoRA 不会直接分解矩阵,而是通过反向传播来学习分解的矩阵。
首先解释常规微调期间的训练程序。假设 W 表示给定神经网络层中的权重矩阵。使用常规反向传播,我们可以获得权重更新 ΔW,它通常被计算为损失乘以学习率的负梯度:
ΔW = -η * ∇L(W)
得到 ΔW 后,原始权重按如下公式更新:
W' = W + ΔW
或者,我们可以保持权重更新矩阵分离,并按如下公式计算输出:
h = Wx + ΔWx
其中 x 表示输入。
当在神经网络中训练全连接(dense)层时,权重矩阵通常具有全秩,这意味着矩阵不具有任何线性相关(即冗余)的行或列。相比之下,低秩意味着矩阵具有冗余的行或列。
尽管预训练模型的权重是满秩矩阵,但 LoRA 的作者指出,预训练的大型语言模型在适应新任务时具有较低的内在维度。低内在维度意味着数据可以由低维空间有效地表示或近似,同时保留大部分基本信息或结构。换句话说,可以将适应任务的新权重矩阵分解为低维(较小)矩阵,而不会丢失太多重要信息。
例如,假设 ΔW 是 A×B 维权重矩阵的权重更新矩阵,这个权重更新矩阵可以分解为两个较小的矩阵:ΔW = WA * WB,其中 WA 是 A×r 维矩阵,WB 是 r×B 维矩阵。在这里,我们保持原始权重 W 冻结,并且只训练新的矩阵 WA 和 WB。
![图:LoRA 权重分解示意图]
上图中的 r 是超参数,指定用于自适应的低秩矩阵的秩。r 越小,低秩矩阵越简单,在自适应过程中需要学习的参数越少,训练越快,计算需求相应减少。然而,r 变小的弊端是,低秩矩阵捕获任务特定信息的能力降低。这可能导致较低的自适应质量,并且与较高的 r 相比,模型在新任务上可能表现不佳。
总之,在 LoRA 中确定 r 的取值,需要在模型复杂性、自适应能力和拟合不足或拟合过度的风险之间进行权衡。因此,重要的是用不同的 r 值进行实验,以找到正确的平衡,从而在新任务中满足所需的性能。
LoRA 的使用很直接,可以将其视为 LLM 中全连接层的前向传递修正版。伪代码如下所示:
h = Wx + BA * x / alpha
在上面的伪代码中,alpha 是一个缩放因子,用于调整组合结果的大小(原始模型输出加上低秩自适应)。这平衡了预训练模型的知识和新的任务特定适应——默认情况下,alpha 通常设置为 1。还要注意,当 WA 被初始化为小的随机权重时,WB 被初始化为 0,从而使得初始状态 h = Wx,这意味着需要从原始权重开始训练。
接下来说一说最棘手的问题:如果引入新的权重矩阵,参数如何才能有效?新的矩阵 WA 和 WB 可以非常小。例如,假设 A=100,B=500,那么 ΔW 的大小为 100×500=50000。如果将其分解为两个较小的矩阵,一个 100×5 维矩阵 WA 和一个 5×500 维矩阵 WB。这两个矩阵总共只有 5×100+5×500=3000 个参数。
在实践中,如果在如上所示的训练后保持原始权重 W 以及矩阵 WA 和 WB 处于分离状态,推理过程中就会额外产生效率损失,因为引入了额外的计算步骤。相反可以在训练后通过 W' = W + WA·WB 更新权重,这类似于前面提到的 W' = W + ΔW。
然而,保持权重矩阵 WA 和 WB 分离也可能有些优势。例如,假设希望保留预训练的模型作为各种客户的基础模型,并且希望从基础模型开始为每个客户创建一个微调的 LLM。在这种情况下,就不需要为每个客户存储完整的权重矩阵 W'。不然存储模型的所有权重 W' = W + WA WB 对于 LLM 来说可能非常大,因为 LLM 通常具有数十亿到数万亿的权重参数。因此,可以保留原始模型 W,只需要存储新的轻量级矩阵 WA 和 WB。用具体的数字来说明的话,一个完整的 7B LLaMA checkpoint 需要 23 GB 的存储容量,而选择 r=8 的秩,则 LoRA 权重可以小到 8 MB。
LoRA 在实践中有多好,与完全微调和其他参数有效方法相比如何?根据 LoRA 的论文,在几个特定任务的基准测试中,使用 LoRA 的模型的建模性能略好于使用 Adapters、prompt tuning 或 prefix tuning 的模型。通常,LoRA 的性能甚至比微调所有层更好。
值得注意的是,LoRA 与其他微调方法正交,这意味着它也可以与 Adapters 或 prefix tuning 相结合。
现在,让我们使用 LoRA 来微调 Meta 提出的 LLaMA 模型。除了用于训练和运行 LLaMA 本身的代码外,还包含用于使用 LLaMA Adapter 和 LoRA 微调 LLaMA 的代码。建议的操作流程如下:
下一节将比较 7B LLaMA 基础模型与使用 LoRA 和 LLaMA Adapter 微调的 7B LLaMA 基础模型。(请注意,需要具有至少 24 GB RAM 的 GPU)。
本节中,作者将比较 LLaMA 7B 基础模型与使用 LoRA 和 LLaMA Adapter 微调的基础模型的计算性能。微调数据集是 Alpaca 52k 指令数据集,其结构如下:
![图:Alpaca 数据集示例]
数据集是按照 Self-Instruct 论文中描述的方法生成的,由 49759 个训练样本和 2000 个验证样本组成。Self-Instruct 的流程可总结为 4 个步骤:
Alpaca 52k 数据集是使用上述 Self-Instruct 程序收集的。但是,也可以使用替代数据集进行比较。例如,Databricks-dolly-15k 数据集包含约 15k 条指令/响应微调记录。
给定以下超参数设置(块大小、批大小和 LoRA 的 r),Adapter 和 LoRA 都可以以 bfloat-16 的混合精度,在具有 24 Gb RAM 的单个 GPU 上微调 7B 参数的 LLaMA 基本模型。
LoRA 资源占用:
![图:LoRA 训练监控截图]
LLaMA Adapter 资源占用:
![图:Adapter 训练监控截图]
如果代码将来发生变化,GitHub 上会同步更新代码(带有超参数设置)。Adapter 在 A100 上使用了大约 22 Gb 的空间,并在 162 分钟内完成了 62400 次迭代。同样的迭代次数下,LoRA 使用了 21 Gb 的内存,在 192 分钟内完成。总之,同样基于 Lit-LLaMA 的 Adapter 和 LoRA 使用的 RAM 数量大致相同,训练时间大致相同。
相比之下,完全微调(LLaMA 7B 由 32 个 Transformer 块和 3 个全连接的输出层组成)需要至少 2 个具有至少 30Gb 的 GPU 和完全分片训练来分配权重。或者,可以使用 4 个 GPU,每个 GPU 的最大内存使用量为 22 Gb。在 4 个 GPU 上进行训练,训练耗时 1956 分钟。在单个 GPU 上至少需要 6000 分钟,这将比参数高效的 LLaMA Adapter 或 LoRA 代价昂贵 30-40 倍。
接下来,本文将介绍应用不同微调策略后的模型输出。
有几种度量标准可用于评估 LLM 生成的文本。例如,困惑度、BLEU 和 ROUGE 分数是自然语言处理中用来评估 LLM 在各种任务中的表现的一些最常见的评估指标。然而,所有这些指标都有很大的缺点,人工评估仍然是黄金标准——人工评估的缺点是创建成本高,难以自动化。简单起见,本文只关注定性比较,看看各种模型产生的一些输出。
为了对模型进行定性比较,本文将使用'请解释权重衰减是如何工作的'作为 prompt。
![图:基准模型输出示例]
Prompt: 请解释一下权重衰减是如何工作的…… 以及为什么它有时看起来有效,有时无效!
模型输出: 最简单地说,权重衰减从模型中删除特征(作为特征重要性的函数),它也被称为正则化。
推理时间: 1:4.18 秒,11.95 个 token/秒
正如我们所看到的,模型开始通过附加"…以及为什么它有时看起来有效,有时不起作用!"来补全 prompt。这是因为基础模型只在下一个单词预测任务中进行了训练,没有经过专门的训练来处理指令。尽管如此,它试图在下面进一步解释。这种解释对正则化做出了一些正确的解释,但它并没有真正捕捉到权重衰减的关键机制。
![图:Adapter 模型输出示例]
模型输出: 权重衰减是一种惩罚词条字数的方法。通过选择单词较少的句子,模型更有可能选择那些可能提供重要信息的句子。
推理时间: 总计 7.04 秒,14.21 个 tokens/sec。使用的内存:13.56 GB。
这个解释在语法上是合理的,但也不一定是我们想要的。
![图:LoRA 模型输出示例]
模型输出: 权重衰减是机器学习模型中用于减少过拟合的算法参数。这是一个调整模型权重的过程,以减少模型中不太重要的特征的影响并防止过拟合。权重衰减是通过向权重添加少量噪声来减少模型对训练数据的影响。这个过程鼓励模型更多地关注对预测任务更重要的特征。
推理时间: 总计 3.25 秒,30.76 个 tokens/sec。使用的内存:27.65 GB。
可以看到离期望的答案越来越近了;放到广义线性模型中,这种解释确实有意义,在广义线性模型中,会强迫模型学习与输入特征相乘结果较小的权重参数。在神经网络中,这通常会应用于模型中的所有权重参数。上面的 LoRA 方法目前来说使用的内存最多。然而,如前所述,可以通过将 LoRA 权重与预训练的模型权重合并来减少这种内存使用。
由于评估 LLM 本身就是一个大课题,因此这种定性概述只能反应每个模型能力的一小部分。但这里的要点是,LoRA 可以用于以相对经济高效的方式在指令数据集上微调 LLM。
本文讨论了低秩自适应(LoRA),这是一种参数完全微调的有效替代方案。使用 LoRA,可以在几个小时内在单个 GPU 上对 LLaMA 等相对较大的模型进行微调,这使得它对那些不想在 GPU 资源上花费数千美元的人特别有吸引力。
LoRA 的特别之处在于,可以选择性地将新的 LoRA 权重矩阵与原始的预训练权重合并,这样在推理过程中就不会产生额外的开销或复杂性。随着越来越多的 ChatGPT 或 GPT-4 开源替代品的出现,在特定的目标数据集或目标上微调和定制这些 LLM 将在各个研究领域和行业变得越来越有吸引力。而 LoRA 等参数有效的微调技术使微调更具资源效率和可访问性。Lit LLaMA 存储库中提供了诸如 LoRA 和 LLaMA Adapter 之类的参数高效微调技术。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online