当前位置: 首页 > news >正文

LoRA 与 QLoRA

LoRA 与 QLoRA

1. 使用背景

  • 大模型越来越大之后,一个很现实的问题就是:全量微调越来越贵。

  • 传统full fine-tuning的做法是,把模型里几乎所有参数都设成可训练,然后在下游任务上继续训练。这样当然直接,但代价也很明显:

  1. 需要更新的参数太多;
  2. 优化器状态很占显存;
  3. 每个任务都保存一整套新权重,存储和部署都很重。
  • 所以后面就有一个很自然的想法:
    能不能尽量不动原模型,只额外训练一小部分参数,让模型适配新任务。

  • 这就是参数高效微调(PEFT)这条线的核心思路。

  • 而LoRA可以说是这条线里最有代表性的方法之一。

  • LoRA之后,QLoRA又进一步往前走了一步:
    不仅只训练小规模增量参数,还把冻结的基座模型做低比特量化,从而把显存进一步压低。


2. 理论基础

(1)为什么全量微调代价大

  • 设预训练模型某一层参数为:
    W∈Rd×k W\in\mathbb{R}^{d\times k}WRd×k

  • 如果做全量微调,那么训练时我们实际上是在学习:
    W′=W+ΔW W' = W + \Delta WW=W+ΔW
    其中ΔW\Delta WΔWWWW同形状。

  • 这意味着:

  1. 参数本身要存;
  2. 梯度要存;
  3. 优化器状态也要存。
  • 当模型很大时,这三部分叠起来,显存开销会非常夸张。

(2)一个关键观察

  • LoRA论文里的一个很核心出发点是:
    很多下游适配其实不一定需要在完整高维空间里自由更新全部参数。

  • 换句话说,任务适配带来的参数变化ΔW\Delta WΔW,很可能本身就带有某种低秩结构。

  • 如果这个观察成立,那么我们就不一定要直接学习整个ΔW\Delta WΔW,而可以把它写成更小的低秩分解。


3. LoRA:Low-Rank Adaptation

(1)核心思想

  • LoRA最核心的做法可以直接写成:
    W′=W+ΔW=W+BA W' = W + \Delta W = W + BAW=W+ΔW=W+BA
    其中:
    B∈Rd×r,A∈Rr×k,r≪min⁡(d,k) B\in\mathbb{R}^{d\times r},\qquad A\in\mathbb{R}^{r\times k},\qquad r\ll \min(d,k)BRd×r,ARr×k,rmin(d,k)

  • 也就是说,原来要学习一个d×kd\times kd×k的完整增量矩阵ΔW\Delta WΔW,现在只学两个更小的矩阵AAABBB

  • 因为rrr很小,所以新增可训练参数量会明显下降。

(2)冻结原模型

  • LoRA里一个非常关键的点是:
    原始预训练权重WWW冻结,不更新。

  • 真正训练的只有低秩增量部分A,BA,BA,B

  • 所以LoRA不是“把模型缩小”,而是:

  • 保留大模型原有能力,只给它外挂一个小规模、可训练的低秩修正项。

(3)前向怎么写

  • 对输入xxx,原来的线性层可以写成:
    h=Wx h = Wxh=Wx

  • 加上LoRA之后,就变成:
    h=Wx+BAx h = Wx + BAxh=Wx+BAx

  • 如果写得更直观一点,就是:
    h=Wx+ΔWx h = Wx + \Delta Wxh=Wx+ΔWx

  • 其中ΔW=BA\Delta W=BAΔW=BA就是LoRA学出来的任务增量。

(4)为什么这样能省参数

  • 原来完整的ΔW\Delta WΔW需要d×kd\times kd×k个参数;

  • 现在只需要:
    d×r+r×k d\times r + r\times kd×r+r×k
    个参数。

  • rrr远小于d,kd,kd,k时,参数量就会大幅下降。

  • 所以LoRA最本质的压缩来自一句话:

  • 把高维增量矩阵,约束到一个低秩子空间里学习。


4. LoRA一般加在哪里

(1)最常见的位置

  • 在Transformer里,LoRA最常被加在线性变换层上,尤其是attention里的投影矩阵,比如:

    • WqW_qWq
    • WkW_kWk
    • WvW_vWv
    • WoW_oWo
  • 有时候也会加在FFN里的线性层上。

  • 但最经典、最常见的做法,还是优先加在attention相关投影上。

