自注意力详解:
- 预处理:将数据输入进行嵌入, 得到嵌入向量
- 获取三个向量:嵌入向量 与 三个矩阵(训练中的出来的) 相乘 分别得到 query 向量、key 向量、value 向量。如图1
- 分数计算:将当前位置的 query 向量 与各个位置的 key 向量 进行相乘得到。表示当前位置单词与其他单词的相关程度。如图2
- 分数处理: 将分数除以 (key向量维数的平方根), 然后进行softmax 。这个分数表示其他单词在这个位置的表达量。如图3
- 注意力的体现:如何体现注意力呢,将 value 向量分别乘上(或加上)softmax 分数。主要是为了增大对需要关注的词的关注度,减少无关词的关注度。
- 获取输出:对上一步的 所有单词的 结果进行加权求和 作为在当前位置的单词的输出。如图4
![](https://i-blog.csdnimg.cn/blog_migrate/a6d3c653d6bf70d74303cca627b507e5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/46c99d946418282bdc67a8cb7938868f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8ab4c33055ceec8975747f89e7a36dc6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c9d2d0be3914de7b06537ab05dfa92b1.png)
以矩阵方式进行运算可以将上面的步骤压缩两步即可:
- 首先获取三个向量矩阵,也即将嵌入后的向量 和 三个权重矩阵进行相乘 得到三个 矩阵 Q 、K、V
- 然后根据数学公式完成后面的步骤:
注意:权重矩阵 刚开始是随机初始化的
所谓多头自注意力:
就是 上面的的 自注意力有N个 在transformer 中默认是8个 ,也就是说 一层中有八组 q k v 权重矩阵。那么为什么要用多头呢? 此处先留个位置。。。。
有了八组 权重矩阵 ,在随机初始化后 进行训练,得到对应的权重矩阵各个 嵌入向量 经过输入 到对应的每一组自注意力 流程里面 会产生对应的Z0 Z1 Z2 ... 也就是各个的一个分数值。那么怎么样像是用单个头一样 输入到前馈神经网络层呢?这里的做法是将这8组 产生的结果进行连接 ,然后经过另外一个权重矩阵 转换成 对用维度的 Z ,再次输入到 前馈层。这里的另一个权重矩阵也是 在训练中不断的调整参数的。这个过程如图5,6
![](https://i-blog.csdnimg.cn/blog_migrate/d3e178bd492677c07c9ebd2fa9c0398c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5ce1bf0f2c1ff0a538669396e8aae442.png)
另一个重要的点:位置编码
为什么要进行位置编码呢 ? 是为了吧位置信息引入到 模型中,使得上面的一些权重矩阵可以学习到 相对的特征。
怎么引入位置编码呢?位置编码的模式又是怎样呢?
首先第一个,怎么引入,transformer模型中是直接对于每一个经过嵌入的 嵌入向量 加上一个 位置向量。这个位置向量是每一个词都有的,如图7。它是怎么来的呢,看下面
第二个就是 编码模式是怎样的,为了使得向量可以相加,对于单个词的位置向量的维度是512 维的 也就是说要和 嵌入向量维度相同。然后编码的话是经过正弦余弦得到对应的位置向量的。如图8, 是20个词的位置编码,前半部分是正弦获取的值,后半部分是余弦获取的值,连在一起就是位置向量了。当然这不是唯一的编码方式,这种好处就是可以编码很(超)长的位置。
![](https://i-blog.csdnimg.cn/blog_migrate/d03a7fbdb8e3e2af09d1d809c35953ed.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ac5d5e8f3521d6db06a86e0b76901df4.png)
残差:
这是 transformer 结构中的另外一个细节地方,残差的操作在每一个子层都有,也就是 自注意力层和前馈层中,同时是结合了normalize 同时进行的。是在 进行 自注意力操作之前 的向量 和 之后的向量相加 然后进行normalize操作。在前馈层同样也是这样的,如图9
![](https://i-blog.csdnimg.cn/blog_migrate/dc3ffede8df757b63920b1041e8ec09f.png)
值得注意的是运用在 解码器层的时候 ,这种思想是在 进行 encode-decoder attention 之前和之后,同样也进行了残差 和normalize 操作,如图10 ,也就是decoder#1 和decoder#2 分别表示 之前和之后,然后像上边那样进行残差和normalize
前面是主要讲了一些基本的操作,那么最主要的就是 怎么进行decode呢?
解码过程
主要是 : 每一个时间步骤都通过 编码器的输出得到一个词,并且在得到输出的词之后,在下一个时间步将这个词 喂入到解码器进行嵌入、位置编码、自注意力并且和 编码输出同时进行注意力操作,接着流经前馈神经网络层,最终输出这个时间步的词。以此循环,直到产生特殊的结束符号表示 输出已经完成,也就是这句话翻译完了。如图11 12
好像是图片太大,这里上传不到csdn服务器,这里直接放一个图片链接
https://jalammar.github.io/images/t/transformer_decoding_2.gif
下面是小尺寸的图,防止外链失效
注意:The “Encoder-Decoder Attention” layer works just like multiheaded self-attention, except it creates its Queries matrix from the layer below it, and takes the Keys and Values matrix from the output of the encoder stack.
接下来就是比较关键的步骤了,怎么把 decoder 出来的内容,转换成人类可读的词语。
线性回归和柔性最大值回归层。(翻译成对应的词)
作用是什么呢,线性层就是一个全连接层,将decoder出来的向量 映射到 一个词表大小的逻辑向量这里的每一个值都表示这个单词的分数。 接下来就是 softmax 层了,这个是将这个分数转换成概率,也就是词的概率,然后呢从这些单元中选择最大概率的,并且找到对应的词,这也就是解码出了输出的词。
如下图13
上面就是transformer的一些关键的地方了,有些地方只是说了怎么做的,具体做法的原因有些还不太清楚,欢迎有想法的同学一起讨论!vx : hpulfc
说的不够详细?没关系,原链接: