GPT-2(small)架构推理解析

发布时间 2023-12-30 11:56:08作者: 宜家数据小哥

1、有字符串BBCAD

2、为字符串中的每个字母添加index索引以进行排序,A、B、C、D的索引下标分别是0、1、2、3,因此排序的数字结果为01123

3、将01123中的每个数字转换为c个元素的向量(这个过程称为embedding,其中c是一个超参数)

4、将每个字母的索引信息分别嵌入到token embedding矩阵的列中,这样矩阵中就拥有了字母的索引信息。

5、再将每个字母的位置信息分别嵌入到position embedding矩阵的列中,这样矩阵中就拥有了字母的位置信息。

6、最后将token embedding矩阵跟position embedding矩阵按位相加,得到input embedding矩阵。这个矩阵是一个T x C矩阵,T代表时间,C代表特征或尺寸,长度C是超参数。

7、对input embedding矩阵的每一列进行Layer Normalization归一化操作。每一列都有平均值μ和标准差σ和ε项(ε=1×10-5,用于防止被零除),所以归一化值的计算公式如下:

  归一化能消除特征之间的量纲影响,可以改善模型训练的稳定性和收敛速度,避免某些特征的值过大或过小对模型的影响过大。(以下为扩展内容)

  假设有以下样本数据:

    样本1: [10, 20, 30]

    样本2: [20, 30, 40]

    样本3: [30, 40, 50]

  我们可以计算每个特征维度上的均值和方差:

    特征1的均值:(10 + 20 + 30) / 3 = 20   特征1的方差:((10-20)^2 + (20-20)^2 + (30-20)^2) / 3 = 66.67

    特征2的均值:(20 + 30 + 40) / 3 = 30   特征2的方差:((20-30)^2 + (30-30)^2 + (40-30)^2) / 3 = 66.67

    特征3的均值:(30 + 40 + 50) / 3 = 40   特征3的方差:((30-40)^2 + (40-40)^2 + (50-40)^2) / 3 = 66.67

  接下来,我们可以对每个特征维度进行归一化:

    样本1的标准化结果: [(-20 / √66.67+ε), (0 / √66.67+ε), (20 / √66.67+ε)] ≈ [-2.16, 0, 2.16]

    样本2的标准化结果: [(-10 / √66.67+ε), (0 / √66.67+ε), (10 / √66.67+ε)] ≈ [-1.08, 0, 1.08]

    样本3的标准化结果: [(0 / √66.67+ε), (10 / √66.67+ε), (20 / √66.67+ε)] ≈ [0, 1.08, 2.16]

  通过归一化,我们可以看到每个特征维度上的均值都为0,方差都为1。这样,不同样本之间的特征取值在相同的尺度上进行比较,更有利于模型学习到普遍适用的规律。

8、前面是归一化计算的第一步,接下来我们需要将每一列中的每个元素减去均值μ,然后乘以学习的权重(γ),然后加上偏差(β)值,才能得到最终的归一化值。计算公式如下:

9、每一列都计算完成后,就会得到一个归一化后的Layer Normalization矩阵,这个矩阵将作为self-attention层的输入。

10、接下来将T x C 的Layer Normalization矩阵的T列中的每一列生成Q、K、V三个向量,其中T可以理解为注意力头的数量。举个例子,Q向量中每一列中的每个元素的计算方法就是将Q权重矩阵的每一行的第 i 元素与Layer Normalization矩阵中的每一列的第i个元素相乘,然后再将所有相乘的结果相加,然后再将相加的结果加上Q的偏执项,这样就得到了Q向量中某一列的第i个元素的值。重复这一步骤,直到计算出Q向量的每一列的所有元素的值,而这些值组合起来就是一个Q向量。另外说明一下,权重矩阵是在训练过程中学习到的参数,假设输入特征的维度为d_model,d_k是指定的较小维度,则权重矩阵的形状就是(d_model,d_k)。

11、生成Q,K,V三个向量后,将每个多头中的Q向量的每一列和K向量的每一列(之前进行过点积的K向量的列到当前列的列,也就是说只能看到之前出现过的列的信息,无法预知未见过的列)进行点积,然后将点击结果除以sqrt(A),其中A是Q/K/V向量的长度。这种缩放是为了防止大值在下一步中主导归一化(softmax)。注意,这些点积是测量两个矢量之间相似性的一种方法。如果它们非常相似,则点积将很大。如果它们非常不同,则点积将是小的或负的。