(2)为什么这些位置有效

  • 因为这些矩阵本身就承担着特征变换和信息路由的作用。

  • 在很多任务适配里,稍微改一下这些投影方向,就足以让模型表现出明显不同的行为。

  • 所以LoRA不是随便往哪儿塞都一样,它之所以常加在这些位置,是因为这些地方本来就对模型行为很敏感。


5. LoRA里的几个关键超参数

(1)rank (r)

  • LoRA里最核心的超参数就是秩rrr

  • rrr越小,参数越省;

  • rrr越大,适配空间越大。

  • 所以rrr本质上控制的是:

  • 你允许模型在多大程度上偏离原始权重。

(2)scaling

  • 在很多实现里,LoRA增量项还会乘一个缩放系数,比如写成:
    W′=W+αrBA W' = W + \frac{\alpha}{r}BAW=W+rαBA

  • 其中α\alphaα是LoRA scaling。

  • 这个系数的作用就是控制LoRA增量项在前向里的影响强度,使训练更稳定。

(3)dropout

  • 实际训练时,也常给LoRA分支加dropout。
  • 这主要是为了防止小规模适配参数过拟合,尤其是在数据量不大时更常见。

6. LoRA为什么有效

(1)它不是重新学一个模型

  • LoRA并没有试图重新训练一个完整模型。

  • 它更像是在已有大模型周围,加了一个低维的“任务偏移层”。

  • 所以它能有效,一个很重要的原因就在于:
    预训练模型本身已经很强了,下游适配很多时候只需要小幅修正,而不需要推倒重来。

(2)低秩约束其实是一种归纳偏置

  • LoRA把增量限制成低秩,本质上是在告诉模型:

  • 任务适配不需要无限自由度,只需要在一个较低维的方向子空间里调整。

  • 这其实是一种很强的结构假设。

  • 它之所以有效,很大程度上说明很多任务适配本身就确实没必要更新整块大矩阵。

(3)和adapter的区别

  • Adapter也是参数高效微调的一条经典路线。

  • 它通常是在原网络层之间插入一个小模块。

  • LoRA和adapter都能少训很多参数,但LoRA的一个典型优势是:

  • 在推理阶段,LoRA增量可以和原权重合并,因此不会像额外插层那样天然引入额外推理路径。

  • 这也是LoRA后来迅速流行起来的一个重要原因。


7. LoRA的优点和问题

(1)优点

  • LoRA的优点很直接:
  1. 可训练参数少;
  2. 显存占用低;
  3. 任务切换方便;
  4. 推理时可合并权重;
  5. 对现有Transformer结构侵入性小。

(2)问题

  • 但LoRA也不是没有代价。

  • 最典型的问题有几个:

  1. rank太小时,表达能力可能不够;
  2. 不同任务对LoRA插入位置和超参数很敏感;
  3. 只训练LoRA分支有时会损失一部分full fine-tuning的上限;
  4. 当基座模型本身很大时,即使冻结不训,光把它完整加载进显存也仍然很贵。
  • 最后这一点其实非常关键,因为它直接引出了QLoRA。

8. 为什么会有QLoRA

(1)LoRA已经省训练参数了,但基座模型还是大

  • LoRA虽然只训练很少参数,但通常还是需要把整个预训练模型以较高精度加载到显存里。

  • 这就意味着:
    训练参数省了,不代表底座模型本身的显存占用就小了。

  • 尤其当模型到了30B、65B这种规模时,就算完全冻结不更新,光加载进去也很费显存。

(2)于是一个很自然的问题出现了

  • 能不能把冻结的基座模型量化得更低,同时仍然保留LoRA式微调能力?

  • QLoRA就是在解决这个问题。


9. QLoRA:Quantized LoRA

(1)核心思想

  • QLoRA的核心可以概括成一句话:

  • 把预训练基座模型量化到4-bit并冻结,只在LoRA适配器上训练。

  • 所以它保留了LoRA“只训小量参数”的优点,又进一步把基座模型本身的显存占用压下去了。

  • 如果写得更直观一点:

  1. 基座模型:4-bit量化,冻结;
  2. LoRA分支:正常可训练;
  3. 梯度通过量化基座反传到LoRA参数。

