Transformers-自注意力机制和层归一化

博主随便发一个笔记,来记录一下!!!

一、自注意力机制:捕捉序列全局依赖的利器

自注意力机制(Self-Attention Mechanism)的核心目标是解决传统序列建模模型(如 RNN、LSTM)在长序列处理中的局限性,实现全局依赖捕捉和并行计算。

1.1基本概念:Q、K、V 的核心角色

自注意力机制的核心是通过 "查询 - 键 - 值"(Query-Key-Value)交互模式,计算序列中每个元素与其他元素的关联关系。其本质是回答两个问题:"我应该关注谁?" 和 "关注后如何融合信息?"

  • Query(Q,查询向量):当前元素的 "需求表达",用于主动查询其他元素的相关性,即 "我想知道对我来说谁重要";
  • Key(K,键向量):其他元素的 "身份标签",用于被查询时提供匹配依据,即 "告诉别人自己是什么";
  • Value(V,值向量):其他元素的 "实际信息内容",即 "被关注后提供的具体信息"。

每个元素在序列中同时扮演这三个角色,通过三者的交互实现上下文信息的动态融合。

1.1实现过程:从输入到注意力输出的完整流程

自注意力机制的实现可分为以下关键步骤:

步骤 1:输入序列表示

设输入为长度为n、维度为d的序列:
X=(x1​,x2​,…,xn​)∈Rn×d
其中xi​为序列中第i个元素的向量表示(如词向量)。

步骤 2:Q、K、V 的线性变换

通过可学习的权重矩阵将输入映射为 Q、K、V:
 

代码示例:

import torch
import math

# 假设输入嵌入维度为512,序列长度为7
embedding_out = torch.randn(7, 512)  # 模拟嵌入层输出

# 生成Q、K、V
Wq = torch.randn(512, 512)  # Query权重矩阵
Wk = torch.randn(512, 512)  # Key权重矩阵
Wv = torch.randn(512, 512)  # Value权重矩阵

Query = torch.matmul(embedding_out, Wq)  # 形状:[7, 512]
Key = torch.matmul(embedding_out, Wk)    # 形状:[7, 512]
Value = torch.matmul(embedding_out, Wv)  # 形状:[7, 512]
步骤 3:计算注意力得分

通过 Q 与 K 的点积计算元素间相似度,并除以dk​​避免数值过大导致的梯度问题:
\text{Attention}(Q, K) = \frac{QK^T}{\sqrt{d_k}}

其中(i,j)位置的元素表示第i个元素与第j个元素的相关性得分。

代码示例:

# 计算注意力得分并缩放
score = torch.matmul(Query, Key.transpose(0, 1)) / math.sqrt(512)
# 输出形状:[7, 7],每个元素(i,j)表示第i个词与第j个词的原始相关性
步骤 4:注意力权重归一化

对得分矩阵按行进行 Softmax 操作,将得分转换为概率分布(每行和为 1):
\text{Attention Weight} = \text{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)

代码示例:

# 归一化注意力得分
normalized_scores = torch.softmax(score, dim=1)  # 按行归一化
# 输出形状:[7, 7],每个元素表示归一化后的注意力权重
步骤 5:加权求和生成输出

用注意力权重对 V 进行加权求和,得到融合上下文信息的输出:
\text{Output} =\text{Attention Weight} \times V = \text{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right) \times V

代码示例:

# 加权求和得到最终输出
attention_result = torch.matmul(normalized_scores, Value)
# 输出形状:[7, 512],每个元素是融合上下文后的向量表示

二、多头注意力机制:增强模型表达能力的扩展

多头注意力机制(Multi-Head Attention)是自注意力的扩展,通过多组并行的注意力计算,让模型在不同子空间学习多样化的上下文关联。

2.1 核心思想

多头注意力将 Q、K、V 分割为h个 "头"(子空间),每个头独立计算自注意力,最后将所有头的输出拼接并映射为最终结果。其核心价值是让模型同时学习不同类型的关联模式(如语法关联、语义关联等)。

2.2 实现过程

步骤 1:多头分割与映射

