
坐标苏州的学员,通过训练营的项目和面试辅导,拿下苏州某国企大模型offer,年薪30w+,虽然相比于互联网不高,但是在二线城市国企,也很稳定了,恭喜上岸!
01
Transformer的位置编码
对于序列处理模型,他的位置信息需要通过显式或者隐式的方式传入给模型。
transformer 系列模型的位置编码常用包括:包括绝对位置编码(包括静态位置编码和可学习位置编码)、相对位置编码、旋转位置编码,下面详细介绍这种位置编码的原理和优缺点。
02
位置编码
(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)相对位置编码
相对位置编码的实现可以参考之前的文章
(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 无关,只与位置有关的问题;
03
新型编码介绍
(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 是否参与注意力计算,门控值是根据公式:


04
总结
位置编码是 transformer 中非常重要的组成部分,随着 LLM 的发展,也要求位置编码有更好的泛化性,适配更多的不同长度的处理场景,随机产生了 NTK/YaRN 等编码,Cope 是考虑了上下文,把 token 信息也考虑到位置编码中。总之,位置编码还在不断改进,值得持续关注和研究。
如何学习AI大模型 ?
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。【保证100%免费】🆓
CSDN粉丝独家福利
这份完整版的 AI 大模型学习资料已经上传CSDN,朋友们如果需要可以扫描下方二维码&点击下方CSDN官方认证链接免费领取 【保证100%免费】

读者福利: 👉👉CSDN大礼包:《最新AI大模型学习资源包》免费分享 👈👈
对于0基础小白入门:
如果你是零基础小白,想快速入门大模型是可以考虑的。
一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。
👉1.大模型入门学习思维导图👈
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。
对于从来没有接触过AI大模型的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。(全套教程文末领取哈)

👉2.AGI大模型配套视频👈
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,每个章节都是当前板块的精华浓缩。


👉3.大模型实际应用报告合集👈
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。(全套教程文末领取哈)

👉4.大模型落地应用案例PPT👈
光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。(全套教程文末领取哈)

👉5.大模型经典学习电子书👈
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。(全套教程文末领取哈)


👉6.大模型面试题&答案👈
截至目前大模型已经超过200个,在大模型纵横的时代,不仅大模型技术越来越卷,就连大模型相关的岗位和面试也开始越来越卷了。为了让大家更容易上车大模型算法赛道,我总结了大模型常考的面试题。(全套教程文末领取哈)

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习
CSDN粉丝独家福利
这份完整版的 AI 大模型学习资料已经上传CSDN,朋友们如果需要可以扫描下方二维码&点击下方CSDN官方认证链接免费领取 【保证100%免费】

读者福利: 👉👉CSDN大礼包:《最新AI大模型学习资源包》免费分享 👈👈
6721

被折叠的 条评论
为什么被折叠?



