当前位置:首页 » 《休闲阅读》 » 正文

Transformer系列:图文详解Decoder解码器原理

6 人参与  2024年12月23日 18:02  分类 : 《休闲阅读》  评论

点击全文阅读


Encoder-Decoder框架简介

理解Transformer的解码器首先要了解Encoder-Decoder框架。在原论文中Transformer用于解决机器翻译任务,机器翻译这种Seq2Seq问题通常以Encoder-Decoder框架来解决,Transformer的网络结构也是基于encoder-decoder框架设计的。这种框架的模型分为两部分编码器Encoder和解码器Decoder,编码器负责将原文本数据编码为中间状态向量,该状态向量传递给解码器生成输出。示意图如下

Encoder-Decoder框架

以机器翻译场景为例,期望将某种语言的句子X翻译成另一种语言的句子Y,句子被表征为每个位置的字符id输入,则给定X=(x1,x2,x3,x4…)输入给模型,期望模型预测出Y=(y1,y2,y3,y4…),模型架构如下

机器翻译场景的Encoder-Decoder

编码器会对完整的输入句子通过各种复杂非线性变换生成State,代表原始输入被编码器编码之后形成的中间语义状态,形如公式

编码器输出中间语义向量

而解码器层需要融合解码器产出的中间状态State,和解码器已经生成出的信息Y1,Y2…Yi-1,来生成i时刻需要生成的单词Yi。

解码器融合解码器语义和历史解码信息

解码器是从第一个单词开始,逐位预测下一个单词,最终实现了从X翻译到Y的任务。

在实际网络中会在解码器中增加注意力机制,如果不添加注意力则对于任何位置Yi的预测中间状态state都是一样的,显然源文本中每个位置的字符应该和目标翻译文本各位置字符存在一定的对照关系,因此源文本的编码器state向量应该在每个位置对于当下要预测的Yi有不一样的权重分配,公式如下

带有注意力机制的Decoder

注意力机制工作的方式是将当下需要预测的单词位置的隐向量,和编码器输出的每个输入位置的状态向量,一一通过一个对齐函数(Attention)来计算目标单词和输入中某单词对齐的可能性大小,可能性越大赋予更大的权重,代表当下预测单词应该更加关注源文本中其对照单词的信息,最终中间状态向量state会给该对照单词位置处的分量给予更多的权重,从而更好地预测出该位置的目标单词。带有注意力机制的Encoder-Decoder示意图如下

带有注意力机制的Encoder-Decoder

shifted right移位训练

Transformer通过逐位依次预测完成Seq2Seq的任务。Transformer解码器结构如下

Transformer的解码器

右侧部分为Decoder解码器,将期望预测的目标文本添加start和end标识位置,底部将目标文本作为输入,顶部将目标文本右移一格(shifted right)作为预测输出,编码器的输出和输出是错位设计的,以编码器输入为“I love you”,解码器输出为“我爱你”为例,在训练过程中编码器的输入和预测目标分别为

错位训练

每次总是以前面已经出现的单词加上编码器的中间状态,来预测下一个单词,比如红色阴影部分使用"+我"来预测下一个单词“爱”,以此类推该条样本可以分为预测“我”,“爱”,“你”,“end”四个任务,Decoder的目标是输出“我”,“爱”,“你”,“end”四个位置的embedding,这四个任务的预测准确度作为整条样本的预测目标。

从输入输出的角度来看,""位置经过Decoder输出的向量embedding服务于“我”,"我"位置经过Decoder输出的向量embedding服务于“爱”,以此类推,当前词的Decoder结果用于预测它右边那个词的概率,这就是shifted right的体现,理解这点很重要。

理解shifted right错位训练

解码器的并行训练和串行预测

shifted right移位训练仅仅解决了预测目标的问题,移位训练实施起来比一般的分类任务要复杂,分为训练和预测两种场景。

