全参微调7B模型要80GB显存,LoRA凭什么只用5GB?
兄弟们,微调大模型这东西,我真香了!
说到这儿,我得先给你们讲个故事。
去年,我捧着刚买的RTX 3090,24G显存,心想这下牛逼了,终于能玩转大模型了!结果呢?呵呵,7B模型全参微调?想都别想!那个显存需求,简直是在跟我开玩笑。
你知道我当时什么心情吗?就像你攒了半年工资买了台跑车,结果发现油费比车还贵!那种绝望,懂吗?
但后来呢?LoRA来了!
它就像个救星,让我这个穷鬼也能玩得起大模型了。今天,我就把这个救命稻草的原理掰开揉碎了讲给你听,顺便把那些让我摔得鼻青脸肿的坑都告诉你。
普通玩家的噩梦:全参微调到底有多贵?
你想想,7B模型,光把参数加载到显存就要14GB(半精度)。好,这还能忍。但训练呢?梯度要存吧?优化器状态要存吧?
我给你算笔账,别眨眼:
半精度下,1B参数占2GB。7B模型本身14GB,梯度14GB,AdamW优化器得存动量和方差——如果优化器用float32,那就是56GB。加起来84GB!什么概念?就是你用两张A100 80GB勉强能跑,单卡?做梦!
我当时看着这个数字,差点把键盘砸了。80多GB啊兄弟们!我上哪搞这么多显存?
LoRA的骚操作:低秩分解
说到这儿,我得先提一篇论文。Aghajanyan他们发现了一个特别反直觉的现象——预训练模型其实有个“内在维度”。
什么意思?
你想想,1750亿参数的GPT-3,为啥只用几千条样本就能微调出不错的效果?因为参数之间存在大量冗余!真正需要调整的自由度,可能就几千个。
这不就是“你以为你买了座山,其实你只需要挖个洞”吗?
LoRA的作者就是受这个启发。他们想:既然参数更新的空间本质上是低秩的,那我干嘛不用两个小矩阵来代表这个更新?
具体来说,对于一个预训练权重矩阵W₀(假设是d×d维),我们不直接训练ΔW(也是d×d维),而是把它分解成两个小矩阵的乘积:
ΔW = B × A
其中B是d×r维,A是r×d维。r远小于d,一般取4、8、16。
参数量从d²降到了2dr。
拿d=4096、r=8来算,参数量从1677万降到了6.5万,差了250多倍!
你说,这得省多少显存?
实操中的坑:差点把我整崩溃
说到这儿,我得单独拎出来一个坑,我踩过,差点把项目搞黄。
LoRA论文里说,初始化时,B初始化为全0矩阵,A用随机初始化。我当时图省事,把两个矩阵都随机初始化了。
结果呢?训练loss死活降不下去!
我折腾了整整两天,重新读论文,才发现问题在哪。
为啥非要有一个是0?
因为如果你两个都是随机初始化的,那ΔW一开始就不是0,相当于模型还没开始训练就已经被改动了。这对预训练模型的初始表现影响极大,尤其是刚开始的几个step,loss会跳得很高。
记住:B初始化为0,A随机初始化。或者反过来也行,反正保证乘积为0。
训练过程:爽就一个字
训练时,预训练权重W₀完全冻结,不参与梯度计算。只有B和A这两个小矩阵在更新。
前向传播时,计算变成:
h = W₀x + BAx
反向传播时,梯度只流到B和A,W₀的梯度根本不算。
推理时更爽:
你可以直接做权重合并:
W_new = W₀ + BA
然后把BA矩阵丢掉,用W_new做推理。完全不会增加推理延迟!
这一点比Adapter好太多了,Adapter在推理时还得额外跑两个小网络,延迟是实打实的。
显存占用对比:一张图看懂
我整理了一下实际测试的数据,给你个直观感受:
| 方法 | 7B模型最小显存需求 |
|------|-------------------|
| 全参微调(AMP) | 84GB |
| 全参微调(FP16) | 56GB |
| Freeze | 20GB |
| LoRA | 16GB |
| QLoRA(int4) | 6GB |
注意,这个表里写的“最小”是指batch size为1、序列长度有限的情况。你要是把batch size调到4或者8,显存会线性增长。
我自己的经验:
- 一张16GB T4:只能跑6B/7B模型的int4 QLoRA,序列长度得控制在512以内
- 一张32GB V100:6B/7B模型的LoRA勉强能跑,batch size设1
- 一张80GB A800:Qwen1.5 72B的int4 QLoRA没问题,Baichuan13B的LoRA也能跑
和其他方法的对比:为什么LoRA赢了?
市面上还有其他几种高效微调方法,我都试过,说说感受:
Adapter Tuning:在每个Transformer层加两个小Adapter结构。效果还行,但推理时有延迟,工业界用得不多。
Prefix Tuning:在输入前面加一些虚拟token。问题是这些虚拟token会挤占输入序列长度,而且训练起来不稳定。
P-tuning v2:在每一层都加prompt tokens。效果比Prefix Tuning好,但容易导致灾难性遗忘——微调完新任务,旧任务的表现明显下降。
相比之下,LoRA的好处很明显:
- 不增加推理延迟
- 训练稳定
- 参数量可控(通过调整r值)
我做了几组BERT的判别任务对比,LoRA的效果和全参微调差不多,甚至有时候更好。我怀疑是因为全参微调容易过拟合,LoRA相当于自带正则化。
结尾的碎碎念:给你一个带走的念头
这篇文章算是LoRA系列的开篇,讲了最核心的原理。下一篇我会讲QLoRA,就是在LoRA的基础上加量化,让显存需求进一步降低。
如果你刚入门,建议先拿7B模型练手,r值设8,学习率设2e-4,batch size能多大就多大。先跑通流程,再慢慢调参。
最后送你一句话:
微调不是重新造轮子,是给轮子画上你的记号。
有问题欢迎留言,我看到了会回复。咱们下期见!
读者评论 5