文章目录
- 为什么需要位置编码?
- 预备知识
- 三角函数求和公式
- 旋转矩阵
- 逆时针旋转
- 顺时针旋转
- 原始Transformer中的位置编码
- 论文中的介绍
- 具体计算过程
- 为什么是线性变换?
- 大模型常用的旋转位置编码RoPE
- 基本原理
- Llama3中的代码实现
- 参考资料
为什么需要位置编码?
众所周知,老生常谈,Transformer模型的核心是自注意力机制(Self-Attention),这一机制的特点是输入序列中的所有元素都是同时被处理的,而不是像RNN那样按顺序处理。这种并行处理的方式虽然具有很高的效率,但也导致了模型无法自然地获取输入序列中元素的位置信息。
比如,自注意力机制在处理 AI 好 难 学
和 难 学 好 AI
这两个元素相同,但是位置不同的序列时,得到的每个元素对应的attention值是相同的,也没办法区分。
因此,Positional Encoding 的作用,就是在把 Word Embedding 送入 Attention 之前,把位置信息给带上,使得模型能够在进行自注意力计算时感知到输入元素的相对和绝对位置。
网络社区中对 Positional Encoding 分类的方法很多,按照不同的分类方法划分,大致可以分为:
- 绝对位置编码和相对位置编码:
- 绝对位置编码,为输入序列中的每个位置提供一个唯一的表示,通常是通过预定义的方法生成,并直接添加到输入表示中
- 相对位置编码,是对两个单词之间的相对位置进行建模,并且将相对位置信息加入到Self-Attention结构中,形如Transformer-XL,DeBERTa等采用的就是相对位置编码。Self-Attention的本质是两个单词信息的内积操作,相对位置编码的思想是对内积的计算方式进行改进,在内积中注入两个单词的相对位置因素
- 固定式位置编码和可学习式位置编码:
- 这种分类方式,说的是 绝对位置编码 的不同实现方式
- 固定位置编码,主要是 Transformer论文中提出的正弦和余弦位置编码(Sinusoidal Positional Encoding)方法,使用正弦和余弦函数生成不同频率的编码
- 可学习式位置编码,没有固定的位置编码公式,通过初始化位置向量让模型根据上下文数据自适应地学习出来,Bert和GPT采用的就是可学习式
- 绝对位置编码添加的位置不同:
- 绝对位置编码加在 Transformer 的输入端,典型代表是绝对位置编码( Sinusoidal 位置编码和可学习位置编码 )
- 绝对位置编码乘在 q , k , v q, k, v q,k,v,典型代表是 RoPE 位置编码
- 相对位置编码加在注意力权重 q T k q^{T}k qTk,典型代表是 ALiBi 位置编码
根据本人面试经历,只要是和Positional Encoding相关的问题,基本都是 Transformer论文中提出的正弦和余弦位置编码,以及目前大模型常用的RoPE,这两个方法。因此,本文主要以这两个方法为例来深入讨论。
预备知识
三角函数求和公式
s
i
n
(
α
+
β
)
=
s
i
n
α
∗
C
o
s
β
+
c
o
s
α
∗
S
i
n
β
\rm{sin}(\alpha+\beta) = sin\alpha*Cos\beta + cos\alpha * Sin\beta
sin(α+β)=sinα∗Cosβ+cosα∗Sinβ
s
i
n
(
α
−
β
)
=
s
i
n
α
∗
C
o
s
β
−
c
o
s
α
∗
S
i
n
β
\rm{sin}(\alpha-\beta) = sin\alpha*Cos\beta - cos\alpha * Sin\beta
sin(α−β)=sinα∗Cosβ−cosα∗Sinβ
c
o
s
(
α
+
β
)
=
c
o
s
α
∗
c
o
s
β
−
s
i
n
α
∗
S
i
n
β
\rm{cos}(\alpha+\beta) = cos\alpha*cos\beta - sin\alpha * Sin\beta
cos(α+β)=cosα∗cosβ−sinα∗Sinβ
c
o
s
(
α
−
β
)
=
c
o
s
α
∗
c
o
s
β
+
s
i
n
α
∗
S
i
n
β
\rm{cos}(\alpha-\beta) = cos\alpha*cos\beta + sin\alpha * Sin\beta
cos(α−β)=cosα∗cosβ+sinα∗Sinβ
旋转矩阵
逆时针旋转
假设向量
a
,
b
\bold{a}, \bold{b}
a,b的长度均为1,将
a
\bold{a}
a逆时针旋转
θ
\theta
θ角度,变成
b
\bold{b}
b的过程如下:
a
=
[
c
o
s
μ
,
s
i
n
μ
\bold{a} = [\rm{cos}\mu, sin\mu
a=[cosμ,sinμ]
b
=
[
c
o
s
(
μ
+
θ
)
,
s
i
n
(
μ
+
θ
)
\bold{b} = [\rm{cos}(\mu+\theta), sin(\mu+\theta)
b=[cos(μ+θ),sin(μ+θ)]
根据上面的三角函数求和公式可得:
b
=
[
c
o
s
θ
c
o
s
μ
−
s
i
n
θ
s
i
n
μ
,
s
i
n
μ
c
o
s
θ
+
c
o
s
μ
s
i
n
θ
\bold{b} = [\rm{cos}\theta cos\mu - sin\theta sin\mu,sin\mu cos\theta + cos\mu sin\theta
b=[cosθcosμ−sinθsinμ,sinμcosθ+cosμsinθ]
这里我们用矩阵乘来简化计算:
b
T
=
[
c
o
s
θ
−
s
i
n
θ
s
i
n
θ
c
o
s
θ
]
[
c
o
s
μ
s
i
n
μ
]
\bold{b}^{\rm{T}} = \begin{bmatrix} \rm{cos}\theta & -sin\theta \\ sin\theta & \rm{cos}\theta \end{bmatrix} \begin{bmatrix} \rm{cos}\mu \\ sin\mu \end{bmatrix}
bT=[cosθsinθ−sinθcosθ][cosμsinμ]
因此,逆时针的旋转矩阵为: [ c o s θ − s i n θ s i n θ c o s θ ] \begin{bmatrix} \rm{cos}\theta & -sin\theta \\ sin\theta & \rm{cos}\theta \end{bmatrix} [cosθsinθ−sinθcosθ]
顺时针旋转
假设向量
a
,
b
\bold{a}, \bold{b}
a,b的长度均为1,将
a
\bold{a}
a顺时针旋转
θ
\theta
θ角度,变成
b
\bold{b}
b的过程如下:
a
=
[
c
o
s
μ
,
s
i
n
μ
\bold{a} = [\rm{cos}\mu, sin\mu
a=[cosμ,sinμ]
b
=
[
c
o
s
(
μ
−
θ
)
,
s
i
n
(
μ
−
θ
)
\bold{b} = [\rm{cos}(\mu-\theta), sin(\mu-\theta)
b=[cos(μ−θ),sin(μ−θ)]
根据上面的三角函数求和公式可得:
b
=
[
c
o
s
θ
c
o
s
μ
+
s
i
n
θ
s
i
n
μ
,
s
i
n
μ
c
o
s
θ
−
c
o
s
μ
s
i
n
θ
\bold{b} = [\rm{cos}\theta cos\mu + sin\theta sin\mu,sin\mu cos\theta - cos\mu sin\theta
b=[cosθcosμ+sinθsinμ,sinμcosθ−cosμsinθ]
这里我们用矩阵乘来简化计算:
b
T
=
[
c
o
s
θ
s
i
n
θ
−
s
i
n
θ
c
o
s
θ
]
[
c
o
s
μ
s
i
n
μ
]
\bold{b}^{\rm{T}} = \begin{bmatrix} \rm{cos}\theta & sin\theta \\ -sin\theta & \rm{cos}\theta \end{bmatrix} \begin{bmatrix} \rm{cos}\mu \\ sin\mu \end{bmatrix}
bT=[cosθ−sinθsinθcosθ][cosμsinμ]
因此,顺时针的旋转矩阵为: [ c o s θ s i n θ − s i n θ c o s θ ] \begin{bmatrix} \rm{cos}\theta & sin\theta \\ -sin\theta & \rm{cos}\theta \end{bmatrix} [cosθ−sinθsinθcosθ]
原始Transformer中的位置编码
论文中的介绍
首先贴上Transformer论文中,对于Positional Encoding部分的全部介绍:
我真的服了,这么重要的位置编码,论文里就写了这么一点??现在看来,内容虽然少,但是句句都是关键,每一句都是面试官想要考你的点,蚌埠住了!
回到正题,论文里面对Positional Encoding的描述主要有以下几个点:
- 位置编码的维度和token的embedding的维度一致,所以可以直接add
- 位置编码的具体实现方式是:
sine and cosine functions of different frequencies
,也就是同时使用正弦函数和余弦函数来表示每个token的绝对位置 - 在
sine and cosine functions of different frequencies
中,包括两个关键变量,一个是pos
,表示 是哪个token,另一个是i
,表示token中不同embedding的位置 - 使用这种正余弦位置编码的方式,可以在计算attention时,很轻松的学习
relative positions
,也就是相对位置,理由是, P E p o s + k PE_{pos+k} PEpos+k可以表示为 P E p o s PE_{pos} PEpos的线性变换!!(其实就是旋转矩阵) - 选择正余弦位置编码方式,也是因为它可以允许模型外推到,比训练期间遇到的序列长度更长的序列长度,这个特性对于扩大模型推理时的长度非常友好!!
具体计算过程
下面,让我们通过一个具体的示例,来理解Transformer论文的正余弦位置编码,到底是怎么计算的?(参考这篇blog)
假设我们的输入如下,第一行是输入文本,第二行tokenization后的tokens,最后是每个token对应的embedding(维度是5):
首先,对于pos=0
的token5
(对应text为When
)来说,计算它的 位置编码 方式如下:
可以看到,token的每个维度,都会计算一个位置编码,对于维度位置i
为奇数,使用sin
函数来计算,对于偶数,则使用cos
函数来计算。这和论文中的PE
计算公式一致
同理,对于所有输入tokens,分别计算他们的位置编码:
这里可以感觉出来,越靠前的token计算的位置编码,他们使用的正余弦函数的频率越大,振荡的越快,相反,越往后的tokne,在embedding维度上振荡越慢,大概如下图所示:
为什么是线性变换?
到这里,相信大家对Transformer论文的正余弦位置编码的计算过程,有了一个清晰的理解。现在来思考论文中的一个点:为什么 P E p o s + k PE_{pos+k} PEpos+k可以表示为 P E p o s PE_{pos} PEpos的线性变换?
大模型常用的旋转位置编码RoPE
基本原理
Llama3中的代码实现
参考资料
- [1] https://note.mowen.cn/note/detail?noteUuid=Q2_oDhFEqD2pD8Iv4uSzn
- [2] https://note.mowen.cn/note/detail?noteUuid=waAeRtCgZXLO62f9RhUWa
- [3] https://www.bilibili.com/video/BV1F1421B7iv/?share_source=copy_web&vd_source=79b1ab42a5b1cccc2807bc14de489fa7
- [4] https://www.jianshu.com/p/e8be3dbfb4c5
- [5] https://blog.csdn.net/BIT_Legend/article/details/137042032
- [6] https://medium.com/@fareedkhandev/understanding-transformers-a-step-by-step-math-example-part-1-a7809015150a