Transformer 的工作原理

要想了解BERT,首先需要掌握他的基本结构Transformer.因为BERT的Encoder就是Transformer
自然语言处理中,有三种特征处理器(就是特征抽取器):卷积神经网络、递归神经网络和后起之秀 Transformer。
这一篇《带你全面认识自然语言处理三大特征抽取器(CNN/RNN/TF)》用诙谐幽默而通俗易懂的语言介绍了上面三种特征处理器。
我们首先对整个BERT的信息流的传递,然后深入encoder的输入输出。
其次我们将分析每一个encoder blocks,并理解Multi-Head Attention.

Information Flow

The data flow through the architecture is as follows:

  1. 模型将每一个token表示为emb_dim大小的向量,给每一个输入token都嵌入为(embedding)一个向量,我们就得到一个特定的输入序列(input sequence),具体为 (input_length) x (emb_dim) 大小的矩阵。
  2. 然后添加位置信息进行位置编码,这一步返回大小(input_length) x (emb_dim)的矩阵。
  3. 数据经过N个encoder blocks后我们得到大小(input_length) x (emb_dim)的矩阵。

步骤1,2,3如下图所示:
在这里插入图片描述
注意,下一个encoder block的输入和上一个encoder block的输出是一样的,每个blocks两两之间无权重。

2 From words to vectors

2.1 Tokenization, numericalization and word embeddings

上图红色区域就是Tokenization, numericalization and embeddings发生的地方。

对于一个语料库中的一个句子:

1“ Hello, how are you?” 2 3

第一步是tokenize it:

1“ Hello, how are you?” → [“Hello”, “,” , “how”, “are”, “you”, “?”] 2 3

第二步是对其数值化numericalization(将上面的每一个token映射成一个语料库词汇表中互不重复的整数)

1[“Hello”, “, “, “how”, “are”, “you”, “?”][34, 90, 15, 684, 55, 193] 2 3

这样我们就得到了一组经过embedding每一个单词后的序列了。 序列中的每一个单词都被映射为emb_dim维度的向量(找一下公式)提供给模型训练学习。
向量中的元素作为模型的参数,在反向传播的过程中得到优化。

所以,对每一个token,我们可以查找到对应的向量:

将所有向量stacking起来,就得到了大小(input_length) x (emb_dim)的矩阵Z: 另外,对于一个batch中的若干输入序列sequences,我们需要保证它们的长度一致,这可以通过对一些长度不足的sequence添加token < pad > 比如上面的序列长度为6,若我需要将其变成9,就需要:

1[<pad>”, “<pad>”, “<pad>”, “Hello”, “, “, “how”, “are”, “you”, “?”][5, 5, 5, 34, 90, 15, 684, 55, 193] 2 3

2.2 Positional Encoding

尽管我们能找到一个矩阵$Z$表示输入的序列,但是这并不能表示同一个单词每次出现在不同的位置。

我们的目标是能够根据特定单词的位置信息来得到单词的意义。这只需要对上述表示矩阵模型进行修改即可。

我们可以用预先确定的(不是通过学习得到的)正弦函数将【-1,1】之间的值嵌入token中。由此哪怕是完全一样的单词,我们也可以根据单词所在的位置不同,构建不同位置的单词的略微不同的表示方式。

另外,我们希望编码器能够实现对于同一个序列,部分单词在初始位置,而另外一部分单词在指定的位置——即**希望网络能够理解相对位置,而不仅仅是绝对位置。**正弦函数可以使位置被表示为彼此的线性组合,从而网络可以学习token位置之间的相对关系。

用数学描述,就是在原来的$Z$矩阵中加入带有位置编码的矩阵$P$。
$$Z+P$$我们用$i$表示token在序列中的位置;用$j$表示嵌入特征(embedding feature)的位置。

具体来说,对于给定的句子P,其位置嵌入矩阵为: *采用这种定值设计法而不是位置学习表示法(just like we did with the embeddings) ,是因为:

  • 可以无限地增加input_length,因为可以计算任意位置的函数。
  • 需要学习的参数更少,模型训练更快。

通过$X=Z+P$,大小为(input_length) x (emb_dim)的矩阵$X$将送入第一个encoder block。

2.3 Encoder Block

Encoder Blocks共有N个encoder block链接在一起,以生成编码器的输出。特定块负责查找输入表示之间的关系,并将它们编码到输出中。

直观地说,这种**通过块的迭代过程将帮助神经网络捕获输入序列中单词之间更复杂的关系**。您可以将其视为迭代地构建整个输入序列意义的过程。

2.3.1 Multi-Head Attention

引入多头注意力的Transformer,在不同时间使用不同的权重矩阵计算注意力h,然后将结果连接在一起。

这些并行计算注意力的结果被称为头head。我们将用下标 $i$ 来表示一个特定的头和相关的权重矩阵。下图描述了并行计算头(computes attention h)及其结果连接在一起(and then concatenates the results together)的过程:

如上图,一旦所有的头h都被计算出来,它们就会被连接起来,得到一个(input_length) x (h*d_v)的矩阵。然后该矩阵经过一个大小(h*d_v) x (emb_dim),权值$W^0$的线性层得到最终大小为(input_length) x (emb_dim)的$X$最终结果。 其中Q、K和V是不同输入矩阵的占位符placeholder。特别是在这种情况下,Q、K和V将被前一步X的输出矩阵所代替。

2.3.2 Scaled Dot-Product Attention

每个头将由三个不同的投影(矩阵乘法)由矩阵给出:

为了计算一个头部head,输入X矩阵,并分别投射X给上述三个权值矩阵:

其中,$d_k=d_v=emb\_dim/h$

得到 $K_i 、Q_i$和 $V_i$后我们用它们来计算缩放的点积注意力Dot-Product Attention:
$$Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V$$
用图描述为:

在编码器块中计算注意不使用mask。在解码器使用mask

2.3.3 Going Deep

GOING DEEP是BERT的关键,所以我们需要仔细理解它。让我们从$Q_i$和$K_i$的转置矩阵乘积开始$$Q_iK_i^T$$

$Q_i$和$K_i$是tokens在$d_k$维空间中的不同投影。因此我们可以把这些投影的点积看作度量tokens投影之间相似性的方法。
对于每一个通过$Q_i$投影得到的向量与每一个通过$K_i$投影得到的向量,可以用点积来度量这些向量之间的相似性。将$v_i$和$u_j$分别称为第$i$个token和第$j$个token通过$Q_i$和$K_i$的投影,则它们的点积为:

因此,这是一个度量$u_i$和$v_j$在方向上有多相似以及它们的长度有多大的方法(方向越接近,长度越大,点积越大)。

也可以认为这个矩阵乘积是作为对输入序列中tokens之间特定关系的encoding(这种关系由矩阵$K_i$和$Q_i$定义)。
在此乘法之后,将矩阵按元素顺序除以$d_k$的平方根,以便进行缩放。

下一步是按行Softmax $$softmax(\frac{QK^T}{\sqrt{d_k}})$$
结果将是数字在0和1之间的行,它们的和为1。最后,将结果乘以$V_i$得到head的结果。 $$softmax(\frac{QK^T}{\sqrt{d_k}})V_i$$

代码交流 2021