news 2026/1/19 13:45:52

Decoder-Only架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Decoder-Only架构

Decoder-Only架构

Decoder-only 架构摒弃了 Encoder-Decoder 架构中的编码器部分以及与编码器交互的交叉注意力模块。在这种架构下,模型仅使用解码器来构建语言模型。这种架构利用“自回归”机制,在给定上文的情况下,生成流畅且连贯的下文。

一、计算流程

1、初始设置

该模型由3个Transformer解码器层(Block)堆叠而成

任务设定:

  • 输入提示词 (Prompt):假设已有2个Token:[T1,T2][\text{T}_1, \text{T}_2][T1,T2]
  • 目标:自回归地生成接下来的4个Token:T3,T4,T5,T6\text{T}_3, \text{T}_4, \text{T}_5, \text{T}_6T3,T4,T5,T6

关键概念铺垫:

在Decode-only架构中,为了防止“剧透”,注意力机制是**因果(Causal)**的。Tokeniii只能看到它自己和它之前的Token (111i−1i-1i1),看不到未来的Token。

为了提高效率,我们使用KV Cache。当生成第NNN个Token时,我们不需要重新计算前N−1N-1N1个Token的Key (K) 和 Value (V) 向量,而是直接从显存中读取之前存好的。


2. 详细计算过程推演

整个过程分为两个阶段:预填充(Prefill)阶段(处理提示词)和解码(Decoding)阶段(逐个生成)。

阶段 0:预填充(Prefill)—— 处理[T1,T2][\text{T}_1, \text{T}_2][T1,T2]

在开始生成之前,必须先并行处理输入的提示词,建立初始的KV Cache。

  • 输入:T1,T2\text{T}_1, \text{T}_2T1,T2的嵌入向量x1,x2x_1, x_2x1,x2
  • 过程(以第 L 层为例,L=1,2,3):
    1. 计算所有输入Token在当前层的Q,K,VQ, K, VQ,K,V
    2. K1,K2K_1, K_2K1,K2V1,V2V_1, V_2V1,V2存入第 L 层的 KV Cache。
    3. 执行因果注意力计算(T1\text{T}_1T1只看自己,T2\text{T}_2T2T1\text{T}_1T1和自己)。
  • 预填充结束状态:
    • 模型输出了T3\text{T}_3T3的预测概率分布。我们采样得到T3\text{T}_3T3
    • 显存中建立了3个独立的Cache:
      • Block 1 Cache:[(K1(1),V1(1)),(K2(1),V2(1))][(K_1^{(1)}, V_1^{(1)}), (K_2^{(1)}, V_2^{(1)})][(K1(1),V1(1)),(K2(1),V2(1))]
      • Block 2 Cache:[(K1(2),V1(2)),(K2(2),V2(2))][(K_1^{(2)}, V_1^{(2)}), (K_2^{(2)}, V_2^{(2)})][(K1(2),V1(2)),(K2(2),V2(2))]
      • Block 3 Cache:[(K1(3),V1(3)),(K2(3),V2(3))][(K_1^{(3)}, V_1^{(3)}), (K_2^{(3)}, V_2^{(3)})][(K1(3),V1(3)),(K2(3),V2(3))]

阶段 1:生成第1个Token (T3→T4\text{T}_3 \to \text{T}_4T3T4)

现在开始正式的Decode过程。当前的输入是刚刚生成的T3\text{T}_3T3。目标是预测T4\text{T}_4T4

当前输入向量:h3(0)h_3^{(0)}h3(0)(即T3\text{T}_3T3的嵌入向量)。

【第1次注意力计算:Block 1】

  1. 计算当前的Q, K, V:

    使用Block 1的权重矩阵计算T3\text{T}_3T3的向量:

    • q3(1)=h3(0)⋅WQ(1)q_3^{(1)} = h_3^{(0)} \cdot W_Q^{(1)}q3(1)=h3(0)WQ(1)
    • k3(1)=h3(0)⋅WK(1)k_3^{(1)} = h_3^{(0)} \cdot W_K^{(1)}k3(1)=h3(0)WK(1)
    • v3(1)=h3(0)⋅WV(1)v_3^{(1)} = h_3^{(0)} \cdot W_V^{(1)}v3(1)=h3(0)WV(1)
  2. KV Cache 更新:

    将新的k3(1)k_3^{(1)}k3(1)v3(1)v_3^{(1)}v3(1)追加到 Block 1 的 Cache 末尾。

    • 当前Kcache(1)K_{cache}^{(1)}Kcache(1)变为:[K1(1),K2(1),k3(1)][K_1^{(1)}, K_2^{(1)}, \mathbf{k_3^{(1)}}][K1(1),K2(1),k3(1)]
    • 当前Vcache(1)V_{cache}^{(1)}Vcache(1)变为:[V1(1),V2(1),v3(1)][V_1^{(1)}, V_2^{(1)}, \mathbf{v_3^{(1)}}][V1(1),V2(1),v3(1)]
  3. 注意力计算 (Attention):

    T3\text{T}_3T3的查询向量q3(1)q_3^{(1)}q3(1)需要与当前Cache中所有的K(包括它自己)进行计算。

    • Scores=Softmax(q3(1)⋅[K1(1),K2(1),k3(1)]Tdk)Scores = \text{Softmax}(\frac{q_3^{(1)} \cdot [K_1^{(1)}, K_2^{(1)}, k_3^{(1)}]^T}{\sqrt{d_k}})Scores=Softmax(dkq3(1)[K1(1),K2(1),k3(1)]T)
    • Output3(1)=Scores⋅[V1(1),V2(1),v3(1)]Output_3^{(1)} = Scores \cdot [V_1^{(1)}, V_2^{(1)}, v_3^{(1)}]Output3(1)=Scores[V1(1),V2(1),v3(1)]
  4. 后续处理:Output3(1)Output_3^{(1)}Output3(1)经过残差连接、层归一化和FFN,得到 Block 1 的输出h3(1)h_3^{(1)}h3(1)

【第2次注意力计算:Block 2】

输入是上一层的输出h3(1)h_3^{(1)}h3(1)

  1. 计算当前的Q, K, V:

    • q3(2)=h3(1)⋅WQ(2)q_3^{(2)} = h_3^{(1)} \cdot W_Q^{(2)}q3(2)=h3(1)WQ(2);k3(2)=…k_3^{(2)} = \dotsk3(2)=;v3(2)=…v_3^{(2)} = \dotsv3(2)=
  2. KV Cache 更新:

    k3(2),v3(2)k_3^{(2)}, v_3^{(2)}k3(2),v3(2)追加到 Block 2 的 Cache。

    • Block 2KcacheK_{cache}Kcache现在包含T1,T2,T3\text{T}_1, \text{T}_2, \text{T}_3T1,T2,T3在第二层的Key。
  3. 注意力计算:

    q3(2)q_3^{(2)}q3(2)对 Block 2 的整个KcacheK_{cache}Kcache做注意力计算,并取回VcacheV_{cache}Vcache

【第3次注意力计算:Block 3】

输入是h3(2)h_3^{(2)}h3(2)。重复上述过程,更新 Block 3 的 KV Cache,并完成注意力计算。

【本步结束】

Block 3 的输出经过最后的线性层(Unembedding)和Softmax,采样得到下一个Token:T4\text{T}_4T4


阶段 2:生成第2个Token (T4→T5\text{T}_4 \to \text{T}_5T4T5)

当前的输入是T4\text{T}_4T4。目标是预测T5\text{T}_5T5

注意观察Cache是如何增长的。

当前输入向量:h4(0)h_4^{(0)}h4(0)(T4\text{T}_4T4的嵌入向量)。

【第1次注意力计算:Block 1】

  1. 计算 Q, K, V:

    计算T4\text{T}_4T4在第一层的q4(1),k4(1),v4(1)q_4^{(1)}, k_4^{(1)}, v_4^{(1)}q4(1),k4(1),v4(1)

  2. KV Cache 更新:

    k4(1),v4(1)k_4^{(1)}, v_4^{(1)}k4(1),v4(1)追加到 Block 1 Cache。

    • Cache中现有Token:[T1,T2,T3,T4][\text{T}_1, \text{T}_2, \text{T}_3, \mathbf{\text{T}_4}][T1,T2,T3,T4]
  3. 注意力计算 (Q与K的详细交互):

    当前的 Queryq4(1)q_4^{(1)}q4(1)需要“关注”之前所有的信息。

    • Attention Scores calculation:

      Score(T4,T1)=q4(1)⋅(K1(1))TScore(\text{T}_4, \text{T}_1) = q_4^{(1)} \cdot (K_1^{(1)})^TScore(T4,T1)=q4(1)(K1(1))T(关注最早的提示词)

      Score(T4,T2)=q4(1)⋅(K2(1))TScore(\text{T}_4, \text{T}_2) = q_4^{(1)} \cdot (K_2^{(1)})^TScore(T4,T2)=q4(1)(K2(1))T

      Score(T4,T3)=q4(1)⋅(k3(1))TScore(\text{T}_4, \text{T}_3) = q_4^{(1)} \cdot (k_3^{(1)})^TScore(T4,T3)=q4(1)(k3(1))T(关注上一步生成的词)

      Score(T4,T4)=q4(1)⋅(k4(1))TScore(\text{T}_4, \text{T}_4) = q_4^{(1)} \cdot (k_4^{(1)})^TScore(T4,T4)=q4(1)(k4(1))T(关注自己)

    • 将这些分数Softmax归一化后,对Vcache(1)V_{cache}^{(1)}Vcache(1)进行加权求和。

