Transformer 万字讲解,超详细
本文详细讲解了Transformer模型的核心原理和实现过程。首先回顾了词嵌入(Word Embedding)的原理,包括如何通过降维和携带语义信息解决one-hot编码的问题。然后重点讲解了位置编码(Positional Encoding)的方法,通过三角函数为词向量添加位置信息。接着深入解析了Transformer的核心部分:注意力机制(Multi-Head Attention)的工作原理,包
小明:新的东西买了,那旧的呢?
你:
上一次,我单独讲了word embeding (词嵌入模型)的原理,这是我们开启Transformer之旅的重要一步:(没学过word embedding 的宝子们可以快速补充一下,点击这里:word embedding):如果实在不想看,可以看我下面的回顾
1.回顾:Word embedding
这里我简单对word embeding 进行回顾(为了保证我博客知识的完整性,我还是有必要回顾一下):
word embedding 处理的是对"词"的编码方式,目的是解决one-hot 编码所存在的问题:
one-hot 编码是简单的0 1编码:
因为one-hot 若要编码词汇(整个搜索引擎的海量词汇)必然会出现维度爆炸的问题,而且其存储的词向量组,构成的是 01稀疏矩阵,使我们保留了大量的无用信息
故我们需要对编码进行改进,我们改进有两个方向:1.降维,2.携带词义信息
1.降维:
上图我们用一个系数矩阵左乘(右乘也可以,这里目的是做变换)我们的词向量所组成的0 1矩阵 即可把向量从高维(这里是4维)降成低维(这里是2维), 如 [0,0,1,0] 它可以变为[c,C]
把这个公式用到网络中:
2.携带词义信息:
我们上面的系数矩阵可以是任意值,但是我们可以通过训练,来使我们的系数矩阵携带词义信息:
词义:即相同的类型的词可以有相似的结果(比如,"我需要关注" 和 "吾渴望关注")这里"我"和"吾"是词义相近的,"需要"和"渴望"是词义相近的,我们可以通过n维的坐标系来描述词的关系,而且相同的词的词向量是相似的(如下面第二张图)
训练网络达到系数矩阵携带语义的效果:
如图,我们左边第一层是我们上面提到的降维,我们主要看右边,
比如我们训练两句话:"我需要关注" 和 "吾渴望关注"
我们先用one-hot 编码"我","需要","关注","吾","渴望"这五个词
然后我们现在想要达到的效果是,在我们的one-hot 编码经过第一层网络的时候转化成低纬度的词向量(图中是h 词向量),这些词向量中"我"和"吾" ;"需要"和"渴望"的词向量是极度相似的
要想达到这样的效果,我们必须通过海量的语句来训练我们的系数矩阵,即在上图的第一层的W
so,这时候我们就可以知道我们的
input:是词的one-hot 编码 如"需要"--[1,0,0,0,0]
output:是下一个词的one-hot 编码 ,如"关注"--[0,1,0,0,0]
下一次训练时
input:是词的one-hot 编码 如"渴望"--[1,0,0,0,0]
output:是下一个词的one-hot 编码 ,如"关注"--[0,1,0,0,0]
这时候我们发现,我们如果网络训练好了的话,词需要"和"渴望"再次放到网络中是不是都可以得到"关注"? 就是说我们的第一层网络的W 已经具备了把具有相似词义的one-hot 编码的词转化成了低纬度而且高度相似的词向量,因为只有相似的向量才会得到相似的结果,(这里有种曲线救国的感觉)
所以我们知道右边第二层网络时干啥的了,就是辅助训练构建第一层的系数矩阵的
OK, Word embedding 回顾完毕,如果你还有一些疑惑,我在我的上一篇博客:word embedding 会的更详细一些
2.词序的嵌入
对于Word Embedding,在完成词向量训练后,我们主要使用第一层的系数矩阵。具体来说,在Transformer训练过程中,我们会将第一层的系数矩阵与独热编码相乘。
虽然这种方法明确了词与词之间的向量关系,能够将相似的词聚集在一起,同时区分不同的词,但它仅解决了词性的问题。实际上,句子中的词不仅包含语义信息,还具有位置特征。因此,我们需要为句子中的每个词嵌入位置信息,这样才能真正表达完整的句子结构。
比如: "我 在 走路" 这句话如果读入时不加入位置信息,则可能失序:"走路 在 我"
所以我们应该怎么在word embedding 上再次融合一个位置embedding呢?
很自然地,我们可以想到一个简单的方法:在词嵌入生成的低维向量基础上,直接叠加一个表示位置信息的向量
现在,假如说我们准备了一个词的one-hot 01 编码,我们把这个编码进行Word embedding,转化成了,低维并且可以携带词义信息的向量组:(如下图,我们下图的向量表示5个词,每个词我们有4个表示维度)

