欢迎光临
我们一直在努力

深入理解 Transformer:理解顺序Positional Encoding

前言

在前面的文章中,我们已经逐步解决了 Transformer 中一个非常核心的问题。

首先,我们在第一篇中讨论了为什么传统的 RNN、LSTM 在处理长距离依赖和并行计算时存在局限,因此需要一种能够直接建立任意 Token 之间联系的机制。

随后,我们进入 Transformer 的核心。

我们先理解了 Self-Attention,知道了 Query、Key、Value 是如何计算的:

Q

=

X

W

Q

Q=XW_Q

Q=XWQ

K

=

X

W

K

K=XW_K

K=XWK

V

=

X

W

V

V=XW_V

V=XWV

然后通过 Scaled Dot-Product Attention 计算 Token 之间的关联:

Attention

(

Q

,

K

,

V

)

=

softmax

(

Q

K

T

d

k

)

V

\\operatorname{Attention}(Q,K,V)= \\operatorname{softmax} \\left( \\frac{QK^T}{\\sqrt{d_k}} \\right)V

Attention(Q,K,V)=softmax(dk

QKT)V

在上一篇文章中,我们又进一步理解了 Multi-Head Attention。

如果只有一个 Attention,模型只能在一个表示空间中建立 Token 之间的关系,而 Multi-Head Attention 则把这种能力扩展到了多个不同的表示子空间:

MultiHead

(

Q

,

K

,

V

)

=

Concat

(

head

1

,

,

head

h

)

W

O

\\operatorname{MultiHead}(Q,K,V)= \\operatorname{Concat} \\left( \\operatorname{head}_1, \\ldots, \\operatorname{head}_h \\right) W^O

MultiHead(Q,K,V)=Concat(head1,,headh)WO

到这里,看起来 Transformer 已经能够很好地理解一句话了。

但是仔细想一想,我们会发现一个非常奇怪的问题:

Transformer 真的知道一个 Token 在句子中的位置吗?

例如:

我 喜欢 你

和:

你 喜欢 我

两个句子使用的是完全相同的三个 Token,只是顺序发生了变化。

但是它们表达的意思显然不同。

如果模型不知道 Token 的位置,那么它又怎么知道谁在前面、谁在后面、谁是第一个词、谁是第二个词?

这就是这一篇我们要解决的问题。

答案就是:

Positional Encoding,位置编码。


目录

  • 一、为什么 Transformer 需要位置编码?
    • 1. Self-Attention 本身不知道顺序
    • 2. 一个非常直观的例子
  • 二、位置编码到底是什么?
    • 1. 给每一个位置一个向量
    • 2. 为什么可以直接相加?
  • 三、Transformer 原论文中的位置编码
    • 1.

      p

      o

      s

      pos

      pos 是什么?

    • 2.

      i

      i

      i 是什么?

    • 3. 为什么要使用正弦和余弦?
  • 四、为什么不同维度要使用不同频率?
  • 五、正弦位置编码为什么能够帮助模型理解相对位置?
  • 六、绝对位置编码和可学习位置编码
    • 1. Sinusoidal Encoding:固定位置编码
    • 2. Learned Positional Embedding:可学习位置编码
    • 3. 两种方法有什么区别?
  • 七、从绝对位置到相对位置
  • 八、RoPE:现代大语言模型中的重要位置表示方法
  • 九、位置编码放在哪里?
  • 十、把前面五篇文章串起来
  • 十一、这一篇最应该记住的内容
  • 结语:Attention 有了,顺序也有了,那么一个 Transformer Block 还缺什么?

一、为什么 Transformer 需要位置编码?

1. Self-Attention 本身不知道顺序

这是理解位置编码最关键的一点。

我们之前讲 Self-Attention 的时候,一直在讨论:

一个 Token 应该关注哪些 Token?

例如:

小明 喜欢 吃 苹果

在 Self-Attention 中,“吃”可以关注“小明”,也可以关注“苹果”。

但是 Attention 做的事情本质上是计算 Token 之间的相关程度。

它看到的是:

Token 1
Token 2
Token 3
Token 4

以及它们对应的向量。

它本身并没有一个天然的机制告诉自己:

Token 1 是第 1 个
Token 2 是第 2 个
Token 3 是第 3 个
Token 4 是第 4 个

这和 RNN 有一个非常明显的区别。

RNN 天然按照顺序处理:

第一个 Token

第二个 Token

第三个 Token

第四个 Token

因此“前后顺序”本身就存在于 RNN 的计算过程里。

而 Transformer 的 Self-Attention 更像是:

Token 1 ─┐
Token 2 ─┤
Token 3 ─┼──→ 同时进行关系计算
Token 4 ─┤
Token 5 ─┘

所有 Token 可以并行参与计算。

这带来了 Transformer 非常重要的并行计算能力,但也带来了一个新的问题:

既然所有 Token 可以同时处理,那么顺序信息从哪里来?


2. 一个非常直观的例子

假设我们有两个句子:

我 喜欢 你

和:

你 喜欢 我

假设暂时不考虑位置,只看 Token:

句子 A:


喜欢

句子 B:


喜欢

两个句子包含完全相同的 Token。

如果模型只有 Token Embedding,而没有任何位置信息,那么模型很难仅仅根据这些 Token 向量知道它们的排列顺序。

我们可以把这个问题理解成:

Token Embedding:

我 → [向量]
喜欢 → [向量]
你 → [向量]

这些向量只描述“这个 Token 是谁”,并没有描述:

它现在位于什么位置?

所以我们还需要额外的信息:

我 + 位置 1
喜欢 + 位置 2
你 + 位置 3

这样模型才能同时知道:

Token 是什么
+
Token 在哪里

这就是位置编码要解决的问题。


下面用一张图对比 RNN 与 Transformer 在处理顺序信息时的本质区别:

#mermaid-svg-XY9xtX0QpmkeuUDk{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-XY9xtX0QpmkeuUDk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XY9xtX0QpmkeuUDk .error-icon{fill:#552222;}#mermaid-svg-XY9xtX0QpmkeuUDk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XY9xtX0QpmkeuUDk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XY9xtX0QpmkeuUDk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XY9xtX0QpmkeuUDk .marker.cross{stroke:#333333;}#mermaid-svg-XY9xtX0QpmkeuUDk svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XY9xtX0QpmkeuUDk p{margin:0;}#mermaid-svg-XY9xtX0QpmkeuUDk .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster-label text{fill:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster-label span{color:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster-label span p{background-color:transparent;}#mermaid-svg-XY9xtX0QpmkeuUDk .label text,#mermaid-svg-XY9xtX0QpmkeuUDk span{fill:#333;color:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk .node rect,#mermaid-svg-XY9xtX0QpmkeuUDk .node circle,#mermaid-svg-XY9xtX0QpmkeuUDk .node ellipse,#mermaid-svg-XY9xtX0QpmkeuUDk .node polygon,#mermaid-svg-XY9xtX0QpmkeuUDk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XY9xtX0QpmkeuUDk .rough-node .label text,#mermaid-svg-XY9xtX0QpmkeuUDk .node .label text,#mermaid-svg-XY9xtX0QpmkeuUDk .image-shape .label,#mermaid-svg-XY9xtX0QpmkeuUDk .icon-shape .label{text-anchor:middle;}#mermaid-svg-XY9xtX0QpmkeuUDk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XY9xtX0QpmkeuUDk .rough-node .label,#mermaid-svg-XY9xtX0QpmkeuUDk .node .label,#mermaid-svg-XY9xtX0QpmkeuUDk .image-shape .label,#mermaid-svg-XY9xtX0QpmkeuUDk .icon-shape .label{text-align:center;}#mermaid-svg-XY9xtX0QpmkeuUDk .node.clickable{cursor:pointer;}#mermaid-svg-XY9xtX0QpmkeuUDk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XY9xtX0QpmkeuUDk .arrowheadPath{fill:#333333;}#mermaid-svg-XY9xtX0QpmkeuUDk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XY9xtX0QpmkeuUDk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XY9xtX0QpmkeuUDk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XY9xtX0QpmkeuUDk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XY9xtX0QpmkeuUDk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XY9xtX0QpmkeuUDk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster text{fill:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk .cluster span{color:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk 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-XY9xtX0QpmkeuUDk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XY9xtX0QpmkeuUDk rect.text{fill:none;stroke-width:0;}#mermaid-svg-XY9xtX0QpmkeuUDk .icon-shape,#mermaid-svg-XY9xtX0QpmkeuUDk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XY9xtX0QpmkeuUDk .icon-shape p,#mermaid-svg-XY9xtX0QpmkeuUDk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XY9xtX0QpmkeuUDk .icon-shape .label rect,#mermaid-svg-XY9xtX0QpmkeuUDk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XY9xtX0QpmkeuUDk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XY9xtX0QpmkeuUDk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XY9xtX0QpmkeuUDk :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Transformer:并行处理

Token 1

同时进行关系计算

Token 2

Token 3

Token 4

RNN:串行处理

第一个 Token

第二个 Token

第三个 Token

第四个 Token

顺序信息从哪里来?

需要引入位置编码

