Transfomer详解

0 直观理解

Transformer 和 LSTM 的最大区别,就是 LSTM 的训练是迭代的、串行的,必须要等当前字处理完,才可以处理下一个字。而 Transformer 的训练时并行的,即所有字是同时训练的,这样就大大增加了计算效率。
Transformer 模型主要分为两大部分,分别是 Encoder 和 Decoder。Encoder 负责把输入(语言序列)隐射成隐藏层,然后解码器再把隐藏层映射为自然语言序列。
本文主要介绍Encoder结构,Decoder内容大致相同

1 Positional Encoding

对于输入X,维度为[batch_size,sequence_length],sequence_length为句子长度。然后首先经过Embedding为每个字生成长度为embedding dimmension的词向量。

由于 Transformer 模型没有循环神经网络的迭代操作,所以我们必须提供每个字的位置信息给 Transformer,这样它才能识别出语言中的顺序关系。现在定义一个位置嵌入的概念,也就是 Positional Encoding,位置嵌入的维度为 [max_sequence_length, embedding_dimension], 位置嵌入的维度与词向量的维度是相同的,都是 embedding_dimension。max_sequence_length 属于超参数,指的是限定每个句子最长由多少个词构成。

一般以字为单位训练 Transformer 模型。首先初始化字编码的大小为 [vocab_size, embedding_dimension],vocab_size 为字库中所有字的数量,embedding_dimension 为字向量的维度,论文中使用了 sin 和 cos 函数的线性变换来提供给模型位置信息:

上式中pos指的是一句话中某个字的位置,取值范围是[0,max_sequence_length] , i i i指的是字向量的维度序号,取值范围是[0,embedding_dimension/2], d m o d e l d_{model} dmodel指的是 embedding_dimension​的值。位置嵌入在 embedding_dimension​维度上随着维度序号增大,周期变化会越来越慢,最终产生一种包含位置信息的纹理。

2 Self Attention

在进行positional encoding后,得到的结果于输入的维度相同,均为[batch_size,sequence_length,embedding_dimension],因此将positional encoding的输入与输出相加,得到该字的真正向量表示,第t个字的向量记做 x t x_t xt

然后定义三个矩阵, W Q W_Q WQ, W K W_K WK, W V W_V WV,使用这三个矩阵分别对所有的字向量进行三次线性变换,于是所有的字向量又衍生出三个新的向量, q t q_t qt, k t k_t kt, v t v_t vt,将所有的 q t q_t qt向量拼为一个大矩阵,记为查询矩阵 Q Q Q。将所有的 k t k_t kt向量拼为一个大矩阵,记为键矩阵 K K K。将所有的 v t v_t vt向量拼为一个大矩阵,记为值矩阵 V V V

step 1:字向量又衍生出三个新的向量, q t q_t qt, k t k_t kt, v t v_t vt

step 2:为了获得第一个字的注意力权重,我们需要用第一个字的查询向量 q 1 q_1 q1乘以键矩阵 K K K

            [0, 4, 2]
[1, 0, 2] x [1, 4, 3] = [2, 4, 4][1, 0, 1]

step 3:将得到的结果经过softmax,使和为1

softmax([2, 4, 4]) = [0.0, 0.5, 0.5]

step 4:得到权重之后,将权重分别乘以对应的字的值向量 v t v_t vt

0.0 * [1, 2, 3] = [0.0, 0.0, 0.0]
0.5 * [2, 8, 0] = [1.0, 4.0, 0.0]
0.5 * [2, 6, 3] = [1.0, 3.0, 1.5]


step 5:最后将这些权重化后的值向量求和,得到第一个字的输出

[0.0, 0.0, 0.0]
+ [1.0, 4.0, 0.0]
+ [1.0, 3.0, 1.5]
-----------------
= [2.0, 7.0, 1.5]


对其它的输入向量也执行相同的操作,即可得到通过 self-attention 后的所有输出。

3 通过矩阵计算简化self-attention

上面介绍的方法需要一个循环遍历所有的字 x t x_t xt,我们可以把上面的向量计算变成矩阵的形式,从而一次计算出所有时刻的输出。
第一步就不是计算某个时刻的 q t q_t qt, k t k_t kt, v t v_t vt了,而是一次计算所有时刻的 Q Q QK K KV V V 。计算过程如下图所示,这里的输入是一个矩阵 X X X,矩阵第 t行为第
个词的向量表示。

接下来将 Q Q QK T K^T KT相乘,然后除以 d k \sqrt{d_k} dk

