深入Transformer架构二:Encoder-Only 推理流程深度解析

123 阅读5分钟

Encoder-Only 推理流程

Encoder-only(如 BERT、RoBERTa、ELECTRA)与 Decoder-only 最大不同是:

  • 没有自回归 Decode 阶段
  • 整个输入序列一次并行计算
  • 双向注意力(全局可见)
  • CLS 位置经过训练自然演化成句子级别向量
  • 普通 Token 位置经过训练自然演化成上下文词义向量

本文将从真实 Transformer 内部机制出发,完整拆解 Encoder-only 的推理全过程


1. 输入与基础表示

1.1 输入序列设定

示例输入 token 序列:

[CLS], T1, T2, T3, T4

目标任务可能包括:

  • 分类任务(使用 CLS)
  • Masked LM 填空任务(预测被 [MASK] 的 token)
  • 句子对任务(使用 segment embedding)

1.2 Embedding 组成

每个 token 都会先映射为:

h_i_pre = TokenEmb(i) + PosEmb(i) + SegmentEmb(i)

例如:

h_cls_pre = Emb(CLS) + Pos1
h1_pre     = Emb(T1)  + Pos2
h2_pre     = Emb(T2)  + Pos3
...

此时每个 token 之间没有“信息交流”,只是位置 + 词义的静态叠加。


2. 编码器总体架构说明

2.1 完全并行,无 Decode

所有 token 在 每一层同时 进行 Transformer 处理:

Layer1: 并行处理 [CLS, T1, T2, T3, T4]
Layer2: 并行处理 [CLS, T1, T2, T3, T4]
...

没有类似 GPT 的“逐 token”增长过程。

2.2 双向注意力 Mask

注意力 Mask 是全开放的:

       CLS  T1  T2  T3  T4
CLS    ✔    ✔   ✔   ✔   ✔
T1     ✔    ✔   ✔   ✔   ✔
T2     ✔    ✔   ✔   ✔   ✔
T3     ✔    ✔   ✔   ✔   ✔
T4     ✔    ✔   ✔   ✔   ✔

每个 token 都能看见全序列。
CLS 也能看到所有 token。

2.3 多层堆叠的整体计算公式

对每一层:

h_i^{l+1} = LayerNorm( h_i^l + MHA(h_i^l) + FFN(h_i^l) )

多个相同结构重复堆叠形成深度编码器。


3. 单层 Transformer 的内部计算(完全具象)

第 1 层 的 CLS 与 T1 为例说明。

3.1 Step 1:线性投影生成 Q/K/V

Q_cls = h_cls_pre × W_Q
K_cls = h_cls_pre × W_K
V_cls = h_cls_pre × W_V

Q1 = h1_pre × W_Q
K1 = h1_pre × W_K
V1 = h1_pre × W_V

所有 token 都会生成自己的 Q/K/V。

3.2 Step 2:注意力得分计算(以 CLS 为例)

CLS 查询全体 token:

score(CLS→i) = Q_cls · K_i

得到:

αcls = softmax([Q_cls·K_cls, Q_cls·K1, Q_cls·K2, Q_cls·K3, Q_cls·K4])

3.3 Step 3:加权求和得到上下文融合向量

context_cls = Σ αcls_i * V_i

这就是第一层的“全局信息初步聚合”。

3.4 Step 4:FFN 非线性变换

ffn_cls = FFN(context_cls)

结构通常是:

Linear → GELU → Linear

3.5 Step 5:残差连接 + LayerNorm

完整更新:

h_cls_1 = LayerNorm(h_cls_pre + context_cls + ffn_cls)

同理:

h1_1 = LayerNorm(h1_pre + context_1 + ffn_1)

所有 token 都被更新为新的隐藏状态,为下一层输入。


4. 逐 Token 逐层的信息流

4.1 CLS 的注意力路径(为何成为“句子向量”)

每一层 CLS 都会:

访问所有 token → 聚合 → 再访问所有 token → 再聚合 → ...

经过 N 层后:

CLS_final = 全序列语义的深度压缩向量

关键不是结构特殊,而是:

分类任务通过反向传播要求 CLS 输出最能表示句子整体语义,
所以模型内部会“自发”让 CLS 学会汇聚全局信息。

4.2 普通 Token 的路径(为何代表该词的上下文含义)

Ti 的注意力是:

Ti → attend to all token → 得到属于自己的上下文语义向量

多层后:

Ti_final = 该词在上下文下的语义表示(masked LM 使用)

4.3 为什么二者自然分化为不同语义?

因为训练目标不同:

  • 分类任务损失来自 CLS
  • MLM 损失来自被 MASK 的位置

模型会自动学习:

  • CLS 负责整个句子的含义
  • 被 MASK 的位置负责还原词义
  • 其它 token 保持上下文语义稳定

5. 多层堆叠后的语义形成机制(极其关键)

每一层的功能不是固定编码,而是训练后自然演化出来的角色。

5.1 第 1 层:局部词面语义

类似词袋 + 局部融合:

  • CLS 初步聚合浅层词义
  • 每个 Ti 捕捉临近词的关系

5.2 第 2 层:句法结构提炼

模型开始学习:

  • 主谓宾关系
  • 修饰结构
  • 依存关系

5.3 第 3 层:长距离依存建模

注意力开始跨越句子:

  • 主语与远处谓词
  • 所有代词的指代关系

5.4 第 4~N 层:深层语义抽象

最终形成:

CLS_final = 整句语义
Ti_final   = 每个词的上下文语义

6. 不同任务的推理路径(非常重要)

6.1 Masked LM(位置级任务)

6.1.1 获得 MASK 位置向量

假设 T3 被 MASK:

h3_final = Transformer_Layers([CLS,T1,T2,MASK,T4])

6.1.2 使用 LM Head 预测词表概率

logits = h3_final × W_vocab^T
P(token) = softmax(logits)

得出最可能的词。


6.2 文本分类(句子级任务)

6.2.1 获得 CLS_final

CLS_final = h_cls_N  # N层后的CLS

6.2.2 分类头

logits = CLS_final × W_cls + b
P(label) = softmax(logits)

分类完全依赖 CLS_final 的全局语义。


7. Encoder-Only 信息流全景图(总览图)

Input → Embedding → Layer1 → Layer2 → ... → LayerN
                                ↓
                             CLS_final ------------------→ Classification Head
                                ↓
                            Ti_final --------------------→ MLM Head

注意:

  • 没有 Decoder、没有 KV Cache、没有自回归过程
  • 所有 token 并行更新,直到达到深层抽象

8. 最终总结(核心要点)

  1. Encoder-only 是纯并行计算,没有 decode 过程。
  2. 注意力是全局双向的,每个 token 看见整句。
  3. CLS 通过训练自动演化为“句子语义压缩向量”。
  4. 普通 token 通过训练演化为“上下文词义向量”。
  5. Masked LM 使用被 MASK 的位置向量进行词预测。
  6. 分类任务使用 CLS_final 经过分类头输出结果。
  7. 多层堆叠从浅层词义 → 句法结构 → 长依存 → 深语义。