二、位置编码到底是什么?

1. 给每一个位置一个向量

最直观的理解就是:

给句子中的每一个位置分配一个位置向量。

例如:

第 0 个位置 → P0
第 1 个位置 → P1
第 2 个位置 → P2
第 3 个位置 → P3

与此同时,每个 Token 本身也有一个 Embedding:

我 → E我
喜欢 → E喜欢
你 → E你

于是我们把两种信息结合起来:

Token Embedding
+
Position Encoding

Transformer 输入

数学上可以简单表示为:

X

=

E

+

P

X=E+P

X=E+P

其中:

  • E

    E

    E 表示 Token Embedding

  • P

    P

    P 表示 Position Encoding

  • X

    X

    X 表示最终输入 Transformer 的表示

对于第

i

i

i 个 Token:

X

i

=

E

i

+

P

i

X_i=E_i+P_i

Xi=Ei+Pi

这样 Transformer 看到的就不再只是“我”这个 Token,而是一个同时携带 Token 内容和位置信息的向量。


2. 为什么可以直接相加?

可能有人会产生一个疑问:

Token Embedding 和 Position Encoding 是两种完全不同的信息,为什么可以直接相加?

关键就在于:

它们通常具有相同的维度。

假设模型的隐藏维度是:

d

model

=

512

d_{\\text{model}}=512

dmodel=512

那么:

Token Embedding:

[512 维]

位置编码:

[512 维]

于是可以直接进行逐元素相加:

X

i

=

E

i

+

P

i

X_i=E_i+P_i

Xi=Ei+Pi

得到的仍然是一个 512 维向量。

这样做的好处是非常简单。

我们不需要把:

Token Embedding
+
Position Encoding

拼成一个更大的向量。

否则维度会变成:

512

+

512

=

1024

512+512=1024

512+512=1024

而直接相加之后:

512

+

512

512

512+512\\rightarrow512

512+512512

模型的整体维度保持不变。

更重要的是,经过后续的线性层和 Attention 计算,模型可以逐渐学会如何从这个组合向量中利用 Token 信息和位置信息。


下面这张图展示了位置编码与 Token Embedding 融合后输入 Transformer 的完整过程:

#mermaid-svg-QHRXFg3XJ7Zty5Jn{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-QHRXFg3XJ7Zty5Jn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .error-icon{fill:#552222;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .marker.cross{stroke:#333333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn p{margin:0;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster-label text{fill:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster-label span{color:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster-label span p{background-color:transparent;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .label text,#mermaid-svg-QHRXFg3XJ7Zty5Jn span{fill:#333;color:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .node rect,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node circle,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node ellipse,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node polygon,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .rough-node .label text,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node .label text,#mermaid-svg-QHRXFg3XJ7Zty5Jn .image-shape .label,#mermaid-svg-QHRXFg3XJ7Zty5Jn .icon-shape .label{text-anchor:middle;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .rough-node .label,#mermaid-svg-QHRXFg3XJ7Zty5Jn .node .label,#mermaid-svg-QHRXFg3XJ7Zty5Jn .image-shape .label,#mermaid-svg-QHRXFg3XJ7Zty5Jn .icon-shape .label{text-align:center;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .node.clickable{cursor:pointer;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .arrowheadPath{fill:#333333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QHRXFg3XJ7Zty5Jn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QHRXFg3XJ7Zty5Jn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster text{fill:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .cluster span{color:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn 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-QHRXFg3XJ7Zty5Jn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QHRXFg3XJ7Zty5Jn rect.text{fill:none;stroke-width:0;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .icon-shape,#mermaid-svg-QHRXFg3XJ7Zty5Jn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .icon-shape p,#mermaid-svg-QHRXFg3XJ7Zty5Jn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .icon-shape .label rect,#mermaid-svg-QHRXFg3XJ7Zty5Jn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QHRXFg3XJ7Zty5Jn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QHRXFg3XJ7Zty5Jn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QHRXFg3XJ7Zty5Jn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Token 输入

Token Embedding

Position Encoding

逐元素相加

X = E + P

Transformer

Multi-Head Attention

三、Transformer 原论文中的位置编码

讲到位置编码,就绕不开 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)

第一次看到这个公式可能会觉得非常复杂。

不要急。

我们把它一点一点拆开。


1.

p

o

s

pos

pos 是什么?

p

o

s

pos

pos 就是 Token 所在的位置。

例如:

我 喜欢 学习 Transformer

0 1 2 3

那么:

我 → pos = 0
喜欢 → pos = 1
学习 → pos = 2
Transformer → pos = 3

这里的编号从 0 开始还是从 1 开始并不是最重要的。

