从训练和推理阶段理解transformers、self-attention的本质是改变输入文本对应tokens的embedding及Mask机制

在这里插入图片描述

1、self-attention机制

写在前面,transformers里的核心,self-attention机制:
Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dk QKT)V

(1)self-attention的本质是改变输入tokens的embedding,使其嵌入上下文信息

今天看了3Blue1Brown对attention的解读,以上公式可以理解为输入上下文的每个token计算得到的attention,就是变相原有embedding加上变化量,这里也就是根本本质:改变输入tokens的embedding。
![[cc6e5bef13c9ea906e17421625c69bf.png]]在这里插入图片描述

先不管训练阶段,在推理阶段,本质是对输入Query的每个token进行结合上下文信息的embedding的改变。怎么理解这句话呢?——以下例说明
假设我们有一个简单的输入句子:“I love coding”,并且我们要通过自注意力机制来计算每个Token的嵌入向量。

  1. 初始化嵌入

    • 首先,我们将每个Token转换为初始的嵌入向量(假设这些嵌入向量是预训练的):
embedding_I = [0.1, 0.2] 
embedding_love = [0.3, 0.4] 
embedding_coding = [0.5, 0.6] embeddings = np.array([embedding_I, embedding_love, embedding_coding])
  1. 权重矩阵(固定的)

    • 假设我们有固定的权重矩阵 WqWkWv
Wq = np.array([[0.1, 0.2], [0.3, 0.4]])
Wk = np.array([[0.5, 0.6], [0.7, 0.8]])
Wv = np.array([[0.9, 1.0], [1.1, 1.2]])
  1. 计算 Q、K、V

    • 使用固定的权重矩阵计算查询向量(Q)、键向量(K)和值向量(V):
