万字长文梳理 LLM 中的长文本问题

分享作者:紫气东来(知乎)编辑:马景锐链接:https://zhuanlan.zhihu.com/p/640641794

近期,随着大模型技术的发展,长文本问题逐渐成为热门且关键的问题,不妨简单梳理一下近期出现的典型的长文本模型:

实际上,随着文本长度的提高,模型能够处理问题的边界也大大提高,因此研究并解决长文本问题就显得非常必要。本文将从长文本问题的本质出发,逐步分析和研究长文本实现的问题及解决办法。

要研究清楚长文本的问题,首先应该搞清楚文本长度在模型中的地位与影响。那么我们便以 Decoder-base 的模型为例来进行分析

Decoder-base 的模型主要包括 3 个部分:embedding, decoder-layer, head。

其中最主要部分是decoder-layer,其由 lll 个层组成,每个层又分为两部分:self-attention 和 MLP。

self-attention的模型参数有、、的权重矩阵 、、及bias,输出矩阵 及bias,4个权重矩阵的形状为 ( 表示 hidden_size),4个bias的形状为 。则 self- attention 的参数量为 。

MLP由2个线性层组成,一般地,第一个线性层是先将维度从 映射到 ,第二个线性层再将维度从映射到。第一个线性层的权重矩阵 的形状为 ,偏置的形状为 。第二个线性层权重矩阵 的形状为 ,偏置形状为 。则 MLP 的参数量为 。

self-attention 和MLP各有一个layer normalization,包含了2个可训练模型参数:缩放参数γ和平移参数β,形状都是。2个layer normalization的参数量为 。

由此,每个Decoder层的参数量为。

此外,embedding和head 的参数量相同,与词表相关,为(如果是 Tied embedding,则二者共用同一个参数)。由于位置编码多样,且参数量小,故忽略此部分。

先分析Decoder中self-attention的计算量,计算公式如下:

图片

图片

图片

图片

图片

图片

接下来分析MLP块的计算,计算公式如下:

图片

图片

因此,对于一个 lll 层的模型,输入数据形状为的情况下,一次前向计算的计算量为。

忽略低次项,一次输入的tokens数为bs, 则计算量与参数量的关系为 在实际中通常 ,因此该项可近似认为约等于2。即在一次前向传递中,对于每个token,每个模型参数,需要进行2次浮点数运算(一次乘法法运算和一次加法运算)。考虑到后向传递的计算量是前向传递的2倍。因此一次训练迭代中,对于每个 token,每个模型参数,需要进行 次浮点数运算。

通过以上分析,我们可以得到结论:计算量主要和模型参数和 token 数相关,文本长度并不会显著增加计算量。那么这就引出另一个问题:文本长度与显存的关系。

除了模型参数、梯度、优化器状态外,占用显存的大头就是前向传递过程中计算得到的中间激活值。这里的激活(activations)指的是:前向传递过程中计算得到的,并在后向传递过程中需要用到的所有张量。

先分析 Decoder layer 中 self-attention 的中间激活:

对于MLP块,需要保存的中间激活值为 。

综上,每个层需要保存的中间激活占用显存大小为 。对于 层transformer模型,还有embedding层、最后的输出层。embedding层不需要中间激活。总的而言,当隐藏维度 比较大,层数 较深时,这部分的中间激活是很少的,可以忽略。因此,对于 层模型,中间激活占用的显存大小可以近似为 ,这个结果与文本长度关系密切。

下面以GPT3-175B为例,对比下文本长度对模型参数与中间激活的显存大小的影响。假设数据类型为 FP16 。

模型名参数量层数隐藏维度注意力头数
GPT3175B961228896

GPT3的模型参数量为175B,占用的显存大小为 。GPT3 模型需要占用350GB的显存。

假设 GPT3 输入的 。对比不同的文本长度下占用的中间激活:

当 时,中间激活占用显存为

当 时,中间激活占用显存为

可以看到长度仅仅到 4K,显存占用就出现了剧烈增加,同时 GPU onchip 的 memory 就显得更加捉襟见肘(因此也就出现了 FlashAttention 这类算法)。因此如何解决长文本带来的巨量显存开销成为关键及核心问题。

当前,为了实现更长长文本的支持,解决思路主要可以分为两个阶段:

阶段一:在预训练阶段尽可能支持更长的文本长度为实现这一阶段目标,通常采用并行化 (parallelism) 方法将显存占用分摊到多个 device,或者改造 attention 结构,避免显存占用与文本长度成二次关系。

