图解注意力分数:用可视化方法理解query-key的5种相似度计算
图解注意力分数5种相似度计算的视觉化探索第一次接触注意力机制时那些数学公式总让我头晕目眩。直到有一天我在白板上随手画了几个向量突然明白了query和key之间的对话方式。本文将带你用视觉化的方式拆解注意力分数计算的五种核心方法让抽象概念变得触手可及。1. 注意力机制的视觉基础想象你在一家咖啡馆周围有十个人在说话。你的大脑会自然地注意某些声音而忽略其他——这就是注意力机制的生物原型。在机器学习中这种选择性聚焦通过query、key和value的三元组实现。关键视觉元素query你当前关心的问题红色箭头表示key环境中各个元素的特征标签蓝色点表示value最终要聚合的内容绿色区域表示二维坐标系中最简单的注意力可以表示为import numpy as np query np.array([1.2, 0.8]) keys np.array([[0.5, 1.0], [1.5, 0.5], [0.8, 1.2]]) values np.array([[1,0], [0,1], [1,1]])注意所有可视化示例都假设使用L2归一化后的向量方便观察角度关系2. 点积注意力角度的秘密点积计算(query·key)本质是测量两个向量的夹角余弦。当我在白板上画出以下三种情况时规律变得显而易见向量关系点积值范围几何解释完全同向≈1.0夹角0°余弦值为1正交0.0夹角90°余弦值为0完全反向≈-1.0夹角180°余弦值为-1def dot_product_attention(query, keys): scores np.dot(keys, query) # 计算点积分数 weights np.exp(scores) / np.sum(np.exp(scores)) # softmax归一化 return np.dot(weights, values)典型误区初学者常忽略向量的模长影响。当我在项目中首次实现时发现未归一化的向量会导致分数爆炸最终权重分布失去区分度。3. 缩放点积注意力维度的诅咒当向量维度(d)增加时点积值的方差会随之增大——这就像在高维空间中所有向量都趋向于相互正交。通过数学推导可以发现方差 d * (σ²)^2解决方案是缩放因子(√d)这在三维示意图中表现为原始点积值的分布范围随d增大而扩散缩放后分布重新收紧到合理区间softmax后的权重分布恢复区分度def scaled_dot_attention(query, keys, d_model): scores np.dot(keys, query) / np.sqrt(d_model) weights softmax(scores) return weights values提示在Transformer实现中这个缩放因子让梯度保持在优化器适合处理的范围内4. 加性注意力神经网络的融合艺术当query和key维度不同时我们可以使用加性注意力。这就像为两种语言配备了翻译器通过可学习的权重矩阵Wq和Wk将不同维度的向量投影到公共空间使用tanh激活函数引入非线性最终通过vᵀ将结果映射为标量分数class AdditiveAttention(nn.Module): def __init__(self, q_dim, k_dim, hidden_dim): super().__init__() self.Wq nn.Linear(q_dim, hidden_dim) self.Wk nn.Linear(k_dim, hidden_dim) self.v nn.Linear(hidden_dim, 1) def forward(self, query, key): h torch.tanh(self.Wq(query) self.Wk(key)) return self.v(h).squeeze()可视化技巧在TensorBoard中观察Wq和Wk的权重分布可以发现网络自动学习的对齐模式。5. 多头注意力的拼图效应当我第一次看到多头注意力时最震撼的是不同头捕获的模式差异。通过三维热力图可以清晰展示头1强烈关注局部相邻位置头2捕捉特定语法结构关系头3跟踪远距离依存关系实现多头注意力的关键步骤将d_model拆分为h个头每个头独立计算缩放点积注意力拼接结果并通过WO线性变换class MultiHeadAttention(nn.Module): def __init__(self, d_model, h): super().__init__() self.d_k d_model // h self.h h self.WQ nn.Linear(d_model, d_model) self.WK nn.Linear(d_model, d_model) self.WV nn.Linear(d_model, d_model) self.WO nn.Linear(d_model, d_model) def forward(self, q, k, v, maskNone): # 线性变换后分头 q self.WQ(q).view(bs, -1, self.h, self.d_k) k self.WK(k).view(bs, -1, self.h, self.d_k) v self.WV(v).view(bs, -1, self.h, self.d_k) # 计算注意力并拼接 attn scaled_dot_attention(q, k, v, mask) return self.WO(attn.view(bs, -1, self.h * self.d_k))在视觉问答任务中这种多头部机制让模型可以同时关注颜色、形状和空间关系等不同特征。