问题与目标
当一个序列模型将整段输入压缩进一个固定长度状态时,输入越长,不同位置就越容易争夺有限表示空间。而且在产生不同输出时,模型往往需要回看输入的不同位置。
Attention 的起点是:不再要求一个状态平等记住所有信息,而是根据当前需求为各位置计算权重,再动态汇总。本篇只实现这个最小加权聚合,完整 Q/K/V、多头自注意力和 Transformer 放在后续阶段。

两行使用相同的四个状态,但查询方向不同,因此聚合时最依赖的位置也不同。
核心概念
固定状态为什么会成为瓶颈
假设编码器为每个输入位置生成一个状态 h₁ ... hₜ。只使用最后 hₜ 时,前面的信息需要经过多次状态更新才能到达输出端。这不仅增加信息损失,也延长了梯度传递路径。
保留所有位置状态后,当前输出可以直接与每个位置比较相关性,不必将全部历史都挤在最后一个状态中。
三步加权聚合
- 用当前查询与每个位置计算相关性得分。
- 用 Softmax 将得分变成和为 1 的权重。
- 对各位置表示做加权和,生成当前上下文。
scores_i = similarity(query, state_i)
weights = softmax(scores)
context = sum(weights_i * state_i)
权重高表示当前计算更依赖该位置,不自动等于人类语义中的解释或因果。
查询不同,聚合结果也不同
对同一组输入状态,一个查询可能更关心规模信号,另一个查询可能更关心时间信号。因此 context 不是输入的固定摘要,而是与当前查询有关的动态摘要。
并行性与二次方成本
基础 RNN 的第 t 步依赖第 t-1 步,很难完全并行。自注意力可以同时构造各位置之间的相关性,但标准形式需要一个长度乘长度的得分矩阵,序列很长时内存和计算成本明显增长。
可运行实现
import torch
states = torch.tensor([
[1.0, 0.0, 0.2],
[0.1, 1.2, 0.0],
[0.8, 0.2, 0.9],
[0.0, 0.5, 1.1],
])
queries = {
"focus_first_feature": torch.tensor([1.0, 0.0, 0.0]),
"focus_third_feature": torch.tensor([0.0, 0.0, 1.0]),
}
for name, query in queries.items():
scores = states @ query
weights = torch.softmax(scores, dim=0)
context = weights @ states
print(name)
print("weights:", weights.round(decimals=3).tolist())
print("context:", context.round(decimals=3).tolist())
第一个查询主要关注第一维值高的位置,第二个查询更关注第三维。Softmax 会为所有位置分配正权重;“不应看到”的 padding 或未来位置需要用 mask 排除,不能只期待模型自己忽略。
批量点积的形状
batch_states = torch.randn(2, 5, 8) # N, T, H
batch_query = torch.randn(2, 8) # N, H
scores = torch.bmm(batch_states, batch_query.unsqueeze(2)).squeeze(2)
weights = torch.softmax(scores, dim=1)
context = torch.bmm(weights.unsqueeze(1), batch_states).squeeze(1)
print(scores.shape, weights.shape, context.shape)
输出形状分别是 (2, 5)、(2, 5) 和 (2, 8)。Softmax 应沿序列维 dim=1 归一化,若选错维度,代码可能仍然能运行,但权重含义已经改变。
常见问题与排查
- Softmax 维度选错:先明确权重应在哪个维度上和为 1。
- 忘记 padding mask:填充位置也会分到权重,干扰 context。
- 将注意力权重当作完整解释:权重是模型内部计算信号,要与对照实验和错误样本结合。
- 点积随维度增大而过于极端:后续的缩放点积注意力会用维度平方根调整得分尺度。
- 认为 Attention 没有序列成本:标准自注意力的得分矩阵随序列长度平方增长。
小结
固定长度状态要求一个向量承担整段序列的信息压缩。Attention 保留各位置表示,根据当前查询动态计算权重,再生成与当前任务相关的上下文。这里只建立了动机和最小计算,其中查询、键、值的投影方式以及多头结构,需要在 Transformer 语境中继续展开。
License: CC BY-NC 4.0
Updated 2 hours ago
Was this article helpful? Give it a like.
0 comments