阶段二:在 SFT 或推理阶段尽可能外推到更大长度为实现这一阶段目标,通常也是需要在两个方面进行考虑:

本文接下来的部分将尽可能详细深入地进行这些问题的研究。为了便于理解和接受,下文将从易到难,先介绍第二阶段的技术,然后再介绍第一阶段(同时也是考虑到直接使用开源模型者,不需要第一阶段的情况)。

在 Transformer 结构的模型中,Attention模块的值与顺序无关,因此需要加入位置编码以确定不同位置的 token。典型的位置编码方式有两类:

绝对位置编码:即将位置信息融入到输入中

相对位置编码:微调Attention结构,使其能够分辨不同位置的Token

随着文本长度的增加,位置编码也会发生相应的变化,因此处理好位置编码问题是解决长文本问题的重要环节。

如下图所示,以二维向量为例来形象说明,图左中黑色剪头为输入向量 ,蓝色箭头为位置向量 (不同方法的长度与角度不同),其相加的结果为绿色箭头。在 Attention 结构中,

图片

图片

由于绝对位置编码由两部分组成,且两部分相互独立,因此无法计算相对距离。下面介绍几种典型的绝对位置编码:

这种方式最为简单直接,即把位置当做词表一样,训练一个 位置向量矩阵。这种训练式的绝对位置编码,一般的认为它没有外推性,但是苏剑林大神提出过一个层次分解的拓展方法。

图片

图片

图片

图片

图片

图片

这样就最大可以表示出 个位置的编码,并且前 个位置编码跟原来模型是相容的。下图反映了经过finetune其准确率在延长的位置编码在MLM任务上是行之有效的。

图片

图片

需要说明的是,这种矩阵式的位置编码方式在当前的大模型中已经比较少采用了,仅有 GPT2 等早期模型中采用了这种方式。

这种方案也是Attention Is All You Need 中提出的方法

图片

图片

整体位置编码如下图所示:

图片

图片

首先研究 Sinusoidal 位置编码与位置之间的关系,绘制不同位置下,函数值与 sin 维度的关系

其曲线如下图所示, 可以从图中得到几点结论:

图片

图片

研究 Sinusoidal 位置编码与维度分量之间的关系,绘制不同维度分量 i 下,函数值与位置的的关系

Sinusoidal位置编码与维度分量的关系如下图所示,可以发现结论如下:

图片

图片

了解了这些基本的特性后,接下来就需要讨论更加深层次的问题:

问题一:为什么用包含各频率的正弦和余弦对?

位置编码存储的是一个包含各频率的正弦和余弦对,这样做有两个好处:

可以使得不同位置的编码向量之间有一定的规律性,比如相邻位置之间的差异较小,而距离较远的位置之间的差异较大。这是由正弦和余弦函数的连续性和单调性保证的,即对于任意两个相邻的位置,它们对应的编码向量在每一个维度上都只有微小的变化,而对于任意两个距离较远的位置,它们对应的编码向量在每一个维度上都有较大的差异。

可以使得编码向量在任意维度上都能保持唯一性,即不同位置在同一个维度上不会有相同的值。这是由正弦和余弦函数的周期性和相位差保证的,即对于任意两个不同的位置,它们对应的编码向量在每一个维度上都不相等。

问题二:底数对结果的影响是什么?

底数越大,位置向量能表示的序列就越长,这是大底数的好处。但是,底数大,意味着在-1到+1的范围内向量的取值越密集,造成两个位置的向量距离越近,这对后续的Self-Attention模块来说是不利的,因为它需要经历更多的训练次数才能准确地找到每个位置的信息,或者说,才能准确地区分不同的位置。长序列需要长编码。但这样又会增加计算量,特别是长编码会影响模型的训练时间。所以,那个底数并非是越大越好。

问题三:Sinusoidal 位置编码如何外推

三角函数式位置编码的特点是有显式的生成规律,因此可以期望于它有一定的外推性。另外一个使用它的理由是:由于

图片

图片

如递归式(如 FLOATER)和相乘式(如PENG Bo:中文语言模型研究:(1) 乘性位置编码),因使用较少,在此不予赘述。

相对位置并没有完整建模每个输入的位置信息,而是在算Attention的时候考虑当前位置与被Attention的位置的相对距离,由于自然语言一般更依赖于相对位置,所以相对位置编码通常也有着更好的表现,灵活性也更大。

