目录

transformer模型介绍大语言模型-LLMBook-学习二

目录

transformer模型介绍——大语言模型 LLMBook 学习(二)

1. transformer模型

1.1 注意力机制

**注意力机制(Attention Mechanism)**在人工智能中的应用,实际上是对人类认知系统中的注意力机制的一种模拟。它主要模仿了人类在处理信息时的选择性注意(Selective Attention),即我们不会平均分配注意力,而是会集中关注关键信息。

https://i-blog.csdnimg.cn/direct/179412443ea746008155f60db1fa345b.png

1.2 注意力机制原理

注意力机制是一种 动态加权机制 ,用于在输入数据中 选取最相关的信息 ,并赋予不同的权重。它最初用于 神经机器翻译(Neural Machine Translation, NMT) ,后来广泛应用于 自然语言处理(NLP)、计算机视觉(CV)和异常检测 等任务。


1. 注意力计算流程

如图所示,注意力机制主要包括 Query(查询)、Key(键)、Value(值) 三个核心概念,它们的计算过程分为 三步

https://i-blog.csdnimg.cn/direct/bceab2b66f2d445c830e93bad69f2e1d.png

第一步:计算 Query 和 Key 之间的相似度
  • 我们用 **查询向量(Query,记作

    q q

    q** ,去匹配多个 **键向量(Keys,记作

    k j k_j

    k

    j

    ​** ,计算它们的 相似度

  • 这里采用的是 点积(Dot Product 来度量相似度:

    e i j

    q T k j e_{ij} = q^T k_j

    e

    ij

    =

    q

    T

    k

    j

  • 其中:

    • q q

      q 是查询向量(query)

    • k j k_j

      k

      j

      是键向量(key)

    • e i j e_{ij}

      e

      ij

      表示查询

      q q

      q 与键

      k j k_j

      k

      j

      的相似度得分

直观理解

  • 如果

    q q

    q 和

    k j k_j

    k

    j

    方向相似(即表示的信息相似),则它们的点积

    e i j e_{ij}

    e

    ij

    会较大。

  • 反之,如果

    q q

    q 和

    k j k_j

    k

    j

    方向不同,则

    e i j e_{ij}

    e

    ij

    会较小。

第二步:将相似度进行 Softmax 归一化
  • 由于点积计算出的相似度值

    e i j e_{ij}

    e

    ij

    可能较大,因此需要进行 Softmax 归一化 ,使其变成一个概率分布:

    a i j

    exp ⁡ ( e i j ) ∑ j ′ exp ⁡ ( e i j ′ ) a_{ij} = \frac{\exp(e_{ij})}{\sum_{j’} \exp(e_{ij’})}

    a

    ij

    =

    j

    exp

    (

    e

    i

    j

    )

    exp

    (

    e

    ij

    )

  • 这样可以确保所有注意力权重

    a i j a_{ij}

    a

    ij

    的总和为 1 ,便于后续加权计算。

直观理解

  • Softmax 归一化后,最相关的 Key 对应的权重

    a i j a_{ij}

    a

    ij

    会更大,而不相关的 Key 权重会接近 0。


第三步:加权求和 Value
  • 计算出的注意力权重

    a i j a_{ij}

    a

    ij

    作用于对应的 Value(值向量),最终得到输出:

    o i

    ∑ j a i j v j o_i = \sum_{j} a_{ij} v_j

    o

    i

    =

    j

    a

    ij

    v

    j

  • 其中:

    • v j v_j

      v

      j

      是对应的值向量(value)

    • o i o_i

      o

      i

      是最终的加权求和结果(即注意力输出)

直观理解

  • 这个过程类似于 信息检索 ,即:
    • 如果某个 Key 与 Query 相似度高(即权重

      a i j a_{ij}

      a

      ij

      大),那么它的 Value(

      v j v_j

      v

      j

      ) 会被 重点关注

    • 最终的输出

      o i o_i

      o

      i

      是所有 Value 的 加权平均


2. 直观理解

可以把 注意力机制 类比为 搜索引擎

  • Query(查询) :用户输入的搜索关键词(如 “Transformer 论文”)。
  • Keys(键) :数据库中的所有文档标题(如 “Attention is All You Need”)。
  • Values(值) :数据库中的所有文档内容(如 Transformer 论文的正文)。
  • 计算相似度 :搜索引擎会计算用户输入的关键词与文档标题的相关性。
  • Softmax 归一化 :搜索引擎会给每个文档一个相关性分数,并归一化为一个排名概率。
  • 加权求和 :最终,搜索引擎会按照相关性高低,返回最相关的文档内容。

3. 在 Transformer 中的应用

Transformer 结构(如 BERT、GPT)中,

注意力机制被用于自注意力 Self-Attention 计算:

  • 输入是一个句子 ,每个单词都有一个 Query、Key、Value。
  • 计算 Query 与所有 Key 的相似度 ,确定哪些单词对当前单词最重要。
  • 对 Value 进行加权求和 ,生成新的单词表示。

示例

  • 句子: “The cat sat on the mat.”
  • 计算 “cat” 的注意力:
    • “cat” 可能关注 “The” 和 “sat” 的信息,而忽略 “mat”。
    • Transformer 通过注意力机制 动态调整单词之间的关系 ,提高理解能力。

4. 计算复杂度
  • 传统 RNN 计算复杂度:( O(n) ) (必须按顺序计算)
  • Transformer 注意力计算复杂度:( O(n^2) ) (可以并行计算)

虽然 Transformer 的注意力计算复杂度较高,但由于可以 并行计算 ,在实际应用中比 RNN 更高效。


1.3 编码器

https://i-blog.csdnimg.cn/direct/9b49333f192d4016a27d0dc0295c182c.png

1. 编码器的作用

编码器(Encoder)是 Transformer 结构的核心组件之一,它的主要作用是 将输入数据转换为隐藏层特征 ,以便后续的解码器(Decoder)进一步处理或用于下游任务(如分类、翻译等)。

在 Transformer 结构中,编码器由 N 个堆叠的编码器层(Encoder Layers) 组成,每个编码器层都包含:

  • 多头注意力机制(Multi-Head Attention, MHA)
  • 前馈神经网络(Feed Forward Network, FFN)
  • 残差连接(Residual Connection)和层归一化(Layer Normalization)

2. 编码器的结构

编码器的计算流程如下:

(1)多头注意力(Multi-Head Attention, MHA)
  • 计算输入序列中每个词对其他词的注意力权重,提取全局依赖关系。
  • 采用 多头注意力机制 (多个注意力头并行计算),以学习不同的特征表示。
(2)残差连接 + 层归一化
  • 计算多头注意力的输出后,使用 残差连接 (Residual Connection):

    X l ′

    LayerNorm ( MHA ( X l − 1 ) + X l − 1 ) X’l = \text{LayerNorm}(\text{MHA}(X{l-1}) + X_{l-1})

    X

    l

    =

    LayerNorm

    (

    MHA

    (

    X

    l

    1

    )

X

l

1

)

其中:

  • X l − 1 X_{l-1}

    X

    l

    1

    是上一层的输出

  • MHA 是多头注意力

  • LayerNorm 是层归一化,防止梯度消失或梯度爆炸

(3)前馈神经网络(Feed Forward Network, FFN)
  • 由两个全连接层(MLP)组成:

    FFN ( X ′ )

    ReLU ( X ′ W 1 + b 1 ) W 2 + b 2 \text{FFN}(X’) = \text{ReLU}(X’ W_1 + b_1) W_2 + b_2

    FFN

    (

    X

    )

    =

    ReLU

    (

    X

    W

    1

b

1

)

W

2

b

2

  • 作用是 增加非线性变换能力 ,提升模型的表达能力。
(4)再次残差连接 + 层归一化
  • 计算 FFN 输出后,再次应用残差连接:

    X l

    LayerNorm ( FFN ( X l ′ ) + X l ′ ) X_l = \text{LayerNorm}(\text{FFN}(X’_l) + X’_l)

    X

    l

    =

    LayerNorm

    (

    FFN

    (

    X

    l

    )

X

l

)

  • 这样可以 稳定梯度传递,提高训练效果

3. 公式解析

从公式来看,编码器的计算流程可以分为两步:

  1. 多头注意力层(MHA)+ 残差连接 + 层归一化

    X l ′

    LayerNorm ( MHA ( X l − 1 ) + X l − 1 ) X’l = \text{LayerNorm}(\text{MHA}(X{l-1}) + X_{l-1})

    X

    l

    =

    LayerNorm

    (

    MHA

    (

    X

    l

    1

    )

X

l

1

) 2. 前馈神经网络(FFN)+ 残差连接 + 层归一化

X l

LayerNorm ( FFN ( X l ′ ) + X l ′ ) X_l = \text{LayerNorm}(\text{FFN}(X’_l) + X’_l)

X

l

=

LayerNorm

(

FFN

(

X

l

)

X

l

)

其中:

  • ( X_{l-1} ) :表示编码器第 ( l-1 ) 层的输出
  • ( X’_l ) :表示经过多头注意力后的中间结果
  • ( X_l ) :表示编码器第 ( l ) 层的最终输出
  • LayerNorm :层归一化,稳定训练
  • MHA :多头注意力
  • FFN :前馈神经网络

4. 编码器的特点
  • 并行计算 :不像 RNN 需要逐步处理序列,Transformer 编码器可以一次性处理整个输入序列,提高计算效率。
  • 长距离依赖建模 :通过 自注意力机制(Self-Attention) ,编码器可以捕捉远距离的词语关系。
  • 层归一化 + 残差连接 :防止梯度消失,提高模型稳定性。
  • 多头注意力 :增强模型的表达能力,让不同的注意力头关注不同的信息。

5. 代码实现

Transformer 编码器层(Encoder Layer)的 PyTorch 实现

import torch
import torch.nn as nn

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        """
        Transformer 编码器层
        
        参数:
        - d_model: 输入特征维度(如 512)
        - num_heads: 多头注意力的头数
        - d_ff: 前馈神经网络的隐藏层维度(一般是 4*d_model)
        - dropout: Dropout 概率
        """
        super(TransformerEncoderLayer, self).__init__()

        # 多头注意力层
        self.self_attn = nn.MultiheadAttention(embed_dim=d_model, num_heads=num_heads, dropout=dropout)

        # 前馈神经网络
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )

        # 层归一化
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)

        # Dropout
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)

    def forward(self, x):
        """
        前向传播
        
        参数:
        - x: 输入张量 (batch_size, seq_len, d_model)
        
        返回:
        - 编码器层的输出 (batch_size, seq_len, d_model)
        """
        # 多头注意力
        attn_output, _ = self.self_attn(x, x, x)
        x = self.norm1(x + self.dropout1(attn_output))  # 残差连接 + 层归一化

        # 前馈神经网络
        ffn_output = self.ffn(x)
        x = self.norm2(x + self.dropout2(ffn_output))  # 残差连接 + 层归一化

        return x

