Transformer 从0到1:注意力机制的数学形式——Query, Key, Value 三元组

news2026/4/1 21:52:51
# Transformer 从0到1注意力机制的数学形式——Query, Key, Value 三元组## 1. 引言从序列建模的困境到注意力机制的诞生在深度学习的发展历程中处理序列数据如文本、音频、时间序列一直是核心挑战之一。早期的循环神经网络RNN及其变体LSTM、GRU通过隐状态的逐层传递试图捕捉序列中的时间依赖关系。然而这种循环结构存在两个根本性缺陷其一长距离依赖问题——当序列长度增加时梯度消失或爆炸使得网络难以学习相隔较远的元素之间的关系其二计算固有的顺序性——每个时间步的计算必须等待前一步完成无法充分利用现代并行计算设备如GPU的算力。卷积神经网络CNN虽然可以并行处理但通过堆叠卷积层来扩大感受野的方式本质上仍然是一种“局部”操作——要建立长距离依赖需要网络深度随着距离线性增长。这种“距离”与“计算路径长度”成正比的特性使得学习远距离交互变得困难。注意力机制的诞生打破了这一僵局。其核心思想简单而深刻**允许模型在处理序列的每一个位置时直接“关注”到序列中所有其他位置并根据内容动态地决定关注的程度**。这意味着任意两个位置之间的交互无论它们在序列中相距多远都只需要一次计算操作即点积计算路径长度被缩短为常数。2017年Vaswani等人发表的论文《Attention Is All You Need》提出了Transformer架构将注意力机制推向了极致。该论文的核心贡献在于**完全摒弃了循环和卷积仅依赖注意力机制构建整个序列转换模型**。其中注意力机制的数学实现被巧妙地形式化为 **Query查询、Key键、Value值三元组**。本文的目标是“从0到1”彻底拆解这一数学形式。我们将从最直观的直觉出发逐步构建其数学表达式解释每一个符号的含义剖析缩放点积注意力的原理并通过代码从零实现每一个细节。我们不仅会展示“如何做”更会深入探讨“为什么这样做”。全文力求详尽无篇幅限制旨在让读者真正理解注意力机制的本质。## 2. 从直觉到形式理解Query, Key, Value### 2.1 一个类比信息检索系统要理解Query、Key、Value最直观的方式是将其类比为经典的信息检索系统。想象你有一个庞大的数据库其中存储着许多文档。当你在搜索框中输入一个查询Query时检索系统会执行以下步骤1. 它将你的 **Query**比如几个关键词与数据库中每个文档的 **Key**比如文档的标题或摘要进行匹配。2. 匹配的过程通常计算Query与每个Key之间的**相关性分数**例如TF-IDF、BM25或向量相似度。3. 根据相关性分数系统对这些文档进行排序选出最相关的几个。4. 最后系统返回这些最相关文档的 **Value**比如文档的完整内容。在注意力机制中这个过程被完全“内化”为神经网络的运算。模型不再是检索外部文档而是在自身的特征空间中进行检索。具体来说- **Query**代表当前时刻“想要寻找什么”的表示。它源于当前正在处理的位置例如在机器翻译中当前要生成的目标词。- **Key**代表序列中每个位置“能够提供什么”的标识。它源于序列中所有位置例如源句子中的每个词。每个Key都可以被理解为该位置内容的“标签”或“索引”。- **Value**代表序列中每个位置“实际携带的信息内容”。它也与序列中所有位置一一对应。当某个位置的Key与Query匹配度高时其对应的Value就会被“提取”出来并参与到后续计算中。注意力机制的本质就是**使用Query去“检索”所有Key得到一组权重即注意力分布然后用这组权重对所有的Value进行加权求和作为最终的输出**。### 2.2 为什么要引入Q、K、V三元组为什么不像更早期的注意力机制如Bahdanau注意力那样直接用一个对齐函数计算当前状态与所有编码器状态的相关性引入Q、K、V三元组并将其作为独立的可学习投影的产物是Transformer实现高效、灵活、并行化建模的关键。关键在于Q、K、V通常是通过对同一个输入序列或不同序列进行**线性变换**得到的。假设输入序列的表示为 $X \in \mathbb{R}^{L \times d_{model}}$其中 $L$ 是序列长度$d_{model}$ 是模型维度那么$$Q XW^Q, \quad K XW^K, \quad V XW^V$$其中 $W^Q, W^K, W^V \in \mathbb{R}^{d_{model} \times d_k}$为了简化通常 $d_k$ 等于 $d_{model}$ 除以头数我们将在后续多头部分详述。这种设计的精妙之处在于1. **灵活的角色分离**同样的输入 $X$通过不同的投影矩阵被映射到三个不同的空间。Query空间负责“询问”Key空间负责“应答”Value空间负责“内容”。这种角色分离允许模型学习到更丰富的表示使得“询问-应答”的匹配机制与“内容”的提取机制解耦。2. **可学习的匹配函数**匹配函数Query与Key的相关性计算不再是固定的如余弦相似度或简单的拼接后线性映射而是通过可学习的投影矩阵 $W^Q$ 和 $W^K$ 隐式地学习得到的。实际上$\text{Attention}(Q,K,V) \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$其中的核心 $QK^T$ 是一个双线性形式相当于对输入 $X$ 应用了一个可学习的马氏距离度量$(XW^Q)(XW^K)^T X (W^Q {W^K}^T) X^T$。3. **并行化与效率**通过矩阵运算一次性计算出所有位置对之间的注意力分数使得整个计算可以高度并行化这是Transformer能够成功扩展到大规模数据和模型的关键。## 3. 缩放点积注意力的数学形式### 3.1 基本公式Transformer中使用的注意力机制被称为**缩放点积注意力**Scaled Dot-Product Attention。其核心公式如下$$\text{Attention}(Q, K, V) \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$让我们逐一剖析这个公式中的各个部分。假设我们有一个长度为 $n$ 的序列作为“源”以及一个长度为 $m$ 的序列作为“目标”。在实际的自注意力中$nm$。但为了通用性我们保持区分。- $Q \in \mathbb{R}^{m \times d_k}$Query矩阵每一行代表一个查询向量目标序列中某个位置的表示。- $K \in \mathbb{R}^{n \times d_k}$Key矩阵每一行代表一个键向量源序列中某个位置的表示。- $V \in \mathbb{R}^{n \times d_v}$Value矩阵每一行代表一个值向量源序列中某个位置的内容表示。通常 $d_v d_k$。- $QK^T \in \mathbb{R}^{m \times n}$这是点积运算的结果。它的第 $i$ 行第 $j$ 列的元素 $(QK^T)_{ij}$ 表示第 $i$ 个Query与第 $j$ 个Key的点积。点积的几何意义是衡量两个向量在方向上的相似性——值越大表示两个向量的夹角越小方向越一致相似度越高。- $\sqrt{d_k}$缩放因子。$d_k$ 是每个Key/Query向量的维度。- $\text{softmax}(\cdot)$对矩阵的每一行应用Softmax函数将每一行的点积结果转化为一个概率分布和为1。即对于第 $i$ 行$\text{softmax}(z_i)_j \frac{e^{z_{ij}}}{\sum_{k1}^{n} e^{z_{ik}}}$。这样对于每个Query我们得到了一组关于所有Key的非负权重且总和为1。- $\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) \in \mathbb{R}^{m \times n}$注意力权重矩阵。- $\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V \in \mathbb{R}^{m \times d_v}$最终的输出矩阵。其第 $i$ 行是第 $i$ 个Query对所有Value的加权求和即 $\sum_{j1}^{n} a_{ij} v_j$其中 $a_{ij}$ 是注意力权重。### 3.2 缩放因子 $\sqrt{d_k}$ 的作用这是公式中一个看似微小却至关重要的细节。为什么需要除以 $\sqrt{d_k}$其根本原因在于**控制点积的方差避免Softmax函数进入梯度极小的饱和区**。假设Query和Key的每个分量都是独立的随机变量均值为0方差为1。那么对于两个维度为 $d_k$ 的向量 $q$ 和 $k$点积 $q \cdot k \sum_{i1}^{d_k} q_i k_i$ 的均值为0方差为$$\text{Var}(q \cdot k) \sum_{i1}^{d_k} \text{Var}(q_i k_i) \sum_{i1}^{d_k} \mathbb{E}[q_i^2] \mathbb{E}[k_i^2] - (\mathbb{E}[q_i]\mathbb{E}[k_i])^2 \sum_{i1}^{d_k} (1 \cdot 1 - 0) d_k$$因此点积的方差随维度 $d_k$ 线性增长。当 $d_k$ 较大时例如在Transformer中常见为64、512甚至更高点积的数值会变得很大正或负。将这些大数值输入Softmax函数会产生什么后果Softmax函数 $\text{softmax}(z)_i e^{z_i} / \sum_j e^{z_j}$ 对输入值的大小非常敏感。如果某个 $z_i$ 远大于其他值那么其指数 $e^{z_i}$ 将主导分母使得该位置的softmax输出接近1而其他位置的输出接近0。这导致注意力权重几乎退化为一个**独热分布**one-hot distribution。更严重的是当 $z_i$ 的绝对值很大时其梯度 $\frac{\partial \text{softmax}(z)_i}{\partial z_j}$ 会变得非常小因为梯度中包含因子 $\text{softmax}(z)_i (1 - \text{softmax}(z)_i)$当概率接近0或1时该项趋近于0导致反向传播时梯度消失模型难以训练。除以 $\sqrt{d_k}$ 后点积的方差被归一化为1从而将点积的数值控制在合理的范围内通常介于 $[-3, 3]$ 或更小使得Softmax函数能够产生平滑的、有区分度但不极端的注意力分布有利于梯度流动和稳定训练。### 3.3 Softmax 与 加权求和在得到注意力权重矩阵 $A \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)$ 后我们将其与 $V$ 相乘。这一步骤有两个关键解释1. **软性信息选择**传统的“硬性”注意力hard attention是从多个Value中选出一个而这里采用的是“软性”注意力即对所有Value进行加权平均。每个Value的权重由其对应的Key与Query的匹配程度决定。这使得整个操作是可微的能够通过反向传播进行端到端的训练。2. **信息聚合**最终输出是Value向量的凸组合因为权重和为1。这使得输出向量位于所有Value向量张成的凸包内起到了信息聚合和平滑的作用。从信号处理的角度看这类似于一个**非线性的、内容自适应的滤波器**——滤波器系数注意力权重取决于输入信号本身通过Q和K。## 4. 代码实现从零构建缩放点积注意力理论阐述完毕现在让我们通过代码来具体实现这一机制。我们将使用Python和NumPy或PyTorch来构建目的是展示最纯粹的计算逻辑。pythonimport numpy as npimport scipy.special as spdef scaled_dot_product_attention(Q, K, V, maskNone, scaleTrue):缩放点积注意力的纯NumPy实现参数:Q: Query矩阵形状 (m, d_k)K: Key矩阵形状 (n, d_k)V: Value矩阵形状 (n, d_v)mask: 掩码矩阵形状 (m, n)可选。用于屏蔽某些位置如未来信息scale: 是否使用缩放因子默认为True返回:output: 注意力输出形状 (m, d_v)attention_weights: 注意力权重形状 (m, n)d_k Q.shape[-1]# 步骤1计算点积 QK^T# (m, d_k) (d_k, n) - (m, n)scores np.dot(Q, K.T)# 步骤2缩放可选if scale:scores scores / np.sqrt(d_k)# 步骤3应用掩码如果提供if mask is not None:# 将掩码中为0的位置设置为一个非常大的负数-1e9使得softmax后这些位置的权重趋近于0# 这里假设mask的形状与scores相同且mask中1表示保留0表示屏蔽scores scores (mask - 1) * 1e9 # 巧妙地将mask0的位置加上 -1e9# 步骤4对每一行应用Softmax# 使用scipy的softmax函数axis1表示对每一行独立操作attention_weights sp.softmax(scores, axis1)# 步骤5加权求和# (m, n) (n, d_v) - (m, d_v)output np.dot(attention_weights, V)return output, attention_weights# 示例演示if __name__ __main__:# 设置随机种子以保证可复现性np.random.seed(42)# 定义参数m 3 # Query数量例如目标序列长度n 5 # Key/Value数量例如源序列长度d_k 4 # Query/Key维度d_v 6 # Value维度# 随机初始化Q, K, VQ np.random.randn(m, d_k)K np.random.randn(n, d_k)V np.random.randn(n, d_v)# 计算注意力output, weights scaled_dot_product_attention(Q, K, V)print(Q (Query矩阵):)print(Q)print(\nK (Key矩阵):)print(K)print(\nV (Value矩阵):)print(V)print(\n注意力权重矩阵 (每一行是一个概率分布):)print(weights)print(\n每一行的和:, np.sum(weights, axis1))print(\n输出矩阵:)print(output)print(\n验证第一个输出应该等于第一个Query对应的注意力权重与V的加权和)print(手动计算第一个输出:, np.dot(weights[0], V))print(输出矩阵第一行:, output[0])运行上述代码我们可以清晰地看到计算过程scores是点积结果缩放后经过softmax转化为权重最后加权求和得到输出。这个简单的实现已经包含了注意力机制的核心。## 5. 自注意力与多头注意力### 5.1 自注意力当Q、K、V源自同一序列在上述例子中我们假设Q、K、V可以来自不同的序列。但在Transformer中最核心的应用是**自注意力**Self-Attention。在自注意力中Q、K、V均源自同一个输入序列 $X$。也就是说序列中的每个位置都可以“关注”到序列中的所有位置包括自身从而捕捉序列内部的依赖关系。在编码器中自注意力是**双向**的即每个位置可以关注到其左侧和右侧的所有位置。而在解码器中自注意力被设计为**因果**的causal即每个位置只能关注到它自身及其左侧的位置以防止未来信息泄露。这种因果约束通常通过**掩码**masking来实现我们将在后续的代码中展示。### 5.2 多头注意力从单视角到多视角单头注意力虽然强大但存在一个局限它只能学习到一种“匹配-聚合”模式。然而语言和序列数据中往往存在多种不同类型的关系。例如在一个句子中一个词可能同时与语法主语、宾语、修饰语等存在不同类型的依赖关系。**多头注意力**Multi-Head Attention的提出正是为了解决这一问题。其核心思想是将Q、K、V分别通过多组不同的线性投影投影到多个不同的表示子空间称为“头”在每个头中独立地执行缩放点积注意力然后将所有头的输出拼接起来再经过一次线性投影得到最终结果。数学形式为$$\text{MultiHead}(Q, K, V) \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O$$其中$$\text{head}_i \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$$这里- $W_i^Q \in \mathbb{R}^{d_{model} \times d_k}$$W_i^K \in \mathbb{R}^{d_{model} \times d_k}$$W_i^V \in \mathbb{R}^{d_{model} \times d_v}$$W^O \in \mathbb{R}^{h d_v \times d_{model}}$ 都是可学习的投影矩阵。- 通常我们设置 $d_k d_v d_{model} / h$这样每个头的维度降低总计算量与单头注意力大致相当但通过多头机制获得了更强的表示能力。多头注意力的优势在于1. **多角度表征**不同的头可以关注到不同类型的依赖关系。例如在机器翻译中某些头可能关注语法结构某些头可能关注语义相似性某些头可能关注长距离依赖。2. **增强稳定性**多个头的输出平均可以降低单个头随机性带来的影响使得整体表示更加鲁棒。### 5.3 代码实现多头注意力下面我们实现一个完整的多头注意力模块并集成掩码机制。pythonimport numpy as npclass MultiHeadAttention:多头注意力机制的NumPy实现def __init__(self, d_model, num_heads, dropout_rate0.0):初始化参数参数:d_model: 模型总维度num_heads: 头数dropout_rate: Dropout比率此处简化不实现实际dropout仅保留接口assert d_model % num_heads 0, d_model must be divisible by num_headsself.d_model d_modelself.num_heads num_headsself.d_k d_model // num_heads # 每个头的维度self.d_v self.d_k# 初始化权重矩阵# 为了简化这里使用标准差为0.01的随机初始化# 实际应用中通常会使用Xavier/Glorot初始化self.W_q np.random.randn(d_model, d_model) * 0.01self.W_k np.random.randn(d_model, d_model) * 0.01self.W_v np.random.randn(d_model, d_model) * 0.01self.W_o np.random.randn(d_model, d_model) * 0.01# 简化不实现真正的dropoutself.dropout_rate dropout_ratedef _split_heads(self, x, batch_size):将最后一维分割为 (num_heads, d_k) 并转置以方便并行计算输入形状: (batch_size, seq_len, d_model)输出形状: (batch_size, num_heads, seq_len, d_k)# 重塑: (batch_size, seq_len, num_heads, d_k)x x.reshape(batch_size, -1, self.num_heads, self.d_k)# 转置: (batch_size, num_heads, seq_len, d_k)return x.transpose(0, 2, 1, 3)def _combine_heads(self, x, batch_size):将多头表示合并回原始形状输入形状: (batch_size, num_heads, seq_len, d_k)输出形状: (batch_size, seq_len, d_model)# 转置: (batch_size, seq_len, num_heads, d_k)x x.transpose(0, 2, 1, 3)# 重塑: (batch_size, seq_len, d_model)return x.reshape(batch_size, -1, self.d_model)def scaled_dot_product_attention(self, Q, K, V, maskNone):缩放点积注意力批量化版本参数:Q: (batch_size, num_heads, seq_len_q, d_k)K: (batch_size, num_heads, seq_len_k, d_k)V: (batch_size, num_heads, seq_len_v, d_v) # 通常 seq_len_k seq_len_vmask: 可选掩码形状 (batch_size, 1, 1, seq_len_k) 或 (batch_size, seq_len_q, seq_len_k)返回:output: (batch_size, num_heads, seq_len_q, d_v)attention_weights: (batch_size, num_heads, seq_len_q, seq_len_k)d_k Q.shape[-1]# 计算点积# (batch, h, q_len, d_k) (batch, h, d_k, k_len) - (batch, h, q_len, k_len)scores np.matmul(Q, K.transpose(0, 1, 3, 2))# 缩放scores scores / np.sqrt(d_k)# 应用掩码if mask is not None:# 将掩码中为0的位置加上一个很大的负数# 扩展掩码维度以匹配 scores: (batch, 1, 1, k_len) 或 (batch, q_len, k_len)scores scores (mask - 1) * 1e9# Softmax# 为了避免数值溢出先减去每行的最大值稳定softmax# 为了简化直接使用scipy的softmax但这里我们手动实现# 注意对最后一个维度进行softmaxmax_vals np.max(scores, axis-1, keepdimsTrue)exp_scores np.exp(scores - max_vals)attention_weights exp_scores / np.sum(exp_scores, axis-1, keepdimsTrue)# 应用dropout略# 加权求和output np.matmul(attention_weights, V)return output, attention_weightsdef forward(self, Q, K, V, maskNone):多头注意力的前向传播参数:Q: Query形状 (batch_size, seq_len_q, d_model)K: Key形状 (batch_size, seq_len_k, d_model)V: Value形状 (batch_size, seq_len_v, d_model) # 通常 seq_len_k seq_len_vmask: 可选掩码返回:output: (batch_size, seq_len_q, d_model)attention_weights: 可选用于可视化batch_size Q.shape[0]# 步骤1线性投影# (batch, seq_len, d_model) (d_model, d_model) - (batch, seq_len, d_model)Q_proj np.matmul(Q, self.W_q)K_proj np.matmul(K, self.W_k)V_proj np.matmul(V, self.W_v)# 步骤2分割为多头# (batch, num_heads, seq_len, d_k)Q_heads self._split_heads(Q_proj, batch_size)K_heads self._split_heads(K_proj, batch_size)V_heads self._split_heads(V_proj, batch_size)# 步骤3在每个头上执行缩放点积注意力# 注意这里我们直接使用上面定义的方法attn_output, attn_weights self.scaled_dot_product_attention(Q_heads, K_heads, V_heads, mask)# 步骤4合并多头# (batch, seq_len, d_model)concat_output self._combine_heads(attn_output, batch_size)# 步骤5最终线性投影output np.matmul(concat_output, self.W_o)return output, attn_weights# 示例多头自注意力if __name__ __main__:# 设置参数batch_size 2seq_len 5d_model 16num_heads 4# 随机生成输入np.random.seed(42)X np.random.randn(batch_size, seq_len, d_model)# 创建多头注意力实例mha MultiHeadAttention(d_model, num_heads)# 自注意力Q、K、V都来自Xoutput, weights mha.forward(X, X, X)print(输入形状:, X.shape)print(输出形状:, output.shape)print(注意力权重形状多头:, weights.shape) # (batch, num_heads, seq_len_q, seq_len_k)# 检查每个头的注意力分布第一个batch第一个头print(\n第一个batch第一个头的注意力权重矩阵每行和为1:)head_weights weights[0, 0]print(head_weights)print(行和:, np.sum(head_weights, axis1))## 6. 深入数学细节梯度与性质分析### 6.1 注意力作为可微的索引机制从数学上看注意力机制可以视为一种**可微的字典查询**differentiable dictionary lookup。传统字典查询是离散的给定一个键 $k$从字典中返回对应的值 $v$。而在注意力中我们通过softmax将这种离散选择连续化。连续化的好处在于整个操作可微允许通过梯度下降来学习投影矩阵 $W^Q$、$W^K$、$W^V$。实际上我们可以将注意力输出对输入 $X$ 的导数展开来分析梯度如何流动。假设 $Q XW^Q$$K XW^K$$V XW^V$。则输出 $O \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V$。反向传播时梯度会通过三条路径流回 $X$通过 $W^Q$、$W^K$ 和 $W^V$。其中通过 $W^V$ 的路径相对直接而通过 $W^Q$ 和 $W^K$ 的路径涉及softmax的梯度这会产生一种**竞争性**的更新提升某个位置的权重会抑制其他位置的权重。### 6.2 对排列等变性与不变性的理解**自注意力**对于输入序列的排列具有**等变性**equivariance。这意味着如果我们将输入序列 $X$ 的各个位置进行任意排列那么经过自注意力模块后输出序列的对应位置也会按照同样的排列进行重排。这是因为点积 $QK^T$ 在行和列上同时重排softmax逐行操作最后的加权求和也遵循同样的重排。这种等变性使得Transformer在处理集合数据时天然适用。然而由于Transformer通常与**位置编码**positional encoding结合使用位置编码打破了排列不变性使得模型能够利用序列的顺序信息。### 6.3 计算复杂度分析缩放点积注意力的计算主要包含三个部分- $QK^T$ 的计算复杂度为 $O(m \cdot n \cdot d_k)$其中 $m$ 和 $n$ 分别是Q和K的序列长度。- Softmax复杂度为 $O(m \cdot n)$。- 加权求和复杂度为 $O(m \cdot n \cdot d_v)$。在自注意力中$m n L$序列长度因此总复杂度为 $O(L^2 \cdot d)$。其中 $L^2$ 是主导项。这意味着当序列长度 $L$ 增大时计算量呈二次增长这是Transformer在处理长序列如长文档、高分辨率图像时的主要瓶颈。这也是后来许多变体如Longformer、BigBird、Linformer等致力于将复杂度降低到 $O(L \log L)$ 或 $O(L)$ 的原因。## 7. 变体与扩展掩码、交叉注意力与位置编码### 7.1 掩码Masking的作用与实现在Transformer中掩码主要有两种应用场景1. **填充掩码Padding Mask**当序列中存在填充padding位置时这些位置不应该参与注意力计算因为它们是人为添加的不包含有效信息。填充掩码将这些位置对应的注意力分数设为 $-\infty$使得softmax后的权重为0。2. **前瞻掩码Look-ahead Mask**在解码器的自注意力中为了保证自回归性质即当前位置的预测只能依赖之前已生成的位置需要屏蔽未来位置的信息。前瞻掩码通常是一个上三角矩阵其中上三角部分不包括对角线被设为 $-\infty$。掩码在代码中通常与注意力分数相加如前面代码所示利用softmax的性质将屏蔽位置的权重置零。### 7.2 交叉注意力Cross-Attention在编码器-解码器架构中除了编码器内的自注意力和解码器内的自注意力外还存在**交叉注意力**。在交叉注意力中**Query 来自解码器的上一层的输出而 Key 和 Value 来自编码器的输出**。这样解码器在生成每个词时可以动态地关注到源序列中的相关信息这正是序列到序列seq2seq任务如机器翻译的核心。交叉注意力的数学形式与自注意力完全相同只是输入来源不同。这也是Transformer能够灵活处理不同模态信息如文本到图像的基础。### 7.3 位置编码Positional Encoding的必要性正如前文所述自注意力本身是排列等变的即它不包含任何关于位置顺序的信息。然而对于序列数据如自然语言顺序至关重要。因此Transformer需要一种方式来注入位置信息。Vaswani等人提出了**正弦位置编码**sinusoidal positional encoding。对于位置 $pos$ 和维度 $i$编码值为$$PE_{(pos, 2i)} \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)$$$$PE_{(pos, 2i1)} \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)$$这种编码具有以下性质- 每个位置的编码是唯一的。- 不同位置之间的编码可以通过线性变换相关联这有助于模型学习相对位置关系。- 编码值被限定在 $[-1, 1]$ 之间与词嵌入相加时不会造成数值不稳定。在实际应用中位置编码通常与输入嵌入相加然后送入后续的注意力层。## 8. 从零实现一个微型Transformer块为了将上述所有概念融会贯通我们现在从零实现一个完整的Transformer编码器块Encoder Block。它由两个主要子层组成**多头自注意力**和**前馈网络**Feed-Forward NetworkFFN。每个子层都应用了**残差连接**Residual Connection和**层归一化**Layer Normalization。pythonimport numpy as npclass FeedForward:前馈网络两个线性层中间使用ReLU激活def __init__(self, d_model, d_ff):self.W1 np.random.randn(d_model, d_ff) * 0.01self.b1 np.zeros(d_ff)self.W2 np.random.randn(d_ff, d_model) * 0.01self.b2 np.zeros(d_model)def forward(self, x):# x: (batch, seq_len, d_model)# 第一层线性 ReLUhidden np.matmul(x, self.W1) self.b1hidden np.maximum(0, hidden) # ReLU# 第二层线性output np.matmul(hidden, self.W2) self.b2return outputclass LayerNorm:层归一化简化版不含可学习的缩放和偏移实际应用中包含可学习的gamma和beta此处仅做演示def __init__(self, d_model, eps1e-6):self.eps eps# 可学习参数self.gamma np.ones(d_model)self.beta np.zeros(d_model)def forward(self, x):# x: (batch, seq_len, d_model)mean np.mean(x, axis-1, keepdimsTrue)variance np.var(x, axis-1, keepdimsTrue)x_norm (x - mean) / np.sqrt(variance self.eps)return self.gamma * x_norm self.betaclass EncoderBlock:一个完整的Transformer编码器块def __init__(self, d_model, num_heads, d_ff, dropout_rate0.0):self.mha MultiHeadAttention(d_model, num_heads, dropout_rate)self.ffn FeedForward(d_model, d_ff)self.layernorm1 LayerNorm(d_model)self.layernorm2 LayerNorm(d_model)# 简化未实现dropoutdef forward(self, x, maskNone):# 子层1多头自注意力 残差连接 层归一化attn_output, _ self.mha.forward(x, x, x, mask)# 残差连接x x attn_output# 层归一化x self.layernorm1.forward(x)# 子层2前馈网络 残差连接 层归一化ffn_output self.ffn.forward(x)x x ffn_outputx self.layernorm2.forward(x)return x# 测试编码器块if __name__ __main__:# 参数设置batch_size 2seq_len 5d_model 16num_heads 4d_ff 32# 随机输入X np.random.randn(batch_size, seq_len, d_model)# 创建编码器块encoder_block EncoderBlock(d_model, num_heads, d_ff)# 前向传播output encoder_block.forward(X)print(输入形状:, X.shape)print(输出形状:, output.shape)## 9. 总结与展望### 9.1 核心回顾本文从最基础的直觉出发逐步推导并实现了Transformer中注意力机制的数学形式——Query、Key、Value三元组。我们详细分析了缩放点积注意力的每一个组成部分点积度量相似性缩放因子 $\sqrt{d_k}$ 控制方差Softmax将分数转化为概率分布加权求和完成信息聚合。我们深入探讨了多头注意力的设计动机——捕捉多种依赖关系并通过代码完整实现了从单头到多头的过渡。我们还讨论了掩码机制、交叉注意力、位置编码以及完整的编码器块展示了这些组件如何协同工作构成一个强大的序列建模模块。### 9.2 注意力机制的哲学意义注意力机制之所以如此成功其背后蕴含的哲学思想值得深思。它让模型摆脱了“必须通过固定结构如循环或卷积来建模关系”的束缚转而采用一种“按需连接”的范式。模型不再被动地按照预设的拓扑结构传递信息而是根据内容本身动态地决定信息流动的路径和强度。这种动态性使得Transformer能够适应多种任务和数据结构从文本到图像从图到多模态。### 9.3 局限性与未来方向尽管Transformer取得了巨大成功但它并非完美无缺。我们已提及的 $O(L^2)$ 计算复杂度限制了其在超长序列上的应用。此外Transformer需要大量数据和大规模计算资源进行预训练对硬件要求较高。同时其对位置信息的处理仍然存在争议——绝对位置编码是否最优相对位置编码如RoPE、ALiBi能否更好地建模长度泛化未来的研究方向包括但不限于- **高效注意力**如稀疏注意力、低秩近似、核方法等旨在降低复杂度。- **结构化状态空间模型**如Mamba试图在保持线性复杂度的同时具备长距离依赖建模能力成为Transformer的有力竞争者。- **更长上下文的建模**随着序列长度增加到百万级别如何设计稳定且高效的模型成为关键。- **多模态统一架构**将Transformer进一步扩展在单一模型中处理文本、图像、视频、音频等多种模态。### 9.4 结束语从最初的“注意力”概念到如今主宰深度学习多个领域的Transformer架构Query、Key、Value三元组以其简洁而深刻的数学形式展现了一种优雅的设计智慧。理解这一机制不仅有助于掌握当前最先进的模型更能够为未来探索新的架构奠定坚实的基础。本文力求从数学和代码两个维度完整地呈现注意力机制的“从0到1”过程。希望读者在阅读之后不仅能够熟练使用现成的Transformer库更能洞悉其底层原理并在此基础上进行创新和拓展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2473316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…