实际上 RoPE 的诸多思想来源于 Sinusoidal 位置编码,区别在于 Sinusoidal 位置编码采用和 word embedding 相加的形式,RoPE 则采用了矩阵相乘的形式。

在正式介绍之前,我们需要回顾一下经典的欧拉公式

图片

图片

图片

图片

接下来我们直接看 RoPE 的表达式,对于位置为 m 的 q 向量,其表达式为

图片

图片

即逆时针旋转了度,如上图右所示。同理,位置为的 k 向量的表达式为

图片

图片

那么便可以通过点积,计算二者的 attention 值

图片

图片

即证明了相对位置关系,即旋转前的 attention 值与旋转后的 attention 值的差值仅与相对位置有关。这一点也可以从上图右中看出来,即旋转前的夹角(橙色区域) 与旋转后的夹角(黄色区域) 相同,即内积也相同。

这时我们就可以写出位置为的q的完整的变换矩阵,即

图片

图片

从改变换矩阵也能看出,随着维度增加,旋转角度也在指数级减小,如下图所示。RoPE 的这一功能使模型可以通过从低维度到更高维度,将嵌入中编码的信息类型从低频(close)转变为高频(far)。

图片

图片

下图展示了不同距离尺度上不同 base 值的积分结果,可以得到以下结论:

长度外推性是一个训练和预测的长度不一致的问题。提现有两点:

图片

图片

其过程如下图所示:

图片

图片

下面分析一下以上操作的本质,经过这种放缩操作后,位置为 的维度为的旋转角变为,即线性减小了旋转弧度,如下图第一列的上图所示(横轴为位置编码,纵轴为旋转弧度)。通过这种方式插值后,向量旋转速度变慢,周期变大,频率变慢。 除了上述的这种差值方式外,还有以下改进方式可以实现外推:

这种方式把旋转角修改为 ,其中表示 basebasebase的缩放因子,在codellama中取值为100 。其修改的方式如下图第二列下图所示(横轴为维度,纵轴为旋转角),在不同维度上修改的程度不同。这种方式保留了高频信息,即高频分量旋转速度降幅低,低频分量旋转速度降幅高;在高频部分进行外推,低频部分进行内插。这是因为靠前的维度,在训练中见过非常多完整的旋转周期,位置信息得到了充分的训练,所以具有较强的外推能力。靠后的维度,在训练中无法见到完整的旋转周期,或者见到的旋转周期非常少,训练不够充分,外推性能弱,需要进行位置插值。

该方法是基于 NTK-Aware 的优化,其核心思想是:不改变高频部分,仅缩小低频部分的旋转弧度。即不改变小维度的旋转弧度,仅减小大维度的旋转弧度,这就是by-patrs的含义。

引入超参数,表示旋转周期个数的约束条件,

当,旋转周期数量足够多,则认为该维度为高频部分,无需改变。

当,旋转周期数量少,则为低频分组,进行Position Interpolation。

这是是一种动态插值的方法:当推理长度小于等于训练长度时,不进行插值;推理长度大于训练长度时,每一步都通过NTK-Aware Interpolation动态放大base。

表示当前的序列长度,表示模型训练长度,

当时,不调整旋转角

图片

图片

需要说明的是,论文Scaling Laws of RoPE-based Extrapolation中深入研究了 RoPE 位置编码的特性,其结论就是:RoPE 中 base 的放大和缩小都能获得很好的外推效果(base=10K 效果最差)。原因在于:

在苏神的文章Transformer升级之路:12、无限外推的ReRoPE中指出:RoPE 形式上是一种绝对位置编码,但实际上给 Attention 带来的是相对位置信息,即如下的Toeplitz矩阵:

图片

图片

这么这种形式的 bias 似乎有种似曾相识的感觉,没错,就是 ALiBi 编码。严格来说,ALiBi并不算位置编码,因为它并没有作用在 embedding 上,而是直接作用在了 Attention 上,通过这种构造方式既实现了远程衰减,又实现了位置的相对关系。

图片

图片

对于外推特性,ALiBi 与前文所述的方法也是不同的,体现在:

Attention 机制也是制约长文本实现的重要因素,以下是几种典型的 Attention 的 方式:

图片

图片

关于 Attention 机制改进的更多类型和细节,笔者在之前的文章中已经有所讨论,可看历史文章。

在此主要想介绍一个方案 —— LongLora。

