前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Transformer

Transformer

作者头像
mathor
发布2020-04-26 14:18:32
1K0
发布2020-04-26 14:18:32
举报
文章被收录于专栏:mathormathor

Transformer是谷歌大脑在2017年底发表的论文attention is all you need中所提出的seq2seq模型。现在已经取得了大范围的应用和扩展,而BERT就是从Transformer中衍生出来的预训连语言模型

这篇文章分为以下几个部分

  • Transformer直观认识
  • Positional Encoding
  • Self Attention Mechanism
  • 残差连接和Layer Normalization
  • Transformer Encoder整体结构

0. Transformer直观认识

Transformer和LSTM的最大区别,就是LSTM的训练是迭代的、串行的,必须要等以上一个字处理完,才可以处理下一个字。而Transformer的训练时并行的,即所有字是同时训练的,这样就大大增加了计算效率。Transformer使用了位置嵌入(Positional Encoding)来理解语言的顺序,使用自注意力机制(Self Attention Mechanism)和全连接层进行计算,这些后面会讲到

Transformer模型主要分为两大部分,分别是编码器解码器编码器负责把输入(语言序列)隐射成隐藏层(下图中第2步用九宫格代表的部分),然后解码器再把隐藏层映射为自然语言序列。例如下图机器翻译的例子

本篇文章内容仅限于编码器部分,即把自然语言序列映射为隐藏层的数学表达的过程。因为理解了编码器中的结构,再理解解码器就很简单了,最重要的是BERT也只用到了编码器的部分

上图为Transformer Block结构图,注意:下面的内容标题编号分别对应着图中1,2,3,4个方框的序号

1. Positional Encoding

由于Transformer模型没有循环神经网络的迭代操作, 所以我们必须提供每个字的位置信息给Transformer, 才能识别出语言中的顺序关系

现在定义一个位置嵌入的概念, 也就是Positional Encoding,位置嵌入的维度为[max sequence length, embedding dimension], 嵌入的维度其实与词向量的维度是相同的,max sequence length属于超参数, 指的是限定的最大单个句长

注意,我们一般以字为单位训练Transformer模型,首先初始化字向量为[vocab size, embedding dimension]vocab size为总共的字库数量,embedding dimension为字向量的维度

论文中使用了sin和cos函数的线性变换来提供给模型位置信息:

PE{(pos,2i)} = sin(pos / 10000^{2i/d_{\text{model}}}) \\ PE{(pos,2i+1)} = cos(pos / 10000^{2i/d_{\text{model}}})

上式中pos指的是一句话中某个字的位置,取值范围是[0, \ max \ sequence \ length)i指的是词向量的维度序号,取值范围是[0, \ embedding \ dimension)d_{\text{model}}指的是embedding\ dimension的总维度

上面有sincos一组公式,也就是对应着embedding \ dimension维度的一组奇数和偶数的序号的维度,例如0, 1一组, 2, 3一组,分别用上面的sincos函数做处理,从而产生不同的周期性变化,而位置嵌入在embedding \ dimension维度上随着维度序号增大,周期变化会越来越慢,最终产生一种包含位置信息的纹理,就像论文原文中第六页讲的,位置嵌入函数的周期从2 \pi10000 * 2 \pi变化,而每一个位置在embedding \ dimension维度上都会得到不同周期的sincos函数的取值组合,从而产生独一的纹理位置信息,从而使得模型学到位置之间的依赖关系和自然语言的时序特性

下面画一下位置嵌入,纵向观察,可见随着embedding \ dimension序号增大,位置嵌入函数呈现不同的周期变化

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math

def get_positional_encoding(max_seq_len, embed_dim):
    # 初始化一个positional encoding
    # embed_dim: 字嵌入的维度
    # max_seq_len: 最大的序列长度
    positional_encoding = np.array([
        [pos / np.power(10000, 2 * i / embed_dim) for i in range(embed_dim)]
        if pos != 0 else np.zeros(embed_dim) for pos in range(max_seq_len)])
    
    positional_encoding[1:, 0::2] = np.sin(positional_encoding[1:, 0::2])  # dim 2i 偶数
    positional_encoding[1:, 1::2] = np.cos(positional_encoding[1:, 1::2])  # dim 2i+1 奇数
    return positional_encoding

