type
status
date
slug
summary
tags
category
icon
password
背景
当需要在特定任务上提高通用大模型的泛化能力时,微调是一个非常常用的方法。然而,在通用领域预训练的大模型模型参数非常庞大,以GPT-3为例,参数数量高达175B,这意味着没有多少公司具备微调如此大规模模型的钞能力。因此,轻量化微调技术在今年引起了学术界和工业界的广泛关注和研究。一些代表性的轻量化微调技术包括Adapter和P-Tuning等。在本文中,我们将介绍一种从低维本征维度的角度出发的技术,即LoRA(Low-Rank Adaption),以解决这个问题。
方法大意
作者的思路来源于2020 Facebook Aghajanyan发表的一篇论文[4],论文的主要观点是:常见的预训练模型有非常低的本征维度。通俗的讲就是说存在一种低维重参数化方式,其在微调时与全参数空间一样有效。受此启发LoRA相对原本架构它增加了一个旁路,使输入向较小的子空间进行随机投影。微调过程时仅更新旁路的较为轻量的权重A,B,取代更新原有权重W。
用公式描述:
- 原来的fintune
前向过程 | |
反向过程 | 根据来更新 |
- 对于LoRA
前向过程 | |
反向过程 | 根据, 来更新权重参数A,B,其中,其中 |
训练完毕可以将和进行合并,不会增加前向推理的时间。
通过这个操作微调的参数从降低到了,大大提升了微调效率。论文通过这个方法仅用35M的参数量微调了GPT-3,并取得了接近全量微调(参数量350GB)的效果。
思路扩展
LoRA通过增加一个旁路,使用低维重参数化方式来降低微调参数。虽然这使得微调参数降低近10000倍,但训练效率并没有显著提升,因为根据链式求导规则,对原有支路计算梯度仍然需要相同的计算量。为了解决这个问题,后续的工作LST[5]对其进行了优化。
LoRA的训练思路同样被应用于图像任务,例如在Stable-Diffusion微调中得到了广泛的应用[3]。
Lora简易实现
下面笔者将从dinov2出发来实现用Lora。
目标:fix
dinov2-vit-base
模型的预训练权重,在dinov2
的qkv
层中引入lora
可训练参数。(注意:dinov2
的qkv
层的module type为nn.Linear
)step1: 找到
dinov2
qkv
层的模型参数首先通过
torchhub
加载dinov2
模型通过
dinov2.named_module
可以找到目标层(qkv
)step2: 将
qkv
层引入lora
可训练参数找到想要添加的层后,我们要将原始的
nn.Linear
module改为自定义的Linear
module参考前文阐述的Lora原理,我们先构建自定义的
Linear
类为了扩展,先定义一个LoraLayer基类
再定义
LoraConfig
,用于设置Lora
的参数自定义的
Linear
类继承LoraLayer
定义好lora-based
Linear
层后,下面的重点是如何将原来的层用替换为新定义的层step3: 将
qkv
层替换为Lora-based qkv
层我们知道qkv层是Attention层的一个子模块, 比如 module name=”
blocks.0.attn.qkv
”的qkv层,我们可以通过get_submodule
方法拿到它的parent随后可以通过
setattr
方法将原来的qkv层改为lora-based qkv层我们再打印一下parent
可以看到qkv层已经成功替换。
下面对所有的qkv层都进行同样的操作
Output:
可以看到以成功添加lora的训练参数。
综上对Lora的代码实现做了简单介绍,如有错误,欢迎指出交流。
代码能力强的同学,可以直接阅读huggingface peft相关的源码。
参考资料
[1]LoRA paper
[2]LoRA github
- 作者:莫叶何竹🍀
- 链接:http://www.myhz0606.com/article/lora
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章