跳转至

二:Transformer 与 Decoding

来源:http://mp.weixin.qq.com/s?__biz=MzYyNTk3Njg1NA==&mid=2247483735&idx=1&sn=a8f760b339df8068351578b4e7abefec&chksm=f01eb22ec7693b38f72c04f4199854a8492d1c6a4aa1fd2f6f69712d62c15b75e167af54421a#rd

1. 学习定位

第一天已经学习了 self-attention 的核心原理。第二天要把 self-attention 放回完整 Transformer 架构中,理解输入如何变成 embedding,encoder 如何做双向上下文建模,decoder 如何做自回归生成,以及语言模型推理时如何从 logits 变成下一个 token。 今天的知识分成两条主线: - Transformer 结构线:Embedding -> Encoder -> Decoder -> 输出 logits。

  • Decoding 策略线:logits -> 概率分布 -> temperature 调整 -> top-k/top-p 截断 -> 采样。

面试中,这一天的内容经常以这些角度被追问: - Transformer encoder 和 decoder 的结构差异。

  • 为什么 encoder 可以双向看,decoder 必须 masked self-attention。

  • decoder-only LLM 和原始 encoder-decoder Transformer 的关系。

  • token embedding、position embedding、output embedding/LM head 的关系。

  • 推理时 greedy、sampling、top-k、top-p、temperature 的区别。

  • 为什么 temperature 降低会更确定,升高会更多样。

  • top-k 和 top-p 如何过滤候选 token,各自有什么缺陷。

2. Transformer 总体结构

Transformer 最早被提出为一个 encoder-decoder 架构,用于机器翻译等 sequence-to-sequence 任务。它用 attention 替代 RNN/CNN 的序列递推或局部卷积,使序列内部的任意位置可以直接交互,并且更适合并行训练。 经典 Transformer 可以抽象为:

source tokens
  -> source embedding + position encoding
  -> encoder stack
  -> encoder memory

target tokens shifted right
  -> target embedding + position encoding
  -> decoder stack
       - masked self-attention
       - cross-attention over encoder memory
       - FFN
  -> linear / LM head
  -> logits over vocabulary
其中 encoder 负责把输入序列编码成上下文表示,decoder 负责在已有目标 token 的条件下逐步生成输出序列。 现代大语言模型常见的是 decoder-only Transformer,例如 GPT、LLaMA、Qwen 等。这类模型保留 decoder 的 masked self-attention 和 MLP 堆叠,但通常没有 encoder,也没有 cross-attention。它们直接用前文 token 预测下一个 token。

3. Embedding 层

Transformer 不能直接处理文本字符串。文本首先经过 tokenizer 切分成 token,再映射成 token id。Embedding 层把离散 token id 映射成连续向量。 基本形式:

input_ids: [B, T]
embedding_table: [V, d_model]
token_embeddings = embedding_table[input_ids]
token_embeddings: [B, T, d_model]
其中: - B 是 batch size。

  • T 是序列长度。

  • V 是词表大小。

  • d_model 是模型隐藏维度。

Embedding table 的每一行对应一个 token 的可学习向量。模型训练时,embedding 也会通过反向传播更新。

4. Token Embedding、Position Encoding 与 Segment Embedding

Transformer 的输入表示通常由多种 embedding 或位置机制组成:

input representation = token embedding + position information
在 BERT 这类 encoder-only 模型中,还可能包含 segment/token type embedding:

input representation = token embedding + position embedding + segment embedding
token embedding 表示 token 内容。position encoding/embedding 表示 token 在序列中的位置。segment embedding 用于区分句子 A/B 或不同片段,在现代 decoder-only LLM 中通常不使用。 纯 self-attention 本身没有顺序意识。如果没有位置信息,模型难以区分“我爱你”和“你爱我”这类 token 集合相同但顺序不同的句子。 常见位置机制包括: - sinusoidal positional encoding:原始 Transformer 使用的固定正弦/余弦位置编码。

  • learned absolute position embedding:可学习绝对位置 embedding。

  • RoPE:旋转位置编码,把相对位置信息注入 Q/K。

  • ALiBi:在 attention score 上加入与距离相关的 bias。