【第2次 & 第3次注意力计算】

数据依次流过 Block 2 和 Block 3。每一层都重复:计算当前T4\text{T}_4T4的K/V -> 存入对应层的Cache -> 用T4\text{T}_4T4的Q去查询该层所有的Cache -> 输出。

【本步结束】

生成Token:T5\text{T}_5T5


阶段 3:生成第3个Token (T5→T6\text{T}_5 \to \text{T}_6T5T6)

过程同上。输入是T5\text{T}_5T5

  • 在经过3个Block的运算后,每个Block的KV Cache长度都会增加到5个([T1,T2,T3,T4,T5][\text{T}_1, \text{T}_2, \text{T}_3, \text{T}_4, \text{T}_5][T1,T2,T3,T4,T5])。
  • T5\text{T}_5T5的 Query 向量会与这 5 个 Key 向量进行点积计算。
  • 本步结束:生成TokenT6\text{T}_6T6

阶段 4:生成第4个Token (完成任务)

虽然题目只需生成4个Token (T3\text{T}_3T3T6\text{T}_6T6),但通常生成T6\text{T}_6T6后模型还会继续预测下一个。我们演示最后这一步的Cache状态。

输入是T6\text{T}_6T6

T6\text{T}_6T6进入Block 3(最后一次注意力计算)时:

  1. 计算出q6(3),k6(3),v6(3)q_6^{(3)}, k_6^{(3)}, v_6^{(3)}q6(3),k6(3),v6(3)
  2. k6(3),v6(3)k_6^{(3)}, v_6^{(3)}k6(3),v6(3)存入 Cache。
  3. 此时 Block 3 的 KV Cache 中包含了完整的历史上下文[T1,T2,T3,T4,T5,T6][\text{T}_1, \text{T}_2, \text{T}_3, \text{T}_4, \text{T}_5, \text{T}_6][T1,T2,T3,T4,T5,T6]在该层的 K 和 V 状态。
  4. q6(3)q_6^{(3)}q6(3)与所有这6个 K 向量进行计算,聚焦相关信息,最终帮助模型预测出序列的下一个词(例如<EOS>\text{<EOS>}<EOS>结束符)。

3、细节解释

(1)在生成多个Token时,假设现在生成完第二个token,要生成第三个token该干嘛?还需要对第二个token进行词嵌入和位置编码吗?

生成第三个Token (T3T_3T3) 的详细步骤

假设我们现在刚刚拿到了T2T_2T2,准备启动生成T3T_3T3的流程。以下是硬件和软件层面发生的确切步骤:

步骤 1:准备新输入(Input Preparation)—— 你的问题所在

这是最关键的一步。模型内部的 Transformer 结构无法直接识别 Token ID(如数字7356),它只认识高维向量。

因此,必须把T2T_2T2这个“生肉”加工成模型能消化的“熟食”。

  1. 词嵌入 (Word Embedding):
    • 拿着T2T_2T2的 ID,去查模型的词嵌入表(Embedding Matrix)。
    • 取出对应的向量VT2V_{T2}VT2。这个向量蕴含了 “apple” 这个词的语义信息。
    • 注意:这一步只针对T2T_2T2做,之前的T1T_1T1和提示词早就在以前的步骤里做过了。
  2. 位置编码 (Positional Encoding):
    • 模型需要知道T2T_2T2在句子里排老几。
    • 假设提示词有 10 个 Token,T1T_1T1是第 11 个,那么T2T_2T2就是第 12 个位置。
    • 计算第 12 个位置的位置向量P12P_{12}P12,把它加到词向量上:XT2=VT2+P12X_{T2} = V_{T2} + P_{12}XT2=VT2+P12