在训练场景下答案数据集会提前给到,令一个批次数量为B,文本长度为L,输出embedding长度为D,我们只需要将前L-1的文本作为Decoder的输入,将后L-1的文本作为Decoder的预测目标即可,永远用前一个词的embedding来预测后一个词的概率分布,此时输入是[B,L-1,D],输出也是[B,L-1,D],再加上Transformer这种Self Attention天然地支持所有词并行输入训练,因此在训练场景可以将答案文本全局移位,然后全部一齐输入训练,考验模型在前词和更早之前的词确定的前提下,对后面一个词的预测能力,将一个完成的句子拆成一个个单词的预测任务。

在预测场景下不存在答案文本,只能从位置开始逐位预测,因此预测场景的解码器必定是串行的。将新预测的单词和历史预测单词合并作为解码器的输入来预测下一个新单词,重复这个过程直到预测结果为截止,预测阶段输入文本是一个一个单独输入的,同时会配合在此之前的历史预测单词完成自注意力机制。

预测阶段解码器串行工作方式

解码器自注意力层和掩码

解码器主要包含两个注意力模块,分别是自注意力层和交互注意力层,自注意力层是对历史已经预测的单词序列做特征表征,交互注意力层是融合历史预测单词序列和编码器输出的特征表征。在自注意力层有两个要点,首先Q,K,V在训练和预测阶段怎么分配,另外是它独有的下三角掩码。

Q,K,V在训练和预测阶段的分配

解码器的自注意力机制和编码器中的网络结构一致,都是基于Self Attention,通过原始embedding加上位置编码来作为Decoder的输入,自注意力层包含Q,K,V注意力计算,残差链接,层归一化,前馈传播模块,mask机制等。

解码器的自注意力机制在训练阶段Q,K,V相同,都是带有mask掩码的答案文本embedding,而在预测阶段由于只需要用Decoder的最后一维(也就是最后一个token)embedding做概率分布,因此只需要将当前前单词的信息作为Q,将当前词和之前所有的词的信息作为K和V,对最后一个token位置单独做Self Attention即可,如果这点难以理解请回看上一段的shifted right训练方式。

下三角掩码

在编码器中仅需要对padding位置进行掩码,因为padding位置的信息不需要带有权重去干扰有实词位置的embedding表征,而在解码器模块不仅要考虑padding导致的mask,还要考虑后词偷看问题。由于答案是一齐输入的,而实际的部署场景是步进预测的,理论上当前步长是看不到当前步长之后的词的信息的,解决方案是使用下三角掩码,将答案中当前位置之后的单词全部mask为0,这样答案文本依旧可以一齐输入,在Keras的Transformer源码中实现如下

令s为一个[batch_size,5,6]每个文本最大长度为5,每个单词映射维度为6,调用GetSubMask生成mask如下

def GetSubMask(s):      # TODO 生成一批下三角矩阵,就是斜对角线以下部分全是1      len_s = tf.shape(s)[1]      bs = tf.shape(s)[:1]      mask = K.cumsum(tf.eye(len_s, batch_shape=bs), 1)      return mask

令s为一个[batch_size,5,6]每个文本最大长度为5,每个单词映射维度为6,调用GetSubMask生成mask如下

>>> a = tf.reshape(tf.convert_to_tensor(list(range(30))), [1, 5, 6])  >>> GetSubMask(a)  >>> <tf.Tensor: shape=(1, 5, 5), dtype=float32, numpy=  array([[[1., 0., 0., 0., 0.],          [1., 1., 0., 0., 0.],          [1., 1., 1., 0., 0.],          [1., 1., 1., 1., 0.],          [1., 1., 1., 1., 1.]]], dtype=float32)>

该下三角掩码每一行代表当前位置,每一行的纵向只有当前位置和之前位置为1,代表自注意力使用该词,否则为0代表该词还看不到不能使用,以句子序列ABCD为例图示如下

下三角掩码

例如在计算C单词的自注意力表征的时候,只能使用候选的ABC三个词的V信息,C和D的注意力权重必须干预改成0。

掩码中1代表计算出的Q,K相似度保留原值,而0位置代表Q,K相似度改为一个极负的值,使得注意力权重为0,如图所示

下三角掩码对自注意力的影响

考虑到在训练过程中答案本身会进行该批次下的统一padding,因此还需要再叠加padding的mask掩码,杜绝padding单词对实词的表征影响,这个和编码器中的掩码一致,在源码中实现如下