# 测试编码器层
d_model = 512
num_heads = 8
d_ff = 2048
seq_len = 10
batch_size = 2

encoder_layer = TransformerEncoderLayer(d_model, num_heads, d_ff)
input_tensor = torch.rand(batch_size, seq_len, d_model)  # 随机输入
output_tensor = encoder_layer(input_tensor)

print("编码器层输出形状:", output_tensor.shape)  # (batch_size, seq_len, d_model)

组件作用
多头注意力(MHA)计算输入序列中不同位置的相关性,提取全局信息
前馈神经网络(FFN)增强特征表达能力
残差连接(Residual)防止梯度消失,提升训练稳定性
层归一化(LayerNorm)归一化激活值,稳定训练

编码器的关键作用是将输入转换为隐藏层特征,并通过层层堆叠提取更高级的语义信息。

1.4 解码器

1. 解码器的作用

https://i-blog.csdnimg.cn/direct/3ea5bd6fb28f4dd3aef5904028bface6.png

解码器(Decoder)是 Transformer 结构的另一核心组件,它的主要作用是 将编码器的隐藏层特征转换为输出序列 (如翻译任务中的目标语言句子)。

在 Transformer 结构中,解码器由 N 个堆叠的解码器层(Decoder Layers) 组成,每个解码器层包含:

  • 掩码多头注意力(Masked Multi-Head Attention, Masked MHA)
  • 交叉多头注意力(Cross Multi-Head Attention, Cross MHA)
  • 前馈神经网络(Feed Forward Network, FFN)
  • 残差连接(Residual Connection)和层归一化(Layer Normalization)

