上一篇讲到,注意力机制读到要填的空时,会回头给前面每个词打一个「相关度分数」,「法国」分数最高,模型就把注意力集中在「法国」上。这一篇讲这个分数到底是怎么算出来的。按四步走:打分需要什么信息,分数怎么算,分数怎么用,最后看为什么要分成 K 和 V 两个角色。
想先看个大概,可以先播放下面的动画讲解,两分钟把四步过一遍,再往下读正文。
上一篇讲到,注意力读到要填的空时,回头给每个词打一个相关度分数,「法国」最高。这一篇讲这个分数到底是怎么算出来的。
朗读用的是浏览器自带的语音,不同设备声音不一样;没有语音的浏览器只显示字幕。
还是用上一篇的句子:
我在法国长大,后来去了很多地方,换过好几份工作,现在住在北京,但我仍然能说一口流利的____。
一、打分需要什么:Q、K、V
注意力的思路和每天用的搜索引擎很像。在搜索框里输入「法国 语言」,网上有几十亿个网页,搜索引擎靠关键字判断哪些网页相关:拿你输入的关键字和每个网页的关键字比,越匹配的排得越靠前,你再点进去读排在前面的网页。
这个过程里有三个角色:
- Q(Query,查询):你输入的「法国 语言」,代表「我想要的内容」。
- K(Key,键):每个网页的标题和标签,是可以被查找到的内容的标签,专门拿来被比对。
- V(Value,值):网页的正文,是可以被查找到的内容的真实内容,比对完以后真正拿走的就是它。
换到句子里,空格就是发起搜索的一方,前面的每个词都是一个「网页」,各自带着 K 和 V。
空格发出的 Q 写着什么?看「我能说一口流利的____」,空里该填的是一种语言,但还不知道是哪种。所以空格的 Q 用大白话说就是:「我要填一种语言,是哪国的?」
前面每个词的 K 又写着什么?「法国」和「北京」都是地名,北京在中国,中文也是一种语言,只看「国家还是城市」区分不开。关键在于它们在句子里的身份:「在法国长大」说明法国是他从小生活的地方,从小说的语言才最可能说得流利;「住在北京」只说明他现在住在哪。所以「法国」的 K 是「我是一个国家,是他从小长大的地方」,「北京」的 K 是「我是一个城市,是他现在住的地方」。空格的 Q 和「法国」的 K 对得更上。
这里有个细节:「法国」这个词本身并不知道自己是「他长大的地方」。Transformer 不只算一次注意力,它叠了很多层。前面的层里,「法国」已经回头看过「在」「长大」这些邻居,把这层意思吸收了进来;到了后面的层,「法国」贴出的 K 才带上「他从小长大的地方」。
二、分数怎么算:点积和 softmax
模型里的 Q 和 K 都是一串数字。为了好理解,假设每串只有 3 个数,分别表示三个特征:跟某种语言有关、是从小生活的地方、是一个动作,1 表示有,0 表示没有。
怎么用两串数字算出一个「匹配分」?最直接的办法是:两串数字一一对应相乘,再全部加起来。这叫点积(dot product)。
点积的意思很直观:两串数字在同一个特征上都大,乘出来就大;一边有一边没有,乘出来就是 0。越多特征对得上,分数越高。Transformer 算注意力分数用的就是点积。
点积算出来的 2、1、0 还不能直接用。上一篇的配图里,分数是 0.62、0.08 这样的小数,所有词加起来正好是 1,相当于把注意力按百分比分给每个词。而且真实的点积可能是负数,比如句子开头的「我」和空格几乎无关,点积可能是 -3。
一个容易想到的办法是:每个都加上一个数变成正数,再除以总和,看各自的占比。但这个办法有两个问题。第一,加几没有标准:加 3 得到 42%、33%、25%、0%,加 4 又是另一组结果。第二,差距被压平了:「法国」的分数明显最高,却只分到四成左右的注意力。
Transformer 的做法是用 e 的分数次方来变正数,e 约等于 2.718,然后再除以总和。这一步叫 softmax。
e 的任何次方都是正数,不用挑「加几」。而且它是指数增长,分数每多 1,结果就乘约 2.7 倍,高分和低分的差距被拉开,注意力集中到「法国」上。
实际模型在 softmax 之前还多做一件事:先把点积除以一个固定的数,这个数是 Q 长度的平方根,写作 √d。真实的 Q 和 K 有几十到上百个数,乘完加起来很容易变得很大;分数太大,softmax 会把几乎全部注意力给一个词,其他词都分不到,模型也就很难学。Q 有 64 个数时就除以 8。
三、分数怎么用:加权求和
现在空格手上有一组百分比:「法国」66%、「北京」24%、「长大」9%、「我」0.4%。接下来,用每个百分比乘上对应词的 V,再全部加起来,这叫加权求和:
空格得到的内容 = 66% ×「法国」的 V + 24% ×「北京」的 V + 9% ×「长大」的 V + 0.4% ×「我」的 V
结果里大部分是「法国」交出的信息,也混进一点「北京」和「长大」的。
为什么不只拿分数最高的那个词?有两个原因。第一,有时候需要的信息分散在好几个词里,比如理解「红色的大苹果」里的「苹果」,「红色」和「大」两个词都要看。第二,模型是靠一点点调整数字学出来的,百分比从 66% 调到 70% 是平滑的变化,模型能算出往哪个方向调更好;如果只拿第一名,第一名从「北京」换成「法国」是突然跳过去的,模型没法一点点学。
四、为什么 K 和 V 要分开
「法国」身上有两种信息,用途不一样。「我是他从小长大的国家」用来让空格找到自己,这是 K 的工作。空格找到它以后,真正要拿走的是「在法国说的语言,也就是法语」,这是 V 的工作。标签只用来被找到,内容才拿去用。
如果 K 和 V 用同一串数字,这串数字就得同时做两件事:既要长得像「长大的地方」,方便被匹配,又要装着「法语」,方便被拿走。两件事挤在一起,哪件都做不好。分开以后,K 负责被找到,V 负责被拿去用,各自承担自己的责任。搜索引擎也是这样:网页标题写得像你要搜的东西,你点进去读的却是正文。
五、Q、K、V 从哪里来
每个词在模型里本来只有一串数字。模型准备了三个矩阵,把这串数字分别乘上这三个矩阵,就得到这个词的 Q、K、V。每个词都有自己的 Q、K、V,所以每个词都既能发起提问,也能被别的词找到。
这三个矩阵一开始是随机的。模型在训练时读大量文本,不断猜下一个词,猜错了就微调这三个矩阵。调到最后,Q 学会了「该问什么」,K 学会了「该贴什么标签」,V 学会了「该交出什么」。前面写的「我要填一种语言」「我是他长大的国家」这些话,都是为了好懂用的比喻,模型里没有这些文字,只有学出来的数字。
六、合起来看
注意力的计算就是四个动作:Q 和每个 K 做点积打分;除以 √d 把分数缩小;用 softmax 变成加起来是 100% 的百分比;按百分比把各个词的 V 加起来。
《Attention Is All You Need》论文里,这四个动作写成一行公式:
Attention(Q, K, V) = softmax(Q·Kᵀ / √d) · V
Q·Kᵀ 是一次算出所有词两两之间的点积,Kᵀ 表示把 K 转过来排好方便相乘;除以 √d 是缩小;softmax 变成百分比;最后乘 V 就是加权求和。每个词的计算互不依赖,所以能并行,这正是上一篇讲的 Transformer 快的原因。
下面把四个动作串起来,你可以自己调一调。先看默认值算出的百分比是不是和前面一样;再把「分数放大」拖到最大,看注意力会怎么变;最后勾上「先除以 √d」,看分数缩小回来以后的样子。
[1, 1, 0]0[1, 0, 0]0[0, 0, 1]0[-2, -1, 0]0分数 = Q 和 K 的点积 × 放大倍数;示意里假设除以 √d 正好抵消放大。
检验一下
空格的 Q 和「法国」的 K 点积最大,说明什么?
点积大,说明 Q 和 K 在很多特征上都对得上,也就是「法国」贴的标签最符合空格想要的内容。和距离远近、V 的大小都没有关系。
softmax 为什么用 e 的分数次方,不给每个分数加上同一个数?
给每个分数加同一个数,加几没有标准,而且差距会被压平。e 的次方都是正数,分数每多 1 就乘约 2.7 倍,注意力能集中到最相关的词上。
点积算完以后,为什么要先除以 √d 再做 softmax?
真实的 Q 和 K 有几十到上百个数,点积很容易变得很大。分数太大时,softmax 会把注意力几乎全挤到一个词上,其他词都分不到,模型也很难学。可以在上面的实验台里把「分数放大」拖大试试。
K 和 V 分别负责什么?
负责提问的是 Q。K 是贴在词身上的标签,用来和 Q 比对;V 是这个词被选中以后交出的内容。
想深入可以看
- Transformer 原论文:Attention Is All You Need(2017),第 3.2.1 节讲的就是这一篇的公式
- 图解 Transformer 的经典文章:The Illustrated Transformer,里面有 Q、K、V 每一步的矩阵图
- 3Blue1Brown 的动画讲解:Attention in transformers, step-by-step