8.2 参数高效微调
在转向第二阶段之前,先考虑一个实际问题。指令微调是一般性微调需求的一个特例:把预训练模型适配到新的任务、领域或语言。尽管大语言模型的海量预训练数据包含许多领域的文本,一些相关数据(例如指令)仍可能没有得到充分呈现。或者,我们可能希望语言模型专门处理法律或医学文本,又或是在某种语言或语言变体上表现得更好。

图 8.6 预训练与微调。可以把预训练模型微调到特定领域或数据集。微调有许多不同方式,区别在于究竟根据微调数据更新哪些参数:全部参数、一部分参数,或仅更新特定附加结构的参数;后续章节将对此加以介绍。
遇到这类情形时,我们会像指令微调一样,继续使用交叉熵损失,在新领域或新语言的相关数据上训练模型(Gururangan et al., 2020),做法与预训练相同。对于指令微调,正如图 8.1 所示,我们把指令词元作为上下文,只在回答词元上进行训练。对于其他微调情形,则可能在整个新数据集的每个词元上训练。图 8.6 展示了这一思路。
不过在实践中,微调非常大的语言模型并不容易,因为需要训练的参数数量极其庞大;批量梯度下降的每一轮都必须通过许许多多巨大的层进行反向传播。这使得巨型语言模型的微调在处理能力、内存和时间方面都极为昂贵。许多实验室根本无法微调最大型模型的全部参数。
因此,在后训练的大多数情况下,我们会使用无需改变全部参数的替代方法来微调模型。这类方法称为 参数高效微调(parameter-efficient fine-tuning, PEFT),因为微调时会高效地选择一个参数子集进行更新。具体而言,我们冻结一部分参数(即不改变它们),只更新某个特定的参数子集。
这里介绍最常见的参数高效微调方法 LoRA,即 低秩适配(Low-Rank Adaptation)(Hu et al., 2022)。LoRA 的直觉是:Transformer 含有许多执行矩阵乘法的稠密层(例如注意力计算中的 、、 和 层)。使用 LoRA 时,我们不在微调期间更新这些层,而是将其冻结,转而更新一个参数更少的低秩近似。图 8.7 展示了这一思路。
考虑一个维度为 的矩阵 ,它需要在微调期间通过梯度下降更新。通常,该矩阵会得到一个同样具有 维度的更新量 ,以便在梯度下降后更新这 个参数。在 LoRA 中,我们冻结 ,转而更新 的一个低秩分解。创建两个矩阵 和 ,其中 的大小为 , 的大小为 ,并把 选得非常小,使 。微调期间更新 和 ,而不是 。也就是说,用 代替 。图 8.8 展示了这一思路。原来的前向传递为 ,替换后的新前向传递则是:

图 8.7 LoRA 等参数高效微调方法。
LoRA 有许多优点。由于不必为大多数参数计算梯度,它能大幅降低硬件要求。

图 8.8 LoRA 的直观原理。把 W 冻结在其预训练值,转而训练一对矩阵 A 和 B,以更新它们而不是 W,再直接将 W 与更新后的 AB 相加。
由于 AB 与 W 大小相同,权重更新可以直接加到预训练权重中。这意味着它不会在推理期间增加额外时间。也正因如此,可以为不同领域构建不同的 LoRA 模块,只需把它们加到 W 或从 W 中减去,就能随时换入或换出。
LoRA 的原始版本只应用于注意力计算中的矩阵(即 、、 和 层)。如今已有许多 LoRA 变体。