一. 引言
大家都知道AI本质就是计算概率然后返回一个最大概率的结果。但是很好奇这里面的计算逻辑具体是如何,以及后续到底哪些因素会影响到训练结果和推断,有必要理解transformer中的数学逻辑。这也是本系列写作的原因之一。
其实transformer中的数学并不是特别高深,只需要大学的线性代数就行。难的是里面的计算量比较大,为了简化,我们使用减少模型的维度,比如原本transformer中会使用512长的向量,我们只使用长度为4的向量。
最后在开始正文之前,经典的transformer模型镇楼。

二.编码器(Encoder)的Input
Tokenization
编码器的目标是“理解”输入文本的含义。什么叫理解?就是编码器产出的向量足够强大到保护了文本的所有信息,这些信息包含词之间的语义信息和关系。编码器能处理的是数字,所以第一步就是将一个文本变成数组,简化起见,可以理解一个单词就是一个token比如“Hello World" 对应的数组就是 [”Hello", "World"]. 这一步就叫 Tokenization
向量化(embedding)
现在我们会慢慢开始步入数学的殿堂。模型能处理的就是数字,得到单词数组后,我们需要将每个单词变成一个一维向量,比如
Hello -> [1,2,3,4]
World -> [2,3,4,5]
这里每个单词对应的数字数组的值,一般是使用诸如word2vec这样的预训练模型来得出,或者也有使用高斯分布的0到1之间的随机数组。我们这样为了演示,就随便给他四个数字就行(本文一开始说了为了简化会把512长的维度变成4)。这样我们就得到了一个矩阵
行数对应你单词的数量,列数就是我们一开始设定的维度4。 这个矩阵就是 embedding martix
Positional encoding
上面的矩阵只是各个单词自身的向量化,我们还需要为每个单词之间的信息(相对位置)添加向量。
我们会使用sin和cos来计算位置编码,优势如下
1. 计算的值收敛,在[-1,1]这个区间间
2. 能很好捕获文本的周期性(没找到具体的原因为什么要假定文本有周期性,只是说根据先人的经验,文本可能会有周期性)。
看一下计算公式
对Hello World进行计算的结果如下
“Hello”
i = 0 (even): PE(0,0) = sin(0 / 10000^(0 / 4)) = sin(0) = 0
i = 1 (odd): PE(0,1) = cos(0 / 10000^(2*1 / 4)) = cos(0) = 1
i = 2 (even): PE(0,2) = sin(0 / 10000^(2*2 / 4)) = sin(0) = 0
i = 3 (odd): PE(0,3) = cos(0 / 10000^(2*3 / 4)) = cos(0) = 1
“World”
i = 0 (even): PE(1,0) = sin(1 / 10000^(0 / 4)) = sin(1 / 10000^0) = sin(1) ≈ 0.84
i = 1 (odd): PE(1,1) = cos(1 / 10000^(2*1 / 4)) = cos(1 / 10000^0.5) ≈ cos(0.01) ≈ 0.99
i = 2 (even): PE(1,2) = sin(1 / 10000^(2*2 / 4)) = sin(1 / 10000^1) ≈ 0
i = 3 (odd): PE(1,3) = cos(1 / 10000^(2*3 / 4)) = cos(1 / 10000^1.5) ≈ 1
上面公式中的PE(x,y),x为该单词在token列表中的位置。y为4维向量的位置。最终结果为
“Hello” -> [0, 1, 0, 1]
“World” -> [0.84, 0.99, 0, 1]
计算encoder的输入
将上面两步获取的矩阵进行求和
“Hello” = [1,2,3,4] + [0, 1, 0, 1] = [1, 3, 3, 5]
“World” = [2,3,4,5] + [0.84, 0.99, 0, 1] = [2.84, 3.99, 4, 6]
这个新矩阵,就是我们要传给encoder的输入,回过头看一开始的架构图,就是图中左下角的部分。
encoder的输入部分的计算就到这,下一篇我们将介绍encoder剩余的self-attention和Feed-Forward layer.