1、Transformer的位置编码
对于序列处理模型,他的位置信息需要通过显式或者隐式的方式传入给模型。
transformer 系列模型的位置编码常用包括:包括绝对位置编码(包括静态位置编码和可学习位置编码)、相对位置编码、旋转位置编码,下面详细介绍这种位置编码的原理和优缺点。
2、位置编码
(1)静态位置编码
transformer 原始位置编码方式,通过正弦/余弦函数得到位置编码,为什么要使用正余弦交替出现的方式来得到位置编码呐?
公式1
主要的考虑的点如下:
-
每个 token 的向量是唯一值;
-
利用三角函数做位置编码可以保证编码的值在 [-1,1] 之间,是有界函数;
-
不同的位置向量是可以通过线性变化得到的,这样 token 的位置信息不仅包含了绝对位置还包含了相对位置信息;
三角函数静态编码的重要性质如下图:
class SinPositionEncoding(nn.Module):
def __init__(self, max_sequence_length, d_model, base=10000):
super().__init__()
self.max_sequence_length = max_sequence_length
self.d_model = d_model
self.base = base
def forward(self):
pe = torch.zeros(self.max_sequence_length, self.d_model, dtype=torch.float) # size(max_sequence_length, d_model)
exp_1 = torch.arange(self.d_model // 2, dtype=torch.float) # 初始化一半维度,sin位置编码的维度被分为了两部分
exp_value = exp_1 / (self.d_model / 2)
alpha = 1 / (self.base ** exp_value) # size(dmodel/2)
out = torch.arange(self.max_sequence_length, dtype=torch.float)[:, None] @ alpha[None, :] # size(max_sequence_length, d_model/2)
embedding_sin = torch.sin(out)
embedding_cos = torch.cos(out)
pe[:, 0::2] = embedding_sin # 奇数位置设置为sin
pe[:, 1::2] = embedding_cos # 偶数位置设置为cos
return pe
SinPositionEncoding(d_model=4, max_sequence_length=10, base=10000).forward()

(2)可学习的位置编码
主要存在于 BERT、VIT 等变种系列模型,直接将位置作为可学习的参数,让模型自己学习。
class TrainablePositionEncoding(nn.Module):
def __init__(self, max_sequence_length, d_model):
super().__init__()
self.max_sequence_length = max_sequence_length
self.d_model = d_model
def forward(self):
pe = nn.Embedding(self.max_sequence_length, self.d_model)
nn.init.constant(pe.weight, 0.)
return pe
(3)相对位置编码
相对位置编码的实现可以参考这篇文章:鹅厂面试官:Transformer为何需要位置编码?
(4)旋转位置编码
旋转位置编码(Rotary Position Embedding,RoPE)是论文 Roformer: Enhanced Transformer With Rotray Position Embedding 提出的一种能够将相对位置信息依赖集成到 self-attention 中并提升 transformer 架构性能的位置编码方式。
而目前很火的 LLaMA、GLM 模型也是采用该位置编码方式。
和相对位置编码相比,RoPE 具有更好的外推性(在训练时和预测时的输入长度不一致,导致模型的泛化能力下降的问题),目前是大模型相对位置编码中应用最广的方式之一。
对于 self- attention 中的 KQV 通过如下方式得到:
其中 qm 表示第 m 个 token 对应的词向量 xm 集成位置信息 m 之后的 query 向量。
而 kn 和 vn 则表示第 n 个 token 对应的词向量 xn 集成位置信息 n 之后的 key 和 value 向量。
对于 transformer 的位置信息是三角函数,所以函数 f 为 x_m+p_i,其中 p_i 是根据公式 1 计算得到的;
对于 BERT 等可学习位置编码,它的f函数是 x_m+p_i,其中 p_i 是模型学习得到的;
对于图例如下:
# 旋转位置编码计算
def apply_rotary_emb(
xq: torch.Tensor,
xk: torch.Tensor,
freqs_cis: torch.Tensor,
) -> Tuple[torch.Tensor, torch.Tensor]:
# xq.shape = [batch_size, seq_len, dim]
# xq_.shape = [batch_size, seq_len, dim // 2, 2]
xq_ = xq.float().reshape(*xq.shape[:-1], -1, 2)
xk_ = xk.float().reshape(*xk.shape[:-1], -1, 2)
# 转为复数域
xq_ = torch.view_as_complex(xq_)
xk_ = torch.view_as_complex(xk_)
# 应用旋转操作,然后将结果转回实数域
# xq_out.shape = [batch_size, seq_len, dim]
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(2)
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(2)
return xq_out.type_as(xq), xk_out.type_as(xk)
class Attention(nn.Module):
def __init__(self, args: ModelArgs):
super().__init__()
self.wq = Linear(...)
self.wk = Linear(...)
self.wv = Linear(...)
self.freqs_cis = precompute_freqs_cis(dim, max_seq_len * 2)
def forward(self, x: torch.Tensor):
bsz, seqlen, _ = x.shape
xq, xk, xv = self.wq(x), self.wk(x), self.wv(x)
xq = xq.view(batch_size, seq_len, dim)
xk = xk.view(batch_size, seq_len, dim)
xv = xv.view(batch_size, seq_len, dim)
# attention 操作之前,应用旋转位置编码
xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)
# scores.shape = (bs, seqlen, seqlen)
scores = torch.matmul(xq, xk.transpose(1, 2)) / math.sqrt(dim)
scores = F.softmax(scores.float(), dim=-1)
output = torch.matmul(scores, xv) # (batch_size, seq_len, dim)
# ......
上面介绍了 transformer 处理序列时的常用位置编码,包括包括绝对位置编码(包括静态位置编码和可学习位置编码)、相对位置编码、旋转位置编码。
随着大模型的兴起,需要模型有更好的外推性,传统的相对和绝对位置编码无法满足时,LLM 是如何处理的。接下来我们介绍 LLM 中常用的位置编码。
位置编码的作用:
-
克服 transformer 的位置不变性,因为双向注意力是位置不敏感的,所以需要位置编码;
-
注入位置相关的先验知识,大部分的位置编码都带有“位置越近,越重要”的先验知识。
传统位置编码的问题:
-
可学习位置编码:不具备外推性
-
正余弦位置编码:有一定的外推性,但是缺少相对位置关系,效果较差;
LLM 的位置编码:
-
Rope: 旋转位置编码,将位置编码通过旋转矩阵的方式,添加到注意力机制中;
-
ALIBI: 添加一个不可学习的偏置项,来代表位置编码,添加到注意力机制中;
-
NTK: 神经正切核,他是一种 scaling 位置编码的算法,常用 NTK-Rope 和 NTK-Alibi;
-
YaRN: 在 Rope 的基础上进行改进,使其有更好的外推性;
-
Cope: 考虑上下文的编码,解决了以往位置编码与 token 无关,只与位置有关的问题;
3、新型编码介绍
(1)Rope
旋转位置编码不像原始的绝对位置编码(在输入中单独加入位置编码信息),而是在计算注意力时,考虑 token 之间的位置关系。
和原始的 transformer 的区别,是在 qkv 中增加位置信息,得到新的 qkv:
在做注意力计算时,将位置信息通过旋转矩阵的方式引入,
注意:截图来自于论文,矩阵中 m 实则为位置差 m-n。
RoPE 形式上和 Sinusoidal 位置编码有点相似,只不过 Sinusoidal 位置编码是加性的,而 RoPE 可以视为乘性的。这么做的其实很大程度上依赖于三角函数的特性。
优点: 去掉了量级笨重且难训练的位置向量矩阵,显著化了相对位置在注意力中的重要性,让每个变量更关注相对位置的变化,增加了模型的外推性。
(2)ALiBi
alibi 的原理相对简单,也是在计算注意力时引入位置关系,但是他是直接通过添加一个不可学习的偏置项,来弱化远距离的注意力系数,强化近距离的注意力系数。
m 的取值与 attention head 有关,假设有 H 个头,那么 m 的取值是:
其中 h 为第 h 个头。
(3)NTK
问题引入: 无论是 Rope 还是 Alibi 位置编码,都存在训练数据长度有限,但是推理时长度要求更高的场景(现在很多大模型都支持上百 k 的输入长度)。
那么如何提升模型处理长文本的能力那,直接想法有两种:
线性内插: 压缩输入长度到模型原本训练的长度,训练数据最大长度 l,需要支持的推理最大长度 L,那么需要将 L 压缩到 l 的长度。
具体做法是:
线性外推: 线性外推(直接外推)就是不做任何处理,直接扩充l到L的长度。
两者的缺点:
-
线性内插:会将不同视野大小下统一缩减,导致相邻位置的差异变小,损失视野分辨率。尤其是原先就在训练范围内的相邻位置(高频),因此需要重新训练。
-
线性外推:因为训练时没有处理过较长文本,所以效果比较差,不如线性内插。
神经正切核(NTK)方式(NTK-aware RoPE)
这里要引入位置编码进制转换,主要参考的是苏剑林:高频外推,低频内插的思想。
位置编码进制转换就是用 2/8/10/16 进制数来表示位置坐标,即同样表示 2048,直接表示是 2048,用 10 进制表示是 [2,0,4,8]。
这样做的好处是:既缩小了数字的跨度,又没有缩小相邻数字的差距(因为直接表示,0 和 2048 跨度太大,梯度优化器不容易优化,直接压缩相邻差距又会变小)。
NTK 的作用是基于 NTK 理论,证明了神经网络无法直接学习高频信号(低维信息),所以高频信号要采用外推的方式,低频信号内插。
NTK-Rope
NTK-Alibi
ntk-alibi 是将 alibi 的 m 缩放成:
动态 NTK(Dynamic NTK)
Dynamic NTK 主要提出了动态的缩放因子。对于自回归模型而言,其所处理的序列是不断变化的,每一步比前一步增加一个 token。
在这种情况下有两种插值的方法:
-
在整个推理阶段,使用固定的缩放因子 a=L’/L, 其中 L’ 是预测阶段文本长度
-
在每轮前向传播中,位置编码更新缩放因子 a = max(1, l’/L), 其中 l’ 是当前序列的长度
方案 1 的问题在于,当序列长度小于 L’ 时,模型性能可能会有一点小折扣;而当序列长度大于 L’ 时,模型性能则会突然下降,而使用方案 2 可以使模型性能下降的更少。
在推理阶段不断调整缩放因子的方式称为 Dynamic 缩放,即动态 NTK 插值。
(4)YaRN
NTK-by-parts
温度系数
YaRN 除了上面说的 NTK-by-parts,还引入了一个在计算 softmax 时的温度系数。
(5)CoPE
上下文位置编码(Contextual Positional Encoding,简称 CoPE)。
对于传统位置的位置编码(可学习或不可学习)和相对位置编码(Rope、ALIBI)是独立于上下文编码的,而且相对位置编码在处理长文本时,位置注意力是个递减的趋势。
因此 Cope 提出了根据上下文的位置编码:
Cope 主要的思想是引入一个“门控”机制来控制当前 token 是否参与注意力计算,门控值是根据公式:
4、总结
位置编码是 transformer 中非常重要的组成部分,随着 LLM 的发展,也要求位置编码有更好的泛化性,适配更多的不同长度的处理场景,随机产生了 NTK/YaRN 等编码,Cope 是考虑了上下文,把 token 信息也考虑到位置编码中。总之,位置编码还在不断改进,值得持续关注和研究。
最后
为了助力朋友们跳槽面试、升职加薪、职业困境,提高自己的技术,本文给大家整了一套涵盖AI大模型所有技术栈的快速学习方法和笔记。目前已经收到了七八个网友的反馈,说是面试问到了很多这里面的知识点。
由于文章篇幅有限,不能将全部的面试题+答案解析展示出来,有需要完整面试题资料的朋友,可以扫描下方二维码免费领取哦!!! 👇👇👇👇

