想象一家主打分子料理的晚宴餐厅。后厨里,备菜组领班已经完整读过了客人的宴席要求——那是一份法文原版菜单——并把它整理成一本厚厚的风味手册,上面记录着每道菜该有的风味、食材与搭配逻辑。而在出菜口的另一端,掌勺主厨站上了灶台。他不能像备菜组那样一次看完所有食材,必须一道菜一道菜地出;他的正前方还有一面单向玻璃——他只能看见已经端出去的那几道菜,绝不允许偷看下一道菜该是什么。为了不跑偏,他每炒完一道菜,都要低头翻一眼风味手册确认口味;为了不低效,他身边还有一位帮厨,每出一道菜就在速记本上记下这道菜的关键信息。 这套流程,就是 Transformer 解码器的工作方式。备菜组是编码器(Encoder),掌勺主厨是解码器(Decoder),单向玻璃对应因果掩码(Causal Mask),翻手册对应交叉注意力(Cross-Attention),速记本对应 KV 缓存(KV Cache)。如果你用过 ChatGPT、做过机器翻译、写过 AI 续写,你其实一直在看这位主厨出菜。接下来,我们就拆开这位主厨的每一个动作。
掌握解码器,就掌握了所有生成式大模型的“心脏”:无论调优 GPT 类模型、做推理加速,还是排查生成质量,你都需要先看懂这位出菜主厨的每一步。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
解码器三层子模块 每个子层:Add & LayerNorm | 多层堆叠构成完整解码器 因果掩码矩阵 位置 j → Attention(Q,K,V) = softmax(QK^T/√d Transformer解码器可视化:展示三层子模块、因果掩码、交叉注意力、...
解码器总览
推开厨房的门,你会看到掌勺主厨的灶台是一条三段式流水线。第一段是一面回放镜——它只会回放已经端出厨房的菜,绝不映照未来的餐桌;第二段是一本摊开的风味手册,主厨每做一道菜都要低头核对手册,确认没有跑题;第三段是一张小调味台,每道菜出锅前在这里单独收味、整形。三段走完,一道菜才算合格,装盘出餐。
这段流水线,就是 Transformer 解码器中“一层”的完整结构。真实的解码器并非只有一层,而是由 N 个完全相同的层垂直堆叠而成——GPT 系列通常堆 12 层、24 层甚至 96 层。每一层内部严格按顺序排列三个子层:掩码自注意力、交叉注意力、前馈网络。由于自注意力不像循环网络那样天然携带顺序感,解码器还会在输入端叠加位置编码,告诉模型每个词排在哪个位置。为了让几十层网络叠加后数值依然稳定,每个子层外面都套着残差连接与层归一化。
每个子层都遵循同一种“先处理、再还原”的更新模式。设输入为 $x$,子层函数为 $\text{SubLayer}(\cdot)$,那么输出为:
这就像主厨对每一道工序都留了一手:菜加工完了,他还会把原始食材拼在旁边一起对照——万一加工过度,还能从原始版本里找回味道。残差连接正是这条保底捷径,而层归一化则是装盘前最后的摆正。理解这一层骨架,再看后面三个子层,就只是往流水线的三个台子上分别填细节了。
- 主路径(主厨炒菜)$\text{SubLayer}(x)$ —— 子层先对输入 $x$ 做变换,比如掩码自注意力完成打分与加权。
- 残差捷径(备份菜样)$x + \text{SubLayer}(x)$ —— 把原始输入原样加回加工结果,防止信息在层层传递中丢失。
- 层归一化(装盘把关)$\text{LayerNorm}(\cdot)$ —— 对每个位置的特征做标准化,让数值分布稳定,训练更快收敛。
掩码自注意力
第一段流水线是回放镜。出菜口的单向玻璃让主厨只能看到已经端走的菜:第 1 道、第 2 道……直到当前这道。至于第 5 道菜还没做出来,它绝不会出现在镜子里。这就是解码器与编码器最本质的区别——生成时绝不看未来。
技术术语叫掩码自注意力(Masked Self-Attention)。“自注意力”指 Q、K、V 三个矩阵全部由解码器自己的输入投影而来,让每个位置都能参考其他位置;“掩码”则负责把未来位置的参考权删除。注意,删除不是硬性把权重归零,而是在 softmax 之前的打分矩阵上加一层遮挡,这正是后面“因果掩码矩阵”一节要展开的内容。打分公式如下:
回到厨房:主厨给每道菜打分时,先看它与已经上桌的菜有多合拍($QK^\top$),除以菜量规模让分数别失控($\sqrt{d_k}$),被单向玻璃挡住的未来菜直接记上“-∞”($+M$),剩下的过去菜按合拍程度分配注意力权重(softmax),最后把这些菜的味道按权重混合进当前这道菜($\times V$)。回放镜就这么工作。
- 查询与键的点积(对味指数)$QK^\top$ —— 当前位置的查询向量,与每个历史位置的键向量做点积,得到“有多相关”的分数。
- 缩放$\frac{1}{\sqrt{d_k}}$ —— 维度越大点积数值越大,除以 $\sqrt{d_k}$ 把分数拉回稳定区间,防止 softmax 饱和。
- 加掩码$+ M$ —— 矩阵 $M$ 把未来位置的分数改成 $-\infty$,让它们无法参与竞争。
- 归一化成权重$\text{softmax}(\cdot)$ —— $-\infty$ 处权重变成 0,历史位置按相关度分配 0~1 的权重。
- 加权求和$\times V$ —— 用权重混合各位置的值向量,得到融合了历史信息的输出。
交叉注意力
第二段流水线是风味手册。主厨不能只凭自己的记忆做菜——他必须确保每一道菜都忠实于客人点的那顿宴席。于是每道菜出锅前,他都要低头翻手册,找到“原文想要什么味道”,然后把手边食材往那个方向靠。
交叉注意力(Cross-Attention)干的正是这件事。它的查询向量 Q 来自解码器当前词,代表“我现在想表达什么”;而键 K、值 V 全部来自编码器的最终输出,代表“原文里每个词的关键信息和内容”。解码器把自己当前的意图与原文每个词逐一比对,把最相关的原文语义“搬运”过来。注意!这里 Q 与 K、V 的来源不同,正是交叉注意力与自注意力唯一的本质区别。
机器翻译里,源文“I love you”被备菜组压成风味手册;主厨要做中文的第二个词时,Q 说“我现在要决定动词了”,手册里 love 的键值立刻被高亮,于是他把“爱”端了出来。没有交叉注意力,解码器就像闭眼做菜的主厨——手艺再好,也会偏离原菜单。
- Q 来自解码器(主厨口味)$Q_d$ —— 由解码器当前位置的隐藏状态投影而来,表示“这道菜我想做成什么样”。
- K、V 来自编码器(备菜手册)$K_e, V_e$ —— 编码器输出的每个词都提供键和值,键负责匹配,值负责内容。
- 跨端打分$Q_d K_e^\top$ —— 当前词逐个对照原文所有词,找出与自己最贴近的原文片段。
- 加权搬运$\text{softmax}(\cdot) V_e$ —— 按匹配程度加权汇总原文信息,注入解码输出。
前馈网络
第三段是调味台。前两个子层像一场场讨论会——每个词都要与别的词交换信息,开完会大家脑子里装满了彼此的想法。但讨论不能替代个人手艺:每个词最终要独立完成自己的“提味”,把混合后的信息加工成更丰富的表达。这张只属于单道菜的调味台,就是前馈网络。
前馈网络(Feed-Forward Network, FFN)对每个位置完全独立地作用:同一套矩阵、同一套偏置,依次作用在序列的每个词向量上。它先把维度从 $d$ 扩到 $4d$,做一次非线性激活,再压缩回 $d$ 维。两层的“形状”像一个中间鼓起的瓶子——先放开、再收口。
前两个台子负责“串味”——让每道菜知道同桌的菜是什么;调味台负责“定味”——每道菜在自己碗里完成最后的调味和整形。没有这一步,解码器就只有一群互相参考、却不会独立思考的菜。
- 升维(把菜放大看)$W_1 x + b_1$ —— 线性变换把维度从 $d$ 扩到 $4d$,提供更大的表达空间。
- 非线性激活(调味)$\text{GELU}(\cdot)$ —— 逐元素引入非线性,否则多层线性变换叠在一起还是线性。
- 降维(装盘收口)$W_2 + b_2$ —— 变换回 $d$ 维,方便与后续残差连接对齐。
- 逐词独立每个位置单独过 FFN,词与词之间不通信,与前两层的“开会”形成互补。
自回归生成
主厨的晚宴有条铁律:菜必须一道接一道地上,不能三盘同时出。第 3 道菜是什么,取决于第 1、2 道菜已经长成什么样;如果第 2 道做成了辣味,第 3 道的搭配就要跟着调整。这就是自回归生成——把自己的输出当作下一步的输入,像滚雪球一样往前滚。
形式化地说,生成整段文本 $w_1 w_2 \ldots w_T$ 的联合概率,可以按链式法则拆成每一步条件概率的乘积:
推理时,模型在每个时间步把“概率最大的词”接到输入末尾,再预测下一个;遇到结束符就收手。这里“概率最大的词”对应解码器输出层对词表的打分——那是主厨唯一能看到“整本菜单”的地方。
- 整句话概率(整桌菜单)$P(w_1, \ldots, w_T)$ —— 生成整段文本的联合概率。
- 链式法则拆解(一盘接一盘)$\prod_{t=1}^{T}$ —— 把联合概率拆成一连串条件概率相乘。
- 条件依赖(只看已上桌的菜)$P(w_t \mid w_{<t})$ —— 第 $t$ 个词只条件于前 $t-1$ 个词,严格单向。
- 逐词选择(点单决策)每个时间步在词表上取概率最大的词(贪心解码)或按概率采样,作为下一轮的输入。
因果掩码矩阵
单向玻璃到底长什么样?把它画成一张坐标纸:行代表“现在轮到预测第几个词”,列代表“允许参考第几个词”。玻璃的存在,让下三角区域透明可见,上三角区域被贴上反光膜。
这张坐标纸就是因果掩码矩阵 $M$。训练时,整个真实目标序列会一次性地同时输入解码器(这是并行训练的关键),如果没有 $M$,第 3 个词在计算注意力时就会偷看到第 5 个词——相当于主厨在菜单还没定稿时就偷看了未来的菜。矩阵的构造极简单,但对正确性至关重要:
示意图里,掩码矩阵被涂成红白分明的两块。softmax 一过,红色区域的权重蒸发成 0,下三角正常加权。训练时大家齐头并进却互不偷看;推理时只剩一个人在前方开路——掩码始终是那位保证“不偷看未来”的守门员。
- 矩阵坐标含义(座位表)$i$ 行表示当前要预测的位置,$j$ 列表示能参考的位置。
- 下三角保留(已上桌)$i \ge j$ 时 $M_{ij} = 0$ —— 当前位置可以看自己和过去的词,注意力权重正常计算。
- 上三角屏蔽(未来的菜不许偷看)$i < j$ 时 $M_{ij} = -\infty$ —— 经过 softmax 后这些位置的权重趋近于 0。
KV缓存优化
主厨出菜越来越快,多亏了帮厨的速记本。每端出一道菜,帮厨就在本子上记下这道菜的关键索引和味道档案。等到做第 50 道菜时,主厨不需要重新回忆前 49 道菜,只要翻到本子最后一条,对照新的要求就行。若没有速记本,每做一道新菜都要把前面所有菜重新品尝一遍——太慢了。
速记本对应 KV 缓存(KV Cache)。推理时,第 $t$ 步只需为当前新词计算新的键 $k_t$、值 $v_t$,并把它追加到缓存数组中;历史词的 K、V 直接复用。这样每步的注意力计算量,从“每次都要重算前 $t$ 步所有点积”,降为“只对新词做一次矩阵乘法”:
长文本生成中,KV 缓存能带来 5~10 倍的推理加速,这正是 ChatGPT 打字那么快的原因之一。你每看到一个词蹦出来,背后都有帮厨在奋笔疾书。
- 只需新词的查询(新菜口味)$q_t$ —— 第 $t$ 步只计算新词一个查询向量,历史词不再重复投影。
- 缓存键(速记本)$K_{\text{cache}}$ —— 历史所有词的键按顺序拼接,随生成不断追加。
- 一次点积(直接翻本子)$q_t K_{\text{cache}}^\top$ —— 新词与全部历史键做一次矩阵乘法,而不是重新计算历史词的 QK 乘积。
- 加权取值(照单混合)$\text{softmax}(\cdot) V_{\text{cache}}$ —— 结果与不缓存完全一致,只是省掉了历史词的重复计算。
训练与推理
最后一个秘密:厨师是怎么学会这手绝活的?训练时,老板会把标准答案直接摆在主厨手边——第 2 道菜的正确答案就放在那,让他对照着练,这叫教师强制(Teacher Forcing);真正开店后,标准答案撤走,他只能凭自己上一道菜的手感继续做,这叫自回归推理。两种模式,同一套炉灶。
训练阶段,把真实目标序列右移一位作为解码器输入,由于有因果掩码,模型可以一次性并行计算出所有位置的预测分布,再与真实词计算损失。推理阶段,没有真实词可喂,只能把上一步的预测词作为输入逐词串行推进,直到预测出结束符。损失函数定义如下:
理解了训练与推理的差异,就理解了为什么大模型推理工程要拼命优化 KV 缓存、为什么训练可以用几千张 GPU 并行、而推理只能一步步来。主厨的晚宴,从学徒到开店,原来是两套规则下的同一门手艺。
- 条件建模(标准答案在手边)$P(y_t \mid y_{<t}, x)$ —— 训练时第 $t$ 步的输入是真实前文,条件是源文本 $x$。
- 取负对数(答错扣分)$-\log$ —— 预测概率越接近 1,$-\log$ 越小,等价于鼓励模型猜中真实词。
- 全序列平均(全班成绩)$\frac{1}{T} \sum_{t}$ —— 对每个位置的损失取平均,作为这一句的最终损失。
- 推理换规则(开卷变闭卷)推理时没有真实前文可用,只能用自己的预测词续写,这就是训练与推理的本质差异。
AI 应用场景
大模型聊天助手推理加速
阶段:推理部署 / 生成阶段
解决的问题:GPT 类模型解码时,每生成一个词都要重新计算前面所有词的注意力。传统做法在生成第 100 个词时,要重复做 99 次历史词的 QK 点积,延迟随生成长度线性暴涨。引入 KV 缓存后,历史键值只算一次并存入显存,每一步只处理新词,生成速度可提升 5~10 倍——这正是主厨翻速记本的故事在工业界的落地。
具体案例:某团队部署 7B 参数的对话模型,首 token 延迟 300ms 后,每生成一个 token 由原来的 80ms 降到 12ms。它们做的核心改动就是在解码器每一层的掩码自注意力处维护 KV 缓存数组,并配合连续内存池减少碎片。
机器翻译中的编码-解码协作
阶段:训练与推理全链路
解决的问题:翻译时,目标语言的每个词都必须“看着”整句源文来生成。传统统计机器翻译靠短语表对齐,生硬且无法处理长句。解码器的交叉注意力让每个目标词直接对源文所有词做软对齐:Q 来自解码器当前词,K、V 来自编码器输出,实现端到端的语义搬运。
具体案例:中英翻译系统中,输入“The weather is nice today”,编码器把它压成 7 个位置的风味手册;解码器生成“今天”时,交叉注意力把权重集中到 “today” 上,从而产出忠实原文的译文。
流式语音字幕实时生成
阶段:在线流式推理
解决的问题:语音识别字幕要求边说边出字,不能等整句说完再识别。解码器天然的自回归性质 + 因果掩码正好匹配流式场景:每个时间步只依赖已识别出的历史字符,配合 KV 缓存把增量计算压到最低,从而实现几百毫秒级别的低延迟字幕输出。
具体案例:实时会议字幕系统,解码器每收到一个声学块就生成一个词,同时把该词的 KV 追加进缓存;说话人停顿 500ms 内字幕即上屏,观众几乎感觉不到滞后。
Python 演示
"""最小Transformer解码器: 掩码自注意力 + 交叉注意力 + KV缓存"""import numpy as np def softmax(x, axis=-1): e = np.exp(x - x.max(axis=axis, keepdims=True)) return e / e.sum(axis=axis, keepdims=True) def causal_mask(n): """上三角为 -inf 的因果掩码, 形状 (n, n)""" m = np.zeros((n, n)) m[np.triu_indices(n, 1)] = -1e9 return m class MiniDecoder(object): def __init__(self, d=16, v=24, seed=0): rng = np.random.default_rng(seed) self.d = d self.v = v self.wq = rng.normal(0, 0.1, (d, d)) self.wk = rng.normal(0, 0.1, (d, d)) self.wv = rng.normal(0, 0.1, (d, d)) self.wf1 = rng.normal(0, 0.1, (d, 4 * d)) self.wf2 = rng.normal(0, 0.1, (4 * d, d)) self.embed = rng.normal(0, 0.1, (v, d)) sos_k = self.embed[0] @ self.wk sos_v = self.embed[0] @ self.wv self.k_cache = sos_k[None, :] self.v_cache = sos_v[None, :] def attn(self, x, k, v, mask=None): q = x @ self.wq s = q @ k.T / np.sqrt(self.d) if mask is not None: s = s + mask return softmax(s) @ v def step(self, token_id, cross_k, cross_v): x = self.embed[token_id][None, :] h = self.attn(x, self.k_cache, self.v_cache) new_k = x @ self.wk new_v = x @ self.wv self.k_cache = np.vstack([self.k_cache, new_k]) self.v_cache = np.vstack([self.v_cache, new_v]) h = self.attn(h, cross_k, cross_v) h = np.maximum(0, h @ self.wf1) @ self.wf2 logits = h[0] @ self.embed.T return int(np.argmax(logits)) def forward_parallel(self, token_ids, cross_k, cross_v): """训练路径: 整句并行 + 因果掩码""" x = self.embed[token_ids] h = self.attn(x, x @ self.wk, x @ self.wv, mask=causal_mask(len(x))) h = self.attn(h, cross_k, cross_v) h = np.maximum(0, h @ self.wf1) @ self.wf2 return h @ self.embed.T def generate(self, start_id, steps=6): rng = np.random.default_rng(1) cross_k = rng.normal(0, 0.1, (4, self.d)) cross_v = rng.normal(0, 0.1, (4, self.d)) ids = [start_id] for _ in range(steps): ids.append(self.step(ids[-1], cross_k, cross_v)) return ids if __name__ == "__main__": dec = MiniDecoder() result = dec.generate(0, steps=6) print("生成轨迹:", result) print("KV缓存中的键数量:", len(dec.k_cache)) rng = np.random.default_rng(1) ck = rng.normal(0, 0.1, (4, dec.d)) cv = rng.normal(0, 0.1, (4, dec.d)) logits = dec.forward_parallel([0, 1, 2], ck, cv) print("并行训练输出形状:", logits.shape)
m[np.triu_indices(n, 1)] = -1e9生成因果掩码:把方阵上三角全部置成很大的负数s = q @ k.T / np.sqrt(self.d)注意力打分:查询向量与每个键点积后缩放return softmax(s) @ v把分数归一化成权重,再对值向量加权求和h = self.attn(x, self.k_cache, self.v_cache)掩码自注意力:KV 来自历史缓存,天然只看到过去self.k_cache = np.vstack([self.k_cache, new_k])KV 缓存追加:新词的键入册,供后续步骤复用h = self.attn(h, cross_k, cross_v)交叉注意力:KV 换成编码器输出,完成语义对接h = np.maximum(0, h @ self.wf1) @ self.wf2前馈网络:先升维再用 ReLU 激活,再降维回原尺寸logits = h[0] @ self.embed.T输出层:隐藏向量与词表向量做点积打分ids.append(self.step(ids[-1], cross_k, cross_v))自回归:把上一步预测结果喂给下一步
常见误区
误区我以为因果掩码就是把未来位置的注意力权重直接乘 0,既然不让看,权重设成 0 最直观了,所以掩码矩阵里未来位置填 0 就行。
正解填 0 会让分数保持原值,经过 softmax 后可能依然分走大量权重——挡住视线不等于把分数归零。正确做法是在 softmax 之前,给未来位置的分数加上一个极大的负数($-1e9$ 或 $-\infty$),softmax 之后这些位置的权重自然趋近于 0。这就像给未来的菜贴上“-∞ 分”的标签,而不是直接说“这道菜 0 分”。
为何常见:“mask”这个词容易让人联想到“遮挡→归零”,加上很多示意图直接把被掩码区域涂黑,初学者很自然会理解成乘 0。
误区我以为交叉注意力就是把注意力公式再算一遍,既然公式长得一模一样,那它和掩码自注意力只是名字不同。
正解两者公式确实相同,但数据来源完全不同。掩码自注意力的 Q、K、V 都来自解码器自身的历史状态;交叉注意力的 Q 来自解码器,而 K、V 来自编码器的最终输出。来源不同决定了行为不同:前者做“内部历史对齐”,后者做“跨端语义搬运”。没有交叉注意力,翻译模型就失去了参考原文的通道。
为何常见:初学者先熟记了统一的注意力公式,注意力被公式形式吸引,忽略了输入来源这个关键差异。
误区我担心用 KV 缓存之后,模型拿到的是“旧记忆”,可能跟不加缓存时生成的词不一样,所以总是不敢在生产环境开启缓存。
正解缓存只是把历史词的 K、V 向量存下来复用,数学上与不缓存严格等价——因为它省掉的是重复计算,不是改变计算逻辑。每一步注意力结果与重新计算历史 QK 乘积完全一致(仅存在浮点舍入级别的微小误差)。可以放心地说:缓存只影响速度,不影响质量。
为何常见:直觉上“缓存≈压缩≈有损”,人们习惯性地担心优化手段会引入信息损失,忽略了这里的缓存是精确复算。
误区我以为生成模型训练时和推理一样,必须串行地把预测词喂回模型,所以训练一千万条句子要跑一千万次前向——训练慢得离谱。
正解训练用的是教师强制(Teacher Forcing):把真实目标序列整体一次性输入解码器,配合因果掩码,所有位置可以并行计算预测分布和损失。推理没有真实词可用,才必须串行逐词生成。训练并行、推理串行,是解码器两种模式最大的分水岭。
为何常见:很多人只接触过推理时的生成流程,看到“自回归”三个字就默认训练也是逐词滚动,忽略了训练有标准答案可以“喂”。
误区我以为生成到固定长度就行,结束符只是装饰品,有没有都不影响训练和推理。
正解结束符是解码器唯一的“刹车信号”。训练时目标序列末尾要加 <eos> 作为预测目标,模型才能学会“这句话到此为止”;推理时一旦预测出 <eos> 就停止生成。没有结束符,模型会一直续写下去,要么无限循环、要么被硬截断产生残缺文本。
为何常见:初学阶段只关注“如何生成下一个词”这个主流程,把结束符当成后处理细节,忽略了它参与训练目标与停止条件的事实。
面试题
Q1. 解码器掩码自注意力中,因果掩码的核心作用是什么?
- A.增加解码器模型的参数量
- B.防止模型提前看到未来词语← 正确答案
- C.加速模型训练的收敛速度
- D.增强梯度反向传播的稳定性
答案:B。因果掩码的本质是让第 t 个位置只能关注前 t-1 个位置,防止信息从未来泄漏到过去,这正是自回归生成的前提。加速收敛、增加参数、增强梯度都不是掩码的职责,它们分别由更深的层、更大的维度、残差连接等机制承担。
Q2. 解码器预测第 t 个词时,它的依赖对象是?
- A.依赖输入中的全部词汇
- B.只依赖已生成的前t-1个词← 正确答案
- C.依赖未来还没生成的词
- D.依赖随机均匀的噪声
答案:B。自回归生成的核心是“只看过去”:第 t 个词的条件概率只依赖于前 t-1 个已生成词。依赖全部输入是编码器的行为,依赖未来词会泄漏答案,依赖随机噪声则毫无信息量。
Q3. 交叉注意力结构中,K 和 V 矩阵来自哪里?
- A.解码器上一步输出投影
- B.前馈网络中间层输出
- C.词嵌入矩阵的固定向量
- D.编码器的最终输出投影← 正确答案
答案:D。交叉注意力是解码器与编码器之间的桥梁,Q 来自解码器,而 K、V 都来自编码器的最终输出。这样每个目标词可以直接“查阅”原文所有词。其余选项描述的都是解码器内部的信息,无法承担跨端语义搬运的职责。
Q4. 因果掩码矩阵中,未来位置填入什么值最合理?
- A.填入数值一增加权重
- B.填入负一使权重变小
- C.填入数值零让权重为0
- D.填入负无穷经softmax归零← 正确答案
答案:D。掩码要加在 softmax 之前,未来位置的分数应设置为 $-\infty$,经过 softmax 后权重严格趋近于 0。填入 0 或 -1 后经过 softmax 仍可能分到非零权重,等于没有完全屏蔽未来。
Q5. KV缓存主要省掉了推理中的哪部分重复计算?
- A.词嵌入层的一次查表操作
- B.历史词键值对应的注意力打分← 正确答案
- C.前馈网络里的两次矩阵乘法
- D.输出层到词表的全部映射
答案:B。没有缓存时,生成第 t 个词会重新计算前 t-1 个词的 K、V 以及它们的 QK 点积,复杂度随 t 线性增长。KV 缓存把历史键值存下来,每步只需对新词做一次查询,省掉的是历史词的全部重复注意力打分。
Q6. 训练阶段解码器能够并行的根本原因是?
- A.GPU显存容量足够大
- B.不需要计算注意力分数
- C.掩码屏蔽未来词后整体输入← 正确答案
- D.解码器参数数量相对较少
答案:C。训练时把真实目标序列整体输入,因果掩码保证每个位置只看历史、互不干扰,因此所有位置可以一次前向并行算出。这与显存大小、参数多少无关;注意力分数也照样要算,只是被掩码限制了可见范围。
Q7. 自回归推理时,每个时间步输入解码器的内容是?
- A.目标序列的真实词语
- B.随机漂移的噪声向量
- C.上一步预测出的那个词← 正确答案
- D.编码器输出的所有向量
答案:C。推理阶段没有真实词可用,必须把上一步预测出的词作为当前步输入,形成“预测→喂入→再预测”的闭环。真实词语只出现在训练的教师强制阶段;编码器输出作为交叉注意力的 K、V,而不是输入序列。
Q8. 下列属于解码器中每一层的标准组件有哪些?
- A.掩码自注意力子层← 正确答案
- B.交叉注意力子层← 正确答案
- C.前馈全连接子层← 正确答案
- D.全局平均池化层
答案:ABC。解码器每一层由掩码自注意力、交叉注意力、前馈网络三个子层组成,外面套残差和层归一化。全局平均池化常见于 CNN 分类网络,不出现在 Transformer 解码器层内。
Q9. 关于KV缓存机制的说法,正确的有哪些?
- A.缓存历史词的键和值← 正确答案
- B.用额外空间换取推理时间← 正确答案
- C.缓存内容来自输入句子
- D.每次生成都重算历史注意力
答案:AB。KV 缓存把每步新词的 K、V 追加进数组并复用,属于典型的空间换时间,其结果与不缓存严格等价。缓存存的是解码器自身的键值而非输入句子的原始内容;重算历史注意力恰恰是缓存要消除的低效行为。
Q10. 关于训练与推理差异的说法,正确的有哪些?
- A.推理必须从起始符逐词进行← 正确答案
- B.训练输入使用真实目标词← 正确答案
- C.训练阶段也必须使用缓存
- D.推理使用模型预测词续写← 正确答案
答案:ABD。训练用教师强制,把真实目标词右移后整体输入,配合因果掩码并行计算;推理没有真实词,只能从起始符开始,用预测词逐词续写。训练是整句并行,缓存没有用武之地,因此“训练也必须用缓存”是错误的。