(2)最关键的一点

  • QLoRA不是把LoRA本身量化训练,而是:

  • 量化的是冻结的预训练主干,真正更新的仍然是LoRA适配器。

  • 这一点很重要,因为它决定了QLoRA的训练逻辑仍然建立在LoRA上,只不过把“底座怎么存”这件事做得更省了。


10. QLoRA里的三个关键技术

(1)NF4

  • QLoRA提出了NormalFloat 4(NF4)这种4-bit数据类型。

  • 其核心出发点是:预训练权重通常近似服从正态分布,那么量化时就应该用更适合这种分布的表示方式。

  • 所以NF4不是普通随便压成4-bit,而是更针对权重统计特性设计的4-bit表示。

(2)Double Quantization

  • 除了量化权重本身,QLoRA还进一步去量化量化过程中的常数项。

  • 这就是所谓的double quantization

  • 这一步的作用是继续压缩显存,因为量化参数本身如果都按高精度存,累积起来也是一笔开销。

(3)Paged Optimizers

  • QLoRA还引入了paged optimizers来处理训练中可能出现的显存峰值问题。

  • 因为大模型训练时,某些时刻内存使用会突然飙高,如果没有额外处理,很容易OOM。

  • paged optimizer的作用,简单理解就是让内存管理更平滑,减少这些峰值冲击。


11. LoRA和QLoRA的关系

(1)共同点

  • LoRA和QLoRA的共同点很清楚:
  1. 都冻结基座模型;
  2. 都只训练小规模LoRA参数;
  3. 都属于PEFT路线。

(2)不同点

  • 真正的差别在于基座模型怎么存:

  • LoRA通常默认基座模型还是常规精度加载;

  • QLoRA则把基座模型做4-bit量化再加载。

  • 所以可以粗略理解成:

  • LoRA解决“训练谁”的问题;

  • QLoRA进一步解决“底座怎么放进显存”的问题。


12. 为什么LoRA / QLoRA会这么流行

(1)因为它们抓住了一个现实矛盾

  • 大模型微调里最现实的矛盾就是:

  • 大家想用更大的模型,但算力和显存又没法无限涨。

  • LoRA和QLoRA之所以这么火,就是因为它们没有试图暴力解决这个矛盾,而是很聪明地绕了一步:

  • 不去训全部参数,只训最必要的一小部分;

  • 不去高精度存全部底座,而是尽量压低冻结部分的存储成本。

(2)因为它们真的容易落地

  • 这也是很关键的一点。

  • 很多方法理论上很好,但很难接进现有系统。

  • LoRA / QLoRA则非常容易工程化:

  1. 改动小;
  2. 适配现有Transformer方便;
  3. 训练脚本好接;
  4. 多任务切换也方便。
  • 所以它们不只是论文里好看,而是真的非常适合实际训练流程。

(3)因为它们给了“中小资源微调”一条现实路径

  • 对很多团队来说,真正的问题不是“能不能训到SOTA”,而是“能不能在有限GPU条件下把模型训起来”。

  • LoRA和QLoRA给的就是这样一条现实路径。

  • 这也是为什么后来很多开源社区、指令微调、领域适配基本都会优先碰到它们。


13. 从更高一层看,LoRA到底是什么

(1)它不是“模型压缩”

  • LoRA经常会被误解成一种模型压缩方法。

  • 其实不太准确。

  • 它更准确的定位应该是:

  • 参数高效适配。

  • 也就是说,它不是把原模型变小,而是让你在不大动原模型的前提下,用更少可训练参数完成任务迁移。

(2)它本质上是在学习一个低维任务偏移

  • 我觉得这是理解LoRA最关键的一句话:

  • LoRA学的不是整个模型,而是“从预训练能力到下游任务能力”的低维偏移量。

  • 一旦这样理解,很多事情就顺了:

  1. 为什么冻结基座还能有效;
  2. 为什么低秩就足够;
  3. 为什么不同任务可以挂不同LoRA分支。

(3)QLoRA则是在这个基础上进一步压缩底座成本

  • 所以如果把两者合在一起看:

  • LoRA解决的是“微调不必全量更新”;

  • QLoRA解决的是“冻结底座也别占太多显存”。


14. 一点理解