真正重要的是:

不同位置必须能够产生不同的位置表示。


2.

i

i

i 是什么?

i

i

i 可以理解成位置向量中的维度索引。

假设:

d

model

=

8

d_{\\text{model}}=8

dmodel=8

那么一个位置编码可以写成:

[PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7]

这里的

i

i

i 就是在控制我们正在计算哪一组维度。

正弦函数负责偶数维:

P

E

(

p

o

s

,

2

i

)

PE_{(pos,2i)}

PE(pos,2i)

余弦函数负责奇数维:

P

E

(

p

o

s

,

2

i

+

1

)

PE_{(pos,2i+1)}

PE(pos,2i+1)

所以可以简单理解成:

偶数维 → sin
奇数维 → cos


3. 为什么要使用正弦和余弦?

我们当然可以直接写:

位置 0 → [0, 0, 0, 0, …]
位置 1 → [1, 1, 1, 1, …]
位置 2 → [2, 2, 2, 2, …]

但是这种方式比较简单粗暴。

Transformer 原论文选择了一组具有不同频率的正弦和余弦函数。

你可以把它理解成:

位置

多个不同频率的波

每个位置得到一个独特的组合

形成位置向量

例如:

维度 0:变化比较快
维度 1:变化比较快

维度 2:变化慢一些
维度 3:变化慢一些

维度 4:变化更慢
维度 5:变化更慢

最终一个位置会得到一组正弦、余弦值。

虽然每一维都只是一个简单的周期函数,但是把很多不同频率组合起来以后,就能够形成丰富的位置表示。


下面这张图展示了位置编码在 Transformer 中的具体位置:

#mermaid-svg-r7xaFm7XtBakr4O2{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-r7xaFm7XtBakr4O2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-r7xaFm7XtBakr4O2 .error-icon{fill:#552222;}#mermaid-svg-r7xaFm7XtBakr4O2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-r7xaFm7XtBakr4O2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-r7xaFm7XtBakr4O2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-r7xaFm7XtBakr4O2 .marker.cross{stroke:#333333;}#mermaid-svg-r7xaFm7XtBakr4O2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-r7xaFm7XtBakr4O2 p{margin:0;}#mermaid-svg-r7xaFm7XtBakr4O2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster-label text{fill:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster-label span{color:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster-label span p{background-color:transparent;}#mermaid-svg-r7xaFm7XtBakr4O2 .label text,#mermaid-svg-r7xaFm7XtBakr4O2 span{fill:#333;color:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 .node rect,#mermaid-svg-r7xaFm7XtBakr4O2 .node circle,#mermaid-svg-r7xaFm7XtBakr4O2 .node ellipse,#mermaid-svg-r7xaFm7XtBakr4O2 .node polygon,#mermaid-svg-r7xaFm7XtBakr4O2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-r7xaFm7XtBakr4O2 .rough-node .label text,#mermaid-svg-r7xaFm7XtBakr4O2 .node .label text,#mermaid-svg-r7xaFm7XtBakr4O2 .image-shape .label,#mermaid-svg-r7xaFm7XtBakr4O2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-r7xaFm7XtBakr4O2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-r7xaFm7XtBakr4O2 .rough-node .label,#mermaid-svg-r7xaFm7XtBakr4O2 .node .label,#mermaid-svg-r7xaFm7XtBakr4O2 .image-shape .label,#mermaid-svg-r7xaFm7XtBakr4O2 .icon-shape .label{text-align:center;}#mermaid-svg-r7xaFm7XtBakr4O2 .node.clickable{cursor:pointer;}#mermaid-svg-r7xaFm7XtBakr4O2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-r7xaFm7XtBakr4O2 .arrowheadPath{fill:#333333;}#mermaid-svg-r7xaFm7XtBakr4O2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-r7xaFm7XtBakr4O2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-r7xaFm7XtBakr4O2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r7xaFm7XtBakr4O2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-r7xaFm7XtBakr4O2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r7xaFm7XtBakr4O2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster text{fill:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 .cluster span{color:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 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-r7xaFm7XtBakr4O2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-r7xaFm7XtBakr4O2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-r7xaFm7XtBakr4O2 .icon-shape,#mermaid-svg-r7xaFm7XtBakr4O2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r7xaFm7XtBakr4O2 .icon-shape p,#mermaid-svg-r7xaFm7XtBakr4O2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-r7xaFm7XtBakr4O2 .icon-shape .label rect,#mermaid-svg-r7xaFm7XtBakr4O2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r7xaFm7XtBakr4O2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-r7xaFm7XtBakr4O2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-r7xaFm7XtBakr4O2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