Q = np.dot(embeddings, Wq) 
K = np.dot(embeddings, Wk) 
V = np.dot(embeddings, Wv)
  1. 计算注意力得分

    • 计算每个Token的查询向量(Q)与所有Token的键向量(K)的点积,得到注意力得分:```````
attention_scores = np.dot(Q, K.T)
#attention_scores = [[0.031, 0.071, 0.111], [0.077, 0.177, 0.277], [0.123, 0.283, 0.443]]
  1. 缩放和 softmax

    • 对注意力得分进行缩放和softmax操作,得到注意力权重:
d_k = K.shape[1]
scaled_attention_scores = attention_scores / np.sqrt(d_k)
# scaled_attention_scores = [[0.0219, 0.0502, 0.0785], [0.0545, 0.1253, 0.1960], [0.0870, 0.2003, 0.3136]]

attention_weights = softmax(scaled_attention_scores, axis=-1)
# attention_weights = [[0.298, 0.401, 0.301], [0.288, 0.423, 0.289], [0.280, 0.440, 0.280]]
  1. 计算注意力输出

    • 使用注意力权重对值向量(V)进行加权求和,得到更新后的嵌入向量:
attention_output = np.dot(attention_weights, V) 
# attention_output = [[0.705, 0.787], [0.706, 0.788], [0.707, 0.790]]
小结:
  • 初始嵌入向量(Embeddings) 是通过预训练词向量得到的。
  • 固定的权重矩阵(Wq、Wk、Wv) 用于计算查询向量(Q)、键向量(K)和值向量(V)。
  • 注意力得分和注意力权重 用于计算每个Token在当前上下文中的重要性。
  • 注意力输出(Attention Output) 是通过对值向量(V)进行加权求和得到的,这个输出向量即是每个Token在当前上下文中的更新后的表示向量。

所以,在推理过程中,每个Token的嵌入向量会根据输入文本的不同而动态变化,这种变化是通过固定的权重矩阵和自注意力机制来实现的。虽然权重矩阵是固定的,但不同的输入会导致不同的注意力权重,从而产生不同的注意力输出(即更新后的嵌入向量)。

2、注意力与自注意力在编码器解码器中的不同体现(三种不同的注意力计算)

Encoder部分:Self-Attention
Decoder部分:Cross-Attention以及Mask-Self-Attention
注意力机制(Cross-Attention)用于解码器中,允许解码器在生成输出时关注编码器的输出。这意味着 Query 向量来自解码器,Key 和 Value 向量来自编码器。这种机制用于跨序列的注意力计算。
(a) 注意力和自注意力在模型的不同部分:
Encoder部分只有自注意力机制,关注输入序列本身tokens之间的上下文信息。但是Encoder部分输出后,Encoder部分输出的K和V就输入进Decoder部分进行注意力计算(Cross-Attention),此时的Q是来自解码器的输出,当然最开始是 <START> \text{<START>} <START>,后面随着预测词的不断输出,会逐渐把前一个预测词不断填入模型的outputs(shifted right)部分,而这里又有一个重要的点,对于预测词的输入,这里的Self-Attention是MASK的,可以简单理解为每次的预测值输入长度并没有符合设定的长度,所以需要mask后面的字符。可以理解为注意力在解码器的Cross-Attention部分是对输出序列(Q)以及在输入序列中做注意力操作;而自注意力是输入序列在自身做自注意力操作。
在这里插入图片描述

3、 从推理阶段理解transformers

在推理过程中,虽然模型的权重矩阵 WqWkWv 是固定的,但输入文本的每个Token的嵌入向量会根据输入的不同动态变化。具体来说,每个Token的最终嵌入向量是通过自注意力机制计算得到的,这个过程包括计算查询向量、键向量和值向量,并基于注意力权重对值向量进行加权求和。因此,即使权重矩阵不变,不同的输入文本仍然会产生不同的嵌入向量,从而捕捉不同的上下文信息。

①举例:在推理阶段,例如输入“x1、x2、x3”——从推理阶段理解transformers

模型会将“x1、x2、x3”嵌入为embedding,在encoder做self-attention部分,输出的K、V矩阵就会输入进decoder部分,但是最开始outputs(shifted right)部分是输入,作为attention之后的Q,结合encoder输出的K、V矩阵就能计算attention(cross-attention),层归一化和残差连接、前馈网络增强模型的表达能力、最后logits接全连接层再softmax将词库中概率最大的词输出。输出预测单词y1后,就继续把y1作为outputs(shifted right)部分输入,周而复始。

在这里插入图片描述

(4)从训练阶段理解transformers

训练阶段:假设输入是x1、x2、x3,真实标签Y1、Y2、Y3,transformers在训练时,是输入x1、x2、x3,decoder在outputs(shifted right)里从起始符开始,从结束符这样预测输出了y1,但是在预测y2时,decoder在outputs(shifted right)里的输入是真实标签Y1,使其输出y2,继续把真实标签Y2输入进去,输出y3…训练与推理阶段的区别就是放进outputs(shifted right)部分的是真实值还是预测值。

这个过程是怎么反向传播训练权重的?——从训练阶段理解transformers

(1)前向传播
假设输入序列为 { x 1 , x 2 , x 3 } \{x_1, x_2, x_3\} {x1,x2,x3},真实标签序列为 { Y 1 , Y 2 , Y 3 } \{Y_1, Y_2, Y_3\} {Y1,Y2,Y3}。训练过程包括以下步骤:
a. 编码器处理输入
编码器将输入序列 { x 1 , x 2 , x 3 } \{x_1, x_2, x_3\} {x1,x2,x3} 转换为一组编码表示 { E 1 , E 2 , E 3 } \{E_1, E_2, E_3\} {E1,E2,E3}

假设输入序列为 { x 1 , x 2 , x 3 } \{x_1, x_2, x_3\} {x1,x2,x3},真实标签序列为 { Y 1 , Y 2 , Y 3 } \{Y_1, Y_2, Y_3\} {Y1,Y2,Y3}。训练过程包括以下步骤:

编码器将输入序列 { x 1 , x 2 , x 3 } \{x_1, x_2, x_3\} {x1,x2,x3} 转换为一组编码表示 { E 1 , E 2 , E 3 } \{E_1, E_2, E_3\} {E1,E2,E3}

E i = Encoder ( x i ) E_i = \text{Encoder}(x_i) Ei=Encoder(xi)
b. 解码器生成预测
解码器从开始符号 <START> \text{<START>} <START>开始,逐步生成预测:

  1. 步骤1:输入 <START> \text{<START>} <START> 预测 y ^ 1 \hat{y}_1 y^1

    y ^ 1 = Decoder ( <START> , E 1 , E 2 , E 3 ) \hat{y}_1 = \text{Decoder}(\text{<START>}, E_1, E_2, E_3) y^1=Decoder(<START>,E1,E2,E3)

  2. 步骤2:输入真实标签 Y 1 Y_1 Y1 预测 y ^ 2 \hat{y}_2 y^2

    y ^ 2 = Decoder ( Y 1 , E 1 , E 2 , E 3 ) \hat{y}_2 = \text{Decoder}(Y_1, E_1, E_2, E_3) y^2=Decoder(Y1,E1,E2,E3)

  3. 步骤3:输入真实标签 Y 2 Y_2 Y2 预测 y ^ 3 \hat{y}_3 y^3

    y ^ 3 = Decoder ( Y 2 , E 1 , E 2 , E 3 ) \hat{y}_3 = \text{Decoder}(Y_2, E_1, E_2, E_3) y^3=Decoder(Y2,E1,E2,E3)

(2)计算损失
损失函数衡量预测和真实标签之间的差异。通常使用交叉熵损失:

L i = − ∑ j Y i , j log ⁡ ( y ^ i , j ) \mathcal{L}_i = -\sum_{j} Y_{i,j} \log(\hat{y}_{i,j}) Li=jYi,jlog(y^i,j)

其中 Y i , j Y_{i,j} Yi,j 是真实标签的概率分布, y ^ i , j \hat{y}_{i,j} y^i,j 是模型预测的概率分布。对于整个序列,损失函数是每个预测的损失之和:

L = ∑ i L i \mathcal{L} = \sum_{i} \mathcal{L}_i L=iLi

(3)反向传播
反向传播过程包括计算损失函数对模型参数的梯度,并更新这些参数。
a. 计算梯度
①计算每个位置的损失对预测的梯度:

对于预测 y ^ i \hat{y}_i y^i,损失对其的梯度是:

∂ L ∂ y ^ i \frac{\partial \mathcal{L}}{\partial \hat{y}_i} y^iL

②梯度传递到解码器的输出层:

计算损失函数相对于解码器输出层权重的梯度:

∂ L ∂ W output = ∂ L ∂ y ^ i ⋅ ∂ y ^ i ∂ W output \frac{\partial \mathcal{L}}{\partial W_{\text{output}}} = \frac{\partial \mathcal{L}}{\partial \hat{y}_i} \cdot \frac{\partial \hat{y}_i}{\partial W_{\text{output}}} WoutputL=y^iLWoutputy^i

这里 W output W_{\text{output}} Woutput 是解码器输出层的权重矩阵。

③计算梯度传递到解码器的内部层:

使用链式法则,将梯度从输出层传递到解码器的各个层:

∂ L ∂ W decoder = ∑ i ∂ L ∂ y ^ i ⋅ ∂ y ^ i ∂ W decoder \frac{\partial \mathcal{L}}{\partial W_{\text{decoder}}} = \sum_{i} \frac{\partial \mathcal{L}}{\partial \hat{y}_i} \cdot \frac{\partial \hat{y}_i}{\partial W_{\text{decoder}}} WdecoderL=iy^iLWdecodery^i

这里 W decoder W_{\text{decoder}} Wdecoder 是解码器内部层的权重矩阵。

④计算梯度传递到编码器的参数:

如果编码器的参数也在训练中,计算解码器输出相对于编码器输入的梯度:

∂ L ∂ W encoder = ∑ i ∂ L ∂ y ^ i ⋅ ∂ y ^ i ∂ E i ⋅ ∂ E i ∂ W encoder \frac{\partial \mathcal{L}}{\partial W_{\text{encoder}}} = \sum_{i} \frac{\partial \mathcal{L}}{\partial \hat{y}_i} \cdot \frac{\partial \hat{y}_i}{\partial E_i} \cdot \frac{\partial E_i}{\partial W_{\text{encoder}}} WencoderL=iy^iLEiy^iWencoderEi
(4)更新参数
利用优化算法(如Adam、SGD等),根据计算出的梯度更新模型的参数:

W output ← W output − η ∂ L ∂ W output W_{\text{output}} \leftarrow W_{\text{output}} - \eta \frac{\partial \mathcal{L}}{\partial W_{\text{output}}} WoutputWoutputηWoutputL

W decoder ← W decoder − η ∂ L ∂ W decoder W_{\text{decoder}} \leftarrow W_{\text{decoder}} - \eta \frac{\partial \mathcal{L}}{\partial W_{\text{decoder}}} WdecoderWdecoderηWdecoderL

W encoder ← W encoder − η ∂ L ∂ W encoder W_{\text{encoder}} \leftarrow W_{\text{encoder}} - \eta \frac{\partial \mathcal{L}}{\partial W_{\text{encoder}}} WencoderWencoderηWencoderL

其中, η \eta η 是学习率。

4、Mask机制

在Mask-Self-Attention模块上,由于在训练阶段,每个输出Y只和Y前面时刻的输出做attention计算,由于看不到当前时刻后面的内容,所以需要做mask,其实并行性是核心关键,这里需要把每个时刻的Y的self-attention计算出来,为了方便操作,将各个时刻的attention计算的向量拼接成矩阵计算,如下图所示。
所以总结起来就是:mask是因为在训练阶段,由于真实标签Y是按预测输出顺序的输入进去作为Q,而这一块的attention的计算具备时序性,所以需要对还未输出的真实标签进行mask掩码。由于softmax的指数性质,在mask时采用接近负无穷大的值,这样计算softmax时probability趋近于0
在这里插入图片描述

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风月ac

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值