(1)LoRA最漂亮的地方

  • 我觉得LoRA最漂亮的地方就在于,它没有去和全量微调正面对抗,而是抓住了一个更本质的问题:

  • 任务适配真的需要更新全部参数吗?

  • 然后它给出的答案非常干脆:
    很多时候,不需要。
    只要学一个低秩增量就够了。

(2)QLoRA最漂亮的地方

  • QLoRA最漂亮的地方则在于,它把LoRA这条线又往现实硬件条件那边推了一大步。

  • 也就是说,它不只是从“算法上省参数”,而是进一步做到:

  • 在真实显存约束下,也能把大模型微调跑起来。

(3)怎么记LoRA与QLoRA

  • 如果只是为了学习,我觉得可以把这条线记成四句话:
  1. 全量微调很贵,因为所有参数都要更新;
  2. LoRA把权重增量写成低秩分解,只训练小规模适配器;
  3. QLoRA进一步把冻结底座量化到4-bit,继续压低显存;
  4. 所以它们共同代表的是“大模型参数高效微调”这条非常现实的路线。

15. 参考鸣谢

  • LoRA: Low-Rank Adaptation of Large Language Models
    https://arxiv.org/abs/2106.09685

  • QLoRA: Efficient Finetuning of Quantized LLMs
    https://arxiv.org/abs/2305.14314

  • Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey
    https://arxiv.org/abs/2403.14608

16. 注

  • 这篇主要是个人学习整理,重点放在主线理解;
  • 文中主要写的是LoRA和QLoRA最核心的思路,很多实现细节如target modules选择、merge/unmerge、bitsandbytes细节、LoRA变体(DoRA、AdaLoRA等)没有展开;
  • 才疏学浅,欢迎批评、指导和交流;
  • 有错误望大家及时指正!
http://www.jsqmd.com/news/500062/

相关文章:

  • Zabbix6.2利用模板和自定义监控项监控华为AR3260路由器
  • ROS2学习记录009-使用面向对象方式编写ROS2节点
  • 从此告别拖延!全场景通用的AI论文工具 —— 千笔写作工具
  • 震惊,杨幂的脸竟然出现在了她的身体上
  • java基础学习3(数据类型转换、运算符)
  • 把坑都踩完了,千笔AI VS 笔捷Ai,全场景通用AI论文网站!
  • 【常见错误】Xilinx Vivado自带编辑器文字部分出现乱码解决办法
  • 数字孪生国内外发展现状
  • 【Xilinx Vivado时序分析/约束系列2】FPGA开发时序分析/约束-建立时间
  • 终极指南:使用Google Map React库快速构建交互式地图应用
  • JetBrains 插件 IDE设置
  • 学霸同款!全领域适配的论文神器 —— 千笔
  • STM32-串口使用注意事项
  • Kubernetes 认证通关指南:CKA/CKS/CKAD 最新题库 + 本地仿真环境 + 模拟考
  • 2.postman断言
  • 具身智能中 Wrapper 架构的深度解构与 Python 实战
  • 深度解析 | 2026新范式:当“Token”取代比特币,成为真正的数字石油
  • 李南左日更3327:为什么员工都在摸鱼?是因为你曾经不信任他们
  • 终极Git与GitHub教程:从零开始掌握版本控制的完整指南
  • 【Xilinx Vivado时序分析/约束系列3】FPGA开发时序分析/约束-保持时间
  • 2026年靠谱的孝感钻井厂家推荐:十堰钻井/养殖场钻井公司精选 - 品牌宣传支持者
  • # 发散创新:用Go语言高效接入InfluxDB实现时序数据采集与可视化在现代微服务架构中,**时序数据
  • 【Xilinx Vivado时序分析/约束系列4】FPGA开发时序分析/约束-实验工程上手实操
  • 终极指南:如何快速掌握JEnv进行Java环境管理
  • reCAPTCHA PHP错误代码完全解析:快速定位和解决验证问题
  • 关于旧系统+旧安卓版本realme手机的原生文件管理不支持向微信好友一次性发送多个非照片格式文件的问题和解决方案
  • 探索阿里云盘: odomu/aliyunpan - 更智能、更便捷的云存储助手
  • 小程序实现“一码通用”
  • 7分钟掌握RuboCop:Ruby代码质量终极守护者指南
  • Python WebSockets 终极指南:构建高性能实时双向通信应用 [特殊字符]