把注意力公式拆成可以动手实现的模块
精读注意力时,不要停在「QKᵀV」。把它拆成投影、打分、归一化和汇聚,实现与消融才有抓手。
《Attention Is All You Need》被引用到几乎失去形状。精读这类论文,目标不是再讲一遍「Transformer 很重要」,而是把公式拆成实现时能单独替换的模块。模块边界清楚,后面的复现和消融才不是凭感觉改代码。
先画数据的形状,再看公式
把一个序列写成 X ∈ R^{n×d}。标准点积注意力可以看成四步,而不是一个符号:
- 投影:
Q = XW_Q,K = XW_K,V = XW_V。这里决定「谁在问、谁在被看」。 - 打分:
S = QKᵀ / √d_k。尺度不是装饰,它管的是后面 softmax 会不会塌掉。 - 归一化:对每一行做 softmax,得到权重。这一步把「相似度」变成「分配方案」。
- 汇聚:权重乘
V,得到每个位置的新表示。
多头只是把 d 切成若干子空间,并行做完再拼回去。位置编码则是在投影之前(或之中)注入顺序,它不是注意力本体。
拆开之后,消融才有意义
如果代码里这四步缠在一个函数里,你很难回答「是打分方式不行,还是汇聚方式不行」。更有用的读法是给每一步标上可替换实现:
| 模块 | 常见替换 | 你要问的问题 |
|---|---|---|
| 投影 | 共享 / 低秩 / 跨层复用 | 表示能力是不是被投影浪费了? |
| 打分 | 加性、线性、稀疏、核方法 | 相似度假设还成立吗? |
| 归一化 | softmax、sparsemax、 entmax | 权重是否必须是稠密分布? |
| 汇聚 | 加权和、只取 top-k | 需不需要看见所有位置? |
论文里的「主要结果」往往只验证了整条链路。你自己的实验若只改一个模块,才能把贡献从工程细节里剥出来。
读实现假设,而不是只读定理味道
原论文默认:序列不太长、显存够做 n × n 的分数矩阵、位置可以用正弦或可学习向量注入。这些假设一变,模块选择就变。长序列工作把打分做成局部或线性;多模态工作则往往先统一投影,再谈注意力。
精读的产出不该是一篇读后感,而应是一张模块图:每张图能直接变成实验卡片上的「可替换部分」。这样,论文栏目才接得上实操栏目,而不是停在概念层。