2. 解码器的结构

解码器的计算流程如下:

(1)掩码多头注意力(Masked Multi-Head Attention, Masked MHA)
  • 作用 :在生成序列时,模型不能看到未来的信息,因此需要掩码(Mask),确保解码器在预测第

    t t

    t 个词时,只能利用

    t t

    t 之前的词,而不能看到

    t + 1 t+1

    t

1 及之后的词。

  • 计算方式

    Y l ′

    LayerNorm ( MaskedMHA ( Y l − 1 ) + Y l − 1 ) Y’l = \text{LayerNorm}(\text{MaskedMHA}(Y{l-1}) + Y_{l-1})

    Y

    l

    =

    LayerNorm

    (

    MaskedMHA

    (

    Y

    l

    1

    )

Y

l

1

)

  • Y l − 1 Y_{l-1}

    Y

    l

    1

    是解码器前一层的输出

  • Masked MHA 计算当前词与之前词的注意力

  • LayerNorm 进行层归一化


(2)交叉多头注意力(Cross Multi-Head Attention, Cross MHA)
  • 作用 :在翻译任务中,解码器需要关注编码器的输出,以获取源语言的信息。

  • 计算方式

    Y l ′ ′

    LayerNorm ( CrossMHA ( Y l ′ , X L ) + Y l ′ ) Y’’_l = \text{LayerNorm}(\text{CrossMHA}(Y’_l, X_L) + Y’_l)

    Y

    l

    ′′

    =

    LayerNorm

    (

    CrossMHA

    (

    Y

    l

    ,

    X

    L

    )

Y

l

)

  • Y l ′ Y’_l

    Y

    l

    是掩码注意力的输出

  • X L X_L

    X

    L

    是编码器的最终输出

  • Cross MHA 计算解码器的隐藏状态与编码器输出之间的注意力关系


(3)前馈神经网络(Feed Forward Network, FFN)
  • 作用 :增强特征表达能力,提高模型的非线性变换能力。

  • 计算方式

    Y l

    LayerNorm ( FFN ( Y l ′ ′ ) + Y l ′ ′ ) Y_l = \text{LayerNorm}(\text{FFN}(Y’’_l) + Y’’_l)

    Y

    l

    =

    LayerNorm

    (

    FFN

    (

    Y

    l

    ′′

    )

Y

l

′′

)

  • FFN 由两个全连接层(MLP)组成:

    FFN ( Y ′ ′ )

    ReLU ( Y ′ ′ W 1 + b 1 ) W 2 + b 2 \text{FFN}(Y’’) = \text{ReLU}(Y’’ W_1 + b_1) W_2 + b_2

    FFN

    (

    Y

    ′′

    )

    =

    ReLU

    (

    Y

    ′′

    W

    1

b









1

​


)


W









2

​




+






b









2

​
  • 采用 ReLU 激活函数,增强非线性表达能力

4. 计算解析

解码器的计算流程可以分为三步:

  1. 掩码多头注意力(Masked MHA)+ 残差连接 + 层归一化

    Y l ′

    LayerNorm ( MaskedMHA ( Y l − 1 ) + Y l − 1 ) Y’l = \text{LayerNorm}(\text{MaskedMHA}(Y{l-1}) + Y_{l-1})

    Y

    l

    =

    LayerNorm

    (

    MaskedMHA

    (

    Y

    l

    1

    )

Y

l

1

) 2. 交叉多头注意力(Cross MHA)+ 残差连接 + 层归一化

Y l ′ ′

LayerNorm ( CrossMHA ( Y l ′ , X L ) + Y l ′ ) Y’’_l = \text{LayerNorm}(\text{CrossMHA}(Y’_l, X_L) + Y’_l)

Y

l

′′

=

LayerNorm

(

CrossMHA

(

Y

l

,

X

L

)

Y

l

) 3. 前馈神经网络(FFN)+ 残差连接 + 层归一化

Y l

