NTU ML2023Spring Part2.5 self attention
License: CC BY-NC-SA 4.0
之前都是输入一个固定长度的东西,但是如果每次输入的东西长度不一样呢?
例如输入一个句子。当然可以用 one-hot encoding 来编码单词,但这样就看不到某些单词之间的相关性。一个更好的方法是 word embedding。
对于音频输入的情况,可以把 25ms 内的音频数据用某些方法变为一个 frame,然后将这个 25ms 的 frame 后移 10ms。至于为什么是 25 和 10,这是先人试验的结果。
如果输入的是(数学上的)图,也可以把所有的点看成向量。一个有机大分子就可以当成图来研究。
然后是对于不定长的输入我们要输出什么。
-
输入与输出长度相同
例:单词的词性标注。
-
无论输入多长,只要输出一个东西
例:输入一句话,判断它是正面的评价还是负面的评价。
-
输出长度不定(seq2seq)
例:机器翻译。
下面讨论输入与输出长度相同的情况:词性标注。一个显然的思路是把句子拆成单词,然后问题就转化为定长输入(只有一个单词)的情况了。但这样做有比较大的问题:多义词要根据语境来标注。如果模型看到的只有单词,它就没办法知道这个词在上下文中是什么含义。
那能不能把「只看一个单词」换成「只看一个单词和它相邻的单词」呢?
可以,但我若是拿出从句,阁下又该如何应对?
开大窗口!大力出奇迹!
注意我们 sequence 的长度是有长有短的。如果开太大就会带来过多的参数,既不好训练又容易过拟合。
于是我们需要 self-attention。它先对输入做了一些处理(但长度不变),然后就可以回到之前「只看一个单词」的想法了。当然这种网络也可以加深,fc(全连接)层的输出可以再给下一层的 self-attention,然后再加一层 fc,不断交替就可以了。
有关 self-attention,最知名的文章就是《Attention is all you need》. 在 transformer 里面,attention 起了重要的作用。
接下来看 self-attention 层具体做了什么。输入是向量的序列,输出也是同样长度的序列。关于这一部分,3b1b 做了直观的视频,这是 B 站链接。
简单来说,注意力就是根据上下文来对某个词的含义做调整。给定一个词,首先要找出上下文中哪些词与这个词有关,一个常见的方法是用向量点积表示相似度。
具体地,假设输入的句子被拆成一堆词,这些词经过 word embedding 后为 \(\vec x_1, \vec x_2, \cdots\),每个向量乘以查询矩阵 \(W^Q\)(q 是 query 的意思)和回答矩阵 \(W^K\)(k 是 key 的意思),得到 \(\vec q_n = W^Q \vec x_n, \vec k_n = W^K \vec x_n\)。对两个词 \(\vec x_i, \vec x_j\),计算相应的 \(\vec q_i \cdot \vec k_j\) 可以粗略地理解为「第 \(j\) 个词对第 \(i\) 个词含义的影响大小」,结果称为 attention score \(\alpha_{i, j}\). 对于同一个 query 计算出的所有 attention score 还要做一次 softmax(也不一定要 softmax)。下面默认 \(\alpha'_{i, j}\) 是做过 softmax 的结果。对每个词乘上一个新的矩阵 \(W^V\) 得到 \(\vec v_n = W^V \vec x_n\),对 attention score 做加权和就能得到 \(\vec x_n\) 下一层的对应向量 \(\vec y_n = \sum_i \alpha'_{n, i} \vec v_i\).
对每个词 \(\vec x_i\) 都这么操作,可以把它们打包成一个矩阵 \(I\),写起来方便,且矩阵乘法(在软硬件级别上都)可以优化。上面的操作可以重写为:\(Q = W^Q I, K = W^K I, V = W^V I\),计算 attention score 组成的 attention matrix \(A = K^T Q\)(还要过一遍 softmax 得到 \(A'\)),就可以得到下一层 \(O = V A'\).
多头注意力就是算出 \(\vec q_n\) 后,再分别乘上两个矩阵得到 \(\vec q_{n,1}\) 和 \(\vec q_{n,2}\),对 \(\vec k, \vec v\) 类似操作即可。最后得到 \(\vec y_{n, 1}, \vec y_{n,2}\) 还要拼接起来乘上 \(W^O\) 才能送给下一层。
还有一点小问题:一个词的意思还与它在句中的位置有关。因此我们需要 positional encoding,这个就有很多做法了。
如果序列长度太大,时间和空间上都无法接受,可以用 truncated self-attention,只考虑周围的一段子序列,例如音频处理,每秒就有很多向量产生。
对于图像处理,CNN 可以看作是简化版的 self-attention. CNN 在数据量较少时有优势,self-attention 则相反(大概以 1e8 为分界).
RNN 也可以用于处理序列。它有一个 memory vector,每次 RNN 接受输入序列的一个向量和 memory,得到新的 memory,并将更新后的 memory 通过 fc 层得到输出。在实际应用上 self-attention 更好.
对于输入是图的情况,图上的边已经暗示了哪些点有相关性,因此算 attention matrix 的时候可以只计算有边相连的点。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探