课程版本:李宏毅《機器學習 2021》spring,Self-attention (下)(2021-03-26) 官方讲义:
self_v7.pdf,43 页(与 P36 同一份)— https://speech.ee.ntu.edu.tw/~hylee/ml/ml2021-course-data/self_v7.pdf 分P:BV1ou411N7X3?p=37,45:58 来源边界:讲义 p26 页内标题为 "Multi-head Self-attention",p38 为 "Self-attention v.s. RNN",p40 为 "Self-attention for Graph"。P36 已覆盖 p1–p25;本篇覆盖 p26–p42。两支视频的逐页切点无法由 metadata 确定,故标注「讲义章节切分复习版」,不声称分钟对应;无字幕,不引用逐字台词。p30 只有一条 arXiv 链接(2003.09229),页内没有正文,本文只说明它属于位置编码的延伸阅读,不替它编内容。
1. 多头:让"相关"有多种定义
单头 attention 只学一种相似度。但同一个词和不同词的相关性可以是不同性质的:它的 与先行词是指代关系,吃 与 饭 是搭配关系,虽然 与 但是 是篇章关系。把这些塞进一个 softmax 分布,会互相挤占权重。
p26–p28 的做法:先把 \(q_i,k_i,v_i\) 再投影到 \(M\) 个子空间,
每个头独立做一次单头 attention 得到 \(b_{i,m}\),再拼起来过一次线性层:
shape(设 \(d\) 为模型维,\(M\) 个头,每头 \(d_k=d_v=d/M\)):
| 量 | shape |
|---|---|
| \(q_{i,m},k_{j,m},v_{j,m}\) | \(d/M\) |
| 单头 \(A'_m\) | \(N\times N\) |
| \(b_{i,m}\) | \(d/M\) |
| 拼接 \([b_{i,1};\dots;b_{i,M}]\) | \(d\) |
| \(W^O\) | \(d\times d\) |
注意讲义 p26 写的是"先 \(q_i=W_q a_i\),再 \(q_{i,1}=W_{q,1}q_i\)"——两级投影。工程上常把两级合并成一个矩阵,但数学上每个头有自己独立的一组参数,不是把同一份 \(q,k,v\) 复制 \(M\) 份。若复制,\(M\) 个头输出完全相同,拼接再乘 \(W^O\) 等价于单头,白增参数。
为什么有效?p26 右侧只写了 "Different types of relevance"。这句话的含义是:每个头可以各自饱和到不同的位置上,有的头盯相邻词,有的头盯句法依存,有的头几乎均匀。多头不是"集成学习",而是把表示空间分块,让不同块学不同的关系。
2. 位置编码:把被公式丢掉的顺序加回来
self-attention 有一个容易被忽略的性质:置换等变。把输入列的顺序打乱,输出只是跟着打乱,数值一模一样。用 P36 的 4-token 例子实测(同一组 \(W_q,W_k,W_v\),置换 [2,0,3,1]):
按同一置换重排输入后:
脚本判定 equal=True。也就是说,模型根本不知道哪个词在前——"我打你"和"你打我"对它完全一样。这不是 bug,是 attention 的定义决定的:它只对"集合"运算。
p29 的补法是给每个位置一个向量 \(e_i\),直接加到输入上:
\(e_i\) 可以 hand-crafted,也可以 learned from data(p29 明确列了这两条)。加了之后,同样的词在不同位置得到不同的 \(a_i\),置换等变被打破。p30 的 arXiv 2003.09229 是位置编码的分析文献,页内无正文,本文不展开。
【补充】原始 Transformer 用的是正弦/余弦手写编码:偶数维 \(\sin(i/10000^{2k/d})\)、奇数维 \(\cos(i/10000^{2k/d})\)。它的好处是不用训练、可以外推到比训练更长的序列。讲义只给"手写 / 学习"两类,没有写这条公式,考试若按讲义作答,答这两类即可。
位置编码不是 mask:前者是加在输入上的向量,参与所有后续计算;后者是加在分数上的 \(-\infty\),只决定"能不能看"。两者经常在同一张图里出现,但作用完全不同。
3. 不是只能做语言:语音、图像、图
这是本讲最该记住的"反常识"点。self-attention 的输入条件只有一条:一组向量。
- 语音(p32):1 秒约 100 帧,10 分钟就是 6 万帧,\(N^2\) 不可行。truncated self-attention 只在一个局部范围内算 attention:\(N=10000\)、范围 \(r=100\) 时,分数矩阵从 \(N^2=10^8\) 降到 \(N\cdot r=10^6\),差 100 倍(Python 计算)。这不是"偷懒",而是承认语音的局部相关性。
- 图像(p33):一个像素的 RGB 就是一个向量,整张图就是向量集合;p34 给出 SAGAN(用 self-attention 做生成)与 DETR(用 Transformer 做检测)。
- 图(p40):只允许 attention 到相连节点,其余位置设 \(-\infty\),注意力矩阵变成邻接矩阵的形状——这就是一种 Graph Neural Network。p41 给了 GNN 的延伸视频。
所以"self-attention = 语言模型"是错的。语言只是最早、最密集的应用场景;p31 的 BERT/Transformer 让人产生这种印象,但 p32–p34、p40 明确把范围推到了语音、图像、图。
4. 与 CNN:不是二选一,而是同一族的两端
p35 给了两句几乎可以互推的话:
CNN: self-attention that can only attends in a receptive field Self-attention: CNN with learnable receptive field
展开:
- CNN 的每个神经元只看一个固定窗口,权重在窗口间共享 → 相当于把 attention 限制在一个固定的邻域、且权重不随内容变化。所以 CNN 是 self-attention 的特例(加了强先验)。
- self-attention 的"感受野"是由 \(q_i\cdot k_j\) 学出来的,可以跨越全图 → 它是感受野可学习的 CNN。
p36 引用 On the Relationship between Self-Attention and Convolutional Layers(1911.03584)证明二者可以互相表示;p37 引用 ViT(2010.11929)给出数据量的经验规律:数据少时 CNN 好,数据多时 self-attention 好。原因不神秘:CNN 的局部性/平移共享是对的先验,小数据下等于免费的正则;数据足够多时,这个先验反而限制了模型,让 attention 自己学更好。
因此"CNN vs attention 谁更强"是个伪问题。真正的选择是:你的数据量能不能撑起更弱的先验。这也是 P29 结尾说的 "model bias" 的另一面。
5. 与 RNN:并行 vs 记忆
p38 的对照只有三个词:parallel / nonparallel、hard to consider / easy to consider、memory。
- 并行:self-attention 一次矩阵乘算完所有位置;RNN 必须 \(h_t\) 算完才能算 \(h_{t+1}\),训练时无法在时间维并行。
- 长距离:RNN 要把第 1 个词的信息一路带过 \(T\) 步,每步都乘一次 \(W_h\),远距离信号容易衰减(P38 会讲 BPTT 的连乘);self-attention 任意两个位置一步直达,路径长度是 \(O(1)\)。
- 代价:self-attention 是 \(O(N^2)\) 内存/计算;RNN 是 \(O(N)\)。序列很长时,这个代价反过来咬人(p32 的 truncated attention、p42 的 Efficient Transformers 综述都是为此)。
p38 还引了 Transformers are RNNs(2006.16236)——从另一个角度说明两者在数学上可以互相改写。不要把"替代"理解成"淘汰"。
6. 伪代码:多头 + 位置编码
def multi_head_attention(A, heads, Wq, Wk, Wv, Wo, pos=None):
if pos is not None:
A = A + pos # (d,N) + (d,N),逐位置加
outs = []
for m in range(heads):
Q, K, V = Wq[m] @ A, Wk[m] @ A, Wv[m] @ A
A_prime = softmax(Q.T @ K, axis=1)
outs.append(V @ A_prime.T)
return Wo @ concat(outs, axis=0) # (d,N)
7. 常见误区
- "多头就是把单头算 M 次再平均"。是各自独立投影、各自 softmax、拼接后过 \(W^O\);参数不共享,输出也不平均。
- "self-attention 天生知道词序"。不。上面的置换实验给出了数值反例;没有位置编码时它是集合函数。
- "位置编码是 mask"。一个是加性向量,一个是乘性/加性屏蔽;位置编码改变表示,mask 改变可见性。
- "attention 一定优于 CNN"。p37 明确:数据少 CNN 更好。ViT 需要大规模预训练才超过 CNN,这不是"架构碾压",是"先验与数据的交换"。
- "attention 权重可以直接当解释"。多头、多层、value 投影之后,权重与最终输出的因果贡献不是一回事;把注意力图当"模型在看哪里"只能作为弱证据。
- "truncated attention 是近似,所以一定差"。在语音这类局部相关性强的任务上,限制范围既是正则也是效率;是否变差要看任务,不能先验判断。
8. 自测
Q1. \(d=512\)、\(M=8\),每头 \(d_k=d_v\) 是多少?拼接后维度是多少?\(W^O\) 的 shape?
答案
每头 \(512/8=64\);8 头拼接回 \(8\times64=512\);\(W^O\) 是 \(512\times512\)。总参数量与单头 \(d_k=512\) 时相近(\(4d^2\) 量级),多头并不是靠增加总维度换效果,而是靠分块。
Q2. 如果没有位置编码,把输入序列循环右移一位,输出会怎样?
答案
输出也会循环右移一位,数值完全不变(置换等变)。模型无法区分"右移一位"和"没移",因为它只对集合运算。加了位置编码后,每个位置的 \(a_i\) 变了,输出才会不同。
Q3. 为什么说 CNN 是 self-attention 的特例?反过来为什么不完全成立?
答案
CNN 相当于把 attention 限制在固定感受野内、且权重与内容无关(同一个 filter 在所有位置共享),这是 self-attention 的一种参数受限形式。反过来,self-attention 的感受野和权重都由 \(q,k\) 学出来,可以表达 CNN 的局部模式,但需要从数据里学出"只看邻域"这件事;没有数据先验时不一定学得到,所以两者是同一族的两端,不是严格的包含关系。
Q4. 一段 10 分钟、100 帧/秒的语音,全 attention 的分数矩阵有多大?truncated(\(r=200\))呢?
答案
\(N=60000\),全 attention 是 \(60000^2=3.6\times10^9\) 个分数;truncated 是 \(60000\times200=1.2\times10^7\),小 300 倍。前者在显存上已不可行,后者才是实际做法(p32)。
9. 30 秒速记
多头 = 多组独立 \(W_q,W_k,W_v\) 在子空间里各算一次,拼接后过 \(W^O\),为的是让"相关"有多种定义。self-attention 对置换等变(数值已验证),所以必须加位置编码 \(a_i\leftarrow a_i+e_i\),它不是 mask。它不只用于语言:语音用 truncated(\(N^2\to Nr\))、图像用 SAGAN/DETR、图只对邻边 attention。与 CNN 是同一族的两端(CNN=受限 attention,attention=可学习感受野),数据少 CNN 好、数据多 attention 好;与 RNN 比是并行与 \(O(N^2)\) 换长距离直达。
跨 P 连接:P36 给了单头与矩阵形式,P37 把它扩展成多头并补上位置;P47 的 encoder block 就是"多头 self-attention + residual + LayerNorm + FC",P48 的 decoder 在此之上再加因果 mask 与 cross attention(Q 来自 decoder、K/V 来自 encoder)。P38 的 RNN 对照解释了为什么 Transformer 要把 recurrence 拿掉。
引用页(PDF 物理页,1 起)
p26–p28(多头:独立投影、拼接、\(W^O\))、p29–p30(位置编码与延伸阅读)、p31–p34(NLP/语音/图像应用,truncated、SAGAN、DETR)、p35–p37(与 CNN 的关系及数据量规律)、p38–p39(与 RNN 的并行/记忆对照)、p40–p42(图上的 attention 与高效 Transformer)。