全网最全,大语言模型LLM的Transformer训练计算过程

图片[1]-全网最全,大语言模型LLM的Transformer训练计算过程-JieYingAI捷鹰AI

Transformer Encoder 和 Decoder

一、用“hello world” 作为输入序列,用“你好世界”作为目标序列,做一个大预言模型LLM翻译训练的例子,计算Transformer的encoder输出。要求:把以上例子的具体的计算细节、数字写出来。

为了详细展示Transformer编码器的计算过程,我们需要简化模型和假设一些参数值。请注意,在实际应用中,这些参数会通过训练来优化,并且使用的是大规模的数据集。这里我们将构建一个非常简化的示例,用于说明概念。

假设

步骤 1: 数据预处理

我们首先定义一个简单的词汇表和嵌入矩阵E:

Vocab = {""0"hello"1"world"2"你"3"好"4"世"5"界"6}Embedding Matrix E (randomly initialized for simplicity):E[0] = [0.00.00.00.0]  # E[1] = [0.1, 0.2, 0.3, 0.4]  # helloE[2] = [0.5, 0.6, 0.7, 0.8]  # worldE[3] = [0.9, 0.1, 0.2, 0.3]  # 你E[4] = [0.4, 0.5, 0.6, 0.7]  # 好E[5] = [0.8, 0.9, 0.1, 0.2]  # 世E[6] = [0.3, 0.4, 0.5, 0.6]  # 界

位置编码P可以简单地是位置索引的one-hot编码,或者更复杂的形式,如sinusoidal位置编码。在这个例子中,我们用简单的整数位置索引:

Position Encoding P:P[0] = [0000]P[1] = [1111]P[2] = [2222]

现在我们可以计算输入序列“hello world”的嵌入加上位置编码:

Input Embeddings + Positional Encoding:"hello" -> E[1] + P[1] = [0.1+10.2+10.3+10.4+1] = [1.11.21.31.4]"world" -> E[2] + P[2] = [0.5+20.6+20.7+20.8+2] = [2.52.62.72.8]

步骤 2: 编码器层

多头自注意力

对于每个词,我们计算其与所有其他词的注意力分数。因为我们只使用了一个头部,所以Q、K、V矩阵实际上就是输入嵌入本身。计算公式如下:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

其中d_k是键向量的维度(这里是4)。注意,这里的softmax操作是在行上执行的,以保证每一行加起来等于1。

因为我们的例子非常简化,我们可以直接计算出注意力矩阵,然后应用到值矩阵上。对于“hello world”,注意力矩阵A将是:

A = softmax([[1.1*1.1 + 1.2*1.2 + 1.3*1.3 + 1.4*1.4,              1.1*2.5 + 1.2*2.6 + 1.3*2.7 + 1.4*2.8],             [2.5*1.1 + 2.6*1.2 + 2.7*1.3 + 2.8*1.4,              2.5*2.5 + 2.6*2.6 + 2.7*2.7 + 2.8*2.8]]) / sqrt(4)

然后我们将其应用于值矩阵V(即原始输入),得到新的上下文向量。

前馈网络

接下来,我们将上下文向量通过一个前馈网络,这个网络包括两个线性变换和中间的ReLU激活函数。例如:

FFN(x) = max(0, xW1 + b1)W2 + b2

其中W1, W2, b1, b2是可学习的参数。由于这是理论上的计算,我们将不会具体给出这些参数的值。

输出

最后,经过一层编码器后,我们得到了“hello world”的新表示,它可以作为解码器部分的输入之一,帮助解码器生成目标语言的翻译。

请注意,上述计算是非常简化的,真正的Transformer模型涉及更多的细节和更复杂的数学运算。此外,权重和偏置项都是通过训练数据学习而来的,而不是预先指定的。如果你需要更精确的数字,你需要运行一个具体的实现,比如使用PyTorch或TensorFlow库。

二、继续以上的例子,把encoder输出给decoder。假设只有一层decoder,写出decoder输出计算过程。要求:把具体的计算细节、数字写出来。

为了继续上述的例子,并计算解码器的输出,我们将遵循一个简化的流程。请注意,实际应用中的Transformer模型包含更多的细节和更复杂的数学运算。下面我将给出一个简化的示例,包括具体的计算细节和数字。