LayerNorm ( FFN ( Y l ′ ′ ) + Y l ′ ′ ) Y_l = \text{LayerNorm}(\text{FFN}(Y’’_l) + Y’’_l)

Y

l

=

LayerNorm

(

FFN

(

Y

l

′′

)

Y

l

′′

)

其中:

  • **Y l − 1 Y_{l-1}

    Y

    l

    1

    )** :表示解码器第

    l − 1 l-1

    l

    1 层的输出

  • **Y l ′ Y’_l

    Y

    l

    ​** :表示掩码多头注意力后的中间结果

  • **Y l ′ ′ Y’’_l

    Y

    l

    ′′

    ​** :表示交叉多头注意力后的中间结果

  • **Y l Y_l

    Y

    l

    ​** :表示解码器第

    l l

    l 层的最终输出

  • **X L X_L

    X

    L

    ​** :编码器的最终输出

  • LayerNorm :层归一化,稳定训练

  • Masked MHA :掩码多头注意力(防止未来信息泄露)

  • Cross MHA :交叉多头注意力(关注编码器输出)

  • FFN :前馈神经网络


5. 编码器 vs. 解码器
组件编码器(Encoder)解码器(Decoder)
输入输入序列(如源语言)目标序列(如目标语言)
多头注意力标准多头注意力 (Self-Attention)掩码多头注意力 (Masked Self-Attention)
交叉注意力✅(关注编码器输出)
前馈神经网络
层归一化 & 残差连接

6. 代码实现

下面是 Transformer 解码器层(Decoder Layer)的 PyTorch 实现

import torch
import torch.nn as nn

class TransformerDecoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        """
        Transformer 解码器层
        
        参数:
        - d_model: 输入特征维度(如 512)
        - num_heads: 多头注意力的头数
        - d_ff: 前馈神经网络的隐藏层维度(一般是 4*d_model)
        - dropout: Dropout 概率
        """
        super(TransformerDecoderLayer, self).__init__()

        # 掩码多头注意力
        self.masked_attn = nn.MultiheadAttention(embed_dim=d_model, num_heads=num_heads, dropout=dropout)

        # 交叉多头注意力(关注编码器输出)
        self.cross_attn = nn.MultiheadAttention(embed_dim=d_model, num_heads=num_heads, dropout=dropout)

        # 前馈神经网络
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )

        # 层归一化
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.norm3 = nn.LayerNorm(d_model)

        # Dropout
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.dropout3 = nn.Dropout(dropout)

    def forward(self, x, encoder_output):
        """
        前向传播
        
        参数:
        - x: 解码器输入 (batch_size, seq_len, d_model)
        - encoder_output: 编码器输出 (batch_size, seq_len, d_model)
        
        返回:
        - 解码器层的输出 (batch_size, seq_len, d_model)
        """
        # 掩码多头注意力
        masked_attn_output, _ = self.masked_attn(x, x, x)
        x = self.norm1(x + self.dropout1(masked_attn_output))  # 残差连接 + 层归一化

        # 交叉多头注意力
        cross_attn_output, _ = self.cross_attn(x, encoder_output, encoder_output)
        x = self.norm2(x + self.dropout2(cross_attn_output))  # 残差连接 + 层归一化

        # 前馈神经网络
        ffn_output = self.ffn(x)
        x = self.norm3(x + self.dropout3(ffn_output))  # 残差连接 + 层归一化

        return x

# 测试解码器层
decoder_layer = TransformerDecoderLayer(d_model=512, num_heads=8, d_ff=2048)
input_tensor = torch.rand(2, 10, 512)  # 解码器输入
encoder_output = torch.rand(2, 10, 512)  # 编码器输出
output_tensor = decoder_layer(input_tensor, encoder_output)

print("解码器层输出形状:", output_tensor.shape)  # (batch_size, seq_len, d_model)

解码器的核心在于:

  • 掩码多头注意力 (Masked MHA):防止未来信息泄露
  • 交叉多头注意力 (Cross MHA):关注编码器的输出
  • 前馈神经网络(FFN) :增强特征表达能力

1.5 多头注意力层

https://i-blog.csdnimg.cn/direct/793506f2d1824881b2b2643489508eb9.png

多头注意力(Multi-Head Attention, MHA)是 Transformer 结构的核心组件之一,它能够 让模型关注输入序列中不同位置的关系 ,并 通过多个注意力头(heads)学习不同的特征表示


1. Scaled Dot-Product Attention(缩放点积注意力)

多头注意力的基础是 缩放点积注意力(Scaled Dot-Product Attention) ,其计算流程如下:

(1)输入映射到 Q、K、V

给定输入矩阵

X X

X ,我们将其映射为:

  • 查询(Query, Q)

    Q

    X W Q Q = X W^Q

    Q

    =

    X

    W

    Q

  • 键(Key, K)

    K

    X W K K = X W^K

    K

    =

    X

    W

    K

  • 值(Value, V) :$ V = X W^V$

其中:

  • W Q , W K , W V W^Q, W^K, W^V

    W

    Q

    ,

    W

    K

    ,

    W

    V 是可训练的权重矩阵

  • X X

    X 是输入特征(如词向量)

(2)计算注意力权重

注意力分数使用 点积计算

S

Q K T S = QK^T

S

=

Q

K

T

然后进行 缩放 (防止梯度爆炸):

S scaled

Q K T d k S_{\text{scaled}} = \frac{QK^T}{\sqrt{d_k}}

S

scaled

=

d

k

Q

K

T

