一、经典Attention计算方式:从加性到双线性的演进之路

Attention机制,说白了就是让模型学会「看哪里」。我最早接触这个概念是在2017年做机器翻译项目的时候,当时被各种Attention变体搞得晕头转向。后来慢慢摸清了门道,发现核心就四种计算方式。

今天咱们就把这四种经典方法掰开揉碎了讲。嗯,我会结合自己踩过的坑,帮你一次性理清楚。

1.1 加性Attention(Additive Attention)

这是最早期的Attention形式,由Bahdanau等人提出。它的核心思想是:通过一个可学习的神经网络来计算注意力权重

公式长这样:

score(q, k) = v^T * tanh(W_q * q + W_k * k + b)

其中W_q、W_k、v都是可学习的参数矩阵。说白了,就是把query和key分别做线性变换,然后加在一起过个tanh激活,最后用v做内积得到标量分数。

核心特点:

  • 可以处理不同长度的query和key
  • 表达能力更强(因为有非线性激活)
  • 计算量较大,不适合大规模场景

我在项目中遇到过一个问题:用加性Attention做长文本摘要时,训练特别慢。后来发现是因为矩阵乘法太多,GPU利用率上不去。所以现在除非是特殊需求,我一般不太推荐用加性Attention。

避坑指南:我曾经在序列标注任务里用加性Attention,结果发现收敛速度比点积慢了一倍。后来分析发现,tanh激活函数在训练初期梯度容易饱和,建议配合LayerNorm使用。

1.2 点积Attention(Dot-Product Attention)

这个就简单粗暴了。直接拿query和key做内积:

score(q, k) = q^T * k

你想想看,这不就是向量之间的相似度吗?两个向量越相似,内积越大,注意力权重就越高。逻辑上非常直观。

优点很明显:

  • 计算速度快,没有额外参数
  • 实现简单,一行代码搞定
  • GPU友好,矩阵乘法效率高

但有个致命问题——方差爆炸。当向量维度d很大时,内积的方差会跟着变大。举个例子,如果q和k的每个元素都是标准正态分布,那么内积的方差就是d。这意味着分数会变得非常大或非常小,softmax之后梯度就消失了。

注意:我刚开始用点积Attention时,在512维的Transformer上直接崩了。训练loss死活不降,查了两天才发现是方差问题。所以千万别在高维场景下裸用点积Attention。

1.3 缩放点积Attention(Scaled Dot-Product Attention)

这个就是Transformer里用的那个。说白了,就是在点积的基础上加了个缩放因子:

score(q, k) = q^T * k / sqrt(d_k)

其中d_k是key的维度。为什么要除以sqrt(d_k)?

我解释一下:假设q和k的每个元素都是均值为0、方差为1的独立随机变量。那么q^T * k的均值是0,方差是d_k。除以sqrt(d_k)之后,方差就变成1了。这样不管维度多大,分数的分布都保持稳定。

完整公式:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

这个设计有多巧妙?我举个例子:

维度d_k 未缩放方差 缩放后方差
64 64 1
256 256 1
512 512 1

你看,缩放之后方差恒为1,梯度传播就稳定多了。这也是为什么Transformer能训练得那么深的原因之一。

我的习惯:现在做任何Attention相关的项目,我默认就用缩放点积。除非有特殊需求,否则不会轻易换。这个方案在效率和效果之间取得了很好的平衡。

1.4 双线性Attention(Bilinear Attention)

这个可以看作是点积Attention的升级版。它引入了一个可学习的权重矩阵W:

score(q, k) = q^T * W * k

你想想看,点积Attention相当于W是单位矩阵,而双线性Attention让W可以学习。这就给了模型更大的灵活性——它可以学习到query和key之间更复杂的交互模式。

适用场景:

  • 当query和key来自不同模态时(比如文本和图像)
  • 需要学习特定任务的对齐方式时
  • 数据量足够大,不怕过拟合时

我记得有一次做多模态检索,用点积Attention效果一直上不去。换成双线性之后,mAP直接涨了3个点。原因就是W矩阵学到了文本和图像之间的跨模态映射关系。

注意参数规模:W的维度是d_q × d_k,如果两个维度都是512,那就是26万个参数。在小数据集上很容易过拟合。我建议至少要有10万条训练数据再考虑用双线性Attention。

1.5 四种方法的对比总结

咱们用一张表格来对比:

方法 计算复杂度 参数量 表达能力 推荐场景
加性Attention O(d^2) 强(有非线性) 小规模、需要精细对齐
点积Attention O(d) 低维场景、快速原型
缩放点积Attention O(d) 中等 通用场景(推荐首选)
双线性Attention O(d^2) 中等 跨模态、大数据量

下面这张图展示了四种Attention的核心计算逻辑:

四种经典Attention计算方式对比 加性Attention score = v^T · tanh( W_q·q + W_k·k + b) 参数量: 高 计算: O(d²) 有非线性激活 点积Attention score = q^T · k 参数量: 无 计算: O(d) 方差随d增大 缩放点积Attention score = q^T·k / √d 参数量: 无 计算: O(d) 方差恒为1 双线性Attention score = q^T·W·k 参数量: 中等 计算: O(d²) 可学习映射 核心演进逻辑 1. 加性 → 点积:去掉非线性,降低计算复杂度 2. 点积 → 缩放点积:解决高维方差爆炸问题 3. 点积 → 双线性:引入可学习参数,增强表达能力 我的建议: 默认用缩放点积Attention,跨模态场景考虑双线性,小规模任务可以试试加性。

嗯,到这里四种经典Attention就讲完了。我个人觉得,理解这四种方法的核心差异,比背公式重要得多。你想想看,它们本质上都是在解决同一个问题——如何计算query和key之间的相关性,只是手段不同而已。

在实际项目中,我90%的情况都用缩放点积Attention。不是因为别的不好,而是它足够稳定、高效,而且有Transformer这样的大规模验证。但如果你遇到特殊场景,比如跨模态对齐或者需要精细的注意力分布,不妨试试双线性或加性Attention。

一句话总结:加性Attention用网络学相似度,点积用内积算相似度,缩放点积解决了内积的方差问题,双线性让模型自己学怎么算相似度。四种方法各有千秋,选对场景才是关键。

专注资料整理