
LoRA 与 QLoRA1. 使用背景大模型越来越大之后一个很现实的问题就是全量微调越来越贵。传统full fine-tuning的做法是把模型里几乎所有参数都设成可训练然后在下游任务上继续训练。这样当然直接但代价也很明显需要更新的参数太多优化器状态很占显存每个任务都保存一整套新权重存储和部署都很重。所以后面就有一个很自然的想法能不能尽量不动原模型只额外训练一小部分参数让模型适配新任务。这就是参数高效微调PEFT这条线的核心思路。而LoRA可以说是这条线里最有代表性的方法之一。LoRA之后QLoRA又进一步往前走了一步不仅只训练小规模增量参数还把冻结的基座模型做低比特量化从而把显存进一步压低。2. 理论基础1为什么全量微调代价大设预训练模型某一层参数为W∈Rd×k W\in\mathbb{R}^{d\times k}W∈Rd×k如果做全量微调那么训练时我们实际上是在学习W′WΔW W W \Delta WW′WΔW其中ΔW\Delta WΔW和WWW同形状。这意味着参数本身要存梯度要存优化器状态也要存。当模型很大时这三部分叠起来显存开销会非常夸张。2一个关键观察LoRA论文里的一个很核心出发点是很多下游适配其实不一定需要在完整高维空间里自由更新全部参数。换句话说任务适配带来的参数变化ΔW\Delta WΔW很可能本身就带有某种低秩结构。如果这个观察成立那么我们就不一定要直接学习整个ΔW\Delta WΔW而可以把它写成更小的低秩分解。3. LoRALow-Rank Adaptation1核心思想LoRA最核心的做法可以直接写成W′WΔWWBA W W \Delta W W BAW′WΔWWBA其中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)B∈Rd×r,A∈Rr×k,r≪min(d,k)也就是说原来要学习一个d×kd\times kd×k的完整增量矩阵ΔW\Delta WΔW现在只学两个更小的矩阵AAA和BBB。因为rrr很小所以新增可训练参数量会明显下降。2冻结原模型LoRA里一个非常关键的点是原始预训练权重WWW冻结不更新。真正训练的只有低秩增量部分A,BA,BA,B。所以LoRA不是“把模型缩小”而是保留大模型原有能力只给它外挂一个小规模、可训练的低秩修正项。3前向怎么写对输入xxx原来的线性层可以写成hWx h WxhWx加上LoRA之后就变成hWxBAx h Wx BAxhWxBAx如果写得更直观一点就是hWxΔWx h Wx \Delta WxhWxΔWx其中ΔWBA\Delta WBAΔWBA就是LoRA学出来的任务增量。4为什么这样能省参数原来完整的ΔW\Delta WΔW需要d×kd\times kd×k个参数现在只需要d×rr×k d\times r r\times kd×rr×k个参数。当rrr远小于d,kd,kd,k时参数量就会大幅下降。所以LoRA最本质的压缩来自一句话把高维增量矩阵约束到一个低秩子空间里学习。4. LoRA一般加在哪里1最常见的位置在Transformer里LoRA最常被加在线性变换层上尤其是attention里的投影矩阵比如WqW_qWqWkW_kWkWvW_vWvWoW_oWo有时候也会加在FFN里的线性层上。但最经典、最常见的做法还是优先加在attention相关投影上。2为什么这些位置有效因为这些矩阵本身就承担着特征变换和信息路由的作用。在很多任务适配里稍微改一下这些投影方向就足以让模型表现出明显不同的行为。所以LoRA不是随便往哪儿塞都一样它之所以常加在这些位置是因为这些地方本来就对模型行为很敏感。5. LoRA里的几个关键超参数1rank (r)LoRA里最核心的超参数就是秩rrr。rrr越小参数越省rrr越大适配空间越大。所以rrr本质上控制的是你允许模型在多大程度上偏离原始权重。2scaling在很多实现里LoRA增量项还会乘一个缩放系数比如写成W′WαrBA W W \frac{\alpha}{r}BAW′WrαBA其中α\alphaα是LoRA scaling。这个系数的作用就是控制LoRA增量项在前向里的影响强度使训练更稳定。3dropout实际训练时也常给LoRA分支加dropout。这主要是为了防止小规模适配参数过拟合尤其是在数据量不大时更常见。6. LoRA为什么有效1它不是重新学一个模型LoRA并没有试图重新训练一个完整模型。它更像是在已有大模型周围加了一个低维的“任务偏移层”。所以它能有效一个很重要的原因就在于预训练模型本身已经很强了下游适配很多时候只需要小幅修正而不需要推倒重来。2低秩约束其实是一种归纳偏置LoRA把增量限制成低秩本质上是在告诉模型任务适配不需要无限自由度只需要在一个较低维的方向子空间里调整。这其实是一种很强的结构假设。它之所以有效很大程度上说明很多任务适配本身就确实没必要更新整块大矩阵。3和adapter的区别Adapter也是参数高效微调的一条经典路线。它通常是在原网络层之间插入一个小模块。LoRA和adapter都能少训很多参数但LoRA的一个典型优势是在推理阶段LoRA增量可以和原权重合并因此不会像额外插层那样天然引入额外推理路径。这也是LoRA后来迅速流行起来的一个重要原因。7. LoRA的优点和问题1优点LoRA的优点很直接可训练参数少显存占用低任务切换方便推理时可合并权重对现有Transformer结构侵入性小。2问题但LoRA也不是没有代价。最典型的问题有几个rank太小时表达能力可能不够不同任务对LoRA插入位置和超参数很敏感只训练LoRA分支有时会损失一部分full fine-tuning的上限当基座模型本身很大时即使冻结不训光把它完整加载进显存也仍然很贵。最后这一点其实非常关键因为它直接引出了QLoRA。8. 为什么会有QLoRA1LoRA已经省训练参数了但基座模型还是大LoRA虽然只训练很少参数但通常还是需要把整个预训练模型以较高精度加载到显存里。这就意味着训练参数省了不代表底座模型本身的显存占用就小了。尤其当模型到了30B、65B这种规模时就算完全冻结不更新光加载进去也很费显存。2于是一个很自然的问题出现了能不能把冻结的基座模型量化得更低同时仍然保留LoRA式微调能力QLoRA就是在解决这个问题。9. QLoRAQuantized LoRA1核心思想QLoRA的核心可以概括成一句话把预训练基座模型量化到4-bit并冻结只在LoRA适配器上训练。所以它保留了LoRA“只训小量参数”的优点又进一步把基座模型本身的显存占用压下去了。如果写得更直观一点基座模型4-bit量化冻结LoRA分支正常可训练梯度通过量化基座反传到LoRA参数。2最关键的一点QLoRA不是把LoRA本身量化训练而是量化的是冻结的预训练主干真正更新的仍然是LoRA适配器。这一点很重要因为它决定了QLoRA的训练逻辑仍然建立在LoRA上只不过把“底座怎么存”这件事做得更省了。10. QLoRA里的三个关键技术1NF4QLoRA提出了NormalFloat 4NF4这种4-bit数据类型。其核心出发点是预训练权重通常近似服从正态分布那么量化时就应该用更适合这种分布的表示方式。所以NF4不是普通随便压成4-bit而是更针对权重统计特性设计的4-bit表示。2Double Quantization除了量化权重本身QLoRA还进一步去量化量化过程中的常数项。这就是所谓的double quantization。这一步的作用是继续压缩显存因为量化参数本身如果都按高精度存累积起来也是一笔开销。3Paged OptimizersQLoRA还引入了paged optimizers来处理训练中可能出现的显存峰值问题。因为大模型训练时某些时刻内存使用会突然飙高如果没有额外处理很容易OOM。paged optimizer的作用简单理解就是让内存管理更平滑减少这些峰值冲击。11. LoRA和QLoRA的关系1共同点LoRA和QLoRA的共同点很清楚都冻结基座模型都只训练小规模LoRA参数都属于PEFT路线。2不同点真正的差别在于基座模型怎么存LoRA通常默认基座模型还是常规精度加载QLoRA则把基座模型做4-bit量化再加载。所以可以粗略理解成LoRA解决“训练谁”的问题QLoRA进一步解决“底座怎么放进显存”的问题。12. 为什么LoRA / QLoRA会这么流行1因为它们抓住了一个现实矛盾大模型微调里最现实的矛盾就是大家想用更大的模型但算力和显存又没法无限涨。LoRA和QLoRA之所以这么火就是因为它们没有试图暴力解决这个矛盾而是很聪明地绕了一步不去训全部参数只训最必要的一小部分不去高精度存全部底座而是尽量压低冻结部分的存储成本。2因为它们真的容易落地这也是很关键的一点。很多方法理论上很好但很难接进现有系统。LoRA / QLoRA则非常容易工程化改动小适配现有Transformer方便训练脚本好接多任务切换也方便。所以它们不只是论文里好看而是真的非常适合实际训练流程。3因为它们给了“中小资源微调”一条现实路径对很多团队来说真正的问题不是“能不能训到SOTA”而是“能不能在有限GPU条件下把模型训起来”。LoRA和QLoRA给的就是这样一条现实路径。这也是为什么后来很多开源社区、指令微调、领域适配基本都会优先碰到它们。13. 从更高一层看LoRA到底是什么1它不是“模型压缩”LoRA经常会被误解成一种模型压缩方法。其实不太准确。它更准确的定位应该是参数高效适配。也就是说它不是把原模型变小而是让你在不大动原模型的前提下用更少可训练参数完成任务迁移。2它本质上是在学习一个低维任务偏移我觉得这是理解LoRA最关键的一句话LoRA学的不是整个模型而是“从预训练能力到下游任务能力”的低维偏移量。一旦这样理解很多事情就顺了为什么冻结基座还能有效为什么低秩就足够为什么不同任务可以挂不同LoRA分支。3QLoRA则是在这个基础上进一步压缩底座成本所以如果把两者合在一起看LoRA解决的是“微调不必全量更新”QLoRA解决的是“冻结底座也别占太多显存”。14. 一点理解1LoRA最漂亮的地方我觉得LoRA最漂亮的地方就在于它没有去和全量微调正面对抗而是抓住了一个更本质的问题任务适配真的需要更新全部参数吗然后它给出的答案非常干脆很多时候不需要。只要学一个低秩增量就够了。2QLoRA最漂亮的地方QLoRA最漂亮的地方则在于它把LoRA这条线又往现实硬件条件那边推了一大步。也就是说它不只是从“算法上省参数”而是进一步做到在真实显存约束下也能把大模型微调跑起来。3怎么记LoRA与QLoRA如果只是为了学习我觉得可以把这条线记成四句话全量微调很贵因为所有参数都要更新LoRA把权重增量写成低秩分解只训练小规模适配器QLoRA进一步把冻结底座量化到4-bit继续压低显存所以它们共同代表的是“大模型参数高效微调”这条非常现实的路线。15. 参考鸣谢LoRA: Low-Rank Adaptation of Large Language Modelshttps://arxiv.org/abs/2106.09685QLoRA: Efficient Finetuning of Quantized LLMshttps://arxiv.org/abs/2305.14314Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Surveyhttps://arxiv.org/abs/2403.1460816. 注这篇主要是个人学习整理重点放在主线理解文中主要写的是LoRA和QLoRA最核心的思路很多实现细节如target modules选择、merge/unmerge、bitsandbytes细节、LoRA变体DoRA、AdaLoRA等没有展开才疏学浅欢迎批评、指导和交流有错误望大家及时指正