CV算法工程师的LLM日志(2)PEFT训练技术——10分钟快速理解DORA【原理&&代码】

摘要

对于LLM的训练,目前主流用的基本都是Lora\q-lora系列的微调与全参的方式(freeze和hypernetwork基本用的很少,蒸馏以及对抗蒸馏也不在讨论范围),最近还新出了一个基于优化器优化内存的训练技术,不过先按顺序来,逐个方法分享下原理和代码,不说废话,原论文为了证明其理论前提,做了一些实验证明,这里我只压缩为结论的叙述,并不影响读者理解,且提高阅读效率。今天分享的是LORA系列的一种改进的微调方法——DORA,为了使LoRA的学习能力更接近FT,研究者们首先通过权重分解分析来探究FT和LoRA之间的内在差异。基于这些发现,他们提出了DoRA,该方法将预训练权重分解为幅度(magnitude)和方向(direction)两个部分,并分别对它们进行微调。
dora paper


一、动机以及原理

回顾下LORA,因为LLM的训练是针对多层的transfromer,因此大参数模型在训练过程中本身以及其优化器的参数更新会对显卡内存产生大量的寻求,因此市面上才围绕多卡或者单卡微调的方式去研发训练和推理算法框架,比如训练deepspeed,推理VLLM等主流的三方库。Lora系列通过在指定的网络层上进行新分支以A\B两个矩阵作低秩分解去训练来逼近原始权重,这样大量节省了训练内存开销,因为通过矩阵分解实际上你的权重矩阵DXD,变成了D x rank* (rank xD),相当于每一个lora标记的训练层节省了 D/rank*2倍的参数训练量。并且独立的训练的Lora还具备灵活插拔性质。(A\B两个矩阵初始化任意一个就行,只要保证一个是0即可,既保证第一次前向时候是原始参数的推理。)LORA相比全参训练就是对世界知识的保留能力稍强,但是对于训练效果一般理论上来说不如全参微调。

在这里插入图片描述

因此基于LORA训练效果不如全参的这个缺点,这篇论文提出了改进LORA的训练技术,简单来说就是再做一步权重分解,如下图:
绿的模型是Dora的可训练参数,可以明显看出是在Lora的流程上,做了改动,先做一步权重分解后,在进行lora中的rank分解,最后再Merge。
在这里插入图片描述
论文中除了DORA的流程和动机,主要还要解释为什么(为什么要做权重分解)和实验证明,和这样做对于全参来说减少过拟合风险和相比于lora训练的更好的效果。具体地:
权重矩阵可以被分解为幅度和方向两个组件。具体而言,给定权重矩阵 W ∈ ℝ^(d×k),我们可以表示为以下公式:
V 是保持方向的矩阵,且每个列向量都是单位向量(即其范数为1)。
权重矩阵W可以分解为幅度m和方向V两个组件,即W = m * V,其中m是幅度向量(通过权重矩阵的列范数计算得到),V是方向矩阵。
微调福哦城中的梯度原始的预训练权重(W0)冻结,而通过DoRA方法,可以训练幅度(m)和方向(V+∆V)的更新。这些更新是通过合并低秩矩阵B和A来实现的,即∆V = BA。

梯度分析

DoRA的更新V,即W’ = m * (V + ∆V),其中∆V按照类似LoRA的方法进行更新,发现权重分解使得梯度的协方差矩阵更趋近于单位矩阵,这对优化过程有益。
对于损失函数 L 关于权重向量 m 和更新后的权重向量 W’ = W + ΔV’

权重分解的重要性:DoRA能够更稳定地优化方向更新 ΔV,因为分解使得优化过程更加直接,减少了参数更新的复杂性。
通过对方向变化(ΔD)和幅度变化(ΔM)的分析,展示了全量微调(FT)和低秩权重适应(LoRA)之间的学习模式差异。
全量微调(FT):在FT中,幅度和方向的变化往往呈现出负相关性。这意味着FT方法在适应下游任务时能够进行更细致的调整。
低秩权重适应(LoRA):相比之下,LoRA显示出正相关性,即幅度和方向的变化之间存在一定的一致性
这些差异有助于我们理解FT和LoRA之间的不同学习行为,以及它们在模型训练中的作用。

这个意思简单来说就是,lora是等比例的在幅度和方向上,而FT并不是,所以Dora要在幅度和方向上作分解,使得其更接近全量的FT。
我们开始讲过LORA的训练参数,类比dora就是多了一个幅度权重m的可训练参数
训练开销降低:为减少反向传播中的内存消耗,DoRA把方向更新的范数当作常数处理,以此减少梯度图的内存使用。

局限性:

模型复杂性: 尽管DoRA减少了参数数量,但它引入了权重分解和低秩更新的额外复杂性。这可能需要更多的技术知识和经验实施和调整。

泛化能力:DoRA在特定任务上表现出色,但其泛化能力到其他类型的任务或数据集上可能存在局限性。FT由于更新了所有参数,可能在某些情况下提供更广泛的泛化能力。

