谷歌在2017年发布Transformer架构的论文时,论文的标题是:Attention Is All You Need。重点说明了这个架构是基于注意力机制的。
一、什么是注意力机制
在深入了解Transformer的架构原理之前,我们首先要了解下,什么是注意力机制。
人类的大脑对于信息的获取也存在注意力机制,下面我举几个简单的例子:
从上面的图片中,我们可能更容易关注,颜色更深的字、字号更大的字,另外像“震惊”这种吸引人眼球的文案也非常容易吸引人的关注。
我们知道在海量的互联网信息中,往往那些起着“标题党”的文章更能吸引人的注意,从而达到吸引流量的目的,这是一种简单粗暴的方式。另外在大量的同质化图片中,如果有一张图片它的色彩、构图等都别出一格,那你也会一眼就能注意到它,这也是一种简单的注意力机制。
假设有以下这两段文字,需要翻译成英文:
1、我在得物上买了最新款的苹果,体验非常好。
2、我在得物上买了阿克苏的苹果,口感非常好。
我们人类能很快注意到第一段文字中的苹果是指苹果手机,那么模型在翻译时就需要把他翻译成iPhone,而第二段文字中的苹果就是指的苹果这种水果,模型翻译时就需要将他翻译成apple。
人类的大脑为什么能分辨出这两个苹果是指代的不同的意思呢?原因就是人类的大脑能从上下文中获取到关键信息,从而帮助我们理解每种苹果是什么意思。
其实说到这里,我们就已经揭开了Transformer架构的核心,即注意力机制的原理:从文本的上下文中找到需要注意的关键信息,帮助模型理解每个字的正确含义。但是实际的实现方式又是非常复杂的。
接下来让我们一起深入理解下Transformer的架构原理。
二、Transformer架构设计
Transformer的架构设计如下图所示:
Transformer架构中有两个核心的组件Encoder和Decoder,左边的这张图是Transformer架构的一个简单表示形式,右边的这张图是Transformer架构的一个完整表示形式,其中有一个重要的Multi-Head Attention组件,称为注意力层。
Transformer架构中的两个核心的组件Encoder和Decoder,每个组件都可以单独使用,具体取决于任务的类型:
-
Encoder-only models: 适用于需要理解输入的任务,如句子分类和命名实体识别。
-
Decoder-only models: 适用于生成任务,如文本生成。
-
Encoder-decoder models 或者 sequence-to-sequence models: 适用于需要根据输入进行生成的任务,如翻译或摘要。
三、理解Transformer中的Token
因为模型是无法直接处理文本的,只能处理数字,就跟ASCII码表、Unicode码表一样,计算机在处理文字时也是先将文字转成对应的字码,然后为每个字码编写一个对应的数字记录在表中,最后再处理。
将文本拆分成token
所以模型在处理文本时,第一步就是先将文本转换成对应的字码,也就是大模型中的token,但是怎么将文本转换成对应的token却是一个复杂的问题,在Transformers(HuggingFace提供的一个对Transformer架构的具体实现的组件库)中提供了专门的Tokenizer分词器来实现这个任务,一般来说有以下几种方式:
基于单词的分词器
第一种标记器是基于单词的(word-based)。它通常很容易设置和使用,只需几条规则,并且通常会产生不错的结果。例如,在下图中,目标是将原始文本拆分为单词,并为每个单词找到一个映射的数字表达:
将文本拆分成单词,也有很多不同的方式,比如通过空格来拆分、通过标点符号来拆分。
如果我们想使用基于单词的标记器(tokenizer)完全覆盖一种语言,我们需要为语言中的每个单词都创建一个数字标记,这将生成大量的标记。除此之外,还可能存在一些无法覆盖的单词,因为单词可能存在很多的变种情况,比如:dogs是dog的变种,running是run的变种。如果我们的标识符中没有覆盖所有的单词,那么当出现一个未覆盖的单词时,标记器将无法准确知道该单词的数字标记是多少,进而只能标记为未知:UNK。如果在文本转换的过程中有大量的文本被标记为UNK,那么也将影响后续模型推理。
基于字符的标记器
为了减少未知标记数量的一种方法是使用更深一层的标记器(tokenizer),即基于字符的(character-based)标记器(tokenizer)。
基于字符的标记器(tokenizer)将文本拆分为字符,而不是单词。这有两个主要好处:
-
词汇量要小得多。
-
未知的标记(token)要少得多,因为每个单词都可以从字符构建。
但是这里也出现了一些关于空格和标点符号的问题:
这种方法也不是完美的。由于现在表示是基于字符而不是单词,因此人们可能会争辩说,从直觉上讲,它的意义不大:每个字符本身并没有多大意义,而单词就是这种情况。然而,这又因语言而异;例如,在中文中,每个字符比拉丁语言中的字符包含更多的信息。
另一件要考虑的事情是,我们的模型最终会处理大量的词符(token):虽然使用基于单词的标记器(tokenizer),单词只会是单个标记,但当转换为字符时,它很容易变成 10 个或更多的词符(token)。
为了两全其美,我们可以使用结合这两种方法的第三种技术:子词标记化(subword tokenization)。
基于子词的标记器
子词分词算法依赖于这样一个原则,即不应将常用词拆分为更小的子词,而应将稀有词分解为有意义的子词。
例如,“annoyingly”可能被认为是一个罕见的词,可以分解为“annoying”和“ly”。这两者都可能作为独立的子词出现得更频繁,同时“annoyingly”的含义由“annoying”和“ly”的复合含义保持。
下面这张图,展示了基于子词标记化算法,如何标记序列“Let’s do tokenization!”:
这些子词最终提供了很多语义含义:例如,在上面的示例中,“tokenization”被拆分为“token”和“ization”,这两个具有语义意义同时节省空间的词符(token)(只需要两个标记(token)代表一个长词)。这使我们能够对较小的词汇表进行相对较好的覆盖,并且几乎没有未知的标记。
向量、矩阵、张量
了解完token之后,我们还要了解下向量、矩阵和张量的概念,因为他们是大模型计算中基础的数据结构。
向量(Vector)
向量是一个有序的数字列表,通常用来表示空间中的点或者方向。在数学中,向量可以表示为一个列向量或行向量,具体取决于上下文。例如,一个三维空间中的点可以用一个三维列向量表示,如 v=[x,y,z]T,其中 x,y,z 是实数。
矩阵(Matrix)
矩阵是一个二维数组,由行和列组成,可以被视为向量的一个特例。矩阵在数学中用于表示线性变换、系统方程的系数等。矩阵的维度通常表示为 m×n,其中 m 是行数,n 是列数。例如,一个 4×3 的矩阵有四行三列。
张量(Tensor)
张量是一个多维数组,可以看作是向量和矩阵的更底层的表示,向量和矩阵是张量的特例。例如向量是一维的张量,矩阵是二维的张量。张量可以有任意数量的维度,而不仅仅是一维(向量)或二维(矩阵)。张量在物理学中用来表示多维空间中的物理量,如应力、应变等。在深度学习中,张量用于表示数据和模型参数的多维结构。
将token转换成向量
在获取到token之后,再将每个token映射为一个数字,当然了,Transformer能够处理的数据,并不是简单的1/2/3这样的数字,而是一种向量数据,如下图所示:
将向量转换成嵌入
得到向量之后,再将向量转换成词嵌入,也就是我们所熟知的embeddings。
在Transformer模型中,编码器接收的词嵌入(embeddings)可以被视为矩阵。这些词嵌入是将输入序列中的每个token映射到一个固定维度的向量空间中的结果。每个词嵌入都是一个向量,而这些向量按顺序排列形成一个矩阵。
具体来说,如果你有一个句子或序列,其中包含了N个token,每个token都被映射到一个d维的向量空间中,那么你将得到一个N×d的矩阵,其中N是序列的长度,d是嵌入向量的维度。这个矩阵就是词嵌入矩阵,它是一个二维张量,因为它具有两个维度:序列长度(时间步长)和嵌入维度。
在Transformer模型的编码器中,这个嵌入矩阵首先会通过一个线性层(可选)进行处理,然后添加位置编码(positional encoding),最后输入到自注意力(self-attention)和前馈网络(feed-forward network)等组件中进行进一步的处理,具体细节我接下来会进行详细解释。
总结来说,编码器接收的词嵌入是一个矩阵,这个矩阵可以被视为一个二维张量,其中包含了序列中每个词的d维向量表示。
四、理解Transformer的编解码器
下面让我们以文本翻译来深入理解Transformer中的Encoder和Decoder是怎样工作的,假设我们有以下这个翻译任务,输入是一段法文,输出是英文。
整个流程是Transformer将输入的input,经过Encoders处理后,将结果投递到Decoders中处理,最后输出翻译后的结果。
但是实际在Transformer的内部,是由多个独立的Encoder和Decoder组成的,这里我们使用6个做验证,当然我们也可以使用其他数量的Encoder和Decoder,笔者怀疑6个是经过验证后相对折中的一个值。
这6个Encoder和Decoder在结构上都是相同的,但是Encoder和Decoder的内部还有更细分的组件:
每一层的Encoder由2个子组件组成:自注意力层和前馈网络层,其中文本的输入会先流入自注意力层,正是由于自注意力层的存在,帮助Encoder在对特定文本进行遍历时,能够让Encoder观察到文本中的其他单词。然后自注意力层的结果被输出到前馈网络层。
每一层的Decoder由3个子组件组成:除了自注意力层、前馈网络层,在两者之间还有一个编解码注意力层,这个组件主要是帮助Decoder专注于输入句子的相关部分。
五、理解Token在编码器中的流转
现在我们已经知道了Transformer模型中的核心组件Encoder和Decoder,接下来我们来看Token在Transformer中是怎么流转的,换句话说Encoder和Decoder是怎么处理Token的。
拿最开始的法文翻译的例子,模型将文本转换token后,紧接着就是将每个token转换成向量表达,在下图中,我们用x1、x2、x3这样的box来表示每个token的向量:
得到每个token的向量之后,从最底层的Encoder开始,每个token会沿着自己的路径从下往上流转,经过每一个Encoder,对每个Encoder来说,共同点是他们接收的向量的维度都是相同的,为了保证这一点,所有的token都需要被embedding成相同大小的向量。
对Token进行位置编码
在流经每个Encoder时,向量都会从自注意力层流向前馈层,如下图所示:
这里需要注意的是,不同位置的向量在进入自注意力层的时候,相互之间是有依赖关系的,这就是注意力层需要关注的上下文的信息。
而当自注意力层处理后的向量进入前馈层后,前馈层是可以并行计算以提升性能的,因为在前馈层中向量之间不存在依赖关系。每个向量在经过Encoder处理后,得到的仍然是一个相同大小的向量,然后再提交给下一个Encoder进行处理。
为什么说不同位置的向量相互之间是有依赖关系的呢?我们可以想象一下,如果不关注一整个句子中token的位置信息,那么翻译出来的结果是不准确的,比如:
-
Sam is always looking for trouble
-
Trouble is always looking for Sam
为了让模型知道每个token的位置信息,传统的RNN网络的做法是,顺序处理每个token,这样在处理当前token时,可以往前查看已经处理过的token的信息,但是缺点是所有的token节点都共用一套相同的参数,即下图中的:
U:输入参数
W:隐藏参数
V:输出参数
由于RNN的窗口较小,这种方案带来的问题是,当token数变大时,模型无法参考更早之前已经参考过的token,这样就会造成上下文记忆丢失。
那么Transformer是怎么对token进行位置编码的呢?
首先我们知道每个token会被转换成512维(或更高的维度)的向量,比如:[0.12142,0.34181,....,-0.21231] 可以将这个向量分为两个部分,奇数和偶数部分。
奇数部分使用cos函数,加上当前token的位置信息pos,通过cos编码得到一个奇数编码值;
偶数部分使用sin函数,加上当前token的位置信息pos,通过sin编码得到一个偶数编码值;
最后拿token的embeddings和pos的embeddings相加,得到位置编码后的positional input embeddings。
自注意力机制
有了位置编码的信息后,模型将接收经过位置编码的embeddings输入,为了方便描述,我们把token换成更简单的文本,如下图所示,Encoder在接收到两个向量之后,通过自注意力层,将原始向量转换成携带了自注意力值的向量,也就是图中的z1和z2。
计算注意力值
那z1和z2这两个向量是怎么得到的呢?原论文中给出了计算公式:
这个公式是用来计算注意力值的,借助了Q、K、V这三个矩阵:
首先通过Q矩阵和转置后的K矩阵转置相乘,得到结果后再除以dk的开平方,再通过softmax函数得到一个归一化的结果,最后将归一化的结果和矩阵V相乘就得到了表示注意力值的矩阵。
这里的Q、K、V三个矩阵(查询矩阵、键矩阵、值矩阵)是通过原始token的embedding矩阵计算得到的,具体的方法是,先训练出三个矩阵:Wq,Wk,Wv, 然后使用embedding处理后的X矩阵和这三个矩阵相乘得到:
Q=Wq * X
K=Wk * X
V=Wv * X
需要注意的是我们embedding输入原本是向量,并不是矩阵,这里是将所有的向量打包之后,形成了一个矩阵,方便矩阵之间的计算。
下面我们一步步了解下注意力值是怎么计算的,使用原始的embedding,而不是打包后的矩阵,首先模型将会为句子中的每个token都计算出一个score分数,这个分数表示了该token对句子中其他token的关注程度,分数越高关注度越高。
但是需要注意的是这里计算得到的中间向量q、k、v的维度是64维,小于Encoder接收的输入向量的维度,这是一个经过计算后得到的相对稳定的数值。
如下图所示,当我们在计算Tinking这个token的注意力值时,会依次计算出Thinking对其他token(在这里也就是Thinking和Machines)的注意力值,计算token1对其他各个token的score的方式是:q1 与 k1 做点积,q1 与 k2 做点积。
得到每个score后,再把score除以K向量维度的平方根也就是√64=8,然后将结果通过Softmax进行归一化,得到一个0~1之间的概率值,所有的归一化的加和值等于1。
最后将Softmax的值,与V向量相乘,得到自注意力层的输出结果向量:z1和z2,需要注意的是相乘的过程中会将不相关的token的关注度降低。
到这里其实已经把Encoder是怎么计算每个token对句子中其他token的注意力值的方法解释清楚了,下面我们用一张图从更高的层面来观察这个过程,假设我们想要翻译下面这个句子:
The animal didn't cross the street because it was too tired.
句子中的it是表示什么呢,是animal还是street?模型就是通过自注意力值来确定的,当对it进行编码时,Encoder会对句子中的每个token都计算一遍注意力值,模型会将it更关注的“The animal”编码到it中。这样模型在后续的处理过程中就能知道it指代的是“The animal”。
多头注意力机制
论文中通过引入多个Encoder形成了一种“多头注意力”的机制,对自注意力层进行了能力的提升,主要包括:
-
多头注意力扩展了模型关注不同位置的能力
-
多头注意力为自注意力层提供了多个子空间
Transformer模型使用了8个注意力头,所以在计算每个Encoder的输出时,我们会得到8个z向量。
但是前馈层只能接收1个z向量,所以我们还需要将这8个z向量做压缩得到1个向量,具体的做法是将这8个z向量链接起来,然后乘以一个附加的权重矩阵Wo,最后得到z向量,如下图所示:
最后我们用一张完整的大图来描述下在多个Encoder下,注意力值的计算过程,也就是多头注意力机制:
下面我们可以看下,在多头注意力机制下,在编码it这个token时,模型在注意哪些其他的token:
可以看到其中一个头(橙色)更关注“The Animal”,因为这两个token对应的橙色更深,另外一个头(绿色)则更关注“tired”,因为这两个token对应的绿色更深。
残差网络
首先我们了解下什么是残差网络,残差网络(Residual Network,简称ResNet)是一种深度卷积神经网络(CNN)架构,由Microsoft Research Asia的Kaiming He等人在2015年提出。ResNet的核心思想是通过引入“残差学习”(residual learning)来解决深度神经网络训练中的退化问题(degradation problem)。
在传统的深度神经网络中,随着网络层数的增加,理论上网络的表示能力应该更强,但实际上,过深的网络往往难以训练,性能反而不如层数较少的网络。这种现象被称为“退化问题”,即随着网络深度的增加,网络的准确率不再提升,甚至下降。
ResNet通过引入“跳跃连接”(skip connections)或“捷径连接”(shortcut connections)来解决这个问题。在ResNet中,输入不仅传递给当前层,还直接传递到后面的层,跳过一些中间层。这样,后面的层可以直接学习到输入与输出之间的残差(即差异),而不是学习到未处理的输入。这种设计允许网络学习到恒等映射(identity mapping),即输出与输入相同,从而使得网络可以通过更简单的路径来学习到正确的映射关系。
在Transformer模型中,残差网络的使用主要是为了解决自注意力机制(self-attention)带来的问题。Transformer模型完全基于注意力机制,没有卷积层,但其结构本质上也是深度网络。在Transformer中,每个编码器(encoder)和解码器(decoder)层都包含自注意力和前馈网络,这些层的参数量非常大,网络深度也很容易变得很深。
使用残差连接可以帮助Transformer模型更有效地训练深层网络。在Transformer的自注意力层中,输入通过自注意力和前馈网络后,与原始输入相加,形成残差连接。这种设计使得网络即使在增加更多层数时,也能保持较好的性能,避免了退化问题。
总结来说,残差网络在Transformer模型中的应用解决了以下几个问题:
-
缓解退化问题:通过残差学习,使得网络即使在增加层数时也能保持或提升性能。
-
加速收敛:残差连接提供了梯度的直接路径,有助于梯度在深层网络中的传播,加速训练过程。
-
提高表示能力:允许网络学习更复杂的函数,同时保持对简单函数的学习能力。
Transformer模型的成功部分归功于残差连接的设计,这使得它能够构建更深、更强大的模型,从而在自然语言处理(NLP)和计算机视觉等领域取得了显著的成果。
可以使用下面这张图来解释残差网络,原始向量x在经过自注意力层之后得到z向量,为了防止网络过深带来的退化问题,Transformer模型使用了残差网络,具体做法是使用计算得到的z矩阵,在和原始输入的x矩阵做残差链接,即图中的X+Z,然后使用LayerNorm函数进行层归一化,计算得到新的z向量,然后输入到前馈层。
将 Add & Normalize 简化之后表示为如下:
前馈网络
归一化后的残差输出,被送入点对点前馈网络进行进一步处理,点对点前馈网络是几个线性层,中间有ReLU激活函数,将点对点输出的结果与前馈网络的输入进行相加做残差链接,然后再做进一步的归一化。
点对点前馈网络主要用于进一步处理注意力的输出,让结果具有更丰富的表达。
到这里编码器就已经介绍完了,编码器输出的结果中携带了每个token的相关注意力信息,将用以帮助解码器在解码过程中关注输入中的特定的token信息。
六、理解Token在解码器中的流转
每个解码器拥有与编码器相似的结构但也有不同的地方,它有两个多头注意力层,一个点对点前馈网络层,并且在每个子层之后都有残差链接和层归一化。
解码器是自回归的,它将前一个Decoder输出的结果和来自编码器输出的注意力信息当做解码器的输入。
这里我们需要了解清楚,解码器的先前的输出结果是怎么得到的,即解码器的第一个输出结果从哪得到的。
在Transformer模型的训练过程中,解码器的第一个输出序列通常是根据特定的起始标记(start token)或者一个预先定义的初始状态得到的。这个起始标记是一个特殊的符号,它标志着输出序列的开始。以下是解码器如何获得第一个输出序列的详细过程:
1. 起始标记:
在训练阶段,解码器的输入序列通常以一个起始标记(例如<START>)开始。这个标记是一个预定义的词汇表中的词,它告诉解码器输出序列的生成即将开始。
2. 初始化状态:
解码器在开始生成输出之前,会接收到编码器的输出,即编码器的上下文向量。这些上下文向量包含了输入序列(如源语言文本)的信息。在某些情况下,解码器的初始状态也可以通过一个额外的向量(如位置编码)来初始化,以提供序列中每个位置的信息。
3. 自注意力机制:
在第一个时间步,解码器使用自注意力机制处理起始标记。由于此时没有之前的输出,自注意力机制会关注起始标记本身,以及可能的位置编码。
4. 编码器-解码器注意力:
解码器接着使用编码器-解码器注意力机制来关注编码器的输出。这允许解码器在生成第一个输出时就利用到输入序列的信息。
5. 输出层:
解码器的输出层将上述步骤得到的向量转换为概率分布,这个分布表示了词汇表中每个词作为第一个输出的概率。
6. 选择第一个输出:
在训练阶段,解码器可能会使用强制策略,这意味着解码器的第一个输出会直接使用目标序列中的第一个词。在推理阶段,解码器会根据概率分布选择概率最高的词作为第一个输出。
7. 迭代生成:
一旦获得了第一个输出,解码器就会将其作为下一个时间步的输入,并重复上述过程来生成后续的输出序列。
在实际应用中,解码器的第一个输出序列的生成方式可能会根据具体的任务和模型配置有所不同。例如,在某些情况下,解码器可能会接收到一个完整的前缀序列,而不是单一的起始标记,这在文本摘要任务中较为常见。在这种情况下,解码器会基于这个前缀序列来生成剩余的输出序列。
Masked多头注意力机制
需要注意的是解码器中的第一层是一个特殊的多头注意力层,是一个执行了mask的注意力层,因为解码器是自回归的,并且依次生成结果token,我们需要防止它在处理某个token时,对未来的token进行处理,原因是模型在训练的时候,是不知道未来输出的token是什么的,为了保证训练过程和解码的过程的一致性,我们需要让解码器在计算某个token的注意力值的时候,只关注这个句子中已经出现过的token,而屏蔽掉句子中当前token之后的其他token的信息。
可以通过以下这张图来描述Mask的过程,当解码器在处理it时,应该把it之后的所有token屏蔽掉。
计算注意力值
在解码器中计算注意力值时,是用Encoder最后的输出,和每一个Decoder进行交互,这就需要Decoder中的第二层Encoder-Decoder Attention。每个Decoder计算出结果之后,再作为输入传递给下一个Decoder。
线性分类器&Softmax
当最后一个Decoder计算完毕后,解码器得到了一个输出结果的向量数据。我们如何把它变成一个词呢?这就是最后一个 Linear 层的工作,后面是 Softmax 层。
线性层是一个简单的全连接神经网络,它将解码器产生的向量投影到一个更大的向量中,称为 logits 向量。
假设我们的模型知道从训练数据集中学习的 10,000 个独特的英语单词。这将使 logits 向量有 10,000 个单元格宽——每个单元格对应一个唯一单词的分数,这就是我们解释线性层模型输出的方式。
然后,softmax 层将这些分数转换为概率(全部为正,全部加起来为 1.0)。选择概率最高的单元格,并生成与其关联的单词作为该时间步的输出。
编解码器的协同工作
现在让我们看看编码器和解码器之间是如何协同工作的。
编码器首先处理输入的文本token,然后输出一组注意力向量 K 和 V。这些向量将由每个解码器在其“编码器-解码器注意力”层中使用,这有助于解码器关注输入序列中的特定token的位置信息,具体计算注意力值的方法跟编码器中是一样的,需要注意的是,这里的K、V矩阵来自于编码器的输出,而Q矩阵来自于解码器的输入。
重复回归以上的步骤,直到出现结束符号的标识,表示解码器已完成其输出。每个步骤的输出在下一个时间步骤中被反馈到底部解码器,并且解码器像编码器一样向上反馈其解码结果。就像我们对编码器输入所做的那样,我们将位置编码嵌入并添加到这些解码器输入中以指示每个单词的位置。
至此,已经分析完Transformer的编码器和解码器的全流程了。
七、Transformer-XL怎样提升上下文长度
传统的Transformer模型中,上下文长度是固定的,主要有以下几个原因:
-
计算效率:在最初的设计中,Transformer模型是为了处理序列到序列的任务,如机器翻译。对于这类任务,输入序列(如源语言句子)和输出序列(如目标语言句子)通常具有相似的长度,因此固定上下文长度可以简化模型设计,提高计算效率。
-
模型复杂度:Transformer模型的核心是自注意力机制,该机制在计算时需要对序列中的每个元素进行成对的比较,以计算注意力权重。如果上下文长度不固定,那么每次添加或删除元素时,都需要重新计算整个序列的注意力权重,这会导致计算复杂度和内存需求急剧增加。
-
训练稳定性:固定长度的上下文可以提供稳定的训练环境,有助于模型学习到更加一致和可靠的表示。如果上下文长度不固定,模型可能需要在每次迭代中适应新的序列长度,这可能会影响训练的稳定性和模型的收敛速度。
-
硬件限制:在实际应用中,硬件资源(如GPU内存)是有限的。固定长度的上下文可以确保模型在任何时候都不会超出硬件资源的限制,从而避免因资源不足而导致的训练中断。
-
模型泛化:固定长度的上下文允许模型在训练时学习到特定长度范围内的依赖关系,这有助于模型在实际应用中泛化到类似的序列长度上。
然而,固定上下文长度也带来了一些限制,特别是在处理长序列时,模型无法捕获超过固定长度的依赖关系,这限制了模型在某些任务(如长文本生成和理解)上的性能。为了解决这个问题,Transformer-XL等模型通过引入新的机制来允许处理更长的上下文,从而在不牺牲计算效率的情况下捕获更长期的依赖关系。
国产开源公司月之暗面的大模型产品kimi,能够处理长达20万字的超长上下文,那么他是怎么做到的呢,核心是他的模型在Transformer的基础上做了扩展,实现了自己的Transformer-XL架构。
Transformer-XL通过引入两个关键的技术改进来提升token上下文长度的处理能力:片段递归机制(segment-level recurrence)和相对位置编码机制(relative positional encoding)。
-
片段递归机制:在传统的Transformer模型中,由于上下文长度是固定的,模型无法捕获超过预定义上下文长度的长期依赖性。Transformer-XL通过引入循环机制来解决这个问题。具体来说,它不再从头开始计算每个新片段的隐藏状态,而是重复使用之前片段中获得的隐藏状态,并将这些状态作为当前片段的“记忆”。这样,信息就可以在不同片段之间传递,从而捕获更长的依赖关系。这种机制允许模型在不引起时间混乱的前提下,超越固定长度去学习依赖性,同时解决了上下文碎片化问题。
-
相对位置编码机制:在Transformer-XL中,为了能够在不造成时间混乱的情况下重复使用状态,引入了相对位置编码的概念。相对位置编码与传统的绝对位置编码不同,它只编码token之间的相对位置关系,而不是token与固定起始点的绝对位置。这种编码方式使得模型能够在处理长序列时更有效地利用位置信息,并且可以泛化至比在训练过程中观察到的长度更长的注意力长度。
通过这两种机制,Transformer-XL显著提升了模型在处理长序列时的性能。
八、Transformer相关应用分享
使用BERT做掩词填充
BERT(Bidirectional Encoder Representations from Transformers)是一种预训练语言表示模型,由Google AI在2018年提出。BERT的核心创新在于利用Transformer架构的编码器部分来学习文本数据的深层次双向表示。这种表示能够捕捉到文本中词汇的上下文关系,从而在多种自然语言处理(NLP)任务中取得了显著的性能提升。
以下是BERT模型的一些关键特点:
双向上下文理解:与之前的单向语言模型不同,BERT通过在预训练阶段使用掩码语言模型(Masked Language Model, MLM)任务,学习了词汇在句子中的双向上下文信息。这意味着模型能够同时考虑一个词前后的词汇来理解其含义。
预训练和微调:BERT采用了两阶段的训练策略。在预训练阶段,BERT在大量文本数据上进行无监督学习,学习语言的通用模式。在微调阶段,BERT可以通过少量标注数据针对特定任务进行有监督学习,以适应各种NLP任务,如情感分析、问答系统、命名实体识别等。
Transformer架构:BERT基于Transformer的编码器部分,这是一种注意力机制(Attention Mechanism)的架构,它允许模型在处理序列数据时考虑序列中所有位置的信息。
大规模预训练:BERT在非常大的文本语料库上进行预训练,这使得模型能够学习到丰富的语言知识。预训练的规模和质量对模型性能有重要影响。
多样化的任务适应性:通过微调,BERT可以适应多种不同的NLP任务,而不需要对模型架构进行大的修改。这使得BERT成为了一个灵活且强大的工具。
BERT的推出标志着NLP领域的一个重大进展,它在多项NLP任务上刷新了记录,并催生了一系列基于BERT的改进模型,如RoBERTa、ALBERT、DistilBERT等。这些模型在不同的方面对BERT进行了优化,以提高性能、减少计算资源消耗或改善特定任务的表现。
以下是使用BERT做掩词填充的示例,输入一段文本,让模型预测出下一个被掩盖的词:
https://huggingface.co/google-bert/bert-base-uncased
使用BART做文本摘要
BART(Bidirectional and Auto-Regressive Transformers)是一种先进的自然语言处理(NLP)模型,它结合了BERT(Bidirectional Encoder Representations from Transformers)和GPT(Generative Pre-trained Transformer)的特点,用于文本理解和生成任务。BART模型特别擅长处理不同类型的文本噪声和序列变换,使其在多种NLP任务中表现出色。
设计原理和结构
BART是基于Transformer架构的自编码自回归模型。它通过两个主要步骤进行预训练:
-
使用任意噪声函数破坏文本(例如,随机打乱句子顺序、删除或遮蔽token)。
-
模型学习重建原始文本。
这种预训练方式使得BART能够有效地处理文本生成、翻译和理解等任务。BART的编码器是双向的,能够捕捉文本的前后文信息,而解码器是自回归的,能够基于前面的输出生成后续的内容。
应用
BART在多种NLP任务上取得了显著的成绩,包括但不限于:
-
文本摘要
-
机器翻译
-
对话生成
-
问答系统
-
文本分类
与其他模型的对比
与其他预训练模型相比,BART在处理文本生成任务时尤其出色。它在自然语言理解任务中也有很好的表现,与BERT和GPT等模型相比,BART在多个基准数据集上取得了竞争性或更好的结果。
预训练和微调
BART模型通过大量的文本数据进行预训练,然后在特定任务上进行微调。预训练阶段,模型学习如何从噪声文本中恢复原始文本,而微调阶段则是针对特定任务调整模型参数,以优化任务性能。
以下是使用BART做文本摘要的应用示例:
https://huggingface.co/facebook/bart-large-cnn
使用DistilBERT做问答
DistilBERT是一种轻量级的BERT模型,它通过知识蒸馏(knowledge distillation)技术从预训练的BERT模型中学习知识。这种方法的核心思想是使用一个较小的BERT模型作为“学生”模型,而原始的、较大的BERT模型则充当“教师”模型。在训练过程中,学生模型尝试复制教师模型的输出,以此来学习教师模型的知识。
主要特点和优势
模型大小和效率:DistilBERT的模型大小和参数量都比原始的BERT模型小,这使得它在资源受限的环境中(如移动设备)更加实用。它的推理速度也比BERT快,因为它需要处理的参数更少。
知识蒸馏:DistilBERT使用了一种称为“软目标”的知识蒸馏方法。在这种方法中,学生模型不仅学习来自训练数据的标签,还学习教师模型的输出,这些输出被视为附加的、软性的标签。
保持性能:尽管DistilBERT的模型大小减小了,但它仍然保持了与原始BERT模型相当的性能,特别是在自然语言理解任务上。
灵活性:DistilBERT保留了BERT模型的基本架构,包括Transformer的串联层,这使得它可以很容易地适应各种下游任务。
结构和训练
DistilBERT的结构相对简单,它仅保留了BERT的6层Transformer,删除了token type embedding和pooler层。在训练过程中,它使用了一种称为“模型压缩”的技术,通过这种方法,模型的层数被减半,同时从教师模型的层初始化学生模型的层。
应用场景
由于其较小的模型大小和较快的推理速度,DistilBERT适用于需要快速处理和低资源消耗的NLP任务,例如文本分类、情感分析、问答系统和语言模型等。
总的来说,DistilBERT是一个高效的BERT变体,它通过知识蒸馏技术实现了模型的压缩,同时保持了良好的性能,特别适合在资源受限的环境中使用。
以下是是使用DistilBERT做问答的实例:
https://huggingface.co/distilbert/distilbert-base-uncased-distilled-squad
使用T5做文本翻译
T5模型,全称为“Text-to-Text Transfer Transformer”,是由Google Research团队开发的一种自然语言处理(NLP)模型。T5模型的核心思想是将所有NLP任务统一转换为文本到文本(Text-to-Text)的格式,从而可以使用同一个模型和训练过程来处理多种不同的任务,如翻译、摘要、问答等。
主要特点和优势
统一的框架:T5模型通过将任务转换为文本到文本的格式,简化了不同NLP任务的处理方式。例如,对于翻译任务,输入可以是“translate English to German: [English text]”,输出则是翻译后的文本。
基于Transformer架构:T5模型采用了Transformer的encoder-decoder架构,这是一种高效的网络结构,特别适合处理序列数据。
预训练和微调:T5模型首先在大规模的数据集上进行预训练,学习语言的通用表示,然后可以针对特定任务进行微调,以优化任务性能。
广泛的应用场景:T5模型可以应用于多种NLP任务,包括但不限于文本分类、命名实体识别、情感分析、机器翻译和对话生成等。
高效的计算能力:T5模型的设计允许它高效地处理大规模数据集,并且具有强大的并行处理能力。
训练和应用
T5模型在训练时使用了一种称为“C4”的大规模数据集,这个数据集由经过清洗的Common Crawl数据组成。模型通过不同的预训练目标和策略进行训练,包括自回归、自编码和文本重排等。
在应用方面,T5模型的强大语言表示能力和广泛的应用场景使其成为NLP领域的一个重要工具。它可以通过微调来适应不同的领域和任务,从而在多个NLP任务上取得优异的性能。
T5模型通过其创新的Text-to-Text框架和基于Transformer的架构,在自然语言处理领域提供了一种新的解决方案,能够处理多种复杂的语言任务,并且具有很好的扩展性和适应性。
以下是使用T5做文本翻译的示例:
https://huggingface.co/google-t5/t5-base
使用GPT-2写小说
GPT-2(Generative Pre-trained Transformer 2)是由OpenAI开发的自然语言处理(NLP)模型,它是GPT系列模型的第二代。GPT-2在自然语言理解和生成方面表现出色,能够生成连贯、相关且多样化的文本。这个模型在发布时因其生成文本的质量和多样性而受到广泛关注。
主要特点和优势
大规模预训练:GPT-2通过在大规模的互联网文本数据集上进行预训练,学习到了丰富的语言模式和知识。这种预训练使得模型能够理解和生成自然语言文本。
Transformer架构:GPT-2基于Transformer模型架构,这是一种依赖于自注意力(self-attention)机制的深度学习架构,非常适合处理序列数据,如文本。
无监督学习:GPT-2采用无监督学习方法,通过预测下一个词的任务来预训练模型。这种训练方式不依赖于标注数据,使得模型能够学习到更广泛的语言知识。
生成能力:GPT-2特别擅长文本生成任务,能够生成连贯、有逻辑的段落和文章,甚至能够模仿特定的写作风格。
多样性:GPT-2能够处理多种语言任务,包括文本生成、翻译、问答、摘要等。
版本和规模
GPT-2有多个版本,不同版本之间主要区别在于模型的大小和参数数量。例如,最小的版本有1.17亿个参数,而最大的版本(GPT-2 1.5 Billion)有15亿个参数。随着模型规模的增加,性能和生成文本的质量也相应提高。
应用场景
GPT-2可以应用于多种场景,如聊天机器人、文本摘要、内容创作辅助、语言翻译等。它的生成能力使得在创意写作、新闻生成和其他需要自然语言生成的领域中具有潜在的应用价值。
挑战和限制
尽管GPT-2在生成文本方面表现出色,但它也面临一些挑战和限制,包括生成文本的偏见问题、事实准确性问题以及潜在的滥用风险。因此,OpenAI在发布GPT-2时采取了谨慎的态度,逐步放开对模型的访问权限。
总的来说,GPT-2是一个强大的NLP模型,它在文本生成和理解方面的能力使其成为自然语言处理领域的一个重要里程碑。
以下是使用GPT-2做文本生成的示例:
https://huggingface.co/openai-community/gpt2
完整的体验地址:https://transformer.huggingface.co/doc/gpt2-large
我们可以输入一段小说的开头,比如:As aliens entered our planet,然后Transformer就会依据我们输入的文本,自动脑补剩下的小说情节。
那Transformer是怎么做到的呢?如下图所示,Transformer在生成每一个token时,会参考前面所有的token,并生成与之相符的token,这样循环往复就能生成完整的一段内容。
九、参考文档
https://arxiv.org/pdf/1706.03762.pdf
https://jalammar.github.io/illustrated-transformer/
https://www.bilibili.com/video/BV1ih4y1J7rx
*文/逅弈
本文属得物技术原创,更多精彩文章请看:得物技术官网
未经得物技术许可严禁转载,否则依法追究法律责任!