其中:

  • d k d_k

    d

    k

    是键向量的维度

  • d k \sqrt{d_k}

    d

    k

    作为缩放因子,防止数值过大导致梯度消失或梯度爆炸

(3)计算 Softmax 权重

α

softmax ( S scaled ) \alpha = \text{softmax}(S_{\text{scaled}})

α

=

softmax

(

S

scaled

)

Softmax 归一化后,表示不同位置的注意力分布。

(4)加权求和

计算最终的注意力输出:

Attention ( Q , K , V )

α V \text{Attention}(Q, K, V) = \alpha V

Attention

(

Q

,

K

,

V

)

=

α

V


2. 多头注意力(Multi-Head Attention, MHA)

在单头注意力机制中,所有信息都通过同一个注意力机制计算,可能会忽略一些重要特征。 多头注意力的核心思想是:使用多个注意力头(heads),让模型关注不同的特征信息。

(1)多头注意力计算流程
  1. 输入映射到多个 Q、K、V

    • 对输入

      X X

      X 进行多组不同的线性变换,得到多个查询、键和值:

      Q i

      X W i Q , K i

      X W i K , V i

      X W i V , i

      1 , 2 , … , h Q_i = X W_i^Q, \quad K_i = X W_i^K, \quad V_i = X W_i^V, \quad i = 1,2,\dots,h

      Q

      i

      =

      X

      W

      i

      Q

      ,

      K

      i

      =

      X

      W

      i

      K

      ,

      V

      i

      =

      X

      W

      i

      V

      ,

      i

      =

      1

      ,

      2

      ,

      ,

      h

    • 其中

      h h

      h 是注意力头的数量,每个注意力头都有自己的权重矩阵

      W i Q , W i K , W i V W_i^Q, W_i^K, W_i^V

      W

      i

      Q

      ,

      W

      i

      K

      ,

      W

      i

      V

  2. 每个头独立计算注意力

    • 每个头独立计算缩放点积注意力:

      Attention i ( Q i , K i , V i )

      softmax ( Q i K i T d k ) V i \text{Attention}_i(Q_i, K_i, V_i) = \text{softmax} \left( \frac{Q_i K_i^T}{\sqrt{d_k}} \right) V_i

      Attention

      i

      (

      Q

      i

      ,

      K

      i

      ,

      V

      i

      )

      =

      softmax

      (

      d

      k

      Q

      i

      K

      i

      T

      )

      V

      i

  3. 拼接多个头的输出

    • 将所有注意力头的输出拼接在一起:

      MultiHead ( Q , K , V )

      Concat ( head 1 , head 2 , … , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, \dots, \text{head}_h) W^O

      MultiHead

      (

      Q

      ,

      K

      ,

      V

      )

      =

      Concat

      (

      head

      1

      ,

      head

      2

      ,

      ,

      head

      h

      )

      W

      O

    • 其中

      W O W^O

      W

      O 是最终的线性变换矩阵,将拼接后的结果映射回原始维度。


3. 公式总结
1.单头注意力(Scaled Dot-Product Attention)

Attention ( Q , K , V )

softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax} \left( \frac{Q K^T}{\sqrt{d_k}} \right) V

Attention

(

Q

,

K

,

V

)

=

softmax

(

d

k

Q

K

T

)

V

2.多头注意力(Multi-Head Attention)

MultiHead ( Q , K , V )

Concat ( head 1 , head 2 , … , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, \dots, \text{head}_h) W^O

MultiHead

(

Q

,

K

,

V

)

=

Concat

(

head

1

,

head

2

,

,

head

h

)

W

O

其中:

head i

Attention ( Q i , K i , V i ) \text{head}_i = \text{Attention}(Q_i, K_i, V_i)

head

i

=

Attention

(

Q

i

,

K

i

,

V

i

)


4. 代码实现

多头注意力(Multi-Head Attention, MHA)的 PyTorch 实现

import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads, dropout=0.1):
        """
        多头注意力层
        
        参数:
        - d_model: 输入特征维度(如 512)
        - num_heads: 注意力头的数量
        - dropout: Dropout 概率
        """
        super(MultiHeadAttention, self).__init__()

        assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"

        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # 每个头的维度

        # 线性变换矩阵
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

        self.dropout = nn.Dropout(dropout)

    def attention(self, Q, K, V, mask=None):
        """
        计算缩放点积注意力
        """
        scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))
        attn_weights = torch.softmax(scores, dim=-1)
        attn_weights = self.dropout(attn_weights)
        return torch.matmul(attn_weights, V), attn_weights

    def forward(self, X):
        batch_size, seq_len, _ = X.shape

        # 计算 Q, K, V
        Q = self.W_q(X).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(X).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(X).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)

        # 计算多头注意力
        attn_output, attn_weights = self.attention(Q, K, V)

        # 拼接多个头的输出
        attn_output = attn_output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.d_model)

        # 线性变换回原始维度
        output = self.W_o(attn_output)

        return output, attn_weights

# 测试多头注意力
d_model = 512
num_heads = 8
seq_len = 10
batch_size = 2

mha = MultiHeadAttention(d_model, num_heads)
input_tensor = torch.rand(batch_size, seq_len, d_model)  # 随机输入
output_tensor, attention_weights = mha(input_tensor)

print("多头注意力输出形状:", output_tensor.shape)  # (batch_size, seq_len, d_model)

  • 多头注意力(MHA)能够学习不同的注意力模式,提高模型的表达能力。
  • 通过多个注意力头,模型可以关注输入序列的不同方面。
  • 缩放点积注意力(Scaled Dot-Product Attention)是 MHA 的基础,计算 Query-Key 相关性并加权 Value。