(这是论文中提到的一个 trick, d k d_k dk是Q、K的列数),经过 softmax 以后再乘以 V V V得到输出。

4 Multi-Head Attention

前面定义的一组 Q Q QK K KV V V可以让一个词 attend to 相关的词,我们可以定义多组 Q Q QK K KV V V,让它们分别关注不同的上下文。计算 Q Q QK K KV V V的过程还是一样,只不过线性变换的矩阵从一组( W Q W^Q WQ, W K W^K WK, W V W^V WV)变成了多组( W 0 Q W^Q_0 W0Q, W 0 K W^K_0 W0K, W 0 V W^V_0 W0V)、( W 1 Q W^Q_1 W1Q, W 1 K W^K_1 W1K, W 1 V W^V_1 W1V),…如下图所示

对于输入矩阵 X X X,每一组 Q Q QK K KV V V都可以得到一个输出矩阵 Z Z Z。如下图所示

5 Padding Mask

上面 Self Attention 的计算过程中,通常使用 mini-batch 来计算,也就是一次计算多句话,即 X X X的维度是 [batch_size, sequence_length],sequence_length​是句长,而一个 mini-batch 是由多个不等长的句子组成的,我们需要按照这个 mini-batch 中最大的句长对剩余的句子进行补齐,一般用 0 进行填充,这个过程叫做 padding。
但这时在进行 softmax 就会产生问题。

因为 e 0 e^0 e0等于1,是有值的,这样的话 softmax 中被 padding 的部分就参与了运算,相当于让无效的部分参与了运算,这可能会产生很大的隐患。因此需要做一个 mask 操作,让这些无效的区域不参与运算,一般是给无效区域加一个很大的负数偏置,即

6 残差连接和Layer Normalization

在上一步得到了经过 self-attention 加权之后输出,也就是 S e l f − A t t e n t i o n ( Q , K , V ) Self-Attention(Q,K,V) SelfAttention(Q,K,V),然后把他们加起来做残差连接:

Layer Normalization 的作用是把神经网络中隐藏层归一为标准正态分布,也就是 i . i . d i.i.d i.i.d独立同分布,以起到加快训练速度,加速收敛的作用:
先用矩阵的列为单位求平均值(即每一列一个平均值):

再用矩阵的列求方差(即每一列一个方差):

最后用每一列的每一个元素减去这一列的均值,再除以这一列的标准差,从而得到归一化后的数值,加 ϵ \epsilon ϵ是为了防止分母为0。

上图是Batch Normalization与Layer Normalization的区别,Batch Normalization是以行为单位,均值与方差的数量与训练样本数相同;Layer Normalization则以列为单位,均值与方差的数量与特征维数相同。

下图展示了更多细节:输入 x 1 x_1 x1x 2 x_2 x2经 self-attention 层之后变成 z 1 z_1 z1z 2 z_2 z2,然后和输入 x 1 x_1 x1x 2 x_2 x2进行残差连接,经过 LayerNorm 后输出给全连接层。全连接层也有一个残差连接和一个 LayerNorm,最后再输出给下一个 Encoder(每个 Encoder Block 中的 FeedForward 层权重都是共享的)

7 Transfomer Encoder的整体结构

经过上面的步骤,已经基本了解了 Encoder 的主要构成部分,下面我们用公式把一个 Encoder block 的计算过程整理一下:
(1)字向量与位置编码

(2)自注意力机制

(3)self-attention 残差连接与 Layer Normalization

(4)下面进行 Encoder block 结构图中的第 4 部分,也就是 FeedForward,其实就是两层线性映射并用激活函数激活,比如说Relu

(5) FeedForward 残差连接与 Layer Normalization

8 Transformer Decoder整体结构

我们先从 HighLevel 的角度观察一下 Decoder 结构,从下到上依次是:
↓ \downarrow Masked Multi-Head Self-Attention
↓ \downarrow Multi-Head Encoder-Decoder Attention
↓ \downarrow FeedForward Network
和 Encoder 一样,上面三个部分的每一个部分,都有一个残差连接,后接一个 Layer Normalization。Decoder 的中间部件并不复杂,大部分在前面 Encoder 里我们已经介绍过了,但是 Decoder 由于其特殊的功能,因此在训练时会涉及到一些细节

9 Masked Self-Attention

具体来说,传统 Seq2Seq 中 Decoder 使用的是 RNN 模型,因此在训练过程中输入t时刻的词,模型无论如何也看不到未来时刻的词,因为循环神经网络是时间驱动的,只有当t时刻运算结束了,才能看到t+1时刻的词。
而 Transformer Decoder 抛弃了 RNN,改为 Self-Attention,由此就产生了一个问题,在训练过程中,整个 ground truth 都暴露在 Decoder 中,这显然是不对的,我们需要对 Decoder 的输入进行一些处理,该处理被称为 Mask。

举个例子,Decoder 的 ground truth 为 “ I am fine”,我们将这个句子输入到 Decoder 中,经过 WordEmbedding 和 Positional Encoding 之后,将得到的矩阵做三次线性变换( W Q W^Q WQ, W K W^K WK, W V W^V WV)。然后进行 self-attention 操作,首先通过 Q ∗ K T d k \frac{Q*K^T}{\sqrt{d_k}} dk

QKT得到 Scaled Scores,接下来非常关键,我们要对 Scaled Scores 进行 Mask

举个例子,当我们输入 “I” 时,模型目前仅知道包括 “I” 在内之前所有字的信息,即 “” 和 “I” 的信息,不应该让其知道 “I” 之后词的信息。道理很简单,我们做预测的时候是按照顺序一个字一个字的预测,怎么能这个字都没预测完,就已经知道后面字的信息了呢?Mask 非常简单,首先生成一个下三角全 0,上三角全为负无穷的矩阵,然后将其与 Scaled Scores 相加即可。

之后再做 softmax,就能将 - inf 变为 0,得到的这个矩阵即为每个字之间的权重

Transfomer详解相关推荐

  1. AI艺术的背后:详解文本生成图像模型【基于GAN】

    系列文章链接: AI艺术的背后:详解文本生成图像模型[基于 VQ-VAE] AI艺术的背后:详解文本生成图像模型[基于GAN] AI艺术的背后:详解文本生成图像模型[基于Diffusion Model ...

  2. 人工智能里程碑ChatGPT之最全详解图解

    人工智能里程碑ChatGPT之最全详解图解 1. ChatGPT的前世今生 1.1 ChatGPT演化路线 1.2技术推进路线 2.ChatGPT主要功能及应用领域 2.1 主要功能 2.2 应用领域 ...

  3. 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)

    首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...

  4. JVM年轻代,老年代,永久代详解​​​​​​​

    秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...

  5. docker常用命令详解

    docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...

  6. 通俗易懂word2vec详解词嵌入-深度学习

    https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...

  7. 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法

    深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...

  8. CUDA之nvidia-smi命令详解---gpu

    nvidia-smi是用来查看GPU使用情况的.我常用这个命令判断哪几块GPU空闲,但是最近的GPU使用状态让我很困惑,于是把nvidia-smi命令显示的GPU使用表中各个内容的具体含义解释一下. ...

  9. Bert代码详解(一)重点详细

    这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretr ...

最新文章

  1. 语义分割--Understanding Convolution for Semantic Segmentation
  2. Delphi 中的 XMLDocument 类详解(5) - 获取元素内容
  3. 国内主流IT公司Field Sales销售薪资 来自著名猎头公司内部信息 给IT的朋友们知道个行情 - 天涯...
  4. 虚拟主机1服务器,虚拟主机1服务器
  5. linux下获取线程号
  6. java如何分页_java中分页的实现
  7. SwiftUI优秀文章经典案例制作简易的新闻列表Demo
  8. 简化springboot部署,太灵活方便了!
  9. phpcmsV9 邮箱注册:邮箱验证(不改代码、含演示截图) - 配置篇
  10. .NET Core 3.0带来桌面支持(Windows Only)
  11. 手摸手带你入门ionic3(六):界面跳转
  12. XCODE中,修改苹果APP支持哪些设备
  13. win7保护视力的电脑设置
  14. labview 游戏 打地鼠
  15. 智能家居系统各个硬件模块功能代码实现
  16. 小X与神牛(dfs)
  17. 联盟链系列 - RootCA颁发证书
  18. java皮丘 博客园,又一个设计工具 Framer X Preview
  19. 用java实现判断回文
  20. 练习题(困难) 百慕大三角 POJ1069

热门文章

  1. Manjaro、ArchLinux 网易云音乐无法启动修复记录
  2. 2020的Android凉了?聊聊 Android 现状及出路!
  3. 手写算法-python代码实现Ridge(L2正则项)回归
  4. wish新店快速出单的方法
  5. 3.1、立项管理内容
  6. 超实用的 Vue 组件通信方式大汇总(8种)
  7. Java 将txt文本文档转换为excel
  8. 记一次COLA架构的实践
  9. SparkCore核心机制详解
  10. Unix/Linux下的Curses库开发指南——第二章 curses库I/O处理