回顾第一节中研究的结论,长文本影响最大的就是 self-attention 中的,随长度二次变化的显存占用和计算复杂度。为解决这个问题,LongLora 的原则是,虽然在推理过程中需要密集的全局注意力,但通过稀疏的局部注意力可以有效且高效地微调模型。

LongLora 在微调期间延长上下文长度,同时使用 Lora 方法保持高性能和低复杂性。其中最关键的是提出了转移短注意力(S2-Attn)方案。下面简要介绍这一方案:

S2-Attn 在微调阶段使用局部注意力而不是全局注意力。即将输入文档分解为几个不同的组,并在每个组中分别应用注意力机制(Pattern 1)。尽管这种方式能够在资源占用不多的情况下拓展长度,由于不同组之间缺乏信息交换,随着上下文长度的增加,会导致混乱增加。

为了解决上述问题,S2-Attn 引入了组大小一半的移位操作,确保相邻组之间顺利的信息交换(Pattern 2)。这种做法有助于模型在文本开头和结尾之间顺利交换信息,从而提高模型稳定性。

图片

图片

而本文提出的 shift short attention 有一半的 head 会被做 shift,如下图所示,然后每个 group 内作 self-attention,从而使信息可以在不同 group 间传递。这种做法实际上将 Pattern 1 和 Pattern 2 结合起来,而没有引入额外的计算开销,使其非常适合高效处理长序列文本。

图片

图片

此外,LongLoRA相比于Lora还可以微调embedding层和normalization层。尽管这两项内容占的参数量很小(以Llama 2-7B为例,embedding层只占1.94%,normalization层更是不到十万分之四),对结果也起到了重要作用。

上两节主要介绍了如何在位置编码和 attention 机制方面进行文本长度的有效拓展,这两个方面都是“经济适用性”的,即只需要简单微调或者直接外推即可,接下来将是最困难,也是成本最高的部分,即讨论如何在预训练阶段提高文本长度。

为解决预训练过程中的长文本问题,思路主要有以下几个方面:

由于笔者精力有限,下面仅选取其中部分方法加以介绍。

在并行化算法大行其道的今天,使用改思想来解决长文本问题变得自然而言,实际上 SP 已逐渐成为 3D(DP, PP, TP)并行之外的第 4 个维度了。简单来说,SP 就是将一段完整的文本拆分到多个设备上进行计算,设备在适当的时候进行通信和信息交互,如下图(c) 所示。

图片

图片

在实现层面,借鉴了 Ring-Allreduce 的思想,将输入序列分割成多个块,并将每个块输入到其相应的设备中。为了计算注意力输出,将环状通信与自注意力计算相结合,实现了环自注意力(RSA),如下图所示。

图片

图片

图片

图片

下面我们来深度理解一下这个过程,论文中的符号表示为

图片

图片

对于:

图片

图片

图片

图片

MLP 部分的计算就更简单了,如下所示:

图片

图片

LongLLaMA 通过引入Focused Transformer(FOT)方法,在保持性能的同时,将 LLaMA 的上下文长度扩展到100k!在长文本的情况下,除了第一节所研究的显存和计算量的问题外,这篇论文还提出了一个分心问题(Distraction Issue),即随着文本长度的增加,其中相关的 tokens 对不相关 tokens 的比例会减少,从而导致与不相关 value 相关的 key 和与相关 value相关的 key 发生重叠,致使模型需要额外区分不同语义的 key 。

为此文章提出了Focused Transformer(FOT)解决方案,其中主要使用了 Memory Attention Layers 以及 CrossBatch 技术,在 Inference 的过程中,绿色的 Memory Attention Layers 使用 kNN 对外部的 Memory 进行查询,从而有效延长了上下文长度,而 Memory Attention Layers 则主要使用 CrossBatch 进行训练。

图片

图片

具体而言,Memory Attention Layers 中的每个 query 在 却符合中会关注局部的上下文以及 Memory 中使用 kNN 计算出的最匹配的 个key,而整个 Memory 则根据 之前处理的 key,value 进行填充。而 CrossBatch 则期望使得 Memory Attention Layers 更加关注长文本之中的“相关 value 的 key” ,CrossBatch 的处理借鉴了对比学习的思想,以相关文档之中的 d-1 个上下文作为正样本,以不相关文档之中的 d-1 个上下文作为负样本,通过对比学习的方式使得 Memory Attention Layers 可以更好的分辨相关与无关的 key-value。

与标准的 Transformer 相比,一般的 Transformer 的训练过程中,相关与不相关文档没有被得到有效区分(正负样本分散均匀),当文档数量扩展时,注意力变得越来越分散,而 Focused Transformer 则通过 CrossBatch 的训练目标使得模型有效的关注与区分的长文本下的相关与无关的 key-value 的空间结构,从而解决了分心的问题。

对于 LLM 来说,其效果通常是通过生成连贯且上下文相关的文本的能力来衡量的。为了量化和衡量这一指标,困惑度 (Perplexity, PPL) 便成了最常见的指标。

PPL 是一种衡量标准,反映模型根据前面的上下文预测下一个单词的能力。PPL 分数越低,模型准确预测下一个单词的能力就越好。

PPL 是使用平均交叉熵计算的,而平均交叉熵又是使用数据集中的单词数量和根据前面的上下文预测的单词(目标单词)的概率来计算的。前面的上下文通常由目标单词之前的固定长度单词序列表示。其公式如下:其中H是平均交叉熵,

PPL 作为一种客观的评估指标被广泛用来进行 LLM 的评估。但是其也存在一些问题和不足:

实际上,StreamingLLM 就很好地证明了 PPL 的局限性,因为尽管 StreamingLLM 的 PPL 值较低,但是由于其损失了大量中间信息,因此无法在“大海捞针”等测试方法中有较好的表现。

“大海捞针” 由 Greg Kamradt 提出的大模型长文本性能测试方法,其做法是在文本语料中藏入一个与文本语料不相关的句子,然后看大模型能不能通过自然语言提问的方式(Prompt)把这句话准确地提取出来。Greg Kamradt 的“大海捞针”实验简述:

“大海”:Paul Graham 的文章合集作为语料“针”:“The best thing to do in San Francisco is eat a sandwich and sit in Dolores Park on a sunny day.”提问:"What is the most fun thing to do in San Francisco based on my context? Don't give information outside the document"期待模型输出的正确答案:The best thing to do in San Francisco is eat a sandwich and sit in Dolores Park on a sunny day.

Greg Kamradt 公布了他对 GPT-4 Turbo(128K)和 Claude 2.1 的测试结果:

图片

图片

图片

图片

图片

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL多数据源是指在一个应用程序同时使用多个不同的MySQL数据库来存储和管理数据的技术。它可以帮助开发人员更灵活地处理各种数据库操作,提高程序的性能和可扩展性。下面是一个完整的MySQL多数据源教程。 一、设置数据库连接信息 1. 在应用程序的配置,创建多个数据库连接的配置项。例如,可以为每个数据源创建一个配置项,分别命名为db1、db2等。 2. 在配置项,设置每个数据源的连接信息,包括数据库地址、用户名、密码等。 二、创建数据源管理器 1. 创建一个数据源管理器类,用于管理多个数据源。该类需要实现数据源的动态切换和获取。 2. 使用Java的线程安全的数据结构,如ConcurrentHashMap来存储数据源信息。将配置的数据库连接信息加载到数据结构。 3. 实现方法来切换不同的数据源,通过传入数据源的名称来切换到对应的数据库。 三、实现数据源切换 1. 在应用程序,根据业务需求选择需要使用的数据源。可以通过调用数据源管理器的方法来切换数据源。 2. 在DAO层的代码,根据当前使用的数据源名称,选择对应的数据源进行数据库操作。 四、使用多数据源进行数据库操作 1. 在DAO层的代码,区分不同的数据源,并将数据库操作的代码包装在对应的数据源。 2. 在业务层的代码,调用DAO层的方法来进行数据库操作。不同的数据源会自动切换。 五、处理事务 1. 如果需要在一个事务操作多个数据源,可以使用分布式事务的方式来处理。 2. 可以使用开源的分布式事务框架,如Atomikos、Bitronix等来实现多数据源的事务管理。 六、监控和维护 1. 使用监控工具来监控多个数据源的使用情况,包括连接数、查询次数等。 2. 定期对数据库进行维护,包括索引优化、数据清理等工作,以保证数据库的性能和稳定性。 通过以上步骤,我们可以实现MySQL多数据源的配置和使用。使用多数据源可以更好地管理和处理不同的数据库操作,在提高程序性能和可扩展性的同时,也提供了更灵活的数据操作方式。同时,需要注意合理选择和配置数据源,以及监控和维护数据库,以保证系统的运行效率和数据的安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值