attention-to-prediction.md · 可读全文
这里保留原文的中文、公式标记、代码和链接。可直接交给 Agent 读取,也可选取下方原文复制。此入口返回 HTML;原始 .md / .py 文件仍保留,完整候选包同时包含 UTF-8 原件。
# 读取之后,系统怎样决定写 him
课堂接续:[T20](https://codingai-lec05.pages.dev/classroom/T20.html?step=b0) · [T21](https://codingai-lec05.pages.dev/classroom/T21.html?step=b0) · [T22](https://codingai-lec05.pages.dev/classroom/T22.html?step=b0) · [T23](https://codingai-lec05.pages.dev/classroom/T23.html?step=b0) · [T24](https://codingai-lec05.pages.dev/classroom/T24.html?step=b0)。连续读本:[第3章](https://codingai-lec05.pages.dev/lecture.html#chapter-3);本主题提供独立定义、例子、代码与来源。
源句为“我/昨天/给/了/他/一/本/书/。”,九个单位来自本课的教学切分。现在保留九个源位置的编码表示,而不是只把最后一个摘要交给decoder。目标已知前缀为 `BOS I gave`,当前还没有him。由这个合法目标状态形成query,对源位置逐项打分,沿源位置归一化,再汇总value;写到 `I gave him a book` 之后,又可形成新的query去读取时间。每个时刻都仍要生成分布、选词并反馈,不能把中间的a、book略成不存在的步骤。

为核算读取到词表的完整链,另建**R7.2局部三槽教学构造**。槽标签为他、书、昨天,只是从九单位事件中选出的三项;下面的二维数并不是九位置encoder的实测状态,更不是旧checkpoint输出。给定未缩放点积、$q=(1,0)$:
|槽|key $k_j$|value $v_j$|$q^\top k_j$|
|---|---|---|---:|
|他|$(1,0)$|$(2,0)$|1|
|书|$(0,1)$|$(0,4)$|0|
|昨天|$(1,1)$|$(1,2)$|1|
源位置softmax给出 $\alpha\approx(.422319,.155362,.422319)$,故
$$c=\sum_j\alpha_jv_j\approx(1.266956,1.466087).$$
再明确一个教学输出矩阵 $G=\begin{bmatrix}2&0&0\\0&1&0\end{bmatrix}$,目标词表依次为him、book、yesterday。$cG\approx(2.533913,1.466087,0)$,词表softmax得到约 $(.702690,.241553,.055757)$;若当前标签是him,这个局部输出头的loss约为 $-\ln(.702690)=.352839$。第一次概率轴是三个源槽,第二次是三个目标候选;高读取权重不是某个英语词的概率。真实decoder还会使用目标状态和完整词表,这个小G只闭合局部接口。

独立从基线只改 $q'=(0,1)$,K/V/G保持不变,得到源权重 $(.155362,.422319,.422319)$、$c'\approx(.733044,2.533913)$,词表概率变成 $(.241553,.702690,.055757)$。需求改变可以改变读取与预测;这些人为参数没有证明“第二维就是书”。译文目标的负对数概率可把误差信号经G、加权和、softmax与打分传回源状态和目标状态,使读取从任务数据中学习。
下面保留旧READ的六片段她/her语境、数值与干预作为独立扩展;它不再承担当前九单位翻译的运行身份。2014年的真实加性打分与这两个未缩放点积构造也分别说明。
[阅读本主题](https://codingai-lec05.pages.dev/course/knowledge/attention-to-prediction.html) · [返回实验](https://deepnote.com/workspace/ise3309jingao-5ba66b0a-4283-4f5a-ae06-3f68d3201e99/project/Fall-26-Lecture-05-841ec8e7-e352-4840-b628-d3742b03d6d0/notebook/LAB-02-bba1d024d8e64a589c290b09381de692?utm_content=bba1d024d8e64a589c290b09381de692&utm_source=openai&utm_medium=mcp&utm_campaign=openaimcp&utm_term=get_notebook) · [与Agent共读全文](https://codingai-lec05.pages.dev/course/knowledge/attention-to-prediction.md.read.html)
读本:[ CLS 02 · Attention 与 Transformer ](https://deepnote.com/workspace/ise3309jingao-5ba66b0a-4283-4f5a-ae06-3f68d3201e99/project/Fall-26-Lecture-05-841ec8e7-e352-4840-b628-d3742b03d6d0/notebook/CLS-02-Attention-Transformer-2d44adcb6f3d409aa7dfb25c21a748a3?utm_content=2d44adcb6f3d409aa7dfb25c21a748a3&utm_source=openai&utm_medium=mcp&utm_campaign=openaimcp&utm_term=get_notebook),查找“读取之后,系统怎样决定写 him”;实验中查找“E · 只改 q 或只改 V,分别会改变什么?”。
<span id="attention-to-prediction-s01"></span>
## 同一个前缀穿过完整系统
以下完整保留**旧六片段她/her与LAB02实现接口**。它采用先读再更新:query来自旧state,所以当步gave的embedding在读取以后才进入更新;这与上面的新课堂“合法前缀形成当前query”是不同的明确时序。二者均不能读未知标签,代码与结果只按各自身份解释。
这里采用与LAB02一致的**先读再更新**时序。设下一步要输出y_t,decoder先持有处理至前一步的h_{t-1};输入token是y_{t-1}。encoder输出z_1…z_6,每个z包含该源词及其上下文,双向encoder还能用左右源词。query由h_{t-1}投影而来,读取c_t后把 `[embedding(y_{t-1});c_t]` 送入decoder更新成h_t,词表头对 `[h_t;c_t]` 打分。h_{t-1}已经依赖更早目标,但本步最后一个输入token要在更新时加入;不要声称它在更新之前已经编码了所有当前输入。
在本例要输出her时,本步输入gave;前一步状态由BOS/I等历史形成,gave的embedding进入本步更新。另一常见实现先形成当前目标hidden再读取,然后送输出头;两种都能定义合法模型,但不能从两张课件各取一半组成时序矛盾的图。
|对象|本例形状(教学设定)|来源与作用|
|---|---|---|
|Z|6×32|六段教学源切分的上下文状态;维度32仅用于接口说明|
|q|1×32|h_old经可训练投影;代表当前读取需求的一部分|
|scores|1×6|q与每个源状态匹配;PAD源位置加−∞|
|α|1×6|沿6个源位置softmax;每一行和为1|
|c|1×32|αZ,加权汇总内容|
|h_new|1×32|LSTMCell接输入词embedding与c,更新状态|
|logits / p|1×词表大小|线性头再softmax;到这里才是下一词分布|
自然句仅解释接口;六行来自本课源句教学切分,32维宽度借用合成实现的接口设置,不是本课训练过的自然翻译模型。其核心代码在主题页可直接读:
```python
q = self.query(h_old) # 32 -> 32
scores = einsum('bd,bnd->bn', q, z) / sqrt(32)
alpha = softmax(scores.masked_fill(~mask, -inf), dim=-1)
context = einsum('bn,bnd->bd', alpha, z)
h, c = decoder(cat([embedding(previous_token), context]), (h_old,c_old))
logits = output(cat([h,context]))
```
query投影、encoder、decoder和输出头都从任务loss学得;mask规则和缩放公式不是训练时另学的标签。LAB02两组初始h=0,动态query无bias,所以第一步是均匀读取。这提供了一个具体可查的解释候选:第一词失败是否与初始读的条件过弱有关?它不是已经证明的原因;改初始化/先更新后读需另做受控训练,不能只改一次图就宣布修复。
<span id="attention-to-prediction-s02"></span>
## scorer改的是匹配规则,轴不能跟着混乱
<span id="read-R33"></span>
前面的LAB02使用投影query与点积打分。2014年的Bahdanau系统采用加性scorer并保留循环;下面先说明这个差别,再以给定未缩放点积核算读取,所有例子的源位置轴与词表轴保持区分。
2014 年的动态软对齐使用小神经网络打分。用本章接口重写的一般形式是
$$e_{ij}=v_a^\top\tanh(W_qq_i+W_kk_j+b_a).$$
Bahdanau 原式使用前一 decoder state 与双向 encoder 的 annotation;这里的 Q/K/V 术语是帮助统一理解的后续记法,不意味着原论文已经采用 2017 年多头投影结构。原始模型及 alignment 公式见 [Bahdanau 等,§2.2、附录 A](https://arxiv.org/abs/1409.0473)。
非线性不是可随意省略的装饰。若只对拼接向量作线性打分,$e_{ij}=a^\top q_i+b^\top k_j$,则固定 query 行中 $a^\top q_i$ 是所有 key 共有的常数,在 softmax 分子分母中会抵消:
$$\operatorname{softmax}_j(a^\top q_i+b^\top k_j)=\operatorname{softmax}_j(b^\top k_j).$$
这样换 query 并不会改变权重,失去了我们想要的动态匹配。加上 tanh 后,query 会改变各 key 经非线性变换后的相对分数。点积 $q_i^\top k_j$ 则直接包含两个向量的相互作用,也能形成依赖 query 的权重。选择 scorer 是建模选择,不是把所有“求和”都叫同一种 attention。
加性score可把不同维度的query/key映到相同隐藏空间;点积需要q/k同维,缩放按每头d_k开根号。value的维度可以不同。batch多头常用scores[B,H,Nq,Nk],沿最后Nk轴归一化。图把列/行换过来时,不能照抄“沿列”而忘记实际张量。
causal mask只允许目标位置读自己及之前的**输入位置**,源端padding mask排除虚填位置。所有key都为−∞的行没有有效softmax,必须避免或显式处理,不能将NaN当“模型选择不读”。
<span id="attention-to-prediction-s03"></span>
## 读到同一位置,不一定传来同一内容
以下是旧READ的“她、书、昨天”三槽与her词表,完整数值保持。新课堂另行用“他、书、昨天”计算相同接口,已在主题开头给出;相同给定数值不等于共用训练checkpoint。

<span id="read-R31"></span>
为看清前面整套翻译图里的一个局部,这里另建三来源、二维向量账本。它借用“她、书、昨天”来标源位置,并不是把六位置示意的训练张量直接抄下来。固定这些小数值之后,可以逐步区分需求、匹配线索、内容向量与输出词。
沿用旧READ独立扩展的二维教学构造,先用未缩放的点积,目的是区分匹配与内容,不给向量维度指派未经训练的语义。query 为 $q=(1,0)$,选取“她、书、昨天”三个源位置,key、value 为
| 位置 $j$ | $k_j$ | $v_j$ | 分数 $q^\top k_j$ |
| --- | --- | --- | ---: |
| 1,她 | $(1,0)$ | $(2,0)$ | $1$ |
| 2,书 | $(0,1)$ | $(0,4)$ | $0$ |
| 3,昨天 | $(1,1)$ | $(1,2)$ | $1$ |
指数为 $(2.718282,1,2.718282)$,分母约为 $6.436564$,得到权重
$$\alpha\approx(0.422319,0.155362,0.422319).$$
逐维相加,结果为
$$c=0.422319(2,0)+0.155362(0,4)+0.422319(1,2)
\approx(1.266956,1.466087).$$
为闭合到词表概率,再给出教学投影 $G=\begin{bmatrix}2&0&0\\0&1&0\end{bmatrix}$,小词表依次为 her、book、yesterday。得到 logits $cG\approx(2.533913,1.466087,0)$,第二次 softmax 约为 $(0.702690,0.241553,0.055757)$。第一次 softmax 在源位置间分配读取权重,第二次在目标词表上归一化,两个概率对象不同。这个小投影省略真实 decoder 的其余状态计算,参数均为给定数值,不能据此宣称模型会翻译。
权重非负且和为 1,所以这个单头输出在当前三个 value 的凸包内;之后的输出投影、残差和 FFN 可以把表示移出这个凸包,不能把这一局部性质扩大到整个 Transformer。计算时保留充分精度,最后才舍入;先把权重粗略写成 0.42、0.16、0.42,只适合解释,不适合与实现做严格比较。
<span id="attention-to-prediction-s04"></span>
## 两条独立干预支路

<span id="read-R32"></span>
只算出一个context,还不足以知道哪一部分在起作用。把两个可能原因拆开,会得到两个不同问题:需求变了但来源没变,读取分配是否改变?来源传递的内容变了但匹配线索没变,权重还能保持吗?两次干预必须各自回到原始基线,才不会把第一项变化混进第二项。
两次干预分别从同一基线出发,预测头 G 均保持不变。第一次固定 K 与 V,换成 $q'=(0,1)$。分数变为 $(0,1,1)$,权重变为 $(0.155362,0.422319,0.422319)$,输出变为约 $(0.733044,2.533913)$。读取需求改变,位置 2 的权重上升,输出随之改变。
第一项 q 干预经同一个 G 得到logits约(1.466087,2.533913,0),her/book/yesterday概率约为(.241553,.702690,.055757)。yesterday对应G第三列为零,因此它的logit仍为0。
第二项 V 干预先独立恢复原 q/K/V 基线,再只把 $v_2$ 从 $(0,4)$ 改为 $(0,8)$。因为 scorer 没有使用 V,权重保持原值;输出却变为约 $(1.266956,2.087537)$,第二维增加 $4\times0.155362\approx0.621450$。这区分了“读哪里”与“那里传来什么”。真实 self-attention 中 Q、K、V 都可能由同一 X 投影,改原始 token 通常同时影响三者。独立改 Q 或 V 是有意拆开计算的机制实验,不能冒称自然语言只换一个词时网络一定如此变化。
两次干预都从原Q/K/V与原输出头重新开始。改q改变匹配,改V在这个受控算子里保持权重而改变传输内容;自然输入改词常常同时改变Q/K/V,不能称同一干预。
假如所有v_j相同,无论热图如何重新分配,c都不变。反过来,即使一个位置权重不高,它的value方向和大小也可能对词表logit贡献明显。残差、后续层和输出头还会加工c,所以“α在她处最大”不保证最后输出her;高权重也可能来自与语义不相干的键方向。查看权重、加权value、后续logits与最终正确性,是四个不同检查。
<span id="attention-to-prediction-s05"></span>
## 译文误差怎样教会读取
<span id="read-R37"></span>
正确目标词的概率低,会先产生词表预测的loss。这条信号经输出头回到context,再经加权和回到value与权重,经softmax和打分回到需求与匹配表示。源表示和解码状态同样可以更新。于是普通的平行译文就能教读操作,不必另外为每一个词标一条唯一对齐线;模型要学的是有助于任务预测的读取方式。
### 从机制返回同一次研究选择
再检查独立旧六片段诊断句“我昨天给了她一本书→I gave him a book yesterday . EOS”,原来笼统的“模型没记住”可以拆得更具体:源位置是否保留了角色信息,当前目标需求是否能读取它,读到的内容是否提高her的相对分数,搜索又是否保留了正确候选?这些问题来自已经学过的计算,不只是换一个模型名字。
固定摘要把源句压成一次条件;逐位置接口保存一组编码表示,按每个合法前缀的需求重新读取。任务误差能训练读操作,这说明接口有可学习的用途,没有证明它会修好当前错译。源序反转改善和强固定向量的长句表现仍支持继续旧路线。
待做设计使用同一小型翻译数据与原始参考,比较源序(正/反)×接口(固定摘要/动态读取)2×2。每列内只改源序,固定编码器方向、深度、宽度、参数量与训练/搜索预算;跨列报告配置和容量差别。额外等容量对照才能进一步分离容量因素。主要观察受控接收者词对的teacher-forced正确词NLL与分距错误率;另外报告自由生成BLEU及推理成本。先控制搜索,以免把搜索差距误作条件信息缺失。若动态读取没有可复现收益而代价更大,保留旧路线。若改善只在反转条件出现,也不能把全部改进归于读取接口。
### 局部梯度细式与其他路径
设某行输出 $c=\sum_j\alpha_jv_j$,上游梯度 $g=\partial L/\partial c$。暂把 Q、K、V 当成独立输入,则
$$\frac{\partial L}{\partial v_j}=\alpha_jg,\qquad
\frac{\partial L}{\partial e_j}=\alpha_jg^\top(v_j-c).$$
后一个式子说明,调高一个位置的分数是否有利,取决于该位置的 value 相对当前汇总输出怎样影响损失。对于 scaled dot product,
$$\frac{\partial L}{\partial q}=\frac1{\sqrt{d_k}}\sum_j\frac{\partial L}{\partial e_j}k_j,\qquad
\frac{\partial L}{\partial k_j}=\frac1{\sqrt{d_k}}\frac{\partial L}{\partial e_j}q.$$
在真实网络里还要把这些梯度经投影矩阵传回 X,并汇合所有使用同一输入的路径。这也说明 attention 权重可由端到端任务损失学习,无需每对词提供人工对齐标签。

这张热图来自Bahdanau v7物理第6页Figure 3(a),横轴为英文源词、纵轴为法文生成词,白色表示较大权重。European Economic Area与zone économique européenne展示不同语言顺序的读取关系。它观察当前权重,不独自证明每条译文忠实;来源版本与使用v1的历史成绩分别标明。
<span id="attention-to-prediction-s06"></span>
## 同一个词上的三类读取
`river bank`里的bank表示读同句river,是self-attention;目标her的query读源句“她”,是cross-attention;生成下个词时读已有`I gave`且屏蔽未生成位置,是causal self-attention。三者可以同时出现在一个encoder–decoder里,不是三个互斥的模型品牌。完整Transformer下一主题会把这些接口接在同一次预测中。
来源:同版读本第三、四章/M18–22;CS224N Lecture05物理p25–36(动态读取)与p39–50(self-attention信息边界);[Bahdanau2014 v1](https://arxiv.org/pdf/1409.0473v1)。v1门式的当前标签下标存在笔误,本课始终采用合法前一目标y_{t−1};[v7附录](https://arxiv.org/html/1409.0473v7)已修正,历史实验数字仍保持v1。
原课程连续页组:CS224N 2026 Lecture05物理p25–31在同一母图完成打分、softmax、内容汇总与decoder预测,p32–36保持源图不变、增长目标前缀并重新读取。此处按物理PDF页码,不使用幻灯片内编号。
<span id="attention-to-prediction-s07"></span>
## 相邻知识与复核资源
[2014:先拥有一个可工作的翻译器,再决定改哪里](https://codingai-lec05.pages.dev/course/knowledge/translation-choices-2014.html) · [让整套 Transformer 共同完成一次预测](https://codingai-lec05.pages.dev/course/knowledge/transformer-information-flow.html)
[全部主题](https://codingai-lec05.pages.dev/course/knowledge/index.html) · [关键结果JSON](https://codingai-lec05.pages.dev/course/knowledge/data/learning-paths.json) · [只读诊断源码](https://codingai-lec05.pages.dev/course/knowledge/code/learning_paths.py.read.html) · [Seq2Seq完整实现](https://codingai-lec05.pages.dev/course/knowledge/code/seq2seq.py.read.html) · [视觉机制实现](https://codingai-lec05.pages.dev/course/knowledge/code/mechanisms.py.read.html) · [TinyDecoder与cache实现](https://codingai-lec05.pages.dev/course/knowledge/code/legacy_numpy.py.read.html)