返回首页

Transformer 内部结构:从输入到输出拆解 LLM 四大核心组件

把 LLM 看成黑盒太简单了 —— 拆解分词器、嵌入层、堆叠的 Transformer 块、语言建模头四个模块,讲清楚一句"我今天很"是怎么变成"开心"的。

2 约 6 分钟 · 5910 字 AI

整个 NLP 的发展中间还经历很多重要的阶段,例如:

  1. 神经概率语言模型
  2. 卷积神经网络模型
  3. 循环神经网络以及长短期记忆网络

再到目前最为流行的 Transformer 架构。

输入和输出

将 LLM 看作是一个黑盒,输入称之为提示词(prompt):

LLM 黑盒输入提示词示意图

在使用模型的时候,模型并不是一次性生成所有的文本,而是一次生成一个词元,如下图所示:

LLM 一次生成一个词元

模型在生成每一个新词元时,都会基于当前的输入序列进行一次 前向传播(Forward Propagation)

🙋 什么是前向传播?

所谓前向传播,是指在神经网络中,从输入层开始,数据依次通过每一层神经元的计算,最终产生输出的过程。

具体步骤:

  1. 输入嵌入
  2. 多个神经网络层处理
  3. 输出一个分布,即所有词元上的概率
  4. 选一个词生成出来

新生成的词元会被追加到输入序列的末尾,作为下一步生成的提示词上下文,从而逐步影响整个输出。

新生成的词元会被追加到输入序列末尾

在机器学习中,有一个专门的词用来描述这种"使用早期预测来进行后续预测"的模型,称之为 自回归模型(Autoregressive Model)

Transformer 模型就是一个自回归模型。

LLM 内部结构

整体来讲分成四大块:

LLM 四大块:分词器 / 嵌入层 / 堆叠的 Transformer 块 / 语言建模头

  1. 分词器
  2. 嵌入层
  3. 堆叠的 Transformer 块
  4. 语言建模头

分词器

模型的第一步是将自然语言输入送入分词器(Tokenizer),将其转换为词元 ID(token IDs)。例如:

"我今天很开心"

分词:

['我', '今天', '很', '开', '心']

映射为词表中的 ID:

[1, 354, 2764, 77, 199]

嵌入层

在分词器将文本转换为词元 ID 之后,这些整数 ID 本身并不能直接用于神经网络计算。此时,需要通过嵌入层将每个 ID 映射为一个向量,形成模型的输入表示。

例如前面得到的词元 ID 列表:

[1, 354, 2764, 77, 199]

通过嵌入层处理后,得到的嵌入向量:

[
  [0.12, -0.87, ...,  0.34],   # 对应 token 1
  [0.02,  0.45, ..., -0.11],   # 对应 token 354
  ...
  [0.76, -0.01, ...,  0.08]    # 对应 token 199
]

每个词元 ID 都会被映射为一个固定维度的向量(例如 768 维或 4096 维),这些向量是模型可学习的参数,在训练过程中会被不断优化。

堆叠的 Transformer 块

Stacked Transformer Blocks,中文译作"堆叠的 Transformer 块",这些 Transformer 块是 LLM 的核心模块,也是模型理解上下文、捕捉语言结构和语义关系的关键所在。

每个 Transformer 块内部包含两个主要子模块:

1. 自注意力机制(Self-Attention)

让每一个词元可以"看见"它前面的所有词元,从而理解上下文。例如:

"我  今天  很  开心"
 ↑    ↑   ↑   ↑
每个词元都能关注到前面的词元(因自回归模型只看左边)
  • 比如模型在预测"开心"时,会去关注"我"、"今天"、"很"这些词,理解语义关系。
  • 注意力机制会为不同词元分配不同的权重。

2. 前馈网络(Feed-Forward Network)

对每个位置上的词元向量单独做非线性变换,提高模型表达能力。

🙋 为什么称之为"堆叠"呢?

因为 Transformer 块并非一层,而是有多层:

Transformer块1 → Transformer块2 → Transformer块3 → Transformer块4 → ...

每一层都会接收上一层的输出,并进一步处理。层数越多,大模型就越能够捕捉高层次、复杂的语言结构,也就是说,对输入文本理解得越准确。

下表是主流大模型的层数对比:

模型名称 参数规模 Transformer 层数 备注
GPT-2 (small) 117M 12 OpenAI
GPT-3 175B 96 OpenAI
GPT-4(推测) ~200B+ 96–128(估计) 可能为 MoE 架构
Claude 2 ~100B+ ~80–100(推测) Anthropic,未公开完整细节
Claude 3 Opus 未知 ~128(推测) 极强编码能力,多模态支持
PaLM 2 340B 120 Google
Gemini 1.5 Pro 推测 >100B 未知 多模态,长上下文(>1M tokens)
LLaMA 2 (7B) 7B 32 Meta,小模型中非常高效
LLaMA 2 (70B) 70B 80 Meta
Mistral (7B) 7B 32 Dense 模型,训练非常高效
Mixtral (MoE) 12.9B act. 32 激活 2/8 experts(MoE 架构)

