欢迎光临
我们一直在努力

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

目录

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

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

前言

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

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

为什么需要 Transformer?

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

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

x₁ → x₂ → x₃ → x₄ → ···

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

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

  • 计算过程存在顺序依赖,难以充分利用并行计算能力;
  • 距离较远的信息需要经过多次传递,长距离依赖难以处理。
  • 随后,Attention 的出现改变了这种思路。

    我们不再要求信息必须:

    Token 1

    Token 2

    Token 3

    Token 4

    一级一级地传递。

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

    Token 1 ─────────────┐
    Token 2 ─────────────┤
    Token 3 ─────────────┼──→ 当前 Token
    Token 4 ─────────────┤
    Token 5 ─────────────┘

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

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

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

    Transformer 不就是 Attention 吗?

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

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

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

    Encoder
    Decoder
    Multi-Head Attention
    Feed Forward Network
    Residual Connection
    Layer Normalization
    Positional Encoding

    这些模块共同组成了 Transformer。

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

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

    只有先知道:

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

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


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

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

    原始 Transformer 是一个典型的:

    Encoder-Decoder 架构。

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

    输入序列

    Encoder

    中间表示

    Decoder

    输出序列

    例如机器翻译:

    I love artificial intelligence.

    Encoder

    理解输入信息

    Decoder

    我喜欢人工智能。

    这里需要注意:

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

    简单来说:

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

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

    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 看成一栋建筑。

    那么:

    Encoder

    和:

    Decoder

    更像是两栋主要建筑。

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

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

    Input

    Embedding

    Positional Encoding

    ┌─────────────────┐
    │ Encoder Block │
    └─────────────────┘

    ┌─────────────────┐
    │ Encoder Block │
    └─────────────────┘

    ···

    Encoder Output

    Decoder 也是类似的结构:

    Output

    Embedding

    Positional Encoding

    ┌─────────────────┐
    │ Decoder Block │
    └─────────────────┘

    ┌─────────────────┐
    │ Decoder Block │
    └─────────────────┘

    ···

    Linear

    Softmax

    预测下一个 Token

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

    第一层:整体架构

    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。

    假设输入一句英文:

    I love artificial intelligence.

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

    I
    love
    artificial
    intelligence

    这些单词。

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

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

    文本

    Tokenization

    Token

    Token ID

    Embedding

    向量

    例如:

    "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 分别是什么,以及它们之间存在什么关系。

    例如:

    I love artificial intelligence.

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

    I
    love
    artificial
    intelligence

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

    I ───────→ love


    artificial intelligence

    也就是说:

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

    这句话非常重要。

    在输入 Transformer 之前:

    love

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

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

    love

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

    它还会结合:

    谁在 love?
    love 什么?
    周围还有哪些词?
    这些词之间是什么关系?

    于是,Token 的表示就从:

    孤立的词表示

    逐渐变成:

    包含上下文信息的表示。

    这就是 Encoder 的核心价值。


    四、Encoder Block:Transformer 的基本积木

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

    它由多个 Encoder Block 叠加而成。

    原始 Transformer 论文中使用了:

    N × Encoder Block

    也就是说:

    Input

    Encoder Block 1

    Encoder Block 2

    Encoder Block 3

    ···

    Encoder Block N

    为什么需要多层?

    我们可以把它理解成:

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

    例如:

    第一层:
    可能关注相邻 Token 之间的关系

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

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

    ……

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

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

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

    真正的情况是:

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

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

    我们先看一个简化结构:

    Input

    Multi-Head Self-Attention

    Add & Norm

    Feed Forward Network

    Add & Norm

    Output

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

  • Multi-Head Self-Attention;
  • Residual Connection;
  • Layer Normalization;
  • 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 之间进行信息交互。

    假设有一句话:

    我 喜欢 学习 人工智能

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


    喜欢
    学习
    人工智能

    那么模型并不知道:

    谁喜欢?
    喜欢什么?
    学习什么?

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

    例如:




    喜欢 ← 学习 → 人工智能

    更准确地说:

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

    因此:

    Self-Attention

    解决的是:

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

    这里的:

    Self

    也非常关键。

    它表示:

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

    例如:

    我 喜欢 学习 人工智能

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


    喜欢
    学习
    人工智能

    包括自己。

    因此:

    Self-Attention

    可以简单理解成:

    序列内部自己关注自己。

    至于为什么还要:

    Multi-Head

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

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

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


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

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

    Add & Norm

    其中:

    Add

    指的就是:

    Residual Connection,残差连接。

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

    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 是最终输出。

    例如:

    Input

    Attention

    处理结果

    同时:

    Input ────────────────┐

    Attention Output + Input

    新输出

    那么问题来了:

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

    最直观的理解是:

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

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

    F

    (

    x

    )

    F(x)

    F(x)

    如果我们直接输出:

    y

    =

    F

    (

    x

    )

    y = F(x)

    y=F(x)

    那么下一层看到的只有:

    处理之后的信息

    而加入残差连接之后:

    y

    =

    x

    +

    F

    (

    x

    )

    y = x + F(x)

    y=x+F(x)

    下一层同时保留:

    原始信息 + 新学习的信息

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

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

    Transformer 往往会堆叠很多层。

    如果信息必须经过:

    Layer 1

    Layer 2

    Layer 3

    ……

    Layer N

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

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

    所以:

    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 后面紧接着:

    Norm

    也就是:

    Normalization,归一化。

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

    Layer Normalization,LayerNorm。

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

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

    某些数值非常大
    某些数值非常小
    某些数据分布变化很明显

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

    这会增加训练难度。

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

    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=1dxi

    然后计算方差:

    σ

    2

    =

    1

    d

    i

    =

    1

    d

    (

    x

    i

    μ

    )

    2

    \\sigma^2 = \\frac{1}{d}\\sum_{i=1}^{d}(x_i-\\mu)^2

    σ2=d1i=1d(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 的作用,是帮助网络保持更加稳定的数值分布,从而让深层网络训练得更加稳定。

    因此:

    Attention

    Add

    LayerNorm

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


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

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

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

    Feed Forward Network,前馈神经网络。

    通常简称:

    FFN

    它的结构其实并不复杂。

    可以理解成:

    输入

    Linear

    Activation

    Linear

    输出

    原始 Transformer 中可以写成:

    $$ \\operatorname{FFN}(x)

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

    其中:

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

    例如:

    d_model

    Linear

    d_ff

    Activation

    Linear

    d_model

    那么问题来了:

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

    这里可以从职责上理解。

    Attention 更擅长做:

    Token 与 Token 之间的信息交互。

    例如:

    Token A

    Token B

    Token C

    而 FFN 则更像是在:

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

    我们可以简单理解为:

    Attention:
    “我应该从其他 Token 获得哪些信息?”

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

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

    Attention

    Token 之间交换信息

    FFN

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

    两者缺一不可。


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

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

    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 的完整工作流程可以理解成:

    原始 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 处理完成之后,会输出什么?

    答案不是:

    一个句子

    也不是:

    最终分类结果

    而是:

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

    例如输入:

    I love artificial intelligence.

    最开始:

    I
    love
    artificial
    intelligence

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

    经过多个 Encoder Block 之后:

    I' ← 结合上下文之后的新表示
    love' ← 结合上下文之后的新表示
    artificial' ← 结合上下文之后的新表示
    intelligence' ← 结合上下文之后的新表示

    这里的:

    I'
    love'

    并不是新的单词。

    而是表示:

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

    例如:

    love

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

    “love 这个词本身”。

    它可能已经包含:

    谁在 love?
    love 的对象是什么?
    这句话整体表达什么?

    这样的上下文信息。

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

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


    十一、接下来轮到 Decoder

    如果说 Encoder 负责:

    理解输入。

    那么 Decoder 负责的就是:

    生成输出。

    例如机器翻译:

    输入:

    I love artificial intelligence.

    输出:

    我喜欢人工智能。

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

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

    开始



    我 喜欢

    我 喜欢 人工智能

    结束

    也就是说:

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

    因此 Decoder 面临两个任务:

  • 关注自己之前生成的内容;
  • 关注 Encoder 对输入序列的理解。
  • 所以,Decoder 的结构会比 Encoder 更复杂一些。


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

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

    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 正在生成:

    我 喜欢 人工智能

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


    喜欢
    人工智能

    这些已经出现的信息。

    因此,第一个 Attention 负责:

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

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

    假设我们正在预测:

    Token 3

    那么模型不能提前偷看:

    Token 4
    Token 5
    Token 6

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

    因此,Decoder 使用的是:

    Masked Self-Attention。

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

    把未来的信息遮住。

    例如:

    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

    但是:

    Token 2

    不能偷看:

    Token 3、Token 4……

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

    ✓ × × ×
    ✓ ✓ × ×
    ✓ ✓ ✓ ×
    ✓ ✓ ✓ ✓

    的结构。

    这就是所谓的:

    Causal Mask,因果掩码。

    它保证:

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

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


    12.2 第二个 Attention:去看 Encoder

    Decoder 只看自己还不够。

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

    输入:

    I love artificial intelligence.

    Decoder 正在生成:

    我 喜欢 …

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

    输入的英文到底是什么?

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

    于是出现第二个 Attention:

    Encoder-Decoder Attention。

    我们可以理解成:

    Decoder 当前状态

    “我现在需要什么信息?”

    Query

    Encoder 输出

    “输入中有哪些信息?”

    Key / Value

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

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

    例如:

    Encoder:
    理解英文输入

    Decoder:
    生成中文输出

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

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

    过去生成的信息
    +
    输入序列的信息

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


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

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

    Encoder

    Input

    Self-Attention

    Add & Norm

    FFN

    Add & Norm

    核心目标:

    理解整个输入序列。

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

    Token 1
    Token 2
    Token 3

    Token N

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

    任意 Token ↔ 任意 Token

    之间的关系。


    Decoder

    Output

    Masked Self-Attention

    Add & Norm

    Encoder-Decoder Attention

    Add & Norm

    FFN

    Add & Norm

    核心目标:

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

    因此 Decoder:

  • 需要关注已经生成的 Token;
  • 不能偷看未来 Token;
  • 还需要关注 Encoder 输出。
  • 所以 Decoder 比 Encoder 多了:

    Masked Self-Attention

    和:

    Encoder-Decoder Attention

    这样的结构。


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

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

    假设:

    输入:

    I love artificial intelligence.

    目标:

    我喜欢人工智能。

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

    英文输入

    Tokenization

    Token Embedding

    Positional Encoding

    Encoder

    Encoder Output

    Decoder

    预测“我”

    Decoder

    预测“喜欢”

    Decoder

    预测“人工智能”

    Decoder

    结束

    展开一点:

    ┌──────────────────────────────┐
    │ Encoder │
    │ │
    │ I love artificial intelligence │
    │ ↓ │
    │ 上下文信息理解 │
    └──────────────┬───────────────┘

    │ Encoder Output

    ┌──────────────────────────────┐
    │ Decoder │
    │ │
    │ <START> │
    │ ↓ │
    │ 我 │
    │ ↓ │
    │ 我 喜欢 │
    │ ↓ │
    │ 我 喜欢 人工智能 │
    └──────────────────────────────┘

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


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

    现在我们已经知道:

    Attention

    可以让不同 Token 建立联系。

    但这里还有一个问题。

    假设输入:

    我 喜欢 你

    和:

    你 喜欢 我

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


    喜欢

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

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

    那么:

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

    这就是:

    Positional Encoding,位置编码。

    Transformer 不像 RNN。

    RNN 天然按照:

    第一个

    第二个

    第三个

    的顺序进行计算。

    因此:

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

    但是 Transformer 可以并行处理:

    Token 1
    Token 2
    Token 3
    Token 4

    这意味着:

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

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

    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 的整体流程串起来了。

    输入序列

    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 简化成:

    Embedding

    把 Token 转换成向量

    Positional Encoding

    告诉模型 Token 的位置

    Attention

    建立 Token 之间的关系

    FFN

    进一步处理 Token 表示

    Residual + LayerNorm

    帮助深层网络稳定训练

    Encoder

    理解输入

    Decoder

    生成输出


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

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

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

    答案是:

    不完全是。

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

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

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

    Encoder-only
    Decoder-only
    Encoder-Decoder

    例如:

    Encoder-only

    典型代表:

    BERT

    主要使用 Transformer Encoder。

    更擅长:

    文本理解
    文本分类
    命名实体识别


    Decoder-only

    典型代表:

    GPT

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

    更擅长:

    文本生成
    对话
    代码生成

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

    Decoder-only Transformer。


    Encoder-Decoder

    典型代表:

    T5

    更适合:

    机器翻译
    文本摘要
    输入序列 → 输出序列

    所以:

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

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

    不同模型可以根据任务:

    只使用 Encoder

    只使用 Decoder

    或者同时使用 Encoder + Decoder

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


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

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

    Q、K、V

    也没有真正计算:

    Attention Score

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

    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 架构。

    其中:

    Encoder

    负责:

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

    而:

    Decoder

    负责:

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

    一个典型的 Encoder Block 包含:

    Multi-Head Self-Attention

    Add & Norm

    Feed Forward Network

    Add & Norm

    而 Decoder Block 则比 Encoder 多出了:

    Masked Self-Attention

    以及:

    Encoder-Decoder Attention

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

    Positional Encoding。

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

    Token

    Embedding

    加入位置信息

    Attention 建立关系

    FFN 进一步处理

    多层 Block 不断提取信息

    完成理解或生成任务


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

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

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

    Attention 到底是怎么工作的?

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

    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。

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

    Q 到底是什么?
    K 到底是什么?
    V 又是什么?

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

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

    赞(0)
    未经允许不得转载:171主机测评 » 深入理解 Transformer:Transformer 究竟是什么?
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址