这里我还是要在强调一下:
1.重复强调内容
首先,我们一个全连接网络一次只能接收一个one-hot 编码的词向量来转化为word embedding 表示的向量

但是,对于一句话,也就是一个序列而言,我们的机器是可以并行的进行词嵌入Word embedding 操作的:

所以,在同一时间,我们就可以吧,一组0-1表示的one-hot 词向量组编码成对应的word embedding 词向量组:如,我现在想要训练一句话"CIty 不 CIty 呀 老铁"
我们首先是要做的就是并行的吧我们的01 one-hot 词向量代入我们的全连接里面然后就得到了我们的词嵌入结果:

OK ,现在我们把位置向量加进去,向量加法恒简单嘛,5个2维的词向量分别加入各自的位置向量即可:

那莫问题来了,我们如何定义位置向量呢?
2.引入
我们是这样想的,你想嘛,位置向量,就是定义词和词之间谁先谁后嘛,所以我位置信息岂不是可以用一个简单的顺序序列表示就可以了吗?
嗯,不错,但是,我们知道,还有一个问题就是,我们一个词向量他是N 维的,它携带了多维的信息,那么,我们的位置向量也必须是多维的顺序序列,
那么位置还能多维吗?这里就有点线性代数的韵味了,我们可以定义几个基向量,来描述不同维度下的向量信息,而这里我们位置序列采用了三角函数来描述不同维度,具体怎么做的呢?

如图,这是我们的Word Embeddding ,它首先进行乘以系数矩阵进行降维

我们一次类推,如上图把其他词也变成了二维,我们这时候我们从上往下看,我们可以知道我们需要给上面的词语组合,提供两个顺序,因为我们有两个维度

那这里我们采用,交叉sin cos 函数的形式来表示顺序的序列:

如上图所示,我们简单的将两个维度的顺序用三角函数进行了区分,
我们将上面的图片中,右边用函数生成的两个序列摘抄下来:

然后,我们就可以把这两个序列拼接起来:

OK,这就得到了我们的位置向量了,然后我们吧位置向量加到我们的word-embedding 上面去

上图,红色的部分表示sin 维度, 蓝色的部分表示cos 的维度:为了更好的表示顺序,关系,我把上面的都画出来:

OK,这样子我们的词语与词语之间就有了,先后的顺序了,
但是,啊,哈哈哈,但是,我刚刚描述的word embedding 之后的词向量是2维的,但是我们还可以是N
维度的,这时候简单的Sin 和 Cos 函数肯定不够用了呀,那我们可以调节sin 和 cos 的缩放系数来解决这个问题:
3.公式
这里我就可以正式介绍Sinusoidal functions :

我们用到的公式:

pos表示单词在句子中的位置,d表示PE的维度(与词Embedding一样),2i表示偶数的维度,2i+1表示奇数维度(即2i≤d,2i+1≤d)
注意上面有一个位置索引和维度索引,
位置索引是我的词序
维度索引是来描述词的维度的
假设我现在有一组Word Embedding 的向量组,而且每个向量组用4个维度表示,一共有五个词向量

我们可以对以上进行位置编码:
第一个向量是偶数位置:

以此类推:

以下是PE的矩阵值:(发现了没有,这里的PE矩阵是和wordEmbedding 的4*5 的矩阵是同型的都是4*5,想想这是为什么?想不通的话可以再次体会上面的公式 )

为了让这个矩阵的表示内容更清晰,我python 画了个图:

这4个图像(两个cos:(紫色,红色) 两个sin:(蓝色,绿色) )表示4个维度,和矩阵里面的值对应起来,是不是就通了?哈哈哈
OK,我们这时候就可以把我们的embedding矩阵+position了:

OK,OK了,家人们,这时候我们的词与词之间的顺序也解决了!!
OK,我们这时候已经通过Embedding解决了词意的关系,通过position解决了一句话或者序列中词与词之间的位置信息,这一系列操作之后,已经是我们完美的数据集input了,我们终于可以进入Transformer 的大门面见Transform er 大帝了

Transformer
1.引入:
我们先看一下整个transformer 整体是什么样子的:

我们之前解决了inputs(one-hot 01 编码)+input Embedding (Word Embedding)+Positional Encoding(词序的嵌入),就是下面我红色的部分

现在我们可以讨论其他的结构内容
2.注意力机制:
想一下,我们分析一句话的前提是知道每个词是什么意思,所以我们通过上学把词语学会,我们脑子里面就等于是进行了Word Embdding 的过程
后来,我终于可以读一句话了,我们开始接收到的是,词语词之间的顺序,这个放前面,这个放后面,可是就像你们做英语阅读一样,词我都认得,但是连起来成为一个句子我居然读不懂了
为什么?因为我们不懂的是这个词在这个句子里的语境是啥 (word Embedding 只是对词的词义进行了向量分类,比如近义词,反义词之类的,但是没有解决词在不同句子内的语义是什么)
so,我们Transformer 也一样,需要引入一套机制来解决这个问题
我们应该怎么定义词与词之间的关系呢?
我们从向量的角度出发因为我们的研究始终把我们的词当作一个向量去看待

上图是我们Word Embedding 之后的结果
当孤立地研究词语时,我们能够明确其所有含义,每个含义都对应词向量的一个维度。然而,当词语融入句子语境后,其意义会随语境(即该词与自身及句中其他词语的互动关系)而发生变化,产生引申义。从词向量的角度来看,这种变化表现为原始词向量在句中其他词向量的影响下发生了动态调整。

上图是词向量因为一个句子中的语境,而让我们的词向量产生了变化,而语境是没办法在Word Embedding 中完成的,需要我们不断通过句子去训练得到语境
怎么训练呢?
步骤1
通过计算词向量之间的相似度,即对每个词向量与其他所有词向量(包括自身)进行点积运算。

如上图所示,由于当前训练的是4字长的序列,因此需要进行4次相似度计算。在每次计算时,都会将当前字符与序列中的所有字符(包括自身)进行相似度比较.
为了完成我们上面的逻辑我们可以设计以下的结构来帮助我们完成上述的内容:

如图所示,我们在原有的词嵌入(Word Embedding)和位置编码(Position Encoding)结构基础上新增了三个分支:Query、Key 和 Value。
需要注意的是,Query、Key和Value本质上都是Word Embedding+Position Encoding结合后的词向量的进一步的变体。具体来说,原始的词向量[2.5,5.5]会分别与三种不同的2×2系数矩阵相乘(对应图中红、蓝、黑三色的连线,每条线代表一个权重),从而生成具有不同语义特征但仍表示同一词语的新词向量。
这些分支的设计旨在实现前文所述的相似度比对功能:
- Query:表示发起比对请求的一方
- Key:表示接收比对请求后,用于与请求方进行比对的一方
- Value:我们等会儿再探讨
比如说我现在我第二个词要和第一个词作比较(注意现在是第二个词要和所有词进行比较):如下图我们只需要将Key 表示的词向量与第二个词的query 进行点积操作即可最后得到了一个数值作为第二个词与第一个词的相似程度

而第二个词也需要和自己做比较:如下图也是恒简单,只需要用自己的query和自己的key进行点积即可

同理我们把所有和第二个词的相似度都进行计算:

上面这个图像太大了上传不了有点模糊,所以我多给你们发点:



上面是3种不同角度的:(为了简化我的画图工作量,所以我后面两个词与第一个词的数值相同,不过问题不大,因为有的句子肯定会有相同的词,哈哈哈,比如:"为所为为")
OK,我们上面的工作就是把第二个词与整个句子的相似度求了出来:

我们获得了4个相似度数值,这些数值是通过Key和Query的点积计算得出的("不"的query 分别与所有的词的Key 做点积)。点积是一种常用的向量相似度测量方法(原理很简单,不清楚的宝子可以百度一下)
步骤2
我们对相似度分数进行softmax归一化处理,然后将归一化后的权重分别与对应的Value向量相乘。最后将这四个加权后的Value向量相加,得到该词语在当前语境下的新词向量表示-->即第二个词语的注意力值。
概念softmax:Softmax 是一种归一化函数,将实数向量转换为概率分布。输入任意实数向量,输出每个元素的概率值,范围在 0 到 1 之间,且所有元素之和为 1
通过上面的讲解我们可以稍微理解:原来我们计算相似度是为了得到一组权值,我们用这组权值与四个词向量相乘 最后求和就得到了我们的新向量:

那么具体怎么做呢?我们的Value 就登场了:
我们首先将我们的softmax 把我们的相似度变成概率分布

然后我们的概率分布分别与对应的Value相乘

这样子我们就得到了4个value的缩放值
然后我们把这四个缩放值相加:

我们就终于得到了我们想要的结合句子语境的词向量!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

OK,这个就大功告成了,我们的网络只需要把K(key),Q(query),V(value) 的参数进行训练就可以得到更加切合很多句子的词向量,我们把这个过程叫做注意力机制训练
但是,在Transformer模型中,为了处理更复杂的多维特征学习,通常会设置多组Q、K、V参数。这些参数组首先进行并行计算,最终将计算结果进行拼接(concat)操作。我们将这个过程叫做:多头注意力(Multi-Head Attention)

如上图,我们设置多组K,Q,V 的参数,然后并行计算:最后把得到的注意力值进行拼接,具体的内容可以日后探索,日后我可能会出一个专门探讨各种改良注意力机制的博客
3.编码器和解码器
1.编码器Encoder:
1.结构解释:
还是来看看我们完成了Transformer 的哪些工作:

红色框框是我们解决的概念
接下来我将要解释图中的编码器(Encoder) 和 解码器(Decoder):

首先我们将我的输入的一句话称为序列:
首先我们将编码后的词向量放在Encoder Block 中进行计算:

如上图我们先并行的计算序列中所有的注意力值.
但是我们在训练参数的时候可以进行resnet 的方法来提高我们的性能,故我们可以进行残差连接:

注意:不了解Resnet 残差网络的宝子们不必担心,我们可以先往下去学,回来再补充这个知识点
想补充知识点可以看我的博客:ResNet(详细易懂解释):残差网络的革命性突破
这时候我们完成了Transformer Encoder的部分如下图:注意这里Transformer 用的是多头注意力(Multi-Head Attention)

最后因为我们的网络矩阵运算时,一个向量经过矩阵运算后值会越来越大,为了网络的稳定性,我们需要及时把值拉回正态分布,这时候就需要Normalization
我们这里采用的是Layer Normalization(横向规范化)
tips:这里的Normalization的内容我在我的博客里提到过,学完Transformer有兴趣可以去补充一下知识点:Normalization(归一化/标准化)的通俗讲解
如果你学过这个知识点,这里有必要说明一些问题:
- 为什么要用Layer Normalization 而不用batch Normalization?
答:Batch Norm 依赖稳定的 Batch,而 Transformer 的输入天生多变:要理解这一点,我们首先要明白 BN 和 LN 的根本区别:
- Batch Norm (BN):跨样本,同特征。它对一个 Batch 内所有样本的同一个特征维度计算均值和方差
- Layer Norm (LN):同样本,跨特征。它对单个样本的所有特征维度计算均值和方差。
在 NLP 任务中,推理时的 batch size 很可能为 1(比如你一次只翻译一个句子)。如果训练时用大的 batch size(如 32),推理时用 1,这个统计量会产生巨大差异,导致性能剧烈下降。而 Layer Norm 无论 batch size 是多少,计算方式完全一样,非常稳定
而且,NLP 中,一个 batch 内的句子长度通常不同。我们会对短句进行 Padding(填充 0)以达到统一长度,but!,BN 会把这些无意义的 Padding 值也计算进均值和方差里!这严重污染了统计量,使得归一化后的结果毫无意义
LN 在每个序列内部独立计算,Padding 通常在一个序列的末尾,它虽然也会被计算,但影响相对局部,并且可以通过引入 Mask(掩码)(这个技术这篇博客马上会提到)在计算时直接忽略这些 Padding 位置,从而得到干净、准确的统计量。
OK,我们对我们的训练的注意力向量组进行了残差连接和归一化,也就是我们Transformer模型中的add&Norm部分:

Nice ,我们已经把一句话进行了Q,K,V操作,计算出来了注意力,然后我们又优化了网络:add&Norm来使我们的训练效果最好:
2.矩阵数学解释:
为了以防万一,怕我解释的不清楚,我这里给出了矩阵的角度:
现在假设我有一句话:"你 吃 饭 了吗?"
我把这个话先one-hot 编码:

随后,通过word Embedding将one-hot编码降维处理,同时利用预先训练好的参数矩阵来保留词义信息。对应的实质就使左乘以一个系数矩阵A(A 是2*4的系数实矩阵):

然后我们进行位置编码:得到B的位置编码,然后与我们的矩阵相加

随后,我们进入注意力机制:

如上图,我们将得到的词向量组分别乘以3个分支的需要训练的系数矩阵得到Q,K,V 的词向量组矩阵
然后我们计算词向量之间的两两的相似度,对于我们的一句话(序列)来说,就是Q矩阵和K转置相乘会得到的是不同词向量的点乘结果,
随后通过softmax将相似度得分矩阵转换为概率矩阵,最终与V矩阵相乘,得到由注意力词向量组成的词向量矩阵。
OKOKOKOKOOk,至此,我们已经将句子输入网络。为了进行训练,我们需要优化W1、W2、W3参数,使注意力值更贴合每个句子的语境。
然后在参数训练过程中,我们采用残差连接(ResNet)和层归一化(Layer Normalization),即add&Norm操作,以优化网络性能,提升参数训练效果
最后,我们还差一个待解决的问题:
因为我们所有的训练,都是矩阵系数,但是这代表我们现在的网络使线性的,我们需要再引入一个非线性结构来适应我们更复杂的线性结果
3.非线性转换: Feed Forward

我们将得到的注意力向量组传入feed forward :Feed Forward 层比较简单,是一个两层的全连接层,第一层的激活函数为 Relu,第二层不使用激活函数,对应的公式如下:

让我们来拆解这个公式:
-
输入 x: 来自上一子层(经过自注意力和归一化后)的单个位置的表示向量。假设它的维度是
d_model。 -
第一层(扩展层):
-
x首先乘以权重矩阵W₁,其维度为(d_model, d_ff)。 -
d_ff是前馈网络的内层维度,它通常比d_model大得多。在原始论文《Attention Is All You Need》中,d_model=512,d_ff=2048。 -
这一步的作用是将向量从一个相对较小的空间投影到一个非常大的空间,相当于对特征进行了扩展和升维。
-
-
激活函数:
-
然后,对这个扩展后的向量应用一个非线性激活函数。在原论文中使用的是 ReLU,即
max(0, z)。 -
非线性激活是神经网络能够学习复杂函数的关键,它引入了模型的非线性表达能力。
-
-
第二层(收缩层):
-
激活后的结果再乘以权重矩阵
W₂,其维度为(d_ff, d_model)。 -
这一步的作用是将向量从大空间投影回原始的
d_model维度。 -
这是为了保持输入和输出的维度一致,使得残差连接可以顺利进行(
x + FFN(x)),并且可以被堆叠成多个编码器层。
-
所以在经过Feed Forward后,我们得到的还是原来维度的词向量,只不过是进行了非线性转后的词向量组
至此Encoder的部分我们结束了,我们得到的是一组词向量的矩阵,而且这个矩阵中的词向量已经具备了语义,还有线性非线性的复杂关系,是时候进入Decoder了!
2.解码器Decoder
让我先回到我博客开头的一句话:
小明:新的东西买了,那旧的呢?
小李:上**呀


