LoRA: Low-Rank Adaptation of Large Language Models

用低秩分解近似全量权重更新,把大模型微调从高门槛 GPU 任务,变成更可复现、更可扩展的工程实践。

年份与会议

2021 · ICLR

作者

Edward J. Hu、Yelong Shen、Phillip Wallis、Zeyuan Allen-Zhu、et al.

主题

高效微调

阅读时长

约 3 分钟

收录时间

2021/06/17

标签

原文链接

https://arxiv.org/abs/2106.09685

为什么 LoRA 对工程团队如此重要

大模型时代有一个很现实的问题:基座模型越来越大,可真正能负担全量微调的团队却没有同比增加。

全量微调的问题包括:

  • 训练参数太多,显存吃紧
  • 优化状态额外占内存
  • 每个任务都保存一整份模型副本,存储成本高
  • 实验迭代慢,小团队难以负担

LoRA 的重要性就在于,它没有试图重新定义微调,而是给出了一个更务实的答案:

如果真正需要学习的更新本身具有低秩结构,那我们就没必要为每次任务都更新整块大矩阵。

这个想法一旦成立,大模型适配的门槛就会显著下降。

核心直觉:大模型权重更新可能并不需要“满秩”

LoRA 的基本观察是:在很多下游任务中,模型权重的有效更新其实可能落在一个相对低维的子空间里。也就是说,你不一定需要对完整权重矩阵 W 做自由更新,而可以把更新项写成:

ΔW = BA

其中:

  • AB 是两个较小的矩阵
  • 它们的秩 r 远小于原矩阵维度
  • 原始预训练权重 W 保持冻结

最终实际使用时,线性层从 xW 变成 x(W + BA)。这样模型就只需要学习较小的低秩更新,而不需要改动整个大权重矩阵。

把这个公式翻成工程图,会更容易理解 LoRA 为什么能把“全量微调”换成“冻结底座 + 训练小增量”:

LoRA 低秩适配示意图 左侧是冻结的基础权重矩阵 W,中间是两个较小的低秩矩阵 A 和 B,右侧是组合后的 W 加上 BA,仅训练 A 和 B 而不更新 W。 LoRA 不是改写整块权重,而是给冻结底座叠加一个低秩“增量补丁”
  <g>
    <rect x="36" y="84" width="280" height="234" rx="24" fill="#f6f9ff" stroke="#d7e2f1" />
    <text x="66" y="118" font-size="20" font-weight="700">基础模型线性层</text>
    <rect x="120" y="144" width="120" height="134" rx="16" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="180" y="210" text-anchor="middle" font-size="26" font-weight="700">W</text>
    <text x="180" y="236" text-anchor="middle" font-size="13" fill="#4b5563">大矩阵,保持冻结</text>
    <rect x="76" y="286" width="200" height="18" rx="9" fill="#dbeafe" />
    <text x="176" y="300" text-anchor="middle" font-size="12" fill="#4b5563">不更新预训练知识本体</text>
  </g>

  <g>
    <rect x="350" y="84" width="288" height="234" rx="24" fill="#f8fbf4" stroke="#d5e4c6" />
    <text x="380" y="118" font-size="20" font-weight="700">LoRA 低秩分解</text>
    <rect x="398" y="154" width="62" height="114" rx="14" fill="#eef6e8" stroke="#a8c48e" />
    <text x="429" y="215" text-anchor="middle" font-size="24" font-weight="700">B</text>
    <rect x="504" y="154" width="110" height="114" rx="14" fill="#fff4dc" stroke="#e2c36f" />
    <text x="559" y="215" text-anchor="middle" font-size="24" font-weight="700">A</text>
    <text x="492" y="222" font-size="22" font-weight="700">×</text>
    <text x="494" y="296" font-size="13" fill="#4b5563">秩 r 很小,只训练 A 和 B</text>
  </g>

  <g>
    <rect x="672" y="84" width="272" height="234" rx="24" fill="#fff8ef" stroke="#eed6a0" />
    <text x="702" y="118" font-size="20" font-weight="700">推理时的有效权重</text>
    <rect x="714" y="160" width="70" height="110" rx="14" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="749" y="220" text-anchor="middle" font-size="24" font-weight="700">W</text>
    <text x="800" y="218" font-size="22" font-weight="700">+</text>
    <rect x="830" y="172" width="78" height="86" rx="14" fill="#fce7ef" stroke="#e2a8bd" />
    <text x="869" y="220" text-anchor="middle" font-size="22" font-weight="700">BA</text>
    <text x="808" y="294" text-anchor="middle" font-size="13" fill="#4b5563">x(W + BA) 完成任务适配</text>
  </g>

  <line x1="316" y1="202" x2="350" y2="202" stroke="#5b6b7f" stroke-width="3" marker-end="url(#lora-arrow)" />
  <line x1="638" y1="202" x2="672" y2="202" stroke="#5b6b7f" stroke-width="3" marker-end="url(#lora-arrow)" />

  <text x="384" y="328" font-size="13" fill="#64748b">训练成本下降:参数量少、优化器状态少、任务切换时只需保存 adapter</text>