第二天重点理解 embedding 和位置编码的职责分工:token embedding 提供内容,位置机制提供顺序。

5. Embedding 与输出 LM Head

语言模型输出层通常把隐藏状态映射回词表维度:

hidden_states: [B, T, d_model]
lm_head: [d_model, V]
logits = hidden_states @ lm_head
logits: [B, T, V]
logits[b, t, :] 表示样本 b 在位置 t 对词表中每个 token 的未归一化分数。 很多语言模型会使用 weight tying,即输入 embedding table 和输出 LM head 共享权重:

lm_head.weight = embedding_table.weight
这样可以减少参数量,并让输入 token 表示和输出 token 分类空间保持一致。weight tying 不是必须的,但在语言模型中非常常见。

6. Encoder 结构

img

Transformer encoder 是多个 encoder layer 的堆叠。每个 encoder layer 通常包含:

Self-Attention
Residual Connection
LayerNorm
Feed-Forward Network
Residual Connection
LayerNorm
现在实现常用 pre-norm 变体:

x = x + SelfAttention(Norm(x))
x = x + MLP(Norm(x))
encoder 的 self-attention 通常是双向的。也就是说,位置 i 可以看到同一输入序列中的所有有效 token。对于理解类任务,这种双向上下文是合理的,因为任务目标允许使用完整输入。 encoder 输出可以看作输入序列的上下文表示:

encoder_input:  [B, S, d_model]
encoder_output: [B, S, d_model]
其中 S 是 source sequence length。 典型 encoder-only 模型包括 BERT、RoBERTa 等,常用于分类、匹配、检索、抽取、序列标注等理解任务。

7. Encoder Layer 的内部模块

encoder layer 的两个核心子层是 multi-head self-attention 和 position-wise feed-forward network。 multi-head self-attention 负责 token 间信息交互。它让每个位置根据内容相关性从其他位置读取信息。 feed-forward network 负责对每个位置独立做非线性变换。原始 Transformer FFN 形式为:

FFN(x) = max(0, xW1 + b1)W2 + b2
现代 LLM 常把 ReLU 替换成 GELU、SiLU 或 SwiGLU 等激活,并扩大中间维度。 Residual connection 保留原始信息并改善梯度流动。LayerNorm/RMSNorm 稳定训练。Dropout 在原始 Transformer 中用于正则化。 encoder 的整体效果是:每一层先做跨 token 信息混合,再做逐 token 非线性变换;堆叠多层后,每个位置获得更深层的上下文表示。

8. Decoder 结构

img

Transformer decoder 也由多个 decoder layer 堆叠。原始 encoder-decoder Transformer 的 decoder layer 通常包含三类子层:

Masked Self-Attention
Cross-Attention
Feed-Forward Network
masked self-attention 让目标序列内部已经生成的 token 互相交互,但不能看到未来 token。cross-attention 让 decoder 当前状态读取 encoder 输出的 source memory。FFN 对每个位置做非线性变换。 原始机器翻译场景中: - encoder 输入源语言句子。

  • decoder 输入右移后的目标语言 token。

  • decoder 每个位置预测目标语言的下一个 token。

decoder 输出经过线性层得到词表 logits。

9. Masked Self-Attention

decoder 的 self-attention 必须使用 causal mask。对于长度为 T 的目标序列,第 i 个位置只能关注 0..i 的位置,不能关注未来位置。 causal mask 形状示例:

      k1 k2 k3 k4 k5
q1    1  0  0  0  0
q2    1  1  0  0  0
q3    1  1  1  0  0
q4    1  1  1  1  0
q5    1  1  1  1  1
不加 causal mask 会造成训练时信息泄漏。模型可以直接看到未来答案,训练 loss 会虚低,但生成时未来 token 不存在,推理效果会明显恶化。 训练时虽然使用 causal mask,但整段序列仍可以并行计算。mask 只是屏蔽 attention score 中的未来位置,不要求像 RNN 一样逐 token 递推训练。