语言建模头

经过多层 Transformer 块处理后,我们会得到每一个位置上的一个高维向量表示。这些向量已经融合了上下文语义信息,接下来需要通过语言建模头(Language Modeling Head)将这些向量转换为我们最终关心的输出:预测下一个词元

在自回归生成中,只用最后一个词元位置上的向量来预测下一个词:

[
  [0.12, -0.87, ...,  0.34],   ← 代表 "我"
  [0.45,  0.10, ..., -0.77],   ← 代表 "今天"
  [-0.22, 0.63, ...,  1.02]    ← 代表 "很"  ✅ 取这个
]

🙋 为什么只用最后一个词?

Transformer 是一个上下文感知的结构。当我们输入"我今天很",并经过多层 Transformer 处理后,虽然只取了最后一个词"很"对应的向量,但这个向量已经不是孤立的"很"了 —— 它已经通过自注意力机制,融合了前面所有词元的信息,即"我"、"今天"、"很"的上下文。

工作流程

假设有一个词表(语料库)大小为 V = 50,000,Transformer 输出的每个向量是 d = 768 维,那么语言建模头就是一个维度为:

[768 × 50000]

的线性变换矩阵,这个矩阵是语言建模头的核心参数,也是参数量最多的一层之一。这里我们把这个矩阵命名为 W

接下来下一步是针对词表里面的每一个词元(50000)进行打分,大致的计算公式如下:

logits(最终的得分) = z(最后一个词元的向量) · W(线性矩阵)
  • z:Transformer 所输出的最后一个词元的嵌入向量,长度为 768
  • W:上面所提到的线性变换矩阵

经过计算后,会得到一个 50000 维的向量数组。这个 50000 维的向量数组里面的每一个值就是词表中词元的得分。

这个分数仅仅是一个未归一化的分数 —— 所谓未归一化,就是指这些分数可以是任何实数(正的、负的、不限制范围),它们还不是概率,还不能直接表示"可能性"。例如假设我们的词表只有 5 个词,这里就能得到词表中每个词元的分数:

词元 logits 值
开心 4.2
2.7
1.5
昨天 -1.2
小狗 -3.5

最后一步是经过 softmax 转换,目的是将分数转换为概率分布,计算公式如下:

                   exp(logits_i)
softmax(logits_i) = ─────────────────
                   Σⱼ exp(logits_j)

整个 softmax 接收上一步拿到的 logits,然后做了两件事:

  1. 先对每个值取指数(确保变成正数)
  2. 再除以总和(确保总和为 1)

最终,语言建模头工作流程大致如下:

z = Transformer_output[-1]  // 取最后一个向量
logits = z · W              // [0.1, 0.3, -1.5, 2.6, ...]
probs = softmax(logits)     // [0.01, 0.02, 0.00001, 0.85, ...]

完整流程

假设当前输入的是一句未完成的话:

我今天很

目标是让大语言模型预测下一个最可能的词元。整体流程:

1. 分词器处理

["我", "今天", "很"]

[1, 354, 2764]

2. 嵌入层处理

每个词元 ID 会被映射为高维度向量:

"我"     → [0.12, -0.87, ..., 0.34]
"今天"   → [-0.11, 0.45, ..., 0.90]
"很"     → [0.20, 0.14, ..., -0.06]

嵌入向量会形成一个二维数组,维度是 [3, 768]

3. Transformer 块处理

经过多层 Transformer 块处理之后,得到的仍然是一个维度为 [3, 768] 的向量数组。我们只取最后一个:

z = [0.12, -0.45, ..., 0.33]   ← 长度为 768

虽然这个 z 只是"很"这个词元所对应的向量,但是已经融入了前面所有词元的语义信息。

4. 语言建模头计算 logits

假设语料库里面的词元数量为 50000:

logits = z × W   →   得到一个 [1 × 50000] 的向量

logits = [0.9, -1.3, 2.1, ..., 5.7]   ← 长度为 50000

5. softmax 归一化为概率

{
  开心: 0.61,
  累:   0.12,
  忙:   0.08,
  郁闷: 0.04,
  美丽: 0.02,
  ...
}

最终模型挑出概率最高的词元(如"开心")作为下一个输出,追加到输入末尾,然后重复整个流程,直到生成结束符或达到最大长度 —— 这就是自回归模型一次生成一个词的完整闭环。


-EOF-