结论:经过这两步,T2T_2T2变成了一个带有语义和位置信息的输入向量XT2X_{T2}XT2,准备好进入 Transformer 的第一层了。

步骤 2:进入 Transformer 层 & 更新 KV Cache

现在,向量XT2X_{T2}XT2进入第 1 个 Transformer 块(Block)。

  1. 计算当前的 Q, K, V:
    • XT2X_{T2}XT2分别乘以三个权重矩阵WQ,WK,WVW_Q, W_K, W_VWQ,WK,WV
    • 得到了针对T2T_2T2的查询向量QT2Q_{T2}QT2、键向量KT2K_{T2}KT2和值向量VT2V_{T2}VT2
  2. 更新 KV Cache(关键动作):
    • 这是 Decoding 阶段最核心的操作。我们把刚刚算出来的KT2K_{T2}KT2VT2V_{T2}VT2存入显存中的 KV Cache 里。
    • 此时,Cache 里已经躺着提示词和T1T_1T1的 K 和 V 了。现在,T2T_2T2的 K 和 V 也加入了队伍。
    • 注意:我们不需要存QT2Q_{T2}QT2,它马上就要被用掉。

步骤 3:注意力计算 (Attention Calculation)

现在开始计算“注意力”,也就是T2T_2T2如何看待它之前的历史。

  1. 拿着 Query 去查询:
    • 使用当前的查询向量QT2Q_{T2}QT2
  2. 回顾所有历史 Key:
    • QT2Q_{T2}QT2必须和 Cache 里所有的 K进行点积计算(包括提示词的 K、T1T_1T1的 K,以及刚刚存进去的它自己的KT2K_{T2}KT2)。
    • 这一步计算出了注意力分数(Attention Scores),表示预测下一个词时,历史上的每个词有多重要。
  3. 加权求和 Value:
    • 根据分数,对 Cache 里所有的 V进行加权求和,得到这一层的输出向量。

步骤 4:层层传递与最终输出

  1. 第 1 层的输出会进入第 2 层,重复步骤 2 和 3(计算新的 QKV,更新第 2 层的 Cache,做注意力计算)。
  2. 直到通过最后一层 Transformer Block。
  3. 最后的输出向量通过一个线性层(Unembedding Layer)映射到词表大小,计算出下一个 Token 是词表中每个词的概率(Logits)。
  4. 采样:根据概率选择可能性最大的词,这就是T3T_3T3
(2)存到Cache中的K,V是什么?为什么称为KV-Cache?为什么不存储Q?

每一个Token的词向量与Qk,Wk,VkQ_k,W_k,V_kQk,Wk,Vk权重矩阵点积后生成的向量是Q(Query),K(Key),V(Value)Q(Query),K(Key),V(Value)Q(Query),K(Key),V(Value)

Q (Query - 查询向量):代表当前这个词(比如“坐”)正在寻找什么信息。“我在找我的主语和状语。”

K (Key - 键向量):代表当前这个词(比如“猫”或“垫子”)具有什么特征线索,用来回答别人的查询。“我是一个名词,也是一个潜在的主语。”

V (Value - 值向量):代表当前这个词包含的实际语义信息。“包含‘猫科动物’的含义”或“包含‘位置地点’的含义”。

Qk,Wk,VkQ_k,W_k,V_kQk,Wk,Vk权重矩阵在每个注意力Block中都是不变的,是固定值,每一个Token进入一个Block中的时候都会用这个Block的Qk,Wk,VkQ_k,W_k,V_kQk,Wk,Vk去计算出这个Token的Q,K,VQ,K,VQ,K,V

1. 为什么存的是计算出的 K, V 激活值,而不是权重值?

因为权重值本来就在那里,不需要存。而 K, V 激活值是“一次性”的,不存就没了。

  • 权重值 (WQ,WK,WVW_Q, W_K, W_VWQ,WK,WV):是模型的参数,是固定的(在推理时)。它们就像厨师手里的刀具和锅具,做第一层蛋糕用这套工具,做第 100 层还是用这套工具。它们一直都在显存里,不需要额外的 Cache 来存。
  • K, V 激活值:特定的输入 Token经过特定的权重矩阵计算出来的临时结果
    • 比如:Ktoken1=Inputtoken1×WKK_{token1} = \text{Input}_{token1} \times W_KKtoken1=Inputtoken1×WK
    • 这个Ktoken1K_{token1}Ktoken1只属于第一个 Token。当计算第二个 Token 时,如果没把Ktoken1K_{token1}Ktoken1存下来,它就丢失了。为了让第二个 Token 能“看到”第一个 Token,你必须把这个计算结果存下来。