输入 Token

Token Embedding

Position Encoding

相加

Transformer

Multi-Head Attention

FFN

下一层

四、为什么不同维度要使用不同频率?

现在我们再回头看公式:

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)

最值得注意的就是:

10000

2

i

d

model

10000^{\\frac{2i}{d_{\\text{model}}}}

10000dmodel2i

它会随着维度

i

i

i 的变化而变化。

于是不同维度对应不同的变化频率。

可以粗略理解成:

低维:

变化快
~~~~~~~

高维:

变化慢
~~~~~~~~~~~~~~

这样做有什么好处?

假设所有维度都使用完全相同的频率:

维度 0 → 快
维度 1 → 快
维度 2 → 快
维度 3 → 快

那么很多维度实际上是在重复表达类似的信息。

而使用不同频率之后:

维度 0 → 高频
维度 1 → 高频

维度 2 → 中高频
维度 3 → 中高频

维度 4 → 中低频
维度 5 → 中低频

维度 6 → 低频
维度 7 → 低频

不同维度就能够从不同尺度描述位置信息。

可以把它理解成:

有些维度负责观察位置的细微变化,有些维度负责观察更大范围的位置变化。

多个不同频率组合起来,就形成了一个更加丰富的位置表示。


五、正弦位置编码为什么能够帮助模型理解相对位置?

这是理解 Sinusoidal Positional Encoding 时非常值得注意的地方。

假设我们有:

P

E

(

p

o

s

)

PE(pos)

PE(pos)

和:

P

E

(

p

o

s

+

k

)

PE(pos+k)

PE(pos+k)

我们希望模型不仅能够知道:

这是第 10 个位置
这是第 20 个位置

还能够在某种程度上学习:

两个位置之间相差 10

正弦和余弦函数具有非常好的数学性质。

利用三角函数的和角公式:

sin

(

a

+

b

)

=

sin

a

cos

b

+

cos

a

sin

b

\\sin(a+b)= \\sin a\\cos b + \\cos a\\sin b

sin(a+b)=sinacosb+cosasinb

以及:

cos

(

a

+

b

)

=

cos

a

cos

b

sin

a

sin

b

\\cos(a+b)= \\cos a\\cos b- \\sin a\\sin b

cos(a+b)=cosacosbsinasinb

可以发现:

如果知道某个位置的正弦和余弦表示,那么移动固定距离

k

k

k 后的位置,可以通过固定的变换关系得到。

这意味着:

位置编码不仅可以表示绝对位置,还能够让模型比较容易地学习位置之间的相对关系。

这里不需要把数学推导全部展开。

真正需要理解的是:

位置 10

一组波形值

位置 11

另一组波形值

位置 12

继续变化

由于这些变化是连续的,所以相邻位置的表示也具有连续变化的特征。


六、绝对位置编码和可学习位置编码

讲到这里,我们需要区分两个概念。

一种是:

固定的位置编码。

另一种是:

可学习的位置编码。

1. Sinusoidal Encoding:固定位置编码

Transformer 原论文使用的就是前面介绍的正弦余弦位置编码。

它的特点是:

位置

数学公式计算

得到位置向量

这些位置向量并不是通过训练得到的。

也就是说,模型训练过程中不会去更新这些位置编码本身。

它们由公式直接计算出来。


2. Learned Positional Embedding:可学习位置编码

另一种方式则更加直接。

我们可以像 Token Embedding 一样,创建一个位置 Embedding 表:

Position 0 → 可学习向量
Position 1 → 可学习向量
Position 2 → 可学习向量
Position 3 → 可学习向量

例如:

位置 0 → P0
位置 1 → P1
位置 2 → P2

这些

P

i

P_i

Pi 本身就是模型参数。

训练过程中,它们会随着梯度下降不断更新。

于是:

Token Embedding
+
可学习 Position Embedding

Transformer

这种方式非常直观。

模型可以自己学习什么样的位置表示对于当前任务最有用。


3. 两种方法有什么区别?

可以简单整理成:

方式位置向量怎么得到是否训练特点
Sinusoidal 数学公式计算 固定、简单、具有连续变化特征
Learned 参数表 灵活,由模型自己学习

这里不能简单说哪一种“绝对更好”。

因为不同模型、不同架构会选择不同的位置表示方式。

而且随着 Transformer 不断发展,位置编码本身也出现了很多新的方案。

例如现代大语言模型中经常出现的:

RoPE
Relative Position
ALiBi

它们都在尝试解决一个更深层的问题:

模型到底应该如何表示 Token 之间的位置关系?


七、从绝对位置到相对位置