调参需求: DoRA可能需要仔细的超参数调整来达到最佳性能,例如确定分解的幅度和方向组件的适当比例。这可能需要额外的实验和验证。
适用性: DoRA的设计是为了提高特定类型的预训练模型(如Transformer架构)的微调效率。它可能不适用于所有类型的模型或架构。

二、代码

代码很简单,就是在Lora基础上,先分解出一个m 幅度,一维向量权重,然后使用Lora更新流程加上merger后,L2范式提取单位方向的向量,最后再以幅度和单位方向乘积形式merge.


import torch
import torch.nn as nn
import torch.nn.functional as F

class DoRALayer(nn.Module):
    def __init__(self, d_in, d_out, rank=4, weight=None, bias=None):
        super().__init__()  # 调用父类 nn.Module 的构造函数

        # 初始化权重和偏置,如果提供了预训练权重,则直接使用它们
        if weight is not None:
            self.weight = nn.Parameter(weight, requires_grad=False)  # 冻结预训练权重,不进行梯度更新
        else:
            self.weight = nn.Parameter(torch.Tensor(d_out, d_in), requires_grad=False)  # 初始化权重为全零

        if bias is not None:
            self.bias = nn.Parameter(bias, requires_grad=False)  # 如果提供了预训练偏置,则直接使用它们
        else:
            self.bias = nn.Parameter(torch.Tensor(d_out), requires_grad=False)  # 否则初始化偏置为全零

        # 计算权重矩阵的幅度(每列的 L2 范数)
        self.m = nn.Parameter(self.weight.norm(p=2, dim=0, keepdim=True))

        # 初始化 LoRA 方法中的两个低秩矩阵
        # self.lora_A 是输出维度上的随机初始化矩阵
        # self.lora_B 是输入维度上的零矩阵
        std_dev = 1 / torch.sqrt(torch.tensor(rank).float())  # 根据秩计算标准差初始化
        self.lora_A = nn.Parameter(torch.randn(d_out, rank) * std_dev)
        self.lora_B = nn.Parameter(torch.zeros(rank, d_in))

    def forward(self, x):
        # 计算 LoRA 更新
        lora = torch.matmul(self.lora_A, self.lora_B)

        # 计算调整后的权重(原始权重加上 LoRA 更新)
        adapted = self.weight + lora

        # 计算调整后权重矩阵的列范数
        column_norm = adapted.norm(p=2, dim=0, keepdim=True)

        # 将调整后的权重矩阵转换为单位方向权重矩阵
        norm_adapted = adapted / column_norm

        # 计算最终的权重(幅度乘以单位方向权重矩阵)
        calc_weights = self.m * norm_adapted

        # 使用 PyTorch 的线性层操作执行前向传播
        return F.linear(x, calc_weights, self.bias)

总结

介绍了dora在Lora基础上,增加了一次权重分解的流程,给其思路和流程作出解释性。在自己的业务数据集中,微调后效果和Lora并没有明显差距。另外Dora比较简单,也不做过多叙述,PEFT还是比较好水的😊,下篇预告glaore或者Longlora.

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LLM(Large Language Model)模型是指基于深度学习的大型语言模型,如GPT(Generative Pre-trained Transformer)模型。下面是对LLM模型工作原理的简要解释: 1. 输入表示:LLM模型的输入是一段文本序列,可以是一个问题或一个完整的对话历史。在输入之前,文本需要经过分词和编码等预处理步骤,将其转换为模型可以处理的形式。 2. 嵌入表示:经过预处理后,文本序列中的每个词或字符会被映射为低维稠密的嵌入向量表示。这些嵌入向量捕捉了语义和语法信息,并用于传递输入文本的语义信息给模型。 3. Transformer架构:LLM模型通常基于Transformer架构,这是一种基于自注意力机制的深度神经网络。Transformer模型由多个编码器和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。 4. 自注意力机制:自注意力机制允许模型在编码输入时关注输入序列中不同位置的信息,并学习它们之间的依赖关系。通过计算注意力权重,模型可以分配不同位置的重要性,并从整个序列中提取上下文相关的表示。 5. 预测生成:在训练过程中,LLM模型使用自回归(autoregressive)的方式来预测下一个词或字符的概率。模型根据之前生成的文本和当前上下文,通过softmax函数计算所有可能词的概率分布,并选择概率最高的词作为生成结果。 6. 预训练和微调:LLM模型通常采用预训练和微调的策略。预训练阶段,模型在大规模无标签的文本数据上进行训练,学习语言的统计规律和语义表示。微调阶段,模型在特定任务或领域的有标签数据上进行训练,以适应具体的应用需求。 通过以上步骤,LLM模型可以理解输入文本的语义,并生成连贯、合理的自然语言回答。需要注意的是,实际的LLM模型可能会有多个变体和改进,具体的工作原理可能会有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值