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)的效果。
notion image

思路扩展

LoRA通过增加一个旁路,使用低维重参数化方式来降低微调参数。虽然这使得微调参数降低近10000倍,但训练效率并没有显著提升,因为根据链式求导规则,对原有支路计算梯度仍然需要相同的计算量。为了解决这个问题,后续的工作LST[5]对其进行了优化。
LoRA的训练思路同样被应用于图像任务,例如在Stable-Diffusion微调中得到了广泛的应用[3]。

Lora简易实现

下面笔者将从dinov2出发来实现用Lora。
目标:fix dinov2-vit-base模型的预训练权重,在dinov2qkv 层中引入lora 可训练参数。(注意:dinov2qkv层的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相关的源码。

参考资料

 
Segment Anything(SAM)🔥Lit: 进一步提升多模态模型Zero-Shot迁移学习的能力
  • Twikoo