</g>
LoRA 的胜点不只是“省显存”,更是把适配变化压缩成可管理、可复用、可组合的小型增量权重。

为什么这件事能省这么多资源

LoRA 能显著降低成本,原因有三层:

1. 可训练参数数量大幅减少

冻结原始模型后,训练时只更新少量低秩矩阵,参数量会比全量微调小很多。

2. 优化器状态也跟着减少

训练中不仅要存参数,还要存梯度、动量、二阶统计等优化器状态。可训练参数少了,这部分开销会同步下降。

3. 任务切换更轻

你不需要为每个任务保存一整份完整模型,只需保存对应的 LoRA adapter 权重。部署、存储和版本管理都会轻松很多。

这也是为什么 LoRA 很快从“论文技巧”变成“工程默认选项”。

它通常插在哪里

LoRA 最常见的做法,是把低秩更新插入到 Transformer 中的线性变换层里,特别是注意力相关投影层,例如:

  • W_q
  • W_k
  • W_v
  • W_o

有时也会扩展到前馈层。不同实现的差别主要体现在:

  • 插在哪些层
  • 低秩 r 取多大
  • 是否与 dropout、scaling 一起使用

这些设计决定了效果、显存和训练稳定性之间的平衡。

LoRA 为什么常常“几乎不损精度”

LoRA 最让人惊喜的地方在于,参数省了很多,但效果往往并没有按比例大幅下降。原因可以这样理解:

  • 预训练模型已经拥有大量通用知识和模式。
  • 下游微调很多时候只是“重排已有能力”,而不是从零学新语言。
  • 任务特定变化可能并不需要在整个权重空间中自由展开。

从这个角度看,LoRA 并不是“削弱版微调”,而是更接近一种结构化更新方式。它利用了基座模型本来就很强这一前提。

论文最重要的工程价值

LoRA 的工程价值不只体现在节省显存,更在于它改变了实验组织方式:

  • 你可以围绕同一个底座维护很多任务 adapter。
  • 不同实验可以快速切换、组合、回滚。
  • 业务团队更容易做领域适配,而不必维护多套完整模型。
  • 开源社区更容易分享任务增量,而不是分发整个大模型。

这也是 LoRA 能迅速成为 Hugging Face、PEFT、开源微调社区基础设施的原因。

它和 Adapter、Prefix Tuning 的关系

LoRA 并不是参数高效微调的唯一路线。和其他方法相比,可以这样粗略理解:

  • Adapter:在网络中插入额外小模块,参数可控,但会改动前向路径结构。
  • Prefix / Prompt Tuning:更多从输入或注意力前缀侧做适配,训练参数更少,但能力表达受限。
  • LoRA:直接作用在线性层权重更新上,结构简单,兼顾效果与易用性。

LoRA 之所以后来成为默认方案,很大程度上是因为它在“效果、实现复杂度、部署便利性”之间取得了很好的平衡。

实践中最常见的搭配:LLaMA + LoRA

LoRA 的爆发,和开源强基座模型的出现几乎是同步的。尤其在 LLaMA 之后,这个组合迅速成为默认工作流:

  1. 先选一个足够强的开源底座。
  2. 用 LoRA 做轻量领域适配或指令微调。
  3. 用较少显存完成实验迭代。
  4. 按需合并权重或单独保存 adapter。

这让大量团队第一次有机会在自己可承受的资源范围内做模型微调。很多“行业专用大模型”的早期版本,本质上就是“基座模型 + LoRA 适配”的产品化形态。

局限:LoRA 并不意味着微调从此免费

虽然 LoRA 非常实用,但也不能把它神化。它的边界包括:

  • 基座模型本身仍然要先能装进你的硬件里。
  • 对某些任务,过低的秩可能限制表达能力。
  • 插入层的位置、秩大小、学习率等超参数依然需要实验。
  • 当任务与基座分布差异过大时,低秩更新未必足够。

此外,LoRA 主要解决的是“适配成本”,不是“数据质量”和“评测体系”问题。数据差、目标不清、评测不严,即便用了 LoRA 也不会自动得到好结果。

后续影响:LoRA 催生了什么

LoRA 之后,高效微调生态几乎进入加速状态:

  • QLoRA 把量化与 LoRA 结合,进一步降低显存门槛。
  • 各类 PEFT 框架把 LoRA 标准化,变成开箱即用能力。
  • 多 adapter 组合、路由和合并,成为任务管理的重要方向。
  • 行业模型训练流程开始默认考虑“全量微调是否真的有必要”。

可以说,LoRA 让“微调大模型”从少数团队专属能力,变成更多工程团队能参与的日常实践。

读这篇论文时最值得抓住什么

如果你只想带走最关键的东西,请记住:

  1. 大模型的有效更新往往不必覆盖整个权重空间。
  2. 冻结底座 + 学小增量,是非常强的工程折中。
  3. LoRA 的真正价值不只是省显存,而是把实验迭代速度抬了上来。

这三点理解清楚后,你再去看 QLoRA、Adapter merging、多任务适配,都会更容易。

延伸阅读

相关内容

沿着相近主题继续阅读,加深对方法边界与实践场景的理解。