10. Cross-Attention

cross-attention 出现在 encoder-decoder Transformer 的 decoder 中。它的 Q 来自 decoder 当前隐藏状态,K/V 来自 encoder 输出。 形式为:

Q = decoder_hidden W_Q
K = encoder_output W_K
V = encoder_output W_V
decoder 通过 cross-attention 在生成目标 token 时读取源序列信息。机器翻译中,decoder 生成每个目标词时可以关注源语言句子的相关部分。 在 decoder-only LLM 中通常没有 cross-attention。模型把 prompt 和待生成文本放在同一序列中,用 masked self-attention 建模上下文。

11. Encoder、Decoder、Decoder-Only 的区别

三类结构可以这样区分:

Encoder-only:
  双向 self-attention
  适合理解任务
  例:BERT

Encoder-decoder:
  encoder 双向编码 source
  decoder masked self-attention + cross-attention
  适合 seq2seq 任务
  例:原始 Transformer、T5、BART

Decoder-only:
  masked self-attention
  自回归 next token prediction
  适合开放式生成和通用 LLM
  例:GPT、LLaMA、Qwen
面试中需要明确:现代 ChatGPT 类模型通常不是原始完整 encoder-decoder Transformer,而是 decoder-only Transformer 或其变体。

12. Training 与 Inference 的差异

训练 decoder-only LM 时,输入是一整段 token:

input:  x1 x2 x3 x4
target: x2 x3 x4 x5
模型一次性计算所有位置的 logits,并用 causal mask 保证每个位置不能看未来。 推理时,模型逐步生成:

prompt -> logits for next token -> choose token -> append -> repeat
每一步只使用当前上下文预测下一个 token。为了避免重复计算历史 token 的 K/V,推理系统通常使用 KV cache。第二天重点在 decoding 策略,KV cache 后续系统课再深入。

13. Logits、Softmax 与下一个 Token 分布

语言模型最后一层输出 logits:

logits: [B, T, V]
生成时通常只取最后一个位置:

next_token_logits = logits[:, -1, :]
再通过 softmax 得到词表概率分布:

p_i = exp(logit_i) / sum_j exp(logit_j)
decoding 策略就是决定如何从这个分布中选出下一个 token。不同策略会影响输出的确定性、多样性、重复率、稳定性和创造性。 常见策略包括: - greedy search:每步选概率最高的 token。

  • beam search:维护多个候选序列。

  • multinomial sampling:按概率分布随机采样。

  • top-k sampling:只从概率最高的 k 个 token 中采样。

  • top-p/nucleus sampling:只从累计概率达到 p 的最小候选集合中采样。

  • temperature scaling:改变概率分布的尖锐程度。

今天重点是 top-k、top-p 和 temperature。

14. Temperature

temperature 用来调整 logits 的尺度。公式为:

p_i = softmax(logit_i / T)
其中 T 是 temperature,不要和序列长度混淆。 temperature 的效果: - T = 1:保持原始分布。

  • T < 1:分布更尖锐,高概率 token 更突出,输出更保守、更确定。

  • T > 1:分布更平坦,低概率 token 更有机会被采样,输出更多样但更容易跑偏。

  • T -> 0:趋近 greedy decoding。

示例 logits:

token A: 5
token B: 4
token C: 1
当 temperature 降低时,A 与 B/C 的概率差距会变大;当 temperature 升高时,B/C 的相对机会会增加。 temperature 只改变分布形状,不直接删除候选 token。它通常与 top-k 或 top-p 组合使用。

15. Top-k Sampling

top-k sampling 的流程是: - 根据 logits 或概率选出分数最高的 k 个 token。

  • 把其他 token 的概率设为 0,或 logits 设为 -inf

  • 对剩下的 k 个 token 重新归一化。

  • 从归一化后的分布中随机采样。