2. 这个激活值存下来干嘛?

为了在计算未来的 Token 时,不用重新计算历史 Token 的注意力信息。

在注意力机制中,计算 Query (Q) 和 Key (K) 的相似度(点积)是核心步骤:

Attention Score=Q当前×K历史T\text{Attention Score} = Q_{\text{当前}} \times K_{\text{历史}}^TAttention Score=Q当前×K历史T

  • 当你要生成第 100 个 Token 时,它的Q100Q_{100}Q100必须和前 99 个 Token 的K1,K2,...,K99K_1, K_2, ..., K_{99}K1,K2,...,K99依次做点积。
  • 如果不存下来,你就得把前 99 个 Token 重新输入模型,重新乘一次权重矩阵WKW_KWK,才能得到这 99 个 K。
  • 把它们存下来,下次直接从显存读取做点积,节省了巨大的计算量。V 值同理,它是用来加权求和的“内容”,也需要存下来。

3. 为什么不存 Q?

因为 Q 是“一次性消费品”,用完就废了,存下来没用。

  • Q (Query):代表的是**“当前正在生成的 Token”的查询需求**。
    • 当生成 Token A 时,我们计算QAQ_AQA,用它去查询历史信息。用完之后,QAQ_AQA的使命就完成了。
    • 当生成下一个 Token B 时,我们需要的是全新的QBQ_BQB,去查询包括 A 在内的历史信息。之前的QAQ_AQA对 B 来说毫无意义。
  • K, V (Key, Value):代表的是**“已生成的历史 Token”的信息存档**。
    • Token A 生成后,它的KAK_AKAVAV_AVA就成了历史档案馆的一部分,供未来所有的 Token (B, C, D…) 来查询。它们需要长期保存。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 10:01:31

信捷XDM PLC三轴可编程运动控制:打造灵活数控体验

信捷xdm plc三轴可编程运动控制程序&#xff0c;支持信捷XDM系列PLC 信捷TG765触摸屏 支持直线插补 &#xff0c;圆弧插补&#xff0c;延时&#xff0c;等待输入ON&#xff0c;等待输入OFF&#xff0c;执行输出ON&#xff0c;执行输出OFF。可视化加工轨迹&#xff0c;支持电子手…

作者头像 李华
网站建设 2025/12/26 2:11:47

高斯变迹光栅滤波器模型建立及其FDTD模型与参考文献

高斯变迹光栅滤波器模型建立&#xff0c;fdtd模型参考文献光纤传感领域最近有个挺有意思的讨论热点——如何用高斯变迹光栅实现更干净的光谱响应。今天咱们就扒开这个黑盒子&#xff0c;用FDTD实战演练下这类滤波器的建模过程。先扔个结论&#xff1a;变迹本质就是给光栅结构加…

作者头像 李华
网站建设 2026/1/12 15:53:55

YOLOv8+PyQt5西红柿成熟度检测(可以重新训练,yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

https://www.bilibili.com/video/BV1sr421j7w4/?spm_id_from333.999.0.0 资源包含可视化的西红柿成熟度检测系统&#xff0c;基于最新的YOLOv8训练的西红柿成熟度检测模型&#xff0c;和基于PyQt5制作的可视化西红柿成熟度检测系统&#xff0c;包含登陆页面、注册页面和检测页…

作者头像 李华
网站建设 2026/1/8 15:13:34

当AI开始“说人话“:微软VibeVoice如何让机器300毫秒内开口

你有没有想过&#xff0c;为什么Siri、小爱同学们总要"思考"一会儿才开口&#xff1f;而人类对话时&#xff0c;几乎是无缝衔接的。今天&#xff0c;我们要聊的这个项目&#xff0c;正在改变这一切。 一、从"哑巴AI"到"话痨机器人"的进化史 还记…

作者头像 李华
网站建设 2026/1/18 7:28:07

汇编语言全接触-26.启动画面

上一章我们学习了位图的使用.在这一章我们要用上帝赋予我们的创造力来融会贯通上一章我们学到的知识.那就是研究如何用位图来创建启动画面. 你可以在这里下载示范: the example. 理论首先,我们先要搞清楚什么是启动画面.举个简单的例子:我们启动某些作的专业一点的程序时(比如N…

作者头像 李华