我们前面讨论的经典位置编码,本质上是在告诉模型:

Token A:

我位于第 10 个位置

这属于绝对位置。

但是对于语言模型来说,很多时候真正重要的并不是:

你是第 10 个 Token

而是:

你和我之间距离是多少?

例如:

小明 喜欢 吃 苹果

如果当前 Token 是:

苹果

那么:

就在它前面一个位置。

而:

喜欢

就在它前面两个位置。

对于很多语言关系来说:

相对距离

可能比:

绝对编号

更加重要。

因此后来的很多 Transformer 结构开始研究:

能不能直接把相对位置信息融入 Attention?

这就形成了相对位置编码等一系列方法。


八、RoPE:现代大语言模型中的重要位置表示方法

如果我们继续学习 GPT 一类的大语言模型,就会经常遇到一个名字:

RoPE,Rotary Positional Embedding,旋转位置编码。

这里先不急着深入数学推导,因为它涉及二维旋转以及复数表示等内容。

我们现在只需要建立一个基本认识:

传统位置编码更像是:

Token Embedding
+
Position Encoding

输入 Transformer

而 RoPE 的思路更加特别。

它不是简单地把一个位置向量加到 Token Embedding 上,而是:

根据 Token 所处的位置,对 Query 和 Key 的表示进行旋转。

可以简单理解为:

Query / Key

根据位置进行旋转

带有位置信息的 Q / K

计算 Attention

这样做的一个重要目的,就是让 Query 和 Key 的点积关系能够自然地包含相对位置信息。

这也是为什么当我们后面学习现代 GPT 类模型时,RoPE 会成为一个非常重要的概念。

现在暂时记住:

位置编码的发展路线,并不是简单地从“没有位置”到“加一个位置向量”就结束了,而是在不断探索如何让 Attention 更自然地理解相对位置。


下面这张图对比了传统位置编码与 RoPE 的核心区别:

#mermaid-svg-ks5hGsIYEUbpXr8K{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-ks5hGsIYEUbpXr8K .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ks5hGsIYEUbpXr8K .error-icon{fill:#552222;}#mermaid-svg-ks5hGsIYEUbpXr8K .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ks5hGsIYEUbpXr8K .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ks5hGsIYEUbpXr8K .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ks5hGsIYEUbpXr8K .marker.cross{stroke:#333333;}#mermaid-svg-ks5hGsIYEUbpXr8K svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ks5hGsIYEUbpXr8K p{margin:0;}#mermaid-svg-ks5hGsIYEUbpXr8K .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster-label text{fill:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster-label span{color:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster-label span p{background-color:transparent;}#mermaid-svg-ks5hGsIYEUbpXr8K .label text,#mermaid-svg-ks5hGsIYEUbpXr8K span{fill:#333;color:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K .node rect,#mermaid-svg-ks5hGsIYEUbpXr8K .node circle,#mermaid-svg-ks5hGsIYEUbpXr8K .node ellipse,#mermaid-svg-ks5hGsIYEUbpXr8K .node polygon,#mermaid-svg-ks5hGsIYEUbpXr8K .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ks5hGsIYEUbpXr8K .rough-node .label text,#mermaid-svg-ks5hGsIYEUbpXr8K .node .label text,#mermaid-svg-ks5hGsIYEUbpXr8K .image-shape .label,#mermaid-svg-ks5hGsIYEUbpXr8K .icon-shape .label{text-anchor:middle;}#mermaid-svg-ks5hGsIYEUbpXr8K .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ks5hGsIYEUbpXr8K .rough-node .label,#mermaid-svg-ks5hGsIYEUbpXr8K .node .label,#mermaid-svg-ks5hGsIYEUbpXr8K .image-shape .label,#mermaid-svg-ks5hGsIYEUbpXr8K .icon-shape .label{text-align:center;}#mermaid-svg-ks5hGsIYEUbpXr8K .node.clickable{cursor:pointer;}#mermaid-svg-ks5hGsIYEUbpXr8K .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ks5hGsIYEUbpXr8K .arrowheadPath{fill:#333333;}#mermaid-svg-ks5hGsIYEUbpXr8K .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ks5hGsIYEUbpXr8K .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ks5hGsIYEUbpXr8K .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ks5hGsIYEUbpXr8K .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ks5hGsIYEUbpXr8K .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ks5hGsIYEUbpXr8K .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster text{fill:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K .cluster span{color:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K 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-ks5hGsIYEUbpXr8K .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ks5hGsIYEUbpXr8K rect.text{fill:none;stroke-width:0;}#mermaid-svg-ks5hGsIYEUbpXr8K .icon-shape,#mermaid-svg-ks5hGsIYEUbpXr8K .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ks5hGsIYEUbpXr8K .icon-shape p,#mermaid-svg-ks5hGsIYEUbpXr8K .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ks5hGsIYEUbpXr8K .icon-shape .label rect,#mermaid-svg-ks5hGsIYEUbpXr8K .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ks5hGsIYEUbpXr8K .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ks5hGsIYEUbpXr8K .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ks5hGsIYEUbpXr8K :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