面试题展示
1、请解释一下BERT模型的原理和应用场景。
答案:BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的语言模型,通过双向Transformer编码器来学习文本的表示。它在自然语言处理任务中取得了很好的效果,如文本分类、命名实体识别等。
2、什么是序列到序列模型(Seq2Seq),并举例说明其在自然语言处理中的应用。
答案:Seq2Seq模型是一种将一个序列映射到另一个序列的模型,常用于机器翻译、对话生成等任务。例如,将英文句子翻译成法文句子。
3、请解释一下Transformer模型的原理和优势。
答案:Transformer是一种基于自注意力机制的模型,用于处理序列数据。它的优势在于能够并行计算,减少了训练时间,并且在很多自然语言处理任务中表现出色。
4、什么是注意力机制(Attention Mechanism),并举例说明其在深度学习中的应用。
答案:注意力机制是一种机制,用于给予模型对不同部分输入的不同权重。在深度学习中,注意力机制常用于提升模型在处理长序列数据时的性能,如机器翻译、文本摘要等任务。
5、请解释一下卷积神经网络(CNN)在计算机视觉中的应用,并说明其优势。
答案:CNN是一种专门用于处理图像数据的神经网络结构,通过卷积层和池化层提取图像特征。它在计算机视觉任务中广泛应用,如图像分类、目标检测等,并且具有参数共享和平移不变性等优势。
6、请解释一下生成对抗网络(GAN)的原理和应用。
答案:GAN是一种由生成器和判别器组成的对抗性网络结构,用于生成逼真的数据样本。它在图像生成、图像修复等任务中取得了很好的效果。
7、请解释一下强化学习(Reinforcement Learning)的原理和应用。
答案:强化学习是一种通过与环境交互学习最优策略的机器学习方法。它在游戏领域、机器人控制等领域有广泛的应用。
8、请解释一下自监督学习(Self-Supervised Learning)的原理和优势。
答案:自监督学习是一种无需人工标注标签的学习方法,通过模型自动生成标签进行训练。它在数据标注困难的情况下有很大的优势。
9、解释一下迁移学习(Transfer Learning)的原理和应用。
答案:迁移学习是一种将在一个任务上学到的知识迁移到另一个任务上的学习方法。它在数据稀缺或新任务数据量较小时有很好的效果。
10、请解释一下模型蒸馏(Model Distillation)的原理和应用。
答案:模型蒸馏是一种通过训练一个小模型来近似一个大模型的方法。它可以减少模型的计算和存储开销,并在移动端部署时有很大的优势。
11、请解释一下LSTM(Long Short-Term Memory)模型的原理和应用场景。
答案:LSTM是一种特殊的循环神经网络结构,用于处理序列数据。它通过门控单元来学习长期依赖关系,常用于语言建模、时间序列预测等任务。
12、请解释一下BERT模型的原理和应用场景。
答案:BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的语言模型,通过双向Transformer编码器来学习文本的表示。它在自然语言处理任务中取得了很好的效果,如文本分类、命名实体识别等。
13、什么是注意力机制(Attention Mechanism),并举例说明其在深度学习中的应用。
答案:注意力机制是一种机制,用于给予模型对不同部分输入的不同权重。在深度学习中,注意力机制常用于提升模型在处理长序列数据时的性能,如机器翻译、文本摘要等任务。
14、请解释一下生成对抗网络(GAN)的原理和应用。
答案:GAN是一种由生成器和判别器组成的对抗性网络结构,用于生成逼真的数据样本。它在图像生成、图像修复等任务中取得了很好的效果。
15、请解释一下卷积神经网络(CNN)在计算机视觉中的应用,并说明其优势。
答案:CNN是一种专门用于处理图像数据的神经网络结构,通过卷积层和池化层提取图像特征。它在计算机视觉任务中广泛应用,如图像分类、目标检测等,并且具有参数共享和平移不变性等优势。
16、请解释一下强化学习(Reinforcement Learning)的原理和应用。
答案:强化学习是一种通过与环境交互学习最优策略的机器学习方法。它在游戏领域、机器人控制等领域有广泛的应用。
17、请解释一下自监督学习(Self-Supervised Learning)的原理和优势。
答案:自监督学习是一种无需人工标注标签的学习方法,通过模型自动生成标签进行训练。它在数据标注困难的情况下有很大的优势。
18、请解释一下迁移学习(Transfer Learning)的原理和应用。
答案:迁移学习是一种将在一个任务上学到的知识迁移到另一个任务上的学习方法。它在数据稀缺或新任务数据量较小时有很好的效果。
19、请解释一下模型蒸馏(Model Distillation)的原理和应用。
答案:模型蒸馏是一种通过训练一个小模型来近似一个大模型的方法。它可以减少模型的计算和存储开销,并在移动端部署时有很大的优势。
20、请解释一下BERT中的Masked Language Model(MLM)任务及其作用。
答案:MLM是BERT预训练任务之一,通过在输入文本中随机mask掉一部分词汇,让模型预测这些被mask掉的词汇。
由于文章篇幅有限,不能将全部的面试题+答案解析展示出来,有需要完整面试题资料的朋友,可以扫描下方二维码免费领取哦!!! 👇👇👇👇