# TODO 输出该批次下每个文本样本,在每个词步长下的mask向量,由于pad和词步长无关,所以每个步长下的mask向量相同,就是pad位置的是0  self_pad_mask = Lambda(lambda x: GetPadMask(x, x))(tgt_seq)  # TODO 只允许该词和该词前面的词纳入计算,下三角 [batch_size, seq_len-1, seq_len-1]  # TODO 输出该批次下每个文本样本,在每个词步长下的mask向量,由于是生成模型,只能基于当下词和前词进行计算,所以是个下三角  self_sub_mask = Lambda(GetSubMask)(tgt_seq)  # TODO 只要两个有一个为0则为0 mask掉  self_mask = Lambda(lambda x: K.minimum(x[0], x[1]))([self_pad_mask, self_sub_mask])

其中self_pad_mask为答案句子的padding掩码,对于答案中每个单词,该掩码是相同的,例如ABCD四个单词组成的答案,其中D词为padding,有词位置仅有ABC,则self_pad_mask如下

编码器层的padding掩码

源码使用K.minimum将两个掩码合并,每个位置取最小值,相当于两个掩码只要有任意一种情况需要被遮蔽则就应该被遮蔽,如图所示

解码器的自注意力最终掩码

通过掩码机制,并行输入整个文本得到的每个单词的自注意力表征和一个一个逐位循环预测进行的表征效果等同。

解码器交互注意力层和掩码

自注意力层是解码器输入自身的特征表征,而交互注意力层用到了编码器的输出,将Decoder和Encoder信息进行融合。交互注意力层和编码器中的注意力层网络结构基本没有差异,但是由于有两方进行交互因此Q,K,V的分配上需要单独设计,解码器交互注意力层的特写如下

交互注意力层

前文提到在Encoder-Decoder框架中会使用对齐函数来计算目标单词和编码器输出的每个单词对齐的可能性大小,而在Transformer中使用点乘注意力来作为对齐函数,解码器和编码器作为该对齐函数的输入,来比对当前解码器位置应该更多地关注哪个源文本位置,进一步将源文本信息携带到当前编码位置,因此解码器交互注意力层Q,K,V安排如下

Q:解码器自注意力层的输出

K:编码器的输出

V:编码器的输出

在训练之前需要对所有源文本和目标文本进行单独padding到最大长度seq_length,因此交互注意层计算的注意矩阵大概率不是一个方阵,计算示意图如下

交互注意力计算

以解码层的单词A为例,A需要融合编码器中的a,b,c,d四个单词的信息表征,其中得分权重分别为(3.2,1.3,0.9,-1),同样的交互注意力也需要mask掩码,掩码的维度和注意力权重矩阵维度相同,在源码中实现如下

def GetPadMask(q, k):      '''      shape: [B, Q, K]      '''      # TODO [batch_size, seq_len - 1] => [batch_size, seq_len - 1, 1]      ones = K.expand_dims(K.ones_like(q, 'float32'), -1)      # TODO [batch_size, 1, seq_len - 1]      mask = K.cast(K.expand_dims(K.not_equal(k, 0), 1), 'float32')      # TODO [batch_size, seq_len-1, seq_len-1],相当于对mask直接复制      # TODO 输出该批次下每个文本样本,在每个词步长下的mask向量,由于pad和词步长无关,所以每个步长下的mask向量相同,就是pad位置的是0      mask = K.batch_dot(ones, mask, axes=[2, 1])      return mask    # TODO 参数1决定步长,参数二决定pad  enc_mask = Lambda(lambda x: GetPadMask(x[0], x[1]))([tgt_seq, src_seq])

此处的掩码根据padding机制生成,其中GetPadMask的第一个参数tgt_seq决定文本步长,第二个参数决定padding的依据,显然使用了源文本的padding信息,例如在源文本abcd中d为padding位置,则mask矩阵如下

交互注意力掩码

代表解码器层中A,B,C都需要携带编码器中的a,b,c,d信息,但是A,B,C每个位置计算的时候都需要舍弃源文本中的d信息,因为d信息是padding的干扰项。