RoPE 旋转位置编码

Query / Key

根据位置进行旋转

带有位置信息的 Q / K

计算 Attention

传统位置编码

Token Embedding

+ Position Encoding

输入 Transformer

核心区别

RoPE 让点积关系自然包含相对位置信息

九、位置编码放在哪里?

我们现在知道位置编码要加入 Transformer。

但是它到底是在什么时候加入?

最经典的做法可以理解成:

输入 Token

Token Embedding

Position Encoding

相加

Transformer

Multi-Head Attention

FFN

下一层

数学上:

X

=

E

+

P

X=E+P

X=E+P

其中:

E

R

n

×

d

model

E\\in\\mathbb{R}^{n\\times d_{\\text{model}}}

ERn×dmodel

表示 Token Embedding。

位置编码则可以表示为:

P

R

n

×

d

model

P\\in\\mathbb{R}^{n\\times d_{\\text{model}}}

PRn×dmodel

所以:

X

R

n

×

d

model

X\\in\\mathbb{R}^{n\\times d_{\\text{model}}}

XRn×dmodel

这样就可以直接把

X

X

X 送入 Transformer。


十、把前面五篇文章串起来

到这里,我们已经可以把 Transformer 前面的几个核心概念真正串起来了。

最开始,我们遇到了 RNN 的问题:

序列计算

难以完全并行

长距离依赖困难

于是 Transformer 使用 Attention:

Token

Self-Attention

直接建立 Token 之间的关系

但是一个 Attention 可能不足以从多个角度表达复杂关系。

于是:

Self-Attention

Multi-Head Attention

多个表示空间

从多个角度建立关系

可是我们又发现:

Attention 本身不知道顺序

于是:

Token Embedding
+
Position Encoding

包含 Token 信息和位置信息

Multi-Head Attention

所以到这里,一个非常重要的 Transformer 输入过程就已经出现了:

Token

Token Embedding

┌────────┴────────┐
│ │
│ Position │
│ Encoding │
│ │
└────────┬────────┘

+

Transformer

Multi-Head Attention

现在我们终于可以回答最开始的问题:

Transformer 是如何理解顺序的?

答案是:

Self-Attention 本身没有天然的顺序概念,因此 Transformer 需要额外引入位置信息。经典 Transformer 使用正弦和余弦函数构造位置编码,并将它与 Token Embedding 融合,让后续的 Attention 在处理 Token 时能够同时利用内容信息和位置信息。


下面这张图把前面几篇文章的核心概念完整串联起来:

#mermaid-svg-rWM86DAdmzZCOogn{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-rWM86DAdmzZCOogn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rWM86DAdmzZCOogn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rWM86DAdmzZCOogn .error-icon{fill:#552222;}#mermaid-svg-rWM86DAdmzZCOogn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rWM86DAdmzZCOogn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rWM86DAdmzZCOogn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rWM86DAdmzZCOogn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rWM86DAdmzZCOogn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rWM86DAdmzZCOogn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rWM86DAdmzZCOogn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rWM86DAdmzZCOogn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rWM86DAdmzZCOogn .marker.cross{stroke:#333333;}#mermaid-svg-rWM86DAdmzZCOogn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rWM86DAdmzZCOogn p{margin:0;}#mermaid-svg-rWM86DAdmzZCOogn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-rWM86DAdmzZCOogn .cluster-label text{fill:#333;}#mermaid-svg-rWM86DAdmzZCOogn .cluster-label span{color:#333;}#mermaid-svg-rWM86DAdmzZCOogn .cluster-label span p{background-color:transparent;}#mermaid-svg-rWM86DAdmzZCOogn .label text,#mermaid-svg-rWM86DAdmzZCOogn span{fill:#333;color:#333;}#mermaid-svg-rWM86DAdmzZCOogn .node rect,#mermaid-svg-rWM86DAdmzZCOogn .node circle,#mermaid-svg-rWM86DAdmzZCOogn .node ellipse,#mermaid-svg-rWM86DAdmzZCOogn .node polygon,#mermaid-svg-rWM86DAdmzZCOogn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rWM86DAdmzZCOogn .rough-node .label text,#mermaid-svg-rWM86DAdmzZCOogn .node .label text,#mermaid-svg-rWM86DAdmzZCOogn .image-shape .label,#mermaid-svg-rWM86DAdmzZCOogn .icon-shape .label{text-anchor:middle;}#mermaid-svg-rWM86DAdmzZCOogn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rWM86DAdmzZCOogn .rough-node .label,#mermaid-svg-rWM86DAdmzZCOogn .node .label,#mermaid-svg-rWM86DAdmzZCOogn .image-shape .label,#mermaid-svg-rWM86DAdmzZCOogn .icon-shape .label{text-align:center;}#mermaid-svg-rWM86DAdmzZCOogn .node.clickable{cursor:pointer;}#mermaid-svg-rWM86DAdmzZCOogn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rWM86DAdmzZCOogn .arrowheadPath{fill:#333333;}#mermaid-svg-rWM86DAdmzZCOogn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rWM86DAdmzZCOogn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rWM86DAdmzZCOogn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rWM86DAdmzZCOogn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rWM86DAdmzZCOogn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rWM86DAdmzZCOogn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rWM86DAdmzZCOogn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rWM86DAdmzZCOogn .cluster text{fill:#333;}#mermaid-svg-rWM86DAdmzZCOogn .cluster span{color:#333;}#mermaid-svg-rWM86DAdmzZCOogn 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-rWM86DAdmzZCOogn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rWM86DAdmzZCOogn rect.text{fill:none;stroke-width:0;}#mermaid-svg-rWM86DAdmzZCOogn .icon-shape,#mermaid-svg-rWM86DAdmzZCOogn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rWM86DAdmzZCOogn .icon-shape p,#mermaid-svg-rWM86DAdmzZCOogn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rWM86DAdmzZCOogn .icon-shape .label rect,#mermaid-svg-rWM86DAdmzZCOogn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rWM86DAdmzZCOogn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rWM86DAdmzZCOogn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rWM86DAdmzZCOogn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

RNN 的局限

难以完全并行

长距离依赖困难

Transformer 使用 Attention

Self-Attention

Multi-Head Attention

Attention 不知道顺序

Token Embedding

Position Encoding

相加

包含 Token 信息和位置信息

Multi-Head Attention

十一、这一篇最应该记住的内容

如果这一篇只记住几个核心知识点,可以记住下面这些。

第一,Self-Attention 本身并不天然包含 Token 的顺序信息。

它擅长回答:

谁应该关注谁?

但并不会自动知道:

谁在第几个位置?

第二,因此 Transformer 需要额外加入位置表示。

最经典的输入形式是:

X

=

E

+

P

X=E+P

X=E+P

其中

E

E

E 是 Token Embedding,

P

P

P 是 Position Encoding。

第三,Transformer 原论文使用正弦和余弦构造位置编码:

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)

它通过不同频率的周期函数,为不同位置构造不同的向量表示。

第四,位置编码不仅仅是为了告诉模型:

“我是第几个 Token”

还希望让模型能够理解:

“两个 Token 之间相隔多远”

因此后来出现了越来越多关注相对位置信息的方法。

第五,现代 Transformer 和大语言模型已经不局限于最初的 Sinusoidal Positional Encoding,RoPE 等位置表示方法也成为现代架构中的重要组成部分。


结语:Attention 有了,顺序也有了,那么一个 Transformer Block 还缺什么?

到现在,我们已经把 Transformer 中最核心的一条主线建立起来了:

为什么需要 Transformer?

Self-Attention

Multi-Head Attention

Position Encoding

现在 Transformer 已经可以:

看到 Token

理解 Token 之间的关系

从多个角度提取信息

同时知道 Token 的位置信息

但是如果你回头看看 Transformer 的完整结构,就会发现还有几个非常重要的模块没有真正展开。

尤其是:

Multi-Head Attention

?

下一层 Transformer

Attention 得到的信息,究竟还要经过什么处理?

为什么 Transformer 中一定还有一个 Feed Forward Network,前馈神经网络?

为什么 Attention 后面总是能够看到:

Residual Connection
Layer Normalization
Feed Forward Network

这些模块到底分别在做什么?

如果说 Attention 负责的是:

让不同 Token 之间进行信息交流。

那么下一篇文章,我们就要继续研究:

Attention 得到信息之后,Transformer 又是如何对这些信息进行进一步加工的?

下一篇:

第六篇:FFN、残差连接与 LayerNorm——Attention 之后发生了什么?

赞(0)
未经允许不得转载:171主机测评 » 深入理解 Transformer:理解顺序Positional Encoding
分享到: 更多 (0)

评论 抢沙发

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