深入理解 Transformer:Transformer 究竟是什么?

目录

  • 一、先从一张经典结构图开始
  • [二、Transformer 不是一个模块,而是一组模块的组合](#二、Transformer 不是一个模块,而是一组模块的组合)
  • [三、什么是 Encoder?](#三、什么是 Encoder?)
  • [四、Encoder Block:Transformer 的基本积木](#四、Encoder Block:Transformer 的基本积木)
  • [五、第一部分:Multi-Head Self-Attention](#五、第一部分:Multi-Head Self-Attention)
  • [六、第二部分:为什么 Attention 后面还需要 Add?](#六、第二部分:为什么 Attention 后面还需要 Add?)
  • [七、第三部分:Norm 又是什么?](#七、第三部分:Norm 又是什么?)
  • [八、第四部分:Attention 之后,为什么还需要 FFN?](#八、第四部分:Attention 之后,为什么还需要 FFN?)
  • [九、现在,我们终于可以看懂 Encoder Block 了](#九、现在,我们终于可以看懂 Encoder Block 了)
  • [十、Encoder 到底输出了什么?](#十、Encoder 到底输出了什么?)
  • [十一、接下来轮到 Decoder](#十一、接下来轮到 Decoder)
  • [十二、Decoder Block 为什么有两个 Attention?](#十二、Decoder Block 为什么有两个 Attention?)
  • [十三、Encoder 和 Decoder 到底有什么区别?](#十三、Encoder 和 Decoder 到底有什么区别?)
  • [十四、Transformer 到底是如何完成一次机器翻译的?](#十四、Transformer 到底是如何完成一次机器翻译的?)
  • [十五、等等,还有一个重要问题:Transformer 怎么知道顺序?](#十五、等等,还有一个重要问题:Transformer 怎么知道顺序?)
  • [十六、Transformer 的完整数据流](#十六、Transformer 的完整数据流)
  • [十七、一个容易产生的误解:现在的 GPT 还是完整 Transformer 吗?](#十七、一个容易产生的误解:现在的 GPT 还是完整 Transformer 吗?)
  • [十八、现在,我们对 Transformer 应该有什么整体认识?](#十八、现在,我们对 Transformer 应该有什么整体认识?)
  • 十九、小结
  • [下一篇:Self-Attention 到底是什么?](#下一篇:Self-Attention 到底是什么?)

《深入理解 Transformer:Transformer 究竟是什么?》

前言

在上一篇文章中,我们暂时没有急着讨论 QKV,也没有直接推导 Attention 的计算公式。

我们先回答了一个更基础的问题:

为什么需要 Transformer?

在 Transformer 出现之前,处理文本等序列数据的主流方案是 RNN、LSTM 和 GRU。

它们都有一个非常明显的共同特点:

text 复制代码
x₁ → x₂ → x₃ → x₄ → ···

也就是说,模型通常需要按照序列的顺序,一步一步地处理数据。

这种方式虽然符合人类阅读文本的直觉,但也带来了两个非常关键的问题:

  1. 计算过程存在顺序依赖,难以充分利用并行计算能力;
  2. 距离较远的信息需要经过多次传递,长距离依赖难以处理。

随后,Attention 的出现改变了这种思路。

我们不再要求信息必须:

text 复制代码
Token 1
   ↓
Token 2
   ↓
Token 3
   ↓
Token 4

一级一级地传递。

而是可以让当前信息直接去关注序列中的其他信息:

text 复制代码
Token 1 ─────────────┐
Token 2 ─────────────┤
Token 3 ─────────────┼──→ 当前 Token
Token 4 ─────────────┤
Token 5 ─────────────┘

于是,一个新的问题出现了:

既然 Attention 已经这么强大,那么 Transformer 到底是什么?

很多刚开始学习 Transformer 的人都会有一种错觉:

Transformer 不就是 Attention 吗?

这个理解不能说完全错误,但显然还不够完整。

Attention 是 Transformer 最核心的思想之一,但一个完整的 Transformer 并不是只有 Attention。

在原始的 Transformer 中,我们还会看到:

text 复制代码
Encoder
Decoder
Multi-Head Attention
Feed Forward Network
Residual Connection
Layer Normalization
Positional Encoding

这些模块共同组成了 Transformer。

因此,这一篇文章我们的目标并不是立刻钻进某一个公式,而是先完成一件更加重要的事情:

先把 Transformer 的整体结构看明白。

只有先知道:

text 复制代码
Transformer 由哪些部分组成?
每一部分负责什么?
数据在模型中如何流动?

后面学习 Self-Attention、Multi-Head Attention 等内容时,才不会只看到一堆零散的公式。


一、先从一张经典结构图开始

Transformer 最早由论文《Attention Is All You Need》提出。

原始 Transformer 是一个典型的:

Encoder-Decoder 架构。

我们可以先把它最外层的结构理解成:

text 复制代码
输入序列
    ↓
 Encoder
    ↓
中间表示
    ↓
 Decoder
    ↓
输出序列

例如机器翻译:

text 复制代码
I love artificial intelligence.
            ↓
         Encoder
            ↓
      理解输入信息
            ↓
         Decoder
            ↓
我喜欢人工智能。

这里需要注意:

Encoder 和 Decoder 并不是 Transformer 随便划分出来的两个部分,它们承担着不同的职责。

简单来说:

  • Encoder:负责理解输入;
  • Decoder:负责根据已有信息生成输出。

我们可以先把它们理解成:

text 复制代码
                 Transformer

        ┌────────────┴────────────┐
        │                         │
        ↓                         ↓
      Encoder                   Decoder
        │                         │
     理解输入                   生成输出

但是,真实的 Transformer 并不是只有一个 Encoder 和一个 Decoder。

它们内部实际上都由多个相同的 Block 堆叠而成。


下面是 Transformer 最外层的整体架构图:
#mermaid-svg-yfssAKUcSuKFkME0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yfssAKUcSuKFkME0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yfssAKUcSuKFkME0 .error-icon{fill:#552222;}#mermaid-svg-yfssAKUcSuKFkME0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yfssAKUcSuKFkME0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yfssAKUcSuKFkME0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yfssAKUcSuKFkME0 .marker.cross{stroke:#333333;}#mermaid-svg-yfssAKUcSuKFkME0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yfssAKUcSuKFkME0 p{margin:0;}#mermaid-svg-yfssAKUcSuKFkME0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yfssAKUcSuKFkME0 .cluster-label text{fill:#333;}#mermaid-svg-yfssAKUcSuKFkME0 .cluster-label span{color:#333;}#mermaid-svg-yfssAKUcSuKFkME0 .cluster-label span p{background-color:transparent;}#mermaid-svg-yfssAKUcSuKFkME0 .label text,#mermaid-svg-yfssAKUcSuKFkME0 span{fill:#333;color:#333;}#mermaid-svg-yfssAKUcSuKFkME0 .node rect,#mermaid-svg-yfssAKUcSuKFkME0 .node circle,#mermaid-svg-yfssAKUcSuKFkME0 .node ellipse,#mermaid-svg-yfssAKUcSuKFkME0 .node polygon,#mermaid-svg-yfssAKUcSuKFkME0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yfssAKUcSuKFkME0 .rough-node .label text,#mermaid-svg-yfssAKUcSuKFkME0 .node .label text,#mermaid-svg-yfssAKUcSuKFkME0 .image-shape .label,#mermaid-svg-yfssAKUcSuKFkME0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-yfssAKUcSuKFkME0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yfssAKUcSuKFkME0 .rough-node .label,#mermaid-svg-yfssAKUcSuKFkME0 .node .label,#mermaid-svg-yfssAKUcSuKFkME0 .image-shape .label,#mermaid-svg-yfssAKUcSuKFkME0 .icon-shape .label{text-align:center;}#mermaid-svg-yfssAKUcSuKFkME0 .node.clickable{cursor:pointer;}#mermaid-svg-yfssAKUcSuKFkME0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yfssAKUcSuKFkME0 .arrowheadPath{fill:#333333;}#mermaid-svg-yfssAKUcSuKFkME0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yfssAKUcSuKFkME0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yfssAKUcSuKFkME0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yfssAKUcSuKFkME0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yfssAKUcSuKFkME0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yfssAKUcSuKFkME0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yfssAKUcSuKFkME0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yfssAKUcSuKFkME0 .cluster text{fill:#333;}#mermaid-svg-yfssAKUcSuKFkME0 .cluster span{color:#333;}#mermaid-svg-yfssAKUcSuKFkME0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yfssAKUcSuKFkME0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yfssAKUcSuKFkME0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-yfssAKUcSuKFkME0 .icon-shape,#mermaid-svg-yfssAKUcSuKFkME0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yfssAKUcSuKFkME0 .icon-shape p,#mermaid-svg-yfssAKUcSuKFkME0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yfssAKUcSuKFkME0 .icon-shape .label rect,#mermaid-svg-yfssAKUcSuKFkME0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yfssAKUcSuKFkME0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yfssAKUcSuKFkME0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yfssAKUcSuKFkME0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入序列
Encoder
中间表示
Decoder
输出序列

二、Transformer 不是一个模块,而是一组模块的组合

假设我们把 Transformer 看成一栋建筑。

那么:

text 复制代码
Encoder

和:

text 复制代码
Decoder

更像是两栋主要建筑。

而真正组成这两栋建筑的,是一个个重复出现的模块。

原始 Transformer 的结构可以简单表示为:

text 复制代码
Input
  ↓
Embedding
  ↓
Positional Encoding
  ↓
┌─────────────────┐
│  Encoder Block  │
└─────────────────┘
  ↓
┌─────────────────┐
│  Encoder Block  │
└─────────────────┘
  ↓
        ···
  ↓
Encoder Output

Decoder 也是类似的结构:

text 复制代码
Output
  ↓
Embedding
  ↓
Positional Encoding
  ↓
┌─────────────────┐
│  Decoder Block  │
└─────────────────┘
  ↓
┌─────────────────┐
│  Decoder Block  │
└─────────────────┘
  ↓
        ···
  ↓
Linear
  ↓
Softmax
  ↓
预测下一个 Token

所以理解 Transformer 时,实际上可以分成三个层次:

text 复制代码
第一层:整体架构
        ↓
Encoder + Decoder

第二层:Block
        ↓
多个相同模块重复堆叠

第三层:具体组件
        ↓
Attention
FFN
Residual
LayerNorm
...

我们这一篇主要解决前两个层次的问题。

至于最底层的 Attention 是怎么计算的,会在后面的文章中逐步展开。


下面是 Transformer 三个理解层次的 Mermaid 图:
#mermaid-svg-2DAOTt9PxWdA6wru{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2DAOTt9PxWdA6wru .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2DAOTt9PxWdA6wru .error-icon{fill:#552222;}#mermaid-svg-2DAOTt9PxWdA6wru .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2DAOTt9PxWdA6wru .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2DAOTt9PxWdA6wru .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2DAOTt9PxWdA6wru .marker.cross{stroke:#333333;}#mermaid-svg-2DAOTt9PxWdA6wru svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2DAOTt9PxWdA6wru p{margin:0;}#mermaid-svg-2DAOTt9PxWdA6wru .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2DAOTt9PxWdA6wru .cluster-label text{fill:#333;}#mermaid-svg-2DAOTt9PxWdA6wru .cluster-label span{color:#333;}#mermaid-svg-2DAOTt9PxWdA6wru .cluster-label span p{background-color:transparent;}#mermaid-svg-2DAOTt9PxWdA6wru .label text,#mermaid-svg-2DAOTt9PxWdA6wru span{fill:#333;color:#333;}#mermaid-svg-2DAOTt9PxWdA6wru .node rect,#mermaid-svg-2DAOTt9PxWdA6wru .node circle,#mermaid-svg-2DAOTt9PxWdA6wru .node ellipse,#mermaid-svg-2DAOTt9PxWdA6wru .node polygon,#mermaid-svg-2DAOTt9PxWdA6wru .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2DAOTt9PxWdA6wru .rough-node .label text,#mermaid-svg-2DAOTt9PxWdA6wru .node .label text,#mermaid-svg-2DAOTt9PxWdA6wru .image-shape .label,#mermaid-svg-2DAOTt9PxWdA6wru .icon-shape .label{text-anchor:middle;}#mermaid-svg-2DAOTt9PxWdA6wru .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2DAOTt9PxWdA6wru .rough-node .label,#mermaid-svg-2DAOTt9PxWdA6wru .node .label,#mermaid-svg-2DAOTt9PxWdA6wru .image-shape .label,#mermaid-svg-2DAOTt9PxWdA6wru .icon-shape .label{text-align:center;}#mermaid-svg-2DAOTt9PxWdA6wru .node.clickable{cursor:pointer;}#mermaid-svg-2DAOTt9PxWdA6wru .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2DAOTt9PxWdA6wru .arrowheadPath{fill:#333333;}#mermaid-svg-2DAOTt9PxWdA6wru .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2DAOTt9PxWdA6wru .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2DAOTt9PxWdA6wru .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DAOTt9PxWdA6wru .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2DAOTt9PxWdA6wru .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DAOTt9PxWdA6wru .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2DAOTt9PxWdA6wru .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2DAOTt9PxWdA6wru .cluster text{fill:#333;}#mermaid-svg-2DAOTt9PxWdA6wru .cluster span{color:#333;}#mermaid-svg-2DAOTt9PxWdA6wru div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2DAOTt9PxWdA6wru .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2DAOTt9PxWdA6wru rect.text{fill:none;stroke-width:0;}#mermaid-svg-2DAOTt9PxWdA6wru .icon-shape,#mermaid-svg-2DAOTt9PxWdA6wru .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DAOTt9PxWdA6wru .icon-shape p,#mermaid-svg-2DAOTt9PxWdA6wru .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2DAOTt9PxWdA6wru .icon-shape .label rect,#mermaid-svg-2DAOTt9PxWdA6wru .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DAOTt9PxWdA6wru .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2DAOTt9PxWdA6wru .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2DAOTt9PxWdA6wru :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 第三层:具体组件
Attention
FFN
Residual
LayerNorm
第二层:Block
多个相同模块重复堆叠
第一层:整体架构
Encoder + Decoder

三、什么是 Encoder?

先来看 Transformer 左边的 Encoder。

假设输入一句英文:

text 复制代码
I love artificial intelligence.

计算机首先并不能直接理解:

text 复制代码
I
love
artificial
intelligence

这些单词。

因为对于神经网络来说,真正能够参与计算的是数字。

所以,输入首先需要经过一个过程:

text 复制代码
文本
 ↓
Tokenization
 ↓
Token
 ↓
Token ID
 ↓
Embedding
 ↓
向量

例如:

text 复制代码
"I"              → [0.12, -0.35, 0.71, ...]
"love"           → [0.43,  0.18, -0.22, ...]
"artificial"     → [-0.61, 0.29, 0.44, ...]
"intelligence"   → [0.07, -0.82, 0.15, ...]

这里得到的向量,就是后续 Transformer 真正处理的数据。

Encoder 的任务,就是不断处理这些 Token 对应的表示,并让模型逐渐理解:

这些 Token 分别是什么,以及它们之间存在什么关系。

例如:

text 复制代码
I love artificial intelligence.

经过 Encoder 之后,我们希望模型不再只是孤立地看:

text 复制代码
I
love
artificial
intelligence

而是能够建立这样的联系:

text 复制代码
I ───────→ love
              │
              ↓
      artificial intelligence

也就是说:

Encoder 的核心任务,是让每一个 Token 都获得"结合上下文之后"的表示。

这句话非常重要。

在输入 Transformer 之前:

text 复制代码
love

可能只是"love"这个词本身的向量。

但是经过 Encoder 的多层处理之后:

text 复制代码
love

所对应的向量,已经不再只包含"love"自身的信息。

它还会结合:

text 复制代码
谁在 love?
love 什么?
周围还有哪些词?
这些词之间是什么关系?

于是,Token 的表示就从:

孤立的词表示

逐渐变成:

包含上下文信息的表示。

这就是 Encoder 的核心价值。


四、Encoder Block:Transformer 的基本积木

一个完整的 Encoder 并不是一次计算就结束。

它由多个 Encoder Block 叠加而成。

原始 Transformer 论文中使用了:

text 复制代码
N × Encoder Block

也就是说:

text 复制代码
Input
  ↓
Encoder Block 1
  ↓
Encoder Block 2
  ↓
Encoder Block 3
  ↓
      ···
  ↓
Encoder Block N

为什么需要多层?

我们可以把它理解成:

第一层建立比较基础的关系,后面的层继续在前一层结果的基础上进行更加复杂的特征提取。

例如:

text 复制代码
第一层:
可能关注相邻 Token 之间的关系

第二层:
开始建立更复杂的语义关系

第三层:
进一步组合这些信息

......

最后:
形成更加丰富的上下文表示

当然,真实模型内部究竟学到了什么关系,并不是人为提前规定好的。

这里的"第一层学语法、第二层学语义"只能帮助我们建立直觉。

真正的情况是:

模型通过训练自己学习应该如何利用每一层的参数。

那么,一个 Encoder Block 内部到底有什么?

我们先看一个简化结构:

text 复制代码
Input
  ↓
Multi-Head Self-Attention
  ↓
Add & Norm
  ↓
Feed Forward Network
  ↓
Add & Norm
  ↓
Output

这里出现了几个重要模块:

  1. Multi-Head Self-Attention;
  2. Residual Connection;
  3. Layer Normalization;
  4. Feed Forward Network。

接下来,我们先从整体职责理解它们。


下面是 Encoder Block 内部结构的 Mermaid 图:
#mermaid-svg-pXXaup0xEa4pMhAp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pXXaup0xEa4pMhAp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pXXaup0xEa4pMhAp .error-icon{fill:#552222;}#mermaid-svg-pXXaup0xEa4pMhAp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pXXaup0xEa4pMhAp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pXXaup0xEa4pMhAp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pXXaup0xEa4pMhAp .marker.cross{stroke:#333333;}#mermaid-svg-pXXaup0xEa4pMhAp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pXXaup0xEa4pMhAp p{margin:0;}#mermaid-svg-pXXaup0xEa4pMhAp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pXXaup0xEa4pMhAp .cluster-label text{fill:#333;}#mermaid-svg-pXXaup0xEa4pMhAp .cluster-label span{color:#333;}#mermaid-svg-pXXaup0xEa4pMhAp .cluster-label span p{background-color:transparent;}#mermaid-svg-pXXaup0xEa4pMhAp .label text,#mermaid-svg-pXXaup0xEa4pMhAp span{fill:#333;color:#333;}#mermaid-svg-pXXaup0xEa4pMhAp .node rect,#mermaid-svg-pXXaup0xEa4pMhAp .node circle,#mermaid-svg-pXXaup0xEa4pMhAp .node ellipse,#mermaid-svg-pXXaup0xEa4pMhAp .node polygon,#mermaid-svg-pXXaup0xEa4pMhAp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pXXaup0xEa4pMhAp .rough-node .label text,#mermaid-svg-pXXaup0xEa4pMhAp .node .label text,#mermaid-svg-pXXaup0xEa4pMhAp .image-shape .label,#mermaid-svg-pXXaup0xEa4pMhAp .icon-shape .label{text-anchor:middle;}#mermaid-svg-pXXaup0xEa4pMhAp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pXXaup0xEa4pMhAp .rough-node .label,#mermaid-svg-pXXaup0xEa4pMhAp .node .label,#mermaid-svg-pXXaup0xEa4pMhAp .image-shape .label,#mermaid-svg-pXXaup0xEa4pMhAp .icon-shape .label{text-align:center;}#mermaid-svg-pXXaup0xEa4pMhAp .node.clickable{cursor:pointer;}#mermaid-svg-pXXaup0xEa4pMhAp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pXXaup0xEa4pMhAp .arrowheadPath{fill:#333333;}#mermaid-svg-pXXaup0xEa4pMhAp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pXXaup0xEa4pMhAp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pXXaup0xEa4pMhAp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pXXaup0xEa4pMhAp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pXXaup0xEa4pMhAp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pXXaup0xEa4pMhAp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pXXaup0xEa4pMhAp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pXXaup0xEa4pMhAp .cluster text{fill:#333;}#mermaid-svg-pXXaup0xEa4pMhAp .cluster span{color:#333;}#mermaid-svg-pXXaup0xEa4pMhAp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pXXaup0xEa4pMhAp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pXXaup0xEa4pMhAp rect.text{fill:none;stroke-width:0;}#mermaid-svg-pXXaup0xEa4pMhAp .icon-shape,#mermaid-svg-pXXaup0xEa4pMhAp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pXXaup0xEa4pMhAp .icon-shape p,#mermaid-svg-pXXaup0xEa4pMhAp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pXXaup0xEa4pMhAp .icon-shape .label rect,#mermaid-svg-pXXaup0xEa4pMhAp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pXXaup0xEa4pMhAp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pXXaup0xEa4pMhAp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pXXaup0xEa4pMhAp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Input
Multi-Head Self-Attention
Add & Norm
Feed Forward Network
Add & Norm
Output

五、第一部分:Multi-Head Self-Attention

这是 Transformer 中最核心的模块之一。

虽然具体计算过程会在后面的文章中详细展开,但现在我们先理解:

它在整个 Transformer 中负责什么?

答案是:

让 Token 之间进行信息交互。

假设有一句话:

text 复制代码
我 喜欢 学习 人工智能

如果每个 Token 都只是独立存在:

text 复制代码
我
喜欢
学习
人工智能

那么模型并不知道:

text 复制代码
谁喜欢?
喜欢什么?
学习什么?

于是 Self-Attention 会让每个 Token 都有机会去关注其他 Token。

例如:

text 复制代码
        我
        ↑
        │
喜欢 ← 学习 → 人工智能

更准确地说:

对于当前 Token,模型会计算序列中其他 Token 对它的重要程度。

因此:

text 复制代码
Self-Attention

解决的是:

Token 与 Token 之间如何交换信息。

这里的:

text 复制代码
Self

也非常关键。

它表示:

Attention 的信息来源和查询对象来自同一个序列。

例如:

text 复制代码
我 喜欢 学习 人工智能

序列中的每一个 Token 都可以关注:

text 复制代码
我
喜欢
学习
人工智能

包括自己。

因此:

text 复制代码
Self-Attention

可以简单理解成:

序列内部自己关注自己。

至于为什么还要:

text 复制代码
Multi-Head

也就是"多头",我们暂时先留一个问题:

如果一个 Attention 能够建立关系,为什么还需要多个 Attention Head?

这个问题会在后面的文章中专门展开。


六、第二部分:为什么 Attention 后面还需要 Add?

在 Transformer 的结构图中,你会经常看到:

text 复制代码
Add & Norm

其中:

text 复制代码
Add

指的就是:

Residual Connection,残差连接。

它的结构可以简单理解为:

text 复制代码
x
├───────────────┐
│               │
↓               │
Sublayer(x)     │
│               │
└─────── + ─────┘
        ↓
      Output

数学上可以写成:

y = x + F ( x ) y = x + F(x) y=x+F(x)

其中:

  • x x x 是原始输入;
  • F ( x ) F(x) F(x) 是某个子层处理之后的结果;
  • y y y 是最终输出。

例如:

text 复制代码
Input
  ↓
Attention
  ↓
处理结果

同时:

Input ────────────────┐
                       ↓
Attention Output + Input
                       ↓
                    新输出

那么问题来了:

为什么不直接使用 Attention 的输出,而要把原始输入再加回来?

最直观的理解是:

让网络在学习新信息的同时,不轻易丢失原始信息。

假设某个模块处理之后产生:

F ( x ) F(x) F(x)

如果我们直接输出:

y = F ( x ) y = F(x) y=F(x)

那么下一层看到的只有:

text 复制代码
处理之后的信息

而加入残差连接之后:

y = x + F ( x ) y = x + F(x) y=x+F(x)

下一层同时保留:

text 复制代码
原始信息 + 新学习的信息

从深度网络训练的角度来看,Residual Connection 还有一个非常重要的作用:

帮助信息和梯度在深层网络中传播。

Transformer 往往会堆叠很多层。

如果信息必须经过:

text 复制代码
Layer 1
 ↓
Layer 2
 ↓
Layer 3
 ↓
......
 ↓
Layer N

每一层都进行复杂变换,那么网络越深,训练就可能越困难。

Residual Connection 相当于提供了一条更加直接的信息通道。

所以:

text 复制代码
Add

并不是一个可有可无的小操作。

它是深层 Transformer 能够稳定训练的重要设计之一。


下面是残差连接(Residual Connection)的 Mermaid 图:
#mermaid-svg-Bj3ezxrbPLqSCgpu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Bj3ezxrbPLqSCgpu .error-icon{fill:#552222;}#mermaid-svg-Bj3ezxrbPLqSCgpu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Bj3ezxrbPLqSCgpu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .marker.cross{stroke:#333333;}#mermaid-svg-Bj3ezxrbPLqSCgpu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Bj3ezxrbPLqSCgpu p{margin:0;}#mermaid-svg-Bj3ezxrbPLqSCgpu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster-label text{fill:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster-label span{color:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster-label span p{background-color:transparent;}#mermaid-svg-Bj3ezxrbPLqSCgpu .label text,#mermaid-svg-Bj3ezxrbPLqSCgpu span{fill:#333;color:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .node rect,#mermaid-svg-Bj3ezxrbPLqSCgpu .node circle,#mermaid-svg-Bj3ezxrbPLqSCgpu .node ellipse,#mermaid-svg-Bj3ezxrbPLqSCgpu .node polygon,#mermaid-svg-Bj3ezxrbPLqSCgpu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .rough-node .label text,#mermaid-svg-Bj3ezxrbPLqSCgpu .node .label text,#mermaid-svg-Bj3ezxrbPLqSCgpu .image-shape .label,#mermaid-svg-Bj3ezxrbPLqSCgpu .icon-shape .label{text-anchor:middle;}#mermaid-svg-Bj3ezxrbPLqSCgpu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .rough-node .label,#mermaid-svg-Bj3ezxrbPLqSCgpu .node .label,#mermaid-svg-Bj3ezxrbPLqSCgpu .image-shape .label,#mermaid-svg-Bj3ezxrbPLqSCgpu .icon-shape .label{text-align:center;}#mermaid-svg-Bj3ezxrbPLqSCgpu .node.clickable{cursor:pointer;}#mermaid-svg-Bj3ezxrbPLqSCgpu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .arrowheadPath{fill:#333333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bj3ezxrbPLqSCgpu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Bj3ezxrbPLqSCgpu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bj3ezxrbPLqSCgpu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster text{fill:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu .cluster span{color:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Bj3ezxrbPLqSCgpu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Bj3ezxrbPLqSCgpu rect.text{fill:none;stroke-width:0;}#mermaid-svg-Bj3ezxrbPLqSCgpu .icon-shape,#mermaid-svg-Bj3ezxrbPLqSCgpu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Bj3ezxrbPLqSCgpu .icon-shape p,#mermaid-svg-Bj3ezxrbPLqSCgpu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Bj3ezxrbPLqSCgpu .icon-shape .label rect,#mermaid-svg-Bj3ezxrbPLqSCgpu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Bj3ezxrbPLqSCgpu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Bj3ezxrbPLqSCgpu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Bj3ezxrbPLqSCgpu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} x
Sublayer(x)
+
y = x + F(x)

七、第三部分:Norm 又是什么?

Add 后面紧接着:

text 复制代码
Norm

也就是:

Normalization,归一化。

在 Transformer 中,经典设计使用的是:

Layer Normalization,LayerNorm。

我们先不急着推导它的全部细节,只理解它的作用。

假设某一层输出的数据分布非常不稳定:

text 复制代码
某些数值非常大
某些数值非常小
某些数据分布变化很明显

那么后面的网络就需要不断适应这些变化。

这会增加训练难度。

于是,我们希望对数据进行一定程度的标准化处理,让后续网络能够在更加稳定的数据分布上进行训练。

LayerNorm 的基本思想是:

对单个样本的特征维度进行归一化。

对于一个输入向量:

x = x 1 , x 2 , ... , x d x = x_1, x_2, \\dots, x_d x=x1,x2,...,xd

首先计算均值:

μ = 1 d ∑ i = 1 d x i \mu = \frac{1}{d}\sum_{i=1}^{d}x_i μ=d1i=1∑dxi

然后计算方差:

σ 2 = 1 d ∑ i = 1 d ( x i − μ ) 2 \sigma^2 = \frac{1}{d}\sum_{i=1}^{d}(x_i-\mu)^2 σ2=d1i=1∑d(xi−μ)2

最后进行归一化:

x ^ i = x i − μ σ 2 + ϵ \hat{x}_i = \frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}} x^i=σ2+ϵ xi−μ

随后再通过可学习参数进行缩放和平移:

y i = γ x ^ i + β y_i = \gamma \hat{x}_i + \beta yi=γx^i+β

其中:

  • γ \gamma γ:缩放参数;
  • β \beta β:平移参数;
  • ϵ \epsilon ϵ:防止分母为 0 0 0 的一个很小的常数。

现在不需要强行记住这些公式。

这一阶段更重要的是知道:

LayerNorm 的作用,是帮助网络保持更加稳定的数值分布,从而让深层网络训练得更加稳定。

因此:

text 复制代码
Attention
    ↓
Add
    ↓
LayerNorm

共同构成了 Transformer 中非常重要的一部分。


八、第四部分:Attention 之后,为什么还需要 FFN?

很多刚学习 Transformer 的人,会把注意力全部放在 Attention 上。

但实际上,一个完整的 Transformer Block 中还有一个非常重要的模块:

Feed Forward Network,前馈神经网络。

通常简称:

text 复制代码
FFN

它的结构其实并不复杂。

可以理解成:

text 复制代码
输入
 ↓
Linear
 ↓
Activation
 ↓
Linear
 ↓
输出

原始 Transformer 中可以写成:

$$

\operatorname{FFN}(x)

\max(0, xW_1+b_1)W_2+b_2

$$

其中:

  • 第一层线性层通常将维度扩大;
  • 中间经过非线性激活函数;
  • 第二层再将维度映射回来。

例如:

text 复制代码
d_model
   ↓
Linear
   ↓
d_ff
   ↓
Activation
   ↓
Linear
   ↓
d_model

那么问题来了:

Attention 不是已经处理完信息了吗?为什么还需要 FFN?

这里可以从职责上理解。

Attention 更擅长做:

Token 与 Token 之间的信息交互。

例如:

text 复制代码
Token A
   ↔
Token B
   ↔
Token C

而 FFN 则更像是在:

每个 Token 获得上下文信息之后,进一步对自己的表示进行非线性变换。

我们可以简单理解为:

text 复制代码
Attention:
"我应该从其他 Token 获得哪些信息?"

FFN:
"获得这些信息之后,我应该如何进一步处理自己?"

因此,一个 Transformer Block 实际上包含两类重要计算:

text 复制代码
Attention
    ↓
Token 之间交换信息

FFN
    ↓
每个 Token 自己进行进一步变换

两者缺一不可。


九、现在,我们终于可以看懂 Encoder Block 了

经过前面的拆解,一个 Encoder Block 可以重新画成:

text 复制代码
Input
  │
  ├──────────────────────────────┐
  ↓                              │
Multi-Head Self-Attention        │
  ↓                              │
        Add ◄────────────────────┘
  ↓
LayerNorm
  │
  ├──────────────────────────────┐
  ↓                              │
Feed Forward Network             │
  ↓                              │
        Add ◄────────────────────┘
  ↓
LayerNorm
  ↓
Output

现在,我们可以给每个模块一句话的定位:

Multi-Head Self-Attention

让不同 Token 之间交换信息。

Residual Connection

保留原始信息,并帮助深层网络训练。

LayerNorm

稳定数据分布,帮助训练过程更加稳定。

Feed Forward Network

对每个 Token 的表示进一步进行非线性变换。

于是,一个 Encoder Block 的完整工作流程可以理解成:

text 复制代码
原始 Token 表示
      ↓
先看看其他 Token
      ↓
获得上下文信息
      ↓
保留原始信息
      ↓
稳定数据分布
      ↓
进一步进行非线性处理
      ↓
再次保留原始信息
      ↓
输出新的 Token 表示

这就是 Encoder Block 的基本思想。


下面是 Encoder Block 完整工作流程的 Mermaid 图:
#mermaid-svg-ZjLv1EgqBsceOf01{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZjLv1EgqBsceOf01 .error-icon{fill:#552222;}#mermaid-svg-ZjLv1EgqBsceOf01 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZjLv1EgqBsceOf01 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZjLv1EgqBsceOf01 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZjLv1EgqBsceOf01 .marker.cross{stroke:#333333;}#mermaid-svg-ZjLv1EgqBsceOf01 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZjLv1EgqBsceOf01 p{margin:0;}#mermaid-svg-ZjLv1EgqBsceOf01 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster-label text{fill:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster-label span{color:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster-label span p{background-color:transparent;}#mermaid-svg-ZjLv1EgqBsceOf01 .label text,#mermaid-svg-ZjLv1EgqBsceOf01 span{fill:#333;color:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 .node rect,#mermaid-svg-ZjLv1EgqBsceOf01 .node circle,#mermaid-svg-ZjLv1EgqBsceOf01 .node ellipse,#mermaid-svg-ZjLv1EgqBsceOf01 .node polygon,#mermaid-svg-ZjLv1EgqBsceOf01 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZjLv1EgqBsceOf01 .rough-node .label text,#mermaid-svg-ZjLv1EgqBsceOf01 .node .label text,#mermaid-svg-ZjLv1EgqBsceOf01 .image-shape .label,#mermaid-svg-ZjLv1EgqBsceOf01 .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZjLv1EgqBsceOf01 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZjLv1EgqBsceOf01 .rough-node .label,#mermaid-svg-ZjLv1EgqBsceOf01 .node .label,#mermaid-svg-ZjLv1EgqBsceOf01 .image-shape .label,#mermaid-svg-ZjLv1EgqBsceOf01 .icon-shape .label{text-align:center;}#mermaid-svg-ZjLv1EgqBsceOf01 .node.clickable{cursor:pointer;}#mermaid-svg-ZjLv1EgqBsceOf01 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZjLv1EgqBsceOf01 .arrowheadPath{fill:#333333;}#mermaid-svg-ZjLv1EgqBsceOf01 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZjLv1EgqBsceOf01 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZjLv1EgqBsceOf01 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZjLv1EgqBsceOf01 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZjLv1EgqBsceOf01 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZjLv1EgqBsceOf01 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster text{fill:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 .cluster span{color:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZjLv1EgqBsceOf01 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZjLv1EgqBsceOf01 rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZjLv1EgqBsceOf01 .icon-shape,#mermaid-svg-ZjLv1EgqBsceOf01 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZjLv1EgqBsceOf01 .icon-shape p,#mermaid-svg-ZjLv1EgqBsceOf01 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZjLv1EgqBsceOf01 .icon-shape .label rect,#mermaid-svg-ZjLv1EgqBsceOf01 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZjLv1EgqBsceOf01 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZjLv1EgqBsceOf01 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZjLv1EgqBsceOf01 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 原始 Token 表示
先看看其他 Token
获得上下文信息
保留原始信息
稳定数据分布
进一步进行非线性处理
再次保留原始信息
输出新的 Token 表示

十、Encoder 到底输出了什么?

Encoder 处理完成之后,会输出什么?

答案不是:

text 复制代码
一个句子

也不是:

text 复制代码
最终分类结果

而是:

经过上下文编码之后的一组 Token 表示。

例如输入:

text 复制代码
I love artificial intelligence.

最开始:

text 复制代码
I
love
artificial
intelligence

每个 Token 都有自己的初始 Embedding。

经过多个 Encoder Block 之后:

text 复制代码
I'                ← 结合上下文之后的新表示
love'             ← 结合上下文之后的新表示
artificial'       ← 结合上下文之后的新表示
intelligence'     ← 结合上下文之后的新表示

这里的:

text 复制代码
I'
love'
...

并不是新的单词。

而是表示:

每个 Token 对应的向量已经发生了变化。

例如:

text 复制代码
love

经过 Encoder 之后,它所对应的向量不再只表示:

"love 这个词本身"。

它可能已经包含:

text 复制代码
谁在 love?
love 的对象是什么?
这句话整体表达什么?

这样的上下文信息。

所以 Encoder 的输出可以理解为:

一组上下文化(Contextualized)的 Token 表示。


十一、接下来轮到 Decoder

如果说 Encoder 负责:

理解输入。

那么 Decoder 负责的就是:

生成输出。

例如机器翻译:

text 复制代码
输入:

I love artificial intelligence.

输出:

我喜欢人工智能。

Decoder 并不是一次性把整句话全部生成出来。

它通常按照自回归的方式:

text 复制代码
开始
 ↓
我
 ↓
我 喜欢
 ↓
我 喜欢 人工智能
 ↓
结束

也就是说:

生成当前 Token 时,需要参考之前已经生成的 Token。

因此 Decoder 面临两个任务:

  1. 关注自己之前生成的内容;
  2. 关注 Encoder 对输入序列的理解。

所以,Decoder 的结构会比 Encoder 更复杂一些。


十二、Decoder Block 为什么有两个 Attention?

一个典型的 Decoder Block 可以简化为:

text 复制代码
Input
  ↓
Masked Multi-Head Self-Attention
  ↓
Add & Norm
  ↓
Encoder-Decoder Attention
  ↓
Add & Norm
  ↓
Feed Forward Network
  ↓
Add & Norm
  ↓
Output

你会发现:

Decoder 里面有两个 Attention。

为什么?

因为它需要解决两个不同的问题。


12.1 第一个 Attention:看自己已经生成的内容

假设 Decoder 正在生成:

text 复制代码
我 喜欢 人工智能

当它准备预测下一个 Token 时,它需要参考:

text 复制代码
我
喜欢
人工智能

这些已经出现的信息。

因此,第一个 Attention 负责:

让 Decoder 内部的 Token 彼此建立关系。

但是,这里有一个非常重要的限制。

假设我们正在预测:

text 复制代码
Token 3

那么模型不能提前偷看:

text 复制代码
Token 4
Token 5
Token 6

否则训练和实际生成时就会出现问题。

因此,Decoder 使用的是:

Masked Self-Attention。

所谓 Mask,可以简单理解成:

把未来的信息遮住。

例如:

text 复制代码
Token 1 可以看:
Token 1

Token 2 可以看:
Token 1、Token 2

Token 3 可以看:
Token 1、Token 2、Token 3

Token 4 可以看:
Token 1、Token 2、Token 3、Token 4

但是:

text 复制代码
Token 2

不能偷看:

text 复制代码
Token 3、Token 4......

所以注意力矩阵会形成一种类似:

text 复制代码
✓ × × ×
✓ ✓ × ×
✓ ✓ ✓ ×
✓ ✓ ✓ ✓

的结构。

这就是所谓的:

Causal Mask,因果掩码。

它保证:

当前 Token 只能看到自己以及过去的信息,不能看到未来。

这也是后面理解 GPT 的一个非常重要的基础。


12.2 第二个 Attention:去看 Encoder

Decoder 只看自己还不够。

例如我们现在正在进行翻译:

text 复制代码
输入:

I love artificial intelligence.

Decoder 正在生成:

text 复制代码
我 喜欢 ...

那么当 Decoder 想继续生成时,它还需要知道:

输入的英文到底是什么?

所以,它需要去关注 Encoder 的输出。

于是出现第二个 Attention:

Encoder-Decoder Attention。

我们可以理解成:

text 复制代码
Decoder 当前状态
       ↓
   "我现在需要什么信息?"
       ↓
       Query

Encoder 输出
       ↓
   "输入中有哪些信息?"
       ↓
       Key / Value

因此,这个 Attention 的核心作用是:

让 Decoder 在生成输出时,能够参考 Encoder 对输入序列的理解。

例如:

text 复制代码
Encoder:
理解英文输入

Decoder:
生成中文输出

Decoder ─────→ 需要时关注 Encoder

所以原始 Transformer 的 Decoder 实际上同时处理:

text 复制代码
过去生成的信息
        +
输入序列的信息

这也是为什么它需要两个不同的 Attention 模块。


十三、Encoder 和 Decoder 到底有什么区别?

现在我们可以把两者放在一起比较。

Encoder

text 复制代码
Input
 ↓
Self-Attention
 ↓
Add & Norm
 ↓
FFN
 ↓
Add & Norm

核心目标:

理解整个输入序列。

因为 Encoder 在处理输入时,通常可以同时看到整个输入:

text 复制代码
Token 1
Token 2
Token 3
...
Token N

因此 Encoder 的 Self-Attention 可以建立:

text 复制代码
任意 Token ↔ 任意 Token

之间的关系。


Decoder

text 复制代码
Output
 ↓
Masked Self-Attention
 ↓
Add & Norm
 ↓
Encoder-Decoder Attention
 ↓
Add & Norm
 ↓
FFN
 ↓
Add & Norm

核心目标:

根据已有信息逐步生成输出。

因此 Decoder:

  1. 需要关注已经生成的 Token;
  2. 不能偷看未来 Token;
  3. 还需要关注 Encoder 输出。

所以 Decoder 比 Encoder 多了:

text 复制代码
Masked Self-Attention

和:

text 复制代码
Encoder-Decoder Attention

这样的结构。


十四、Transformer 到底是如何完成一次机器翻译的?

现在我们把整个过程串起来。

假设:

text 复制代码
输入:

I love artificial intelligence.

目标:

text 复制代码
我喜欢人工智能。

整个流程可以简单理解成:

text 复制代码
英文输入
   ↓
Tokenization
   ↓
Token Embedding
   ↓
Positional Encoding
   ↓
Encoder
   ↓
Encoder Output
   ↓
Decoder
   ↓
预测"我"
   ↓
Decoder
   ↓
预测"喜欢"
   ↓
Decoder
   ↓
预测"人工智能"
   ↓
Decoder
   ↓
结束

展开一点:

text 复制代码
┌──────────────────────────────┐
│          Encoder             │
│                              │
│ I love artificial intelligence │
│              ↓               │
│      上下文信息理解           │
└──────────────┬───────────────┘
               │
               │ Encoder Output
               ↓
┌──────────────────────────────┐
│          Decoder             │
│                              │
│ <START>                      │
│     ↓                        │
│     我                       │
│     ↓                        │
│     我 喜欢                  │
│     ↓                        │
│     我 喜欢 人工智能          │
└──────────────────────────────┘

这就是原始 Transformer Encoder-Decoder 架构的整体工作方式。


十五、等等,还有一个重要问题:Transformer 怎么知道顺序?

现在我们已经知道:

text 复制代码
Attention

可以让不同 Token 建立联系。

但这里还有一个问题。

假设输入:

text 复制代码
我 喜欢 你

和:

text 复制代码
你 喜欢 我

这两句话使用的 Token 完全一样:

text 复制代码
我
喜欢
你

但是顺序不同,含义也完全不同。

然而 Attention 本身只是在计算 Token 之间的关系。

那么:

Transformer 怎么知道哪个 Token 在前,哪个 Token 在后?

这就是:

Positional Encoding,位置编码。

Transformer 不像 RNN。

RNN 天然按照:

text 复制代码
第一个
↓
第二个
↓
第三个

的顺序进行计算。

因此:

顺序本身就包含在计算过程中。

但是 Transformer 可以并行处理:

text 复制代码
Token 1
Token 2
Token 3
Token 4

这意味着:

模型本身并不知道这些 Token 的先后顺序。

所以必须额外把位置信息加入进去:

text 复制代码
Token Embedding
       +
Position Information
       ↓
Transformer Input

原始 Transformer 使用的是:

Sinusoidal Positional Encoding,正弦余弦位置编码。

位置编码公式如下:

P E ( p o s , 2 i ) = sin ⁡ ( p o s 10000 2 i d model ) PE(pos, 2i) = \sin\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PE(pos,2i)=sin(10000dmodel2ipos)

P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 10000 2 i d model ) PE(pos, 2i+1) = \cos\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PE(pos,2i+1)=cos(10000dmodel2ipos)

其中 p o s pos pos 为位置索引, i i i 为维度索引, d model d_{\text{model}} dmodel 为模型维度。

现在不需要强行理解:

为什么是 10000?

为什么使用 sin?

为什么使用 cos?

这一篇只需要先建立一个概念:

Attention 本身不包含顺序信息,所以 Transformer 必须额外告诉模型每个 Token 的位置。

后面我们会专门讨论 Position Encoding。


十六、Transformer 的完整数据流

到这里,我们已经可以把原始 Transformer 的整体流程串起来了。

text 复制代码
                    输入序列
                        ↓
                  Token Embedding
                        ↓
                Positional Encoding
                        ↓
              ┌────────────────┐
              │ Encoder Block  │
              └────────────────┘
                        ↓
              ┌────────────────┐
              │ Encoder Block  │
              └────────────────┘
                        ↓
                       ...
                        ↓
                   Encoder Output
                        │
                        │
                        ↓
输出序列 → Token Embedding
                        ↓
                Positional Encoding
                        ↓
              Masked Self-Attention
                        ↓
                   Add & Norm
                        ↓
             Encoder-Decoder Attention
                        ↓
                   Add & Norm
                        ↓
               Feed Forward Network
                        ↓
                   Add & Norm
                        ↓
                     Linear
                        ↓
                     Softmax
                        ↓
                  下一个 Token

从职责上,我们也可以把 Transformer 简化成:

text 复制代码
Embedding
    ↓
把 Token 转换成向量

Positional Encoding
    ↓
告诉模型 Token 的位置

Attention
    ↓
建立 Token 之间的关系

FFN
    ↓
进一步处理 Token 表示

Residual + LayerNorm
    ↓
帮助深层网络稳定训练

Encoder
    ↓
理解输入

Decoder
    ↓
生成输出

十七、一个容易产生的误解:现在的 GPT 还是完整 Transformer 吗?

看到这里,可能会有一个问题:

我们现在使用的大语言模型,例如 GPT,真的还是上面这种完整的 Encoder-Decoder Transformer 吗?

答案是:

不完全是。

Transformer 最初是一种完整的 Encoder-Decoder 架构。

但后来研究人员发现,不同任务可以使用 Transformer 的不同部分。

于是逐渐出现了三种非常重要的架构:

text 复制代码
Encoder-only
Decoder-only
Encoder-Decoder

例如:

Encoder-only

典型代表:

text 复制代码
BERT

主要使用 Transformer Encoder。

更擅长:

text 复制代码
文本理解
文本分类
命名实体识别

Decoder-only

典型代表:

text 复制代码
GPT

主要使用 Transformer Decoder 中适合自回归生成的结构。

更擅长:

text 复制代码
文本生成
对话
代码生成

今天的大语言模型,大量采用的就是这种:

Decoder-only Transformer。


Encoder-Decoder

典型代表:

text 复制代码
T5

更适合:

text 复制代码
机器翻译
文本摘要
输入序列 → 输出序列

所以:

Transformer 并不是只有一种固定形态。

它更像是一套非常成功的基础架构思想。

不同模型可以根据任务:

text 复制代码
只使用 Encoder

只使用 Decoder

或者同时使用 Encoder + Decoder

这也是 Transformer 后来能够广泛发展的一个重要原因。


十八、现在,我们对 Transformer 应该有什么整体认识?

经过这一篇文章,我们暂时还没有深入:

text 复制代码
Q、K、V

也没有真正计算:

text 复制代码
Attention Score

但现在,我们至少应该建立起这样一张地图:

text 复制代码
                     Transformer
                          │
          ┌───────────────┴───────────────┐
          │                               │
          ↓                               ↓
       Encoder                         Decoder
          │                               │
          │                         Masked Self-Attention
          │                               │
    Self-Attention                         ↓
          │                       Encoder-Decoder Attention
          ↓                               │
      Add & Norm                           ↓
          ↓                              FFN
         FFN                              │
          ↓                               ↓
      Add & Norm                       Add & Norm

并且知道每个模块的大致职责:

模块 核心作用
Embedding 将 Token 转换为向量
Positional Encoding 提供位置信息
Self-Attention 建立 Token 之间的关系
Multi-Head Attention 从多个角度建立关系
FFN 对 Token 表示进行非线性变换
Residual Connection 保留信息,帮助深层训练
LayerNorm 稳定数据分布
Encoder 理解输入
Decoder 逐步生成输出

如果能够建立起这张地图,那么后面学习 Transformer 的细节就会轻松很多。


十九、小结

这一篇,我们主要完成了一件事情:

从整体上认识 Transformer 到底是什么。

Transformer 最初采用的是:

Encoder-Decoder 架构。

其中:

text 复制代码
Encoder

负责:

理解输入序列,并生成包含上下文信息的表示。

而:

text 复制代码
Decoder

负责:

在参考已有输出和 Encoder 信息的基础上,逐步生成新的 Token。

一个典型的 Encoder Block 包含:

text 复制代码
Multi-Head Self-Attention
        ↓
Add & Norm
        ↓
Feed Forward Network
        ↓
Add & Norm

而 Decoder Block 则比 Encoder 多出了:

text 复制代码
Masked Self-Attention

以及:

text 复制代码
Encoder-Decoder Attention

同时,因为 Transformer 不像 RNN 一样天然按照顺序处理数据,所以还需要:

Positional Encoding。

最终,整个 Transformer 可以理解成:

text 复制代码
Token
 ↓
Embedding
 ↓
加入位置信息
 ↓
Attention 建立关系
 ↓
FFN 进一步处理
 ↓
多层 Block 不断提取信息
 ↓
完成理解或生成任务

下一篇:Self-Attention 到底是什么?

现在,我们已经看清了 Transformer 的整体结构。

但是整套架构中最核心的问题仍然没有真正解决:

Attention 到底是怎么工作的?

为什么 Transformer 会把输入转换成:

text 复制代码
Q
K
V

为什么要计算:

Q K T QK^T QKT

为什么还要进行:

softmax ⁡ ( Q K T d k ) \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right) softmax(dk QKT)

这些操作究竟在做什么?

下一篇,我们将正式进入 Transformer 最核心的部分:

Self-Attention。

我们会从一个具体的句子开始,一步一步理解:

text 复制代码
Q 到底是什么?
K 到底是什么?
V 又是什么?

然后亲手走完整个 Attention 的计算过程。

只有真正理解了 Self-Attention,Transformer 的核心才算真正开始展开。

相关推荐
咖啡星人k1 小时前
2026 AI 自动化测试:让 AI 帮你写用例、跑测试、修 Bug(MonkeyCode 云端实战)
人工智能·功能测试·单元测试·测试用例·bug·集成测试
Tisfy3 小时前
LeetCode 1927.求和游戏:抵消+看最值
java·leetcode·游戏·题解·博弈论
Elastic 中国社区官方博客7 小时前
搜索倍增器:推动收入、生产力和 AI 实现规模化
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
wjkjpcba7 小时前
机器人控制板PCBA怎么加工?从SMT贴片到BGA焊接解析机器人电子制造工艺
大数据·人工智能
光电的一只菜鸡7 小时前
ubuntu之坑(二十)——VMware虚拟机系统无法正常进入如何处理
linux·运维·ubuntu
青 春 记 忆7 小时前
Dify Docker Compose 通用无损升级指南:从备份、双版本预演到切换与回滚
运维·人工智能·python·docker·容器
小猪妈咪爱学法7 小时前
欧盟最新发布《AI数字综合法案(Digital Omnibus‑on‑AI,AI综合修订法案)
人工智能·网络安全
ZGIAI7 小时前
ZGI Workflow 变量池:接住节点输出
人工智能·架构
梵构广告8 小时前
提升品牌识别度有哪些方法?
人工智能