1.6 位置编码

https://i-blog.csdnimg.cn/direct/24f51373e75a4777b978d5259a8b58be.png

https://i-blog.csdnimg.cn/direct/4cdeb6359dc34dab809a67aebd5d046e.png

在 Transformer 模型中,由于 自注意力机制(Self-Attention) 没有内置的序列顺序信息,因此需要 位置编码(Positional Encoding) 来显式地提供序列位置信息,使模型能够区分不同单词的顺序。


1. 位置编码的数学定义

位置编码采用 正弦(sin)和余弦(cos)函数 生成,如下公式:

p t ( i )

{ sin ⁡ ( ω k ⋅ t ) , if  i

2 k cos ⁡ ( ω k ⋅ t ) , if  i

2 k + 1 p_t^{(i)} = \begin{cases} \sin(\omega_k \cdot t), & \text{if } i = 2k \ \cos(\omega_k \cdot t), & \text{if } i = 2k+1 \end{cases}

p

t

(

i

)

=

{

sin

(

ω

k

t

)

,

cos

(

ω

k

t

)

,

if

i

=

2

k

if

i

=

2

k

1

其中:

  • p t ( i ) p_t^{(i)}

    p

    t

    (

    i

    )

    表示 **位置

    t t

    t 处,第

    i i

    i 维的编码值** 。

  • ω k \omega_k

    ω

    k

    是不同维度的频率,定义为:

    ω k

    1 1000 0 2 k / d \omega_k = \frac{1}{10000^{2k/d}}

    ω

    k

    =

    1000

    0

    2

    k

    /

    d

    1

    其中:

    • k k

      k 表示当前维度的索引(偶数维和奇数维分别使用 sin 和 cos)。

    • d d

      d 是隐藏层维度(例如 512)。

    • 这个公式确保 不同维度的频率不同 ,以捕捉不同粒度的位置信息。


2. 位置编码的特点
  • 使用不同频率的正弦和余弦函数
    • 低维度使用较大的频率(变化较快),编码局部信息。
    • 高维度使用较小的频率(变化较慢),编码全局信息。
  • 编码值是固定的,不需要训练 ,不同位置的编码是固定的数学计算结果,不依赖数据训练。
  • 可以外推到更长的序列 ,因为是基于数学函数计算的,而不是学习得到的。

3. 位置编码的作用
  • 提供位置信息 :帮助 Transformer 区分不同单词的顺序。
  • 支持长序列建模 :由于编码是基于数学函数计算的,可以推广到比训练时更长的序列。
  • 平滑的连续变化 :由于使用正弦和余弦函数,编码值在相邻位置之间连续变化,使得模型可以更容易学习相对位置信息。

4. 代码实现

可以使用 Python(PyTorch)实现位置编码:

import numpy as np
import matplotlib.pyplot as plt

def positional_encoding(seq_len, d_model):
    pos = np.arange(seq_len)[:, np.newaxis]  # 位置 (t)
    i = np.arange(d_model)[np.newaxis, :]  # 维度 (i)

    # 计算频率
    omega = 1 / (10000 ** (2 * (i // 2) / d_model))

    # 计算位置编码
    pos_encoding = np.zeros((seq_len, d_model))
    pos_encoding[:, 0::2] = np.sin(pos * omega[:, 0::2])  # 偶数维
    pos_encoding[:, 1::2] = np.cos(pos * omega[:, 1::2])  # 奇数维

    return pos_encoding

# 生成位置编码
seq_len, d_model = 100, 512
pos_encoding = positional_encoding(seq_len, d_model)

# 可视化
plt.figure(figsize=(10, 6))
plt.imshow(pos_encoding, aspect='auto', cmap='coolwarm')
plt.xlabel("Dimension i")
plt.ylabel("Position t")
plt.title("Positional Encoding Heatmap")
plt.colorbar()
plt.show()

位置编码通过 sin 和 cos 赋予 Transformer 位置信息

不同维度使用不同频率,捕捉局部和全局信息

数学计算得到,不需要训练,可推广到长序列

2. 问题备注

Transformer 结构 中, Q(Query)、K(Key)、V(Value) 的来源在 编码器(Encoder)解码器(Decoder) 中有所不同,具体如下:


1. 编码器(Encoder)中的 Q、K、V

编码器的自注意力(Self-Attention) 机制中:

  • 输入 :编码器的输入是一个序列 ( X )(如源语言句子)。

  • Q、K、V 的来源

    Q

    X W Q , K

    X W K , V

    X W V Q = X W^Q, \quad K = X W^K, \quad V = X W^V

    Q

    =

    X

    W

    Q

    ,

    K

    =

    X

    W

    K

    ,

    V

    =

    X

    W

    V

    • Query(查询) :由输入

      X X

      X 经过线性变换得到

    • Key(键) :由输入

      X X

      X 经过线性变换得到

    • Value(值) :由输入

      X X

      X 经过线性变换得到

特点

  • 自注意力(Self-Attention) :Q、K、V 都来自相同的输入 ( X )。
  • 作用 :让编码器的每个词关注输入序列中的其他词,捕捉全局信息。

2. 解码器(Decoder)中的 Q、K、V

解码器的注意力机制 中,注意力分为两种:

  1. Masked 自注意力(Masked Self-Attention)
  2. 交叉注意力(Cross-Attention)
(1)Masked 自注意力中的 Q、K、V
  • 输入 :解码器的输入是目标序列 ( Y )(如目标语言句子)。

  • Q、K、V 的来源

    Q

    Y W Q , K

    Y W K , V

    Y W V Q = Y W^Q, \quad K = Y W^K, \quad V = Y W^V

    Q

    =

    Y

    W

    Q

    ,

    K

    =

    Y

    W

    K

    ,

    V

    =

    Y

    W

    V

    • Query(查询) :由目标序列

      Y Y

      Y 计算

    • Key(键) :由目标序列

      Y Y

      Y 计算

    • Value(值) :由目标序列

      Y Y

      Y 计算

特点

  • Masked 机制 :在计算注意力时,屏蔽未来的信息,防止看到后续词语。
  • 作用 :让解码器的每个词只能关注当前及之前的词,确保自回归特性。

(2)交叉注意力(Cross-Attention)中的 Q、K、V
  • 输入 :交叉注意力的输入是 解码器的隐藏状态编码器的输出

  • Q、K、V 的来源

    Q

    Y W Q , K

    X L W K , V

    X L W V Q = Y W^Q, \quad K = X_L W^K, \quad V = X_L W^V

    Q

    =

    Y

    W

    Q

    ,

    K

    =

    X

    L

    W

    K

    ,

    V

    =

    X

    L

    W

    V

    • Query(查询) :来自解码器的隐藏状态

      Y Y

      Y

    • Key(键) :来自编码器的输出

      X L X_L

      X

      L

    • Value(值) :来自编码器的输出

      X L X_L

      X

      L

特点

  • Q 来自解码器,K 和 V 来自编码器 ,让解码器能够关注编码器的信息。
  • 作用 :让解码器在生成目标序列时,能够参考源语言的信息。

位置Query(Q)来源Key(K)来源Value(V)来源作用
编码器(Encoder)输入 (X)输入 (X)输入 (X)让每个词关注整个输入序列
解码器(Masked 自注意力)目标序列 (Y)目标序列 (Y)目标序列 (Y )让解码器的每个词关注当前及之前的词
解码器(交叉注意力)目标序列 (Y)编码器输出 X L X_L X L ​编码器输出 X L X_L X L ​

  • 编码器的 Q、K、V 都来自输入 ( X ) ,用于捕捉全局信息。

  • 解码器的 Masked 自注意力的 Q、K、V 都来自目标序列

    Y Y

    Y ,用于保证自回归特性。

  • 解码器的交叉注意力的 Q 来自解码器,K 和 V 来自编码器的输出

    X L X_L

    X

    L

    **,用于关注源语言信息。

3.为什么注意力模型计算选用点积(Dot-Product)?

在 Transformer 的注意力机制(Self-Attention 和 Cross-Attention)中, 点积(Dot-Product) 是计算 Query(查询)和 Key(键)之间相似度的核心操作。主要原因包括以下几点:


1. 计算效率高

点积计算的核心公式是:

S

Q K T S = QK^T

S

=

Q

K

T

其中:

  • Q Q

    Q (查询):

    ( b a t c h , s e q _ l e n , d k ) (batch, seq_len, d_k)

    (

    ba

    t

    c

    h

    ,

    se

    q

    _

    l

    e

    n

    ,

    d

    k

    )

  • K K

    K (键):

    ( b a t c h , s e q _ l e n , d k ) (batch, seq_len, d_k)

    (

    ba

    t

    c

    h

    ,

    se

    q

    _

    l

    e

    n

    ,

    d

    k

    )

点积计算的时间复杂度为 **O ( d k ) O(d_k)

O

(

d

k

)** ,相比其他相似度计算方法(如欧几里得距离、余弦相似度)更加高效,尤其适用于 GPU 并行计算。

对比计算复杂度:

  • **点积(Dot-Product):

    O ( d k ) O(d_k)

    O

    (

    d

    k

    )** (只需乘法和加法)

  • **欧几里得距离(Euclidean Distance):

    O ( d k ) O(d_k)

    O

    (

    d

    k

    )** (需要平方、开方)

  • **余弦相似度(Cosine Similarity):

    O ( d k ) O(d_k)

    O

    (

    d

    k

    )** (需要归一化)

由于 Transformer 需要处理大规模数据(如 NLP 任务中的长文本、视频分析中的时序数据),选择计算效率高的点积是更优的选择。


2. 点积能够有效衡量相似性
(1)点积的几何解释

点积计算:

Q i ⋅ K j

∑ d

1 d k Q i d K j d Q_i \cdot K_j = \sum_{d=1}^{d_k} Q_{id} K_{jd}

Q

i

K

j

=

d

=

1

d

k

Q

i

d

K

j

d

  • 如果

    Q Q

    Q 和

    K K

    K 的方向相同(即两个向量相似),点积值较大。

  • 如果

    Q Q

    Q 和

    K K

    K 的方向正交(即无关),点积值接近 0。

  • 如果

    Q Q

    Q 和

    K K

    K 的方向相反,点积值较小(可能为负)。

这与注意力机制的需求一致: 希望让 Query 关注与自己最相关的 Key

(2)点积 vs. 余弦相似度

余弦相似度计算如下:

cos ⁡ ( θ )

Q ⋅ K ∥ Q ∥ ∥ K ∥ \cos(\theta) = \frac{Q \cdot K}{|Q| |K|}

cos

(

θ

)

=

Q

∥∥

K

Q

K

虽然余弦相似度也能衡量向量的相似性,但它需要额外的归一化操作(计算向量模长),这会增加计算成本。而点积本质上是未归一化的余弦相似度,因此可以直接用于注意力计算。


3. 结合 Softmax 归一化

点积计算的结果:

S

Q K T S = QK^T

S

=

Q

K

T

通常会经过 Softmax 归一化

α

softmax ( Q K T d k ) \alpha = \text{softmax} \left(\frac{QK^T}{\sqrt{d_k}}\right)

α

=

softmax

(

d

k

Q

K

T

)

  • Softmax 作用 :将点积结果转换为概率分布,使得所有注意力权重之和为 1。

  • **缩放因子

    d k \sqrt{d_k}

    d

    k

    ​** :防止点积值过大导致梯度消失。

这种组合方式使得点积注意力(Scaled Dot-Product Attention)既高效又稳定。


4. 经验验证:点积注意力效果优于加性注意力

在早期的注意力机制(如 Bahdanau Attention)中,使用的是 加性注意力(Additive Attention)

score ( Q , K )

V T tanh ⁡ ( W q Q + W k K ) \text{score}(Q, K) = V^T \tanh(W_q Q + W_k K)

score

(

Q

,

K

)

=

V

T

tanh

(

W

q

Q

W

k

K

)

但研究发现:

  • 点积注意力(Dot-Product Attention)在大规模数据上效果更好

  • 点积计算可以更好地利用矩阵运算加速(GPU 友好)

  • **加性注意力需要额外的参数

    W q , W k , V W_q, W_k, V

    W

    q

    ,

    W

    k

    ,

    V ,而点积注意力不需要额外参数** 。

因此,在 Transformer 及其变体(如 BERT、GPT、ViT)中, 点积注意力成为主流选择


  • 点积计算高效,适合 GPU 并行计算 (相比加性注意力更快)。
  • 点积能够有效衡量向量相似性 (与余弦相似度类似,但计算更简单)。
  • 结合 Softmax 归一化,使注意力机制更加稳定 (避免梯度消失)。
  • 实验验证:点积注意力在大规模数据上效果优于加性注意力

因此, Transformer 采用点积注意力(Dot-Product Attention)作为核心计算方式 ,并结合 Softmax 归一化和缩放因子

d k \sqrt{d_k}

d

k

进行优化。

4. 为什么要除以 D \sqrt{D} D ​ (Scale)?

点积注意力(Dot-Product Attention) 计算中,我们使用 Query(Q)和 Key(K) 的点积来衡量相似性:

S

Q K T S = QK^T

S

=

Q

K

T

然后通过 Softmax 归一化计算注意力权重:

α

softmax ( S ) V \alpha = \text{softmax}(S)V

α

=

softmax

(

S

)

V

但是,如果不进行缩放,点积值可能会变得 过大 ,导致 Softmax 输出极端化 ,影响模型训练。

因此,我们 除以 ( \sqrt{D} )(D 为特征维度) 来进行缩放,最终计算方式如下:

S

Q K T D S = \frac{QK^T}{\sqrt{D}}

S

=

D

Q

K

T


1. 避免点积值过大,防止梯度消失

在高维空间(例如

D

512 D=512

D

=

512 ,

Q Q

Q 和

K K

K 的元素通常服从 均值为 0,方差为 1 的正态分布(假设初始化时)。

那么,点积

S S

S 的期望值和方差计算如下:

  • 点积的期望值

    E [ Q K T ]

    0 \mathbb{E}[QK^T] = 0

    E

    [

    Q

    K

    T

    ]

    =

    0 $$

    因为 ( Q ) 和 ( K ) 服从均值为 0 的分布,所以它们的点积的均值仍然是 0。

  • 点积的方差

    Var ( Q K T )

    D \text{Var}(QK^T) = D

    Var

    (

    Q

    K

    T

    )

    =

    D

    由于点积涉及 ( D ) 个独立变量的乘积求和,方差会随着 ( D ) 增大而增大。

D D

D 很大时,例如

D

512 或 1024 D = 512 或 1024

D

=

512

1024 ,点积值的方差也会变得很大,导致 Softmax 计算时的指数函数

e x e^x

e

x 的值过大,使得:

  • Softmax 输出接近 one-hot (即某个值接近 1,其他值接近 0)。
  • 反向传播时梯度变得很小(梯度消失),影响模型训练。

解决方案:

  • 通过 除以 ( \sqrt{D} ) ,让点积值的方差变为 1:

    Var ( Q K T D )

    1 \text{Var} \left(\frac{QK^T}{\sqrt{D}}\right) = 1

    Var

    (

    D

    Q

    K

    T

    )

    =

    1

  • 这样,Softmax 输出更加平滑,梯度不会消失,有助于稳定训练。


2. 直观理解

可以用一个形象的例子来理解:

  • 未缩放的点积 (大值输入 Softmax):就像一个考试成绩满分 1000 分的系统,99 分和 100 分的差距微乎其微,但 Softmax 会放大这个差距,使得 100 分的注意力远大于 99 分。
  • 缩放后的点积 (小值输入 Softmax):就像一个满分 100 分的考试,99 分和 100 分的差距不会被过度放大,注意力分布更加合理。

防止 Softmax 过度偏向单个 token (避免 one-hot 现象)。

保持梯度稳定,防止梯度消失,使模型更容易训练

在高维空间(如 D=512)时,避免点积值过大,保证数值稳定性

因此, **Transformer 采用 Scaled Dot-Product Attention,即在计算

Q K T QK^T

Q

K

T 后除以

D \sqrt{D}

D

,确保模型训练更稳定,注意力分布更合理。**

参考文献