形式化地说,top-k 把候选集合限制为:

S_k = top k tokens by probability
然后从 S_k 中采样。 top-k 的优点是简单、有效,可以过滤掉大量低概率噪声 token。缺点是 k 是固定的,无法根据当前分布形状动态调整。 如果当前分布很尖锐,k=50 可能包含很多不必要 token。如果当前分布很平坦,k=10 可能过滤掉合理候选,损失多样性。

16. Top-p / Nucleus Sampling

top-p sampling 又叫 nucleus sampling。它不是固定保留 k 个 token,而是保留累计概率达到阈值 p 的最小 token 集合。 流程: - 按概率从高到低排序 token。

  • 从最高概率 token 开始累加概率。

  • 找到累计概率达到 p 的最小集合。

  • 把集合外 token 概率设为 0。

  • 对集合内 token 重新归一化并采样。

候选集合:

S_p = smallest set such that sum_{i in S_p} p_i &gt;= p
top-p 的优点是候选集合大小会随分布形状动态变化: - 当分布很尖锐时,只保留少量 token。

  • 当分布较平坦时,保留更多 token。

常见参数如 top_p=0.9top_p=0.95。top-p 也不是越大越好。top_p 太高会引入更多低质量候选,太低会使输出过于保守。

17. Top-k 与 Top-p 的组合

实际生成中,top-k、top-p、temperature 常组合使用。一个典型流程是:

logits
-&gt; temperature scaling
-&gt; top-k filter
-&gt; top-p filter
-&gt; softmax / renormalize
-&gt; sample next token
不同框架的具体顺序可能略有差异,但核心思想是先调整分布,再过滤候选,再采样。 组合使用时: - temperature 控制分布尖锐程度。

  • top-k 设置候选数量上限。

  • top-p 根据累计概率动态控制候选范围。

例如 temperature=0.7, top_p=0.9 通常会比纯随机采样更稳定,也比 greedy 更有多样性。具体参数要根据任务调试。

18. Decoding 策略与任务适配

不同任务适合不同 decoding 策略。 确定性任务更适合低温度、greedy 或较保守的 sampling: - 信息抽取

  • 分类标签生成

  • JSON 格式输出

  • 代码补全中的严格片段

  • 数学推理的最终答案格式

开放式生成更适合适度 sampling: - 创意写作

  • 头脑风暴

  • 对话回复

  • 多样化改写

需要注意,decoding 不能从根本上修复模型能力问题。它只能改变从概率分布中选择 token 的方式。模型不知道答案、prompt 不清晰、上下文不足、训练偏差严重时,调 top-k/top-p/temperature 的收益有限。

19. 常见实现参考

下面是一个简化的 top-k/top-p/temperature sampling 伪代码:

import torch
import torch.nn.functional as F

def sample_next_token(logits, temperature=1.0, top_k=None, top_p=None):
&nbsp; &nbsp; # logits: [V]
&nbsp; &nbsp; if temperature &lt;= 0:
&nbsp; &nbsp; &nbsp; &nbsp; return torch.argmax(logits)

&nbsp; &nbsp; logits = logits / temperature

&nbsp; &nbsp; if top_k is not None and top_k &gt; 0:
&nbsp; &nbsp; &nbsp; &nbsp; values, _ = torch.topk(logits, k=top_k)
&nbsp; &nbsp; &nbsp; &nbsp; threshold = values[-1]
&nbsp; &nbsp; &nbsp; &nbsp; logits = torch.where(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logits &lt; threshold,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; torch.full_like(logits, float("-inf")),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logits,
&nbsp; &nbsp; &nbsp; &nbsp; )

&nbsp; &nbsp; if top_p is not None and 0 &lt; top_p &lt; 1:
&nbsp; &nbsp; &nbsp; &nbsp; sorted_logits, sorted_indices = torch.sort(logits, descending=True)
&nbsp; &nbsp; &nbsp; &nbsp; sorted_probs = F.softmax(sorted_logits, dim=-1)
&nbsp; &nbsp; &nbsp; &nbsp; cumulative_probs = torch.cumsum(sorted_probs, dim=-1)

