尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

python神经网络编程入门(三十一)——自注意力(Self-Attention):Q、K、V 三件套

python神经网络编程入门(三十一)——自注意力(Self-Attention):Q、K、V 三件套 路标本篇位于《从零构建 Transformer》系列第 2/16 章 · 基石篇。系列主线注意力思想 → 自注意力 → 多头 → 位置编码 → 编解码架构 → 手撕实现 → 预训练模型 → 实战微调 → 知识收官。进度▸基石篇(1-5·本篇)▸ 架构篇(6-10) ▸ 预训练篇(11-13) ▸ 实战篇(14-16)上一篇三十Transformer 从 RNN 到注意力模型为什么需要瞄一眼引言上一章问了为什么这一章回答怎么瞄上一章我们把 RNN 的老底掀开串行读、单一记忆导致越读越忘。然后提出了治本思路——不传而看让模型回头给全句每个词打分加权。我们还用我 love 猫的小例子手工指定了一个查询向量跑出了 0.457 的最大权重落在最相关的词上。但那个例子有个作弊味查询向量是我们手工拍的不是模型自己算的。这章要做的就是把这块作弊补上——让模型自己从输入里把 Q、K、V 三个向量算出来。这才是自注意力真正的样子也是词和词互相打探消息的完整机制。本章目标用生活类比彻底搞懂 Q查询、K键、V值三者的分工吃透关键公式Q、K、V 是同一个输入乘三个权重矩阵得到的手写完整self_attention一步步把每个词的上下文表示算出来看懂为什么权重矩阵一变模型爱看谁就变——注意力是可学习的。一、三件套查询、键、值先给 Q、K、V 一个最朴素的生活类比——查图书馆找书QQuery查询心里现在要找什么。比如我要找讲深度学习的书——这就是查询。KKey键每本书的标签。比如《Attention Is All You Need》的标签是深度学习《小王子》的标签是童话。VValue值每本书的正文内容。这才是真正要拿走的东西。找书的过程就是拿 Q要什么去和每本书的 K标签比对越匹配的权重越高然后按权重把对应的 V内容取出来加权合并。标签越像要的这本书的内容在心里的分量越大。把这三者对应到自注意力里一句话就能连起来自注意力三件套Q 问、K 答、V 给Q 查询 Query我要看什么K 键 Key我是什么标签V 值 Value我提供什么内容打分取内容Q 和 K 配对打分 → softmax 成权重 → 加权取 V标签越像我想要的对应的内容分量越大Q 负责问每个词都提出自己的问题我要了解句子里哪些词K 负责答身份每个词都亮出自己的标签我是谁、和什么有关V 负责给内容每个词都准备好自己的实质内容我到底说了什么。于是词和词互相对话就具象成每个词用自己的 Q 去匹配所有词的 K得到一组权重再按权重把所有词的 V 加权求和。这就是自注意力的完整流程。二、核心公式Q、K、V 从哪来关键问题来了上面三个向量到底怎么得到答案极其简洁——都是同一个输入X XX分别乘三个可学习的权重矩阵Q X W q , K X W k , V X W v Q X\,W_q, \qquad K X\,W_k, \qquad V X\,W_vQXWq​,KXWk​,VXWv​其中X XX是所有词的向量拼成的矩阵W q , W k , W v W_q, W_k, W_vWq​,Wk​,Wv​是三个不同的权重矩阵。注意Q、K、V 来自同一个输入X XX只是被三个不同的滤镜权重矩阵各滤了一遍提取出三种不同角色。这就是为什么它叫自注意力Self-Attention——注意力作用在自己和自己上每个词都跟全句包括自己发生关系。把这条公式画成一张数据流向图一眼看清X XX变出三个分身同一个输入 X三个权重矩阵变出 Q / K / VX(3, 4) 所有词向量Q X·Wq(3, 3) 查询K X·Wk(3, 3) 键V X·Wv(3, 3) 值Wq (4×3)Wk (4×3)Wv (4×3)同一个 X 分身成 Q/K/V三个权重矩阵都是可学习的为什么是同一个X XX因为这正是自Self的含义不是去外部找参考而是每个词都在观察整句话里的其他词包括它自己。Q、K、V 都从这句话本身提取所以叫自注意力。三、手撕自注意力一步步把矩阵算出来理论讲完了直接上手。用小例子我 love 猫3 个词每个词 4 维向量一步步把 Q/K/V 算出来再算出注意力权重和最终的上下文表示。第一步准备输入X XX把 3 个词编码成 4 维向量拼成矩阵X ∈ R 3 × 4 X \in \mathbb{R}^{3\times4}X∈R3×4importnumpyasnp Xnp.array([[1.0,0.0,0.0,0.0],# 我[0.0,1.0,0.0,0.0],# love[0.0,0.0,1.0,0.2],# 猫])print(X.shape ,X.shape)# (3, 4)3 个词每个 4 维第二步定义三个可学习权重矩阵W q , W k , W v W_q,W_k,W_vWq​,Wk​,Wv​都是4 × 3 4\times34×3把 4 维输入降成 3 维的查询/键/值空间。这里用随机初始化的值来演示真实训练时它们会被梯度更新np.random.seed(42)Wqnp.random.randn(4,3)*0.3Wknp.random.randn(4,3)*0.3Wvnp.random.randn(4,3)*0.3print(Wq.shape ,Wq.shape)# (4, 3)第三步算出 Q、K、V一行矩阵乘法QX Wq# (3, 3)KX Wk# (3, 3)VX Wv# (3, 3)真实数值每个词一行Q每个词一个查询向量 我: [ 0.149 -0.041 0.194] love: [ 0.457 -0.07 -0.07 ] 猫: [ 0.506 0.202 -0.169] K每个词一个键向量 我: [ 0.073 -0.574 -0.517] love: [-0.169 -0.304 0.094] 猫: [-0.286 -0.42 0.354] V每个词一个值向量 我: [-0.163 0.033 -0.345] love: [ 0.113 -0.18 -0.088] 猫: [-0.244 0.605 -0.077]到这里Q、K、V 三件套就齐了。注意它们不是我们手工指定的而是X XX乘权重矩阵自动变出来的——这正是上一章作弊被补上的地方。第四步用 Q 去匹配 K算相似度打分每个词用自己的 Q 去点乘所有词的 K得到Q K ⊤ QK^\topQK⊤相似度矩阵越大越相关d_kK.shape[1]# 3scoresQ K.T# (3, 3) 打分矩阵真实数值列: 我 love 猫 我: -0.066 0.006 0.044 love: 0.110 -0.062 -0.126 猫: 0.008 -0.163 -0.290第i ii行第j jj列就是第i ii个词对第j jj个词的关注程度。比如第一行我的三列都很小且接近说明在当前这组随机权重下我对三个词都一视同仁还没训练注意力还没分化。第五步softmax 把打分变成权重对打分矩阵每一行做 softmax让每行之和等于 1得到注意力权重矩阵defsoftmax_rows(M):enp.exp(M)returne/e.sum(axis1,keepdimsTrue)weightssoftmax_rows(scores)真实数值每行和为 1我 看全句权重: [0.313 0.337 0.35 ] love 看全句权重: [0.38 0.32 0.3 ] 猫 看全句权重: [0.387 0.326 0.287]每一行都是这个词如何分配自己 100% 的注意力给全句。当前这组权重下大家分配得比较平均——因为权重还没被训练等学出合适的W q , W k W_q,W_kWq​,Wk​各行就会分化出明确的关注偏好。第六步按权重取 V加权求和最后用权重矩阵去加权求和所有 V得到每个词的上下文表示outweights V# (3, 3)真实数值我 的上下文表示: [-0.099 0.161 -0.165] love 的上下文表示: [-0.099 0.137 -0.182] 猫 的上下文表示: [-0.096 0.128 -0.184]这个输出就是自注意力的结果每个词的向量此时已经掺入了全句相关词的信息。比如我的上下文表示不再是孤零零的[1,0,0,0]而是综合了 love、猫的信息后的一份新表示——这就是词和词互相打探消息的最终产物。四、封装成完整函数把上面六步收进一个函数就是标准的自注意力这一章先不除以d k \sqrt{d_k}dk​​那是下一章《缩放点积注意力》的主角后面会补上defself_attention(X,Wq,Wk,Wv):Q,K,VX Wq,X Wk,X Wv scoresQ K.T# 打分enp.exp(scores)# softmaxweightse/e.sum(axis1,keepdimsTrue)returnweights V,weights# 输出 权重out,attnself_attention(X,Wq,Wk,Wv)print(输出 shape ,out.shape)# (3, 3) 与输入行数一致验证要点输入X XX是( 3 , 4 ) (3,4)(3,4)输出是( 3 , 3 ) (3,3)(3,3)——行数不变3 个词还是 3 个词只是每个词的向量维度从 4 变成了 3进入注意力空间。这符合直觉自注意力不改变词的个数只改写每个词的表示。五、注意力是可学习的权重一变爱看谁就变很多初学者背下公式却不懂可学习到底什么意思。用一个直观实验讲透Q 由W q W_qWq​决定而W q W_qWq​是训练学出来的——所以模型爱看谁是学出来的不是写死的。实验把我这个词的查询向量强行调成我自己的键向量并放大 5 倍放大差异模拟我特别想把注意力放在自己身上Q_selfQ.copy()Q_self[0,:]K[0,:]*5.0# 让我的查询贴近我的键scores_selfQ_self K.T w_selfsoftmax_rows(scores_self)print(我 的注意力:,w_self[0].round(3))真实结果改查询前 我 的注意力: [0.313 0.337 0.35 ] 改查询后 我 的注意力: [0.695 0.169 0.136]看我只是把我的查询向量调成偏向我自己它这一行的注意力瞬间从平均分配变成高度集中在自己身上0.695。这说明查询向量决定了这个词爱看谁而查询向量是W q W_qWq​变出来的W q W_qWq​是训练学出来的——一层套一层最终就是注意力权重是模型学出来的偏好。翻译成大白话训练时模型为了让预测更准会不断调整W q , W k W_q,W_kWq​,Wk​让每个词学会去关注对自己真正有用的词。比如理解猫时模型可能学会重点看可爱理解他时学会重点看上文的某个名词。这一切都在W q , W k W_q,W_kWq​,Wk​的更新里自动完成。六、常见坑与自查误以为 Q/K/V 是三个不同的输入它们是同一个X XX乘三个不同的权重矩阵得到的三个分身。搞混这个后面多头注意力必乱。把W q , W k , W v W_q,W_k,W_vWq​,Wk​,Wv​当成固定值它们是可学习参数训练时通过反向传播更新。随机初始化时注意力很平均训练后才会分化。形状搞错输入( S , E ) (S, E)(S,E)乘以( E , d k ) (E, d_k)(E,dk​)的权重得到( S , d k ) (S, d_k)(S,dk​)。Q、K、V 的维度都是d k d_kdk​本章三者维度相同。S SS是词数自注意力输出词数不变。softmax 方向搞反对每一行每个查询词做 softmax让一个词对全句的注意力加起来等于 1不是对列。把打分和权重混为一谈打分是Q K ⊤ QK^\topQK⊤的原始相似度可正可负权重是打过 softmax、非负且行和为 1 的值。只有权重才用于加权求和。小结这一章把上一章的注意力思想变成了自注意力的完整机制三件套Q 问我要看什么、K 答我是什么标签、V 给我提供什么内容用查图书馆类比记牢分工核心公式Q X W q , K X W k , V X W v QXW_q,\ KXW_k,\ VXW_vQXWq​,KXWk​,VXWv​——三个分身都来自同一个输入X XX这就是自的含义完整流程X → Q / K / V → Q K ⊤ → softmax → weighted V X \to Q/K/V \to QK^\top \to \text{softmax} \to \text{weighted}\,VX→Q/K/V→QK⊤→softmax→weightedV手撕成 6 步每个词的上下文表示都算出了真实数值可学习查询向量由W q W_qWq​变出W q W_qWq​由训练更新——模型爱看谁是学出来的实验里改一下查询向量我的注意力就从 0.337 跳到 0.695。到这一步我们已经有了让词和词互相对话的完整骨架。但还有三个细节等着补当前打分没经过缩放维度大时容易让 softmax 饱和第 3 章单头注意力只能关注一种关系不够第 4 章注意力不分先后顺序得给词补上位置第 5 章。下一章先解决第一个——缩放点积注意力。下一篇三十二缩放点积注意力——打分、归一、加权
返回列表