将 Q、K、V 通过不同的权重矩阵映射到h个子空间,每个子空间维度为dk​/h(通常总维度保持不变):
 

代码示例:

head_num = 8  # 头数量
d_k = 512 // head_num  # 每个头的维度

# 生成每个头的Q、K、V权重矩阵
W_Q_list = torch.stack([torch.randn(512, d_k) for _ in range(head_num)])
W_K_list = torch.stack([torch.randn(512, d_k) for _ in range(head_num)])
W_V_list = torch.stack([torch.randn(512, d_k) for _ in range(head_num)])

# 映射得到每个头的Q、K、V
Query_list = torch.stack([torch.matmul(embedding_out, W_Q_list[i]) for i in range(head_num)])
Key_list = torch.stack([torch.matmul(embedding_out, W_K_list[i]) for i in range(head_num)])
Value_list = torch.stack([torch.matmul(embedding_out, W_V_list[i]) for i in range(head_num)])
# 形状:[8, 7, 64](8个头,每个头序列长度7,维度64)
步骤 2:多头独立计算

每个头独立执行自注意力计算(得分→归一化→加权求和):
O_h = A_h V_h

代码示例:

# 每个头计算注意力得分
scores_list = torch.stack([
    torch.matmul(Query_list[i], Key_list[i].transpose(0, 1)) / math.sqrt(d_k) 
    for i in range(head_num)
])
# 归一化
scores_list = torch.stack([torch.softmax(scores_list[i], dim=-1) for i in range(head_num)])
# 加权求和得到每个头的输出
Output_list = [torch.matmul(scores_list[i], Value_list[i]) for i in range(head_num)]
步骤 3:输出拼接与线性变换

将所有头的输出拼接,再通过线性变换得到最终结果:
O_{\text{concat}} = [O_1, O_2, \dots, O_h] \in \mathbb{R}^{n \times h \cdot d_v}

其中,O_{\text{concat}} 是所有头拼接的结果,维度是 n \times (h \cdot d_v),其中 h 是头的数量,d_v 是每个头的值向量的维度。

代码示例:

# 拼接所有头的输出
Output = torch.cat(Output_list, dim=-1)  # 形状:[7, 512]
# 最终线性变换
W_O = torch.randn(512, 512)
Output = torch.matmul(Output, W_O)  # 形状:[7, 512]

2.3 表达能力提升

多头注意力通过多子空间并行学习,让模型:

  • 同时捕捉不同类型的关联(如语法、语义、位置等);
  • 增强对复杂上下文的建模能力;
  • 提高模型的鲁棒性和泛化能力。

三、层归一化:稳定训练的关键技术

层归一化(Layer Normalization)是用于规范化神经网络中间特征分布的技术,与 BatchNorm 相比,更适合 Transformer、RNN 等序列建模场景。

3.1 与 BatchNorm 的核心区别

特征BatchNormLayerNorm
归一化维度对每个特征维度在 batch 内归一化对每个样本的所有特征维度归一化
应用场景CNN 常用Transformer、RNN 等序列模型常用
依赖 batch_size依赖(batch_size 过小效果差)不依赖(单样本即可计算)
推理阶段处理需要存储训练时的均值 / 方差直接用当前样本计算,无需存储

3.2 计算过程

层归一化以单个样本为单位,对其所有特征维度进行归一化,步骤如下:

     1.计算均值:对样本的所有特征维度求平均

      \mu_c = \frac{1}{N \cdot H \cdot W} \sum_{n,h,w} x_{nchw}

     2.计算方差

     \quad \sigma_c^2 = \frac{1}{N \cdot H \cdot W} \sum_{n,h,w} (x_{nchw} - \mu_c)^2

     3.归一化

     \hat{x}_{nchw} = \frac{x_{nchw} - \mu_c}{\sqrt{\sigma_c^2 + \epsilon}}

3.3 实例说明

假设你有一句话经过嵌入层后的表示是一个矩阵,形状是:

[句子长度, 特征维度] = [5, 4]

一句 5 个词,每个词用 4 维向量表示:

["I", "am", "a", "good", "student"]

经过 embedding 之后得到:

I        -> [1.2, -0.5, 0.3, 0.7]  
am       -> [1.0,  0.0, 0.1, 0.6]  
a        -> [0.9,  0.2, 0.4, 0.3]  
good     -> [1.3, -0.3, 0.5, 0.8]  
student  -> [1.1, -0.1, 0.2, 0.4]

它对每个词的 4 维向量分别归一化:

  1. 计算均值:\mu = \frac{1.2 + (-0.5) + 0.3 + 0.7}{4} = 0.425
  2. 计算方差:\sigma^2 = \frac{(1.2 - 0.425)^2 + (-0.5 - 0.425)^2 + ...}{4} \approx 0.4319
  3. 归一化:每个维度减去均值并除以标准差\text{LayerNorm}(x_i) = \frac{x_i - \mu}{\sqrt{\sigma^2 + \epsilon}}, 最终你得到一个新的 [1.2, -0.5, 0.3, 0.7] 的“归一化版本”,然后对“am”、“a”、“good”、“student”每一个词都分别做这个过程。

### 自注意力机制的核心思想 自注意力机制(Self-Attention Mechanism)是一种特殊的注意力机制,其核心思想是在输入序列内部建立依赖关系。具体而言,它通过对同一序列的不同位置进行加权组合,从而捕捉全局上下文信息[^1]。这种机制使得模型能够在不同时间步之间动态分配权重,而无需显式的距离约束或顺序限制[^2]。 #### 计算过程概述 在实现层面,自注意力机制通常涉及三个关键组件:查询(Query)、键(Key)以及值(Value)。对于每一个输入元素,都会生成对应的 Query 向量、Key 向量 Value 向量。接着,通过计算 Query Key 的相似度得分,并将其经过 Softmax 归一化后作为权重系数,对相应的 Value 进行加权求,得到最终输出[^1]。 这一过程不仅保留了原始输入的位置信息,还增强了语义关联性强的部分在整个表示中的重要程度[^3]。 --- ### 主要应用场景 1. **自然语言处理 (NLP)** 在诸如文本分类、情感分析、命名实体识别等领域中,利用 Transformer 架构所包含的 Self-Attention 层可以显著改善长程依存建模效果。例如,在机器翻译任务中,Self-Attention 能够有效捕获源语言句子与目标语言句子间的对应关系,即使两者长度差异较大也能保持良好的泛化能力[^1]。 2. **计算机视觉** 将 Self-Attention 引入卷积神经网络(CNN),形成混合架构如 Vision Transformers(ViT),可以在图片分类、物体检测等方面取得突破性进展。这类方法打破了传统滑动窗口操作的空间局限性,允许更大范围的感受野参与决策制定过程。 3. **语音信号处理** 面向端到端自动语音识别(ASR)系统开发时,采用带有 Self-Attention 组件的编码器解码器结构有助于更好地表征音频帧间潜在联系,进而提升字错率(WER)[^3]。 4. **推荐系统** 用户行为日志往往呈现稀疏性高维度特性,借助 Self-Attention 技术可以从海量交互事件里挖掘深层次兴趣偏好模式,进一步优化个性化推送策略[^3]。 ```python import torch import torch.nn.functional as F def scaled_dot_product_attention(query, key, value): """ 实现缩放点乘法自注意力机制。 参数: query: 查询张量形状为 [batch_size, num_heads, seq_len_q, depth_k] key: 键张量形状为 [batch_size, num_heads, seq_len_v, depth_k] value: 值张量形状为 [batch_size, num_heads, seq_len_v, depth_v] 返回: context_vector: 上下文向量 """ scores = torch.matmul(query, key.transpose(-2, -1)) / torch.sqrt(torch.tensor(key.size(-1)).float()) attention_weights = F.softmax(scores, dim=-1) output = torch.matmul(attention_weights, value) return output # 示例调用 query = torch.randn((32, 8, 50, 64)) key = torch.randn((32, 8, 50, 64)) value = torch.randn((32, 8, 50, 64)) context_vector = scaled_dot_product_attention(query, key, value) print(context_vector.shape) # 输出应为 [32, 8, 50, 64] ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值