&nbsp; &nbsp; &nbsp; &nbsp; remove = cumulative_probs &gt; top_p
&nbsp; &nbsp; &nbsp; &nbsp; remove[1:] = remove[:-1].clone()
&nbsp; &nbsp; &nbsp; &nbsp; remove[0] = False

&nbsp; &nbsp; &nbsp; &nbsp; sorted_logits[remove] = float("-inf")
&nbsp; &nbsp; &nbsp; &nbsp; logits = torch.full_like(logits, float("-inf"))
&nbsp; &nbsp; &nbsp; &nbsp; logits.scatter_(0, sorted_indices, sorted_logits)

&nbsp; &nbsp; probs = F.softmax(logits, dim=-1)
&nbsp; &nbsp; return torch.multinomial(probs, num_samples=1)
工程中通常直接使用成熟框架的 generate 接口,但面试中能写出这个流程可以说明理解了 decoding 的本质。

20. 常见易错点

embedding 相关易错点: - 把 token embedding 和 one-hot 编码混为一谈。one-hot 是离散索引表示,embedding 是可学习连续向量。

  • 忽略位置编码,误以为 self-attention 天然知道顺序。

  • 混淆 input embedding 和 output LM head。

  • 不理解 weight tying 的作用。

encoder/decoder 相关易错点: - 认为所有 Transformer 都是 encoder-decoder。现代 LLM 多数是 decoder-only。

  • 认为 decoder 只能用于翻译。decoder-only 已经成为通用生成模型主流架构。

  • 混淆 masked self-attention 和 cross-attention。

  • 不知道 decoder 训练时可以并行,推理时必须逐步生成。

decoding 相关易错点: - 把 top-k 当成“选 top-k 中最大的 token”,实际 top-k sampling 是从 top-k 候选中按概率采样。

  • 把 top-p 理解成“保留概率大于 p 的 token”,实际是保留累计概率达到 p 的最小集合。

  • 认为 temperature 会删除 token,实际它只缩放 logits。

  • 认为 temperature 越高越好,实际过高会增加幻觉和无关输出。

  • 忘记过滤后要重新归一化概率。

21. 知识闭环总结

第二天的知识闭环可以压缩为:

文本先经 tokenizer 得到 token id。
token id 经 embedding table 变成连续向量。
位置机制注入顺序信息。
encoder 用双向 self-attention 建模输入序列。
decoder 用 masked self-attention 保证自回归因果约束。
encoder-decoder decoder 还通过 cross-attention 读取 encoder 输出。
decoder-only LLM 省略 encoder 和 cross-attention,直接做 next token prediction。
模型输出 logits 后,decoding 策略决定如何选择下一个 token。
temperature 调整分布尖锐程度。
top-k 固定候选数量,top-p 按累计概率动态确定候选集合。

22. 参考资料

  • Attention Is All You Need: https://arxiv.org/abs/1706.03762

  • Hugging Face Transformers Generation Strategies: https://huggingface.co/docs/transformers/main/en/generation_strategies

  • Hugging Face Blog - How to generate text: https://huggingface.co/blog/how-to-generate

  • The Curious Case of Neural Text Degeneration: https://arxiv.org/abs/1904.09751

  • PyTorch Transformer API: https://docs.pytorch.org/docs/2.12/generated/torch.nn.Transformer.html

  • 截图推荐:李宏毅老师讲解 Transformer: https://www.bilibili.com/video/BV1L142187HH

  • 截图推荐:讲解的很清楚的大模型解码: https://www.zhihu.com/tardis/zm/art/647813179

  • 截图推荐:有图有代码的大模型解码: https://blog.csdn.net/Mike0010/article/details/13832616

            预览时标签不可点
    

    <div class="