假设

步骤 1: 解码器输入

首先,我们需要对目标序列“你好世界”进行预处理,添加开始标记和结束标记。在第一个时间步中,我们只提供作为输入,然后依次加入已知的目标词汇来预测下一个词。

假设我们的词汇表如下:

Vocab = {""0""7""8"你"3"好"4"世"5"界"6}

解码器的输入嵌入加上位置编码:

"你好世界" -> ["""你""好""世""界"""]

对于第一个时间步,我们只有:

Input Embedding + Positional Encoding for :"" -> E[7] + P[0]

如果我们假设E[7][0.7, 0.8, 0.9, 1.0],那么加上位置编码P[0](这里假设为[0, 0, 0, 0])后仍然是[0.7, 0.8, 0.9, 1.0]

步骤 2: 解码器层

自注意力机制

在解码器中,自注意力机制需要屏蔽未来的时间步(即未来的词汇),以防止信息泄露。这通过掩码矩阵实现,该矩阵确保每个位置只能看到之前的位置。

对于,自注意力机制将不会改变其值,因为没有其他之前的词汇。

编码器-解码器注意力

接下来,解码器使用来自编码器的输出来帮助理解上下文。这是通过编码器-解码器注意力机制完成的,其中解码器的查询Q与编码器的键K和值V进行比较:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

其中Q是解码器的输出,而K和V来自于编码器的输出。

假设编码器输出为E_output = [[1.1, 1.2, 1.3, 1.4], [2.5, 2.6, 2.7, 2.8]](对应于“hello world”的两个词)。我们计算注意力分数:

A = softmax([[0.7*1.1 + 0.8*1.2 + 0.9*1.3 + 1.0*1.4,              0.7*2.5 + 0.8*2.6 + 0.9*2.7 + 1.0*2.8]]) / sqrt(4)

简化计算后的注意力分数应用于编码器的值V,得到新的上下文向量C。

前馈网络

最后,上下文向量C通过一个前馈网络,产生最终的输出。这个输出通常会通过一个线性变换和softmax层转换成词汇表大小的分布,从而预测下一个词的概率分布。

FFN(C) = max(0, CW1 + b1)W2 + b2

假设我们得到的最终输出为O,那么我们选择概率最高的词汇作为下一个词。在这个例子中,假设我们得到了:

O = [0.1, 0.2, 0.6, 0.1]

这样的概率分布(对应于简化后的词汇表),我们会选择索引为2的词汇,即“你”。

输出

解码器的第一个时间步输出预测了“你”。然后,我们将“你”加入到解码器的输入中,重复上述过程,直到我们生成整个句子或遇到结束标记。

请注意,以上计算是非常简化的。实际上,Transformer模型的权重、偏置项和其他参数都是通过训练数据学习而来的,并且涉及到更多的数学运算。如果你想要更精确的数字,你需要运行一个具体的实现,例如使用PyTorch或TensorFlow库。

三、继续写出训练下一个字 “好” 的训练计算,要求:写出矩阵计算

为了继续计算解码器输出下一个字“好”的过程,我们需要明确几个步骤。我们假设上一步已经成功预测了“你”,现在我们要用这个信息来预测下一个字“好”。我们将使用矩阵运算来进行具体的计算。

解码器输入

在上一步中,我们得到了“你”作为第一个预测的词。现在我们将和“你”一起作为新的解码器输入:

Input Sequence = ["""你"]

对于每个词,我们查找其嵌入向量,并加上相应的位置编码。假设我们的位置编码是简单的整数索引(实际上会更复杂):

Positional Encoding P:P[0] = [0000]P[1] = [1111]Embeddings + Positional Encoding:"" -> E[7] + P[0] = [0.70.80.91.0] + [0000] = [0.70.80.91.0]"你"     -> E[3] + P[1] = [0.90.10.20.3] + [1111] = [1.91.11.21.3]

所以,解码器输入矩阵X为:

X = [[0.7, 0.8, 0.9, 1.0],     [1.9, 1.1, 1.2, 1.3]]

步骤 2: 解码器层

自注意力机制

在解码器中,自注意力需要屏蔽未来的时间步。这意味着当计算某个时间步的注意力时,只能看到之前的时间步。我们创建一个掩码矩阵M,它将用于防止信息泄露:

Mask M:[[10], [11]]

这里,1表示可以关注,0表示不能关注。然后我们计算自注意力:

设Q, K, V都是解码器输入X,计算公式如下:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

首先计算Q * K^T:

Q * K^T = X * X^T = [[0.7*0.7 + 0.8*0.8 + 0.9*0.9 + 1.0*1.0, 0.7*1.9 + 0.8*1.1 + 0.9*1.2 + 1.0*1.3], [1.9*0.7 + 1.1*0.8 + 1.2*0.9 + 1.3*1.0, 1.9*1.9 + 1.1*1.1 + 1.2*1.2 + 1.3*1.3]][[2.46, 3.9], [3.9, 7.06]]

然后应用掩码M:

Masked Attention Scores = Mask(M, Q * K^T) =[[2.46, -inf], [3.97.06]]

其中-inf代表被屏蔽的位置,它们将在softmax后变为0。

接着计算softmax:

Softmax = softmax([[2.46, -inf],                   [3.9, 7.06]])

由于-inf的存在,第一行只有第一个元素有效,第二行则是两个元素的竞争。假设结果为:

Softmax = [[1, 0],           [0.05, 0.95]]

最后乘以V得到新的上下文向量C:

C = Softmax * X =[[1*0.7 + 0*1.9, 1*0.8 + 0*1.1, 1*0.9 + 0*1.2, 1*1.0 + 0*1.3], [0.05*0.7 + 0.95*1.9, 0.05*0.8 + 0.95*1.1, 0.05*0.9 + 0.95*1.2, 0.05*1.0 + 0.95*1.3]][[0.7, 0.8, 0.9, 1.0], [1.82, 1.085, 1.195, 1.285]]

编码器-解码器注意力

接下来,解码器使用来自编码器的输出E_output进行编码器-解码器注意力机制。假设编码器输出为:

E_output = [[1.1, 1.2, 1.3, 1.4], [2.5, 2.6, 2.7, 2.8]]

计算查询Q(即自注意力后的输出C),键K和值V(均为E_output)。我们重复之前的注意力计算:

Attention(C, E_output, E_output) = softmax(C * E_output^T / sqrt(d_k)) * E_output

先计算C * E_output^T:

C * E_output^T =[[0.7*1.1 + 0.8*1.2 + 0.9*1.3 + 1.0*1.4,  0.7*2.5 + 0.8*2.6 + 0.9*2.7 + 1.0*2.8], [1.82*1.1 + 1.085*1.2 + 1.195*1.3 + 1.285*1.4,  1.82*2.5 + 1.085*2.6 + 1.195*2.7 + 1.285*2.8]]=[[3.6, 8.2], [7.44, 16.88]]

然后计算softmax并乘以E_output,得到最终的上下文向量D:

D = softmax([[3.6, 8.2],             [7.44, 16.88]]) * E_output

简化计算后的结果可能类似于:

D ≈ [[1.1, 1.2, 1.3, 1.4],     [2.5, 2.6, 2.7, 2.8]]

前馈网络

最后,上下文向量D通过一个前馈网络FFN产生最终的输出。这个网络通常包括两层线性变换和中间的ReLU激活函数。假设我们有随机初始化的权重W1, W2和偏置b1, b2,计算如下:

FFN(D) = ReLU(D * W1 + b1) * W2 + b2

假设我们得到的结果是:

FFN(D) ≈ [[0.1, 0.2, 0.6, 0.1],          [0.05, 0.1, 0.7, 0.15]]

这将转换成词汇表大小的概率分布,用于预测下一个词。选择概率最高的词汇作为预测结果,这里是第二个时间步的预测为“好”。

输出

解码器的第二个时间步输出预测了“好”。然后,我们可以将“好”加入到解码器的输入中,重复上述过程,直到生成整个句子或遇到结束标记。

请注意,这些计算是高度简化的,实际的Transformer模型涉及更多的细节和更复杂的数学运算。此外,权重、偏置项和其他参数通常是通过训练数据学习而来的,并且涉及到大量的优化和调整。如果你想要更精确的数字,你需要运行一个具体的实现,例如使用PyTorch或TensorFlow库。

四、假设以上输出不是“你”,存在loss,请写出梯度下降重新计算参数。要求,写出矩阵计算。

为了展示如何通过梯度下降重新计算参数,我们需要考虑损失函数(loss function),以及如何基于这个损失来更新模型的权重。在这个例子中,我们将使用交叉熵损失(cross-entropy loss),这是在分类任务中常用的损失函数。

假设

步骤 1: 计算损失

假设解码器输出的概率分布为:

Output = [0.10.20.60.1]  # 对应于 ["""你""好""世"]

而目标标签是“好”,其索引为2。交叉熵损失公式如下:

Loss = -log(Output[target])

代入具体值:

Loss = -log(0.6) ≈ 0.5108

步骤 2: 反向传播

反向传播的目标是计算损失相对于每个可训练参数的梯度,然后使用这些梯度来更新参数。我们将从最后的线性变换开始,逐步向前推导。

前馈网络的梯度

假设前馈网络的输出层有如下形式:

FFN(D) = ReLU(D * W1 + b1) * W2 + b2

其中D是来自编码器-解码器注意力的上下文向量,W1, W2, b1, b2是可训练参数。为了简化,我们假设激活函数ReLU不涉及非零梯度的区域。

损失对最终输出的梯度是:

dL/dO = O - target_one_hot_vector

对于我们的例子:

target_one_hot_vector = [0, 0, 1, 0]dL/dO = [0.1, 0.2, 0.6, 0.1] - [0, 0, 1, 0] = [0.1, 0.2, -0.4, 0.1]

接下来,我们将这个梯度传递给前馈网络的参数。因为FFN是一个简单的两层网络,我们可以直接应用链式法则:

dL/dW2 = dL/dO * D.TdL/db2 = dL/dOdL/dH = dL/dO * W2.T

其中H是ReLU后的隐藏层输出,D.T是D的转置。

注意力机制的梯度

接下来,我们需要将梯度传递到注意力机制。这里我们将简化处理,只关注编码器-解码器注意力部分。损失对注意力输出的梯度是:

dL/dC = dL/dH * (dH/dC)

其中dH/dC取决于前馈网络的具体结构。

对于自注意力机制,我们需要计算损失对Q、K、V的梯度,这涉及到softmax梯度的计算。由于这部分计算较为复杂,通常由深度学习框架自动完成。

步骤 3: 更新参数

一旦我们有了所有参数的梯度,就可以使用随机梯度下降(SGD)来更新它们。更新规则如下:

W_new = W_old - learning_rate * dL/dWb_new = b_old - learning_rate * dL/db

其中learning_rate是学习率,它决定了每次更新的步伐大小。

矩阵计算示例

为了给出具体的矩阵计算,让我们假设一些简化的数值。假设我们有以下的权重矩阵和偏置向量:

W1 = [[0.1, 0.2, 0.3, 0.4],      [0.5, 0.6, 0.7, 0.8]]b1 = [0.1, 0.1]W2 = [[0.9, 0.1],      [0.2, 0.3],      [0.4, 0.5],      [0.6, 0.7]]b2 = [0.1, 0.1]

并且我们有上下文向量D:

D = [[1.1, 1.2, 1.3, 1.4]]

现在,我们计算前馈网络的梯度:

dL/dO = [0.1, 0.2, -0.4, 0.1]dL/dW2 = dL/dO * D.T =[[0.1, 0.2, -0.4, 0.1]] * [[1.1], [1.2], [1.3], [1.4]] =[[0.1*1.1 + 0.2*1.2 + (-0.4)*1.3 + 0.1*1.4,  0.1*1.2 + 0.2*1.3 + (-0.4)*1.4 + 0.1*1.5]]= [[0.11 + 0.24 - 0.52 + 0.14, 0.12 + 0.26 - 0.56 + 0.15]]= [[-0.03, -0.03]]

更新W2:

W2_new = W2 - learning_rate * dL/dW2

类似地,我们计算其他参数的梯度并更新它们。注意,这里的计算是为了说明概念,实际上所有的矩阵运算都会由深度学习框架高效地执行。

结论

以上过程展示了如何通过梯度下降重新计算参数。在实践中,整个过程是由深度学习框架自动处理的,开发者只需要定义模型架构、损失函数和优化器。如果你想要更精确的数字和完整的实现,建议使用PyTorch或TensorFlow等工具。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享