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 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。