交互注意力层计算解码器输入每个单词位置相对于编码器源文本的表征,解码器每个输入本身通过下三角mask机制代表当前和之前位置信息,而编码器源文本是完整可见的,因此解码器每个位置都可以和全部编码器输出计算注意力,只需要主要编码器的padding部分在交互注意力的时候同样需要删除,源文本中的padding信息不能带入到解码器中,示意图如下

解码器中mask工作流程

解码器输出和损失函数

解码器经过自注意力层提取当前预测位置的表征,经过交互注意力层以当前预测位置的表征和编码器层的中间状态进行对齐,融合编码器中的信息到解码器中来,令该批次样本数为B,解码器最大文本长度为L,embedding维度为D,则解码器最终输出一个三维向量,维度为[B,L-1,D],其中L-1是在训练过程中使用错位训练策略导致。

Transformer在解码器的输出层加入线性层Linear使每个位置的embedding表征映射到预测词库中每个词的概率,以英文到德文翻译的数据集为例,输出为3665个样本中德文单词的得分,源码实现如下

target_layer = TimeDistributed(Dense(o_tokens.num(), use_bias=False))    # TODO decode out [batch_size, seq_len-1, 256]  dec_output = self.decoder(tgt_emb, tgt_seq, src_seq, enc_output, active_layers=active_layers)  # TODO final_output [batch_size, seq_len-1, 3665]  final_output = target_layer(dec_output)

因为错位训练的存在,L-1代表从源文本中除去之外,第2个单词到最后位置的信息表征,只需要将Linear的结果和实际的错位单词id进行比对即可计算该条样本的损失,源码中采用softmax交叉熵来计算每个L-1位置的loss,如果该位置实际为padding则忽略loss,最终采用所有实词位置的loss均值作为该样本的总损失,采用该批次的平均损失作为该批次的总损失。

零基础如何学习AI大模型

领取方式在文末

为什么要学习大模型?

学习大模型课程的重要性在于它能够极大地促进个人在人工智能领域的专业发展。大模型技术,如自然语言处理和图像识别,正在推动着人工智能的新发展阶段。通过学习大模型课程,可以掌握设计和实现基于大模型的应用系统所需的基本原理和技术,从而提升自己在数据处理、分析和决策制定方面的能力。此外,大模型技术在多个行业中的应用日益增加,掌握这一技术将有助于提高就业竞争力,并为未来的创新创业提供坚实的基础。

大模型典型应用场景

AI+教育:智能教学助手和自动评分系统使个性化教育成为可能。通过AI分析学生的学习数据,提供量身定制的学习方案,提高学习效果。
AI+医疗:智能诊断系统和个性化医疗方案让医疗服务更加精准高效。AI可以分析医学影像,辅助医生进行早期诊断,同时根据患者数据制定个性化治疗方案。
AI+金融:智能投顾和风险管理系统帮助投资者做出更明智的决策,并实时监控金融市场,识别潜在风险。
AI+制造:智能制造和自动化工厂提高了生产效率和质量。通过AI技术,工厂可以实现设备预测性维护,减少停机时间。

这些案例表明,学习大模型课程不仅能够提升个人技能,还能为企业带来实际效益,推动行业创新发展。

学习资料领取

如果你对大模型感兴趣,可以看看我整合并且整理成了一份AI大模型资料包,需要的小伙伴文末免费领取哦,无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发

在这里插入图片描述

部分资料展示

一、 AI大模型学习路线图

整个学习分为7个阶段
在这里插入图片描述
请添加图片描述

二、AI大模型实战案例

涵盖AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,皆可用。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三、视频和书籍PDF合集

从入门到进阶这里都有,跟着老师学习事半功倍。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

四、LLM面试题

在这里插入图片描述
在这里插入图片描述

五、AI产品经理面试题

在这里插入图片描述

?朋友们如果有需要的话,可以V扫描下方二维码联系领取~
在这里插入图片描述

?[CSDN大礼包?:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]?


点击全文阅读


本文链接:http://zhangshiyu.com/post/205836.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1