12、得到点积除以sqrt(A)的结果后,再将所有结果输入到softmax函数中,每一行都会被归一化为和为1,也就是softmax函数输出的是概率值。

13、将每一行的每个元素的概率值乘以V向量的每一列,从而得到输出向量。重复点积的过程获取每一列输出向量,最终将向量组合,就得到输出矩阵。

14、在经过self-attention层之后,得到了每个多头的输出。这些输出是受Q和K矢量影响的适当混合的V输出矢量。然后叠加每个多头的V输出矢量,从而得到最终的V Output矢量,该V Output矢量的原始长度是C,(其中C / 多头数量=多头矢量长度)。

15、然后再将V Output矢量的每一列乘以Projection Weights权重矩阵的每一行,再加上一个Projection Bias偏执项,就可以得到每一个列向量,这些列向量组成了一个矩阵,该矩阵就是Attention Output输出。

16、然后将Attention Output矩阵与最开始的Input Embedding矩阵按位相加,即进行残差层的计算。我们将相加的结果矩阵称为Attention Residual矩阵。

17、接下来进入MLP(多层感知器),这是一个简单的神经网络,有两层。在进入MLP之前,先将Attention Residual矩阵进行Layer Normalization归一化操作,公式还是一样,只不过权重和偏执是MLP的权重和偏执:

18、然后用归一化后的Attention Residual矩阵的一列与MLP Weights权重矩阵的每一列进行相乘,然后加上MLP Bais偏执,得到一个长度为4*C的向量。

19、让长度为4*C的向量中的每个元素都经过GELU激活函数。

20、然后,我们将经过GELU激活函数的4*C向量投影回长度C。即用4*C向量乘以一个MLP Projection Weights权重矩阵,然后再加上MLP Projection Bias偏置。就可以得到一个长度为C的列向量。重复这个上述操作,就可以得到一个MLP Result矩阵,此矩阵的每一列都是由一个长度为4*C的向量经过GELU激活函数后,乘以MLP Projection Weights权重矩阵,然后再加上MLP Projection Bias偏置得到的。

21、最后将MLP Result矩阵与之前的Attention Residual矩阵进行按位相加,即进行残差层的计算,得到最终的MLP Residual矩阵。

22、从将Input Embedding进行归一化开始,到最终得到MLP Residual矩阵的过程,就是一次完整Transformer的Decoder。这个Decoder过程形成了任何GPT模型的主体,并重复多次,一个块的输出进入下一个块,直到走完全部的Transformer Decoder。正如深度学习中常见的那样,很难说这些层中的每一层到底在做什么,但我们有一些总体想法:早期的层往往专注于学习较低级别的特征和模式,而后期的层则学习识别和理解更高级别的抽象和关系。在自然语言处理的背景下,较低层可能学习语法、句法和简单的单词联想,而较高层可能捕捉更复杂的语义关系、话语结构和上下文相关的含义。

23、接下来将MLP Residual矩阵进行Layer Normalization归一化操作,之后使用线性变换(矩阵乘法),这一次没有偏差。这个最后的转换将我们的每个列向量从长度C转换为长度nvocab。因此,它有效地为我们每个专栏的词汇表中的每个单词生成了一个分数。这些分数有一个特殊的名字:logits。“logits”这个名字来源于“log赔率”,即每个代币赔率的对数。之所以使用“Log”,是因为我们接下来应用的softmax会进行幂运算,将其转换为“赔率”或概率。

24、接下来进行softmax操作。softmax的目标是取一个向量并对其值进行归一化,使其总和为1.0。首先对每个输入值进行幂运算,a=exp(x_1),这具有使所有值为正的效果。一旦我们有了指数值的向量,我们就可以将每个值除以所有值的总和。这将确保这些值的总和为1.0。由于所有的指数值都是正的,我们知道结果值将在0.0和1.0之间,这提供了原始值的概率分布。softmax就是这样:简单地对值求幂,然后除以和。但是如果输入值中的任何一个都非常大,那么指数值将非常大。我们最终会把一个很大的数字除以一个非常大的数字,这可能会导致浮点运算的问题。softmax运算的一个有用特性是:如果我们将一个常数添加到所有输入值,结果将是相同的。因此,我们可以找到输入向量中的最大值,并将其从所有值中减去。这样可以确保最大值为0.0,并且softmax在数值上保持稳定。