positional_encoding = get_positional_encoding(max_seq_len=100, embed_dim=16)
plt.figure(figsize=(10,10))
sns.heatmap(positional_encoding)
plt.title("Sinusoidal Function")
plt.xlabel("hidden dimension")
plt.ylabel("sequence length")
代码语言:javascript
复制
plt.figure(figsize=(8, 5))
plt.plot(positional_encoding[1:, 1], label="dimension 1")
plt.plot(positional_encoding[1:, 2], label="dimension 2")
plt.plot(positional_encoding[1:, 3], label="dimension 3")
plt.legend()
plt.xlabel("Sequence length")
plt.ylabel("Period of Positional Encoding")

2. Self Attention Mechanism

Attention Mask

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

但这时在进行softmax就会产生问题。回顾softmax函数\sigma(z)_i=\frac{e^{z_i}}{\sum_{j=1}^K e^{z_j}}e^0是1,是有值的,这样的话softmax中被padding的部分就参与了运算,相当于让无效的部分参与了运算,这可能会产生很大的隐患。因此需要做一个mask操作,让这些无效的区域不参与运算,一般是给无效区域加一个很大的负数偏置,即

$$ Z_{illegal}=Z_{illegal}+bias_{illegal}\\ bias_{illegal}→-∞ $$

3. 残差连接和Layer Normalization

残差连接

我们在上一步得到了经过注意力矩阵加权之后的V,也就是Attention(Q, \ K, \ V), 我们对它进行一下转置,使其和X_{embedding}的维度一致,也就是[batch size, sequence length, embedding dimension]​,然后把他们加起来做残差连接,直接进行元素相加,因为他们的维度一致:

X_{embedding} + Attention(Q, \ K, \ V)

在之后的运算里,每经过一个模块的运算,都要把运算之前的值和运算之后的值相加,从而得到残差连接,训练的时候可以使梯度直接走捷径反传到最初始层:

X + SubLayer(X)
Layer Normalization

Layer Normalization的作用是把神经网络中隐藏层归一为标准正态分布,也就是i.i.d独立同分布,以起到加快训练速度,加速收敛的作用

\mu_{j}=\frac{1}{m} \sum^{m}_{i=1}x_{ij}

上式中以矩阵的行(row)为单位求均值;

\sigma^{2}_{j}=\frac{1}{m} \sum^{m}_{i=1}(x_{ij}-\mu_{j})^{2}

上式中以矩阵的行(row)为单位求方差

LayerNorm(x)=\alpha \odot \frac{x_{ij}-\mu_{j}}{\sqrt{\sigma^{2}_{j}+\epsilon}} + \beta

然后用每一行的每一个元素减去这行的均值,再除以这行的标准差**,从而得到归一化后的数值,\epsilon是为了防止除0

之后引入两个可训练参数\alpha,\beta来弥补归一化的过程中损失掉的信息,注意\odot表示元素相乘而不是点积,我们一般初始化\alpha为全1,而\beta为全0

4. Transformer Encoder整体结构

经过上面3个步骤,我们已经基本了解到来Transformer​编码器的主要构成部分,我们下面用公式把一个​transformer block​的计算过程整理一下:

1). 字向量与位置编码

X = EmbeddingLookup(X) + PositionalEncoding

2). 自注意力机制

$$ Q = Linear(X) = XW_{Q}\\ K = Linear(X) = XW_{K}\\ V = Linear(X) = XW_{V}\\ X_{attention} = SelfAttention(Q, \ K, \ V) $$

3). 残差连接与Layer Normalization

$$ X_{attention} = X + X_{attention}\\ X_{attention} = LayerNorm(X_{attention}) $$

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

X_{hidden} = Activate(Linear(Linear(X_{attention})))

5). 重复3).

$$ X_{hidden} = X_{attention} + X_{hidden}\\ X_{hidden} = LayerNorm(X_{hidden}) $$

其中,

X_{hidden} \in \mathbb{R}^{batch \ size \ * \ seq. \ len. \ * \ embed. \ dim.}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. Transformer直观认识
  • 1. Positional Encoding
  • 2. Self Attention Mechanism
  • 3. 残差连接和Layer Normalization
    • 残差连接
      • Layer Normalization
      • 4. Transformer Encoder整体结构
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档