这时候我如果问Transformer,"新的东西买了,那旧的呢" ,
开始没有训练的Transformer肯定回答不出来,
所以Transformer 从我们这里问道了答案:"上**呀"
然后Transformer 把上一句话:"新的东西买了,那旧的呢?"作为input
我们首先对这句话进行词嵌入处理,随后加入位置嵌入信息,接着执行Q,K,V操作生成注意力向量组,再进行非线性转换,最终得到Encoder的输出。
然后,我们把下语句话带入解码器decoder ,指导我们的Decoder 得到正确的输出.
然后下一次你再问Transformer,你把"新的东西买了,那旧的呢?"带入input,Transformer 会根据之前训练的Q,K,V参数得到词向量的注意力词向量,然后我们的解码器会开始Encoder的注意力向量生成一个输出矩阵,最后通过全连接得到我们的答案:"上**呀"
那具体是怎么训练Decoder的呢?:
1.开始和结束符:
在我们看来,一句话就是表达的内容。但对机器而言,每句话必须明确界定起始和结束。因此,我们需要为每个语句序列添加开始符和结束符来标识输出范围。虽然之前没有提及,但现在需要补充说明:处理自然语言时,必须为每个语句添加开始和结束标记。
它们通常被称为:
-
<s>或[BOS]: 开始符 -
</s>或[EOS]: 结束符
所以说我们transformer接受到的一句话应该是这样子的:
"[BOS]新的东西买了,那旧的呢[EOS]"
为了便于理解,我在示例中同时保留了开始符和结束符,尽管部分设计可能会省略开始符而仅保留结束符。
开始符和结束符在我们的编码器里面可能显得不会那么重要,但是对于我们解码器来说,它却是非常重要的,因为在解码器中生成句子时,通常从起始符或结束符开始生成。为了便于理解,这里选择从起始符开始生成,当然从结束符开始生成也是可行的
在Decoder生成句子时,具体流程是怎样的?假设我们从起始符开始,期望下一个生成的字符是"上"。若已正确生成当前词向量,那么下一个词向量应为"转转",接着再生成"呀"。图示:

我们发现当"呀"后面生成EOS(停止符)时,transformer模型检测到这个停止符就会自动停止。
2.具体原理:
我们decoder里面主要有两个重要角色,一个是老师,一个是自己生成句子的学生
老师:他已经拿到了,我要生成句子的答案 它的作用就是在transform decoder里面不断纠正我们生成的内容
学生:就是不断生成句子的注意力机制 ,和我们在encoder里面的结构是十分相似的:
图示:

如上图,学生在开始生成句子之前,他虽然不知道怎么生成,但是他知道第一个字符肯定是开始字BOS
左图展示了编码器中的序列。为了简化图示,仅模拟了向量A与各向量的相似度比较过程。实际上,还包括向量A与各向量的相似度比较,以及起始字符和终止字符与各向量的相似度比较。
在decoder阶段,学生应该如何生成句子呢?我们可以模仿encoder中的相似度比较过程。初始阶段,bus向量只能与自身进行比较,随后再与encoder中的所有向量进行相似度计算。
请注意,此时Encoder中的词向量已完成训练。这些词向量经过QKV操作、feedforward线性转换的处理,目前已具备上下文语境关系。我们现在使用的是包含上下文关系的编码器词向量,与解BOS"的词向量进行相似度计算。[注意力词向量和没有训练过的词向量是同维度的(这个理解之前的原理后很清楚),所以放心的计算就行]

我们会对BOS字符进行Q,K,V的操作,最终 BOS(开始符)会输出一个注意力词向量。该词向量随后通过全连接层处理,生成下一个预测值C。

如图所示,BOS生成注意力值后(我们假设Q,K,V注意力操作后生成的是二维的词向量),首先通过全连接层将二维数据转换为四维,以匹配先前one-hot编码的维度。随后经过softmax处理转换为概率分布,最终从中选取概率最高的预测值。结果显示a和c的概率最高,其中c的概率更大,因此最终预测值为c。
这相当于将word embedding编码网络逆向处理,从低维转换为高维。之所以采用one-hot编码,是因为它能让人直观地识别每个编码对应的具体对象。
接下来,我们将BOS生成的词向量C的one-hot,作为第二个字符的输出,。假设生成的字符"c"是正确的,并且经与老师核对后确认无误。此时,我们需要对字符"c"进行相似度比较。需要注意的是,这里的比较是将编码器(encoder)的向量与解码器(decoder)生成的所有词向量进行对比。如下图所示

以此类推,我们把c也生成了相应的注意力的词向量,然后同样进行全连接操作,得到下一个字符D.
但是如果c向量生成错误呢?
错误的词向量,此时不会作为下一个位置的输入,而老师会把正确的词作为输入输到下一个词:
如图所示,错误的词向量不会作为下一个位置的输入,而是采用老师提供的正确答案。这样做是为了确保每个位置都能生成正确的向量,避免前一个位置的错误影响当前生成结果。
而错误的词向量会通过与教师词向量的比较来计算误差,随后进行反向传播,以优化Q、K、V参数以及前馈网络: Feed Forward中的相关参数。
因此,我们的学习者(即解码器)在生成错误词向量的过程中会持续优化参数,通过逐步减小误差来提升性能,从而确保后续词向量的准确生成。
要判断句子何时结束,我们之前提到过,可以通过EOS(End Of Sentence)标记来实现。例如,当词向量E预测的下一个词是EOS时,就表示句子已经结束,此时解码过程也会随之终止。
然后要实现上面的原理,我们就直接可以看我们的transformer的架构:
在实际的Transformer模型中,encoder和decoder之间的相似度比较并非同步进行(为了解释清楚原理我上面才放到一起说的)。具体流程是:首先对decoder生成的向量组中所有向量进行相似度计算,得到注意力向量;然后将其与encoder产生的注意力向量进行相似度比对。具体如下图:

而我将遵循Transformer 里面的结构来讲下面的实现问题:
3.实现:
我在重新引进一个概念:在encoder中的相似度比较称为注意力机制,而decoder部分则涉及已生成的词向量集合之间的比较,即自注意力机制。因此,在生成过程中,注意力机制由两部分组成:一部分是与encoder向量的相似度比较,另一部分是与已生成的decoder词向量之间的比较(自注意力)。
1.自注意力机制:
自注意力机制(即前文所述的方法)通过对编码器生成的词向量进行相似度计算来实现。
图示:
在初始阶段,当输入是BOS时,BOS只能进行与自己相似度计算。当正确输出C后,模型会将C与BOS及自身进行比较。同理,输出D时,模型会与BOS、C及自身进行对比。
那我们想一下,我们在编码器Encoder的时候是如何进行相似度比较呢?我们是算出了此向量组的k和v,然后将它们相乘
回顾的图示:
通过将编码器中的两个矩阵相乘,可以计算出每个词向量两两点积后的相似度值,并输出为结果矩阵。
我们的解码器也可以采用类似方法,但存在一些细节差异:生成的QK矩阵需要通过掩码机制来屏蔽未来待预测的值。

假设我们采用类似编码器的方法,获得了相似度矩阵(即QK^T矩阵)。如上图所示,该矩阵的对角线元素表示各元素自身的相似度点积(a1a1,b1b1,c1c1)。观察矩阵右上角部分可以发现,例如a1b1代表a1与b1的点积,即当前词与其后一词的相似度计算。然而这种情况在实际运算中是不可能发生的,因为在计算相似度时,我们无法获取到后续预测值的信息。因此,需要通过掩码机制将该区域屏蔽处理。

如下图所示,我们采用零填充的方式(或者负值填充)处理相似度值。这样在进行softmax计算后,相应的概率值会变为零。这意味着该位置不会对生成的自注意力向量产生任何影响,因为其权重为零。
OK,这样子我们就解决了自注意力机制问题:也就是下面图中的Masked Muti-Head Attention

现在你应该已经理解了,我们已经解决了自注意力问题。接下来只需将自注意力向量与编码器中的向量进行相似度比较即可。
总结:
此时,相信你通读了博客应该已经了解到了Transformer 的实现过程,总结就在下面的图中,亲细细品味(绝对不是因为我不带写总结了,哈哈哈哈哈)

这篇博客写了12000字,希望读完博客觉得不错的话,点个关注和赞吧!!谢谢!满足一下我的输出型人格,神经网路都要一个正反馈,我要一个关注不过分吧,嘤嘤嘤



火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐






所有评论(0)