Transformer学习
本文最后更新于25 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

2017 年,Google 在论文《Attention Is All You Need》中提出了 Transformer。今天我们接触到的大语言模型,绝大多数都可以追溯到 Transformer。

但 Transformer 并不是凭空出现的,它最初要解决的仍然是自然语言处理中的一个经典问题:如何把一个序列转换成另一个序列。

与当时主流的序列模型不同,Transformer 不再依赖循环神经网络(Recurrent Neural Network,RNN)沿序列逐步传递隐藏状态,而是让注意力机制承担不同位置之间的信息交换。

以机器翻译为例,整个过程可以概括为:

  1. 转换输入——Embedding: 源序列中的 Token 首先经过 Input Embedding,被转换成模型可以处理的向量表示。
  2. 理解源序列——Encoder: Encoder 读取源序列,为每个输入 Token 生成包含上下文信息的表示。
  3. 生成目标表示——Decoder: Decoder 读取 Encoder 的输出,并结合当前已经生成的目标前缀,生成当前位置的隐藏表示。
  4. 映射到词表——Linear: Linear 层将 Decoder 的隐藏表示映射到词表空间,为词表中的每个候选 Token 打分。
  5. 转换为概率——Softmax: Softmax 将这些分数转换成总和为 1 的概率分布,表示下一个位置生成各个 Token 的概率。
  6. 预测下一个 Token——自回归生成: 模型根据概率分布选择下一个 Token,并将它加入目标前缀。下一轮预测时,更新后的目标前缀经过 Output Embedding 转换成向量,再输入 Decoder。模型重复上述过程,直到生成 <EOS>。

从整体流程来看,Transformer 与 Seq2Seq 并没有本质区别:Encoder 负责理解输入,Decoder 负责逐步生成输出。真正发生变化的是 Encoder 和 Decoder 内部生成上下文表示的方式。

Positional Encoding:为 Token 加入位置信息

但 Transformer 不再像 RNN 一样沿序列逐步计算,Self-Attention 会同时处理并比较不同位置的 Token。这样虽然消除了顺序计算的依赖,却也意味着模型无法从计算顺序中获得位置信息。

因此,Transformer 还需要为每个 Token 提供位置信息。它会对序列中的位置进行编码,并将位置编码(Positional Encoding)直接加到对应 Token 的 Embedding 上,使进入第一层 Encoder 和 Decoder 的向量同时包含 Token 信息和位置信息。

假设 img 表示序列中第 img 个位置的 Token,那么它进入第一层 Encoder 或 Decoder 前的表示为:

img

Self-Attention:让输入位置直接交换信息

在 RNN 中,只有得到前一个位置的隐藏状态,才能继续计算下一个位置。句尾的词想要获得句首的信息,这些信息必须经过中间多个隐藏状态逐步传递。序列越长,传递路径越长,同一层中的不同位置也无法同时完成计算。

Self-Attention 改变了这种信息传递方式。输入序列中的每个 Token 都会根据自身表示生成 Query,与整个序列中各个位置的 Key 计算匹配程度,再根据得到的注意力权重对相应的 Value 进行加权汇总。这样,每个 Token 都可以直接读取其他位置的信息,生成融合上下文的新表示。img

img

在同一层中,各个位置 Token 关系的计算不需要等待前一个位置的结果。只要整段输入已经存在,所有 Token 的注意力计算就可以组织成矩阵并行完成,这正是 Transformer 相比 RNN 更适合并行训练的重要原因。

Transformer 还使用了多头注意力,多组不同的参数对同一段输入进行映射,让多个 Attention Head 分别从不同的表示空间提取信息,最后再将各个 Head 的结果拼接并融合。

Add & Norm:让信息稳定地穿过深层网络

架构图中的 Nx 代表可以堆叠多层,Self-Attention 完成了不同 Token 之间的信息交换,但随着网络不断堆叠,原有信息可能在连续变换中逐渐丢失,各层输出的数值分布也可能发生较大变化。因此,Transformer 会在每个子层之后加入 Add & Norm。

其中,Add 表示残差连接。假设子层的输入为 img,子层完成的变换为 img,那么残差连接会把原始输入直接加回子层输出:

img

Norm 表示层归一化(Layer Normalization,LayerNorm)。它会对每个 Token 隐藏表示内部的各个维度进行归一化,将数值调整到相对稳定的范围,减少网络层层堆叠时数值分布的剧烈变化。

Add & Norm 的过程可以写成:

img

Encoder 中的 Self-Attention 和 FFN 后面都跟着 Add & Norm,Decoder 中的掩码自注意力、交叉注意力和 FFN 后面也分别使用 Add & Norm,作用同样是保留原始信息、稳定数值分布,让信息能够顺利穿过多层 Decoder。

FFN:进一步加工每个位置的信息

经过 Encoder 的 Self-Attention 后,每个 Token 已经从序列中的其他位置汇总了与自己相关的信息。但注意力主要解决的是“应该关注哪些位置、从这些位置读取多少信息”,得到的上下文表示还需要进一步加工,才能形成更有表达能力的特征。

Transformer 使用前馈神经网络对这些信息进行重新组合和转换。FFN 由两个线性层组成,中间加入一个 ReLU 激活函数:

img

整个过程可以分为三步:

  1. 第一个线性层将隐藏表示映射到更高的维度,提供更宽的特征空间;
  2. ReLU 引入非线性,使网络能够学习更复杂的特征转换;
  3. 第二个线性层将结果映射回原来的隐藏维度,以便与残差连接相加,并继续传递给下一层。

也就是说 Self-Attention 负责在不同 Token 之间交换信息,FFN 负责进一步加工每个 Token 已经获得的信息。

FFN 处理完成后,数据会再次经过 Add & Norm,然后继续进入下一层 Encoder。经过多层 Encoder 的信息交换和加工,模型最终会为源序列中的每个 Token 生成一个上下文表示。这些表示经过线性映射后,将作为 Decoder Cross-Attention 使用的 Key 和 Value。

Masked Self-Attention:训练时也不能看见未来

在推理阶段,Decoder 每次只能获得已经生成的目标前缀,未来的 Token 尚不存在,因此本来就无从读取。掩码真正需要解决的是训练阶段的问题。

训练时,为了并行计算所有位置,模型不会像推理时一样逐个生成 Token,而是通过 Teacher Forcing,一次性把右移后的完整目标序列交给 Decoder

但问题也随之出现:既然完整的目标序列已经放进 Decoder,如果不加任何限制,用于预测“喜欢”的位置就可能直接读取后面的“喜欢”,相当于提前看到了正确答案。模型可能由此找到一条训练时有效、推理时却无法使用的捷径。

因此,掩码自注意力会在 Self-Attention 的基础上增加因果掩码(Causal Mask),限制每个位置只能关注自己以及前面的位置。img

经过掩码自注意力后,Decoder 会为每个位置生成一份只包含目标前缀信息的上下文表示。它记录了目标序列到当前位置为止已经出现的内容,接下来将作为 Query,通过交叉注意力从 Encoder 输出中寻找预测下一个 Token 所需要的源序列信息。

Cross-Attention:让 Decoder 查询 Encoder

掩码自注意力整理了已经生成的目标内容,但只看目标前缀还不足以完成翻译。Decoder 还需要知道源序列表达了什么,因此接下来要通过交叉注意力读取 Encoder 的输出。

这一步与 Seq2Seq Attention 的思想如出一辙,Decoder 先描述当前需要什么信息,再与 Encoder 保存的源序列信息进行匹配,最后取出相关内容。

在 Cross-Attention 中

  • Query 来自 Decoder 掩码自注意力产生的目标序列上下文表示;
  • Key 来自 Encoder 输出的源序列上下文表示;
  • Value 同样来自 Encoder 输出的源序列上下文表示。

可以简化写成:

img

其中,img表示 Decoder 根据目标前缀生成的上下文表示,img表示 Encoder 输出的源序列上下文表示。

Linear 和 Softmax:把隐藏表示变成 Token 概率

Linear 会把 Decoder 隐藏表示映射到词表空间,为每个位置输出打分,随后Softmax 将这些分数转换成总和为 1 的概率分布。

推理时,模型会根据这个概率分布选择下一个 Token,将它加入目标前缀,再次送入 Decoder,继续预测后面的内容。这个不断把已生成结果作为下一步输入的过程,就是自回归生成。

训练阶段由于正确的目标序列已经存在,Decoder 可以同时得到各个位置的输出,并行计算它们在词表上的概率和训练误差;推理阶段则只能在获得前一个 Token 后继续生成下一个 Token。因此,Transformer 消除的是已知序列内部的循环计算依赖,并没有消除自回归生成本身的先后顺序。

总结

编码器

  1. 源序列进入 Encoder 之前,先经过 Embedding 并加入位置信息
  2. Encoder 使用 Self-Attention 让源序列中的不同位置直接交换信息
  3. 再通过 Add & Norm 和 FFN 继续加工每个位置的表示,最终输出一组源序列上下文表示

解码器

  1. 目标前缀进入 Decoder 后,同样先经过 Embedding 和位置编码
  2. Masked Self-Attention 生成目标前缀的上下文表示,并由它进一步映射得到 Cross-Attention 的 Q
  3. Cross-Attention 再使用来自 Decoder 的 Q 查询来自 Encoder 的 K 和 V
  4. 经过后续的 FFN 和 Add & Norm,Decoder 得到用于预测 Token 的隐藏表示
  5. 最后由 Linear 和 Softmax 生成词表概率

注意力究竟在做什么

Transformer 中使用了三类注意力:编码器中的自注意力、解码器中的掩码自注意力和交叉注意力。

Attention 会计算序列中不同位置之间的匹配关系,再按照匹配程度读取并汇总信息,为每个 Token 生成新的上下文表示。

在 Attention 之前,每个 Token 的向量主要表示自身的语义和位置;经过 Attention 之后,每个 Token 的新向量已经融合了序列中其他相关位置的信息。img

相较于基于cnn架构的seq2seq,Transformer 完成的是相同的任务,只是不再使用 RNN 逐步生成隐藏状态,而是把理解序列这件事本身也交给了 Attention。整体流程可以概括为:

  1. Encoder 使用自注意力处理输入序列,生成输入序列的上下文表示;
  2. Decoder 使用掩码自注意力处理已经生成的输出序列;
  3. Decoder 使用交叉注意力,根据当前生成状态读取输入序列的信息;
  4. 经过 FFN、线性映射和 Softmax,预测下一个 Token。

三类注意力内部使用的是同一种计算机制,主要区别在于 Query、Key 和 Value 来自哪里。

注意力类型Query 来源Key、Value 来源主要作用
自注意力输入序列输入序列生成输入序列的上下文表示
掩码自注意力输出序列输出序列生成当前输出前缀的上下文表示
交叉注意力DecoderEncoder根据当前生成状态读取输入序列

输入序列预处理

在进入 Encoder 之前,输入序列会首先经过 Embedding 和 Positional Encoding 处理,转换成一个序列表示矩阵。

I love deep learning

假设模型使用 512 维向量表示每个 Token,那么这个序列会形成一个 img 的矩阵,矩阵中的每一行对应一个 Token,包含这个 Token 的语义和位置信息:

img

img

此时,每一行主要描述的仍然是对应 Token 自身。例如,img 包含 learning 的语义和位置,却还没有直接融合 I、love 和 deep 的信息。

但一个 Token 在句子中的含义和作用,往往取决于它与其他 Token 的关系。learning 前面的 deep 修饰了它,love 则描述了 I 与 deep learning 之间的关系。

Self-Attention 要做的事情,就是让每个位置观察整个序列,根据它与其他位置的关系,重新生成一个包含上下文信息的向量。

Q、K、V 是输入矩阵的三种投影

为了计算不同位置之间的关系,模型会学习三组参数矩阵:

img

输入矩阵 img 分别与它们相乘,得到 Query、Key 和 Value:

img

矩阵乘法会一次完成所有 Token 的线性投影,因此 img、img、img 中仍然各有一行对应序列中的一个 Token。可以这样理解三种投影:

  • Query:描述当前位置在更新自身表示时,希望寻找什么信息;
  • Key:描述当前位置提供了哪些可以参与匹配的特征;
  • Value:描述匹配成功后,当前位置真正提供给其他位置的内容。

img

这里的“寻找”“提供”只是为了帮助我们理解 Attention 的信息流。Query、Key 和 Value 都是模型训练出来的向量,我们无需把其中某个具体维度直接解释成一种固定的人类语义。

一个 Token 如何读取整个序列

下面以 learning 为例,观察它如何通过 Self-Attention 生成新的上下文表示。

img

1. Query 与所有 Key 计算匹配分数

取出 learning 对应的 Query 向量 img,分别与序列中所有 Token 的 Key 做点积:

img

这些点积结果表示 learning 的 Query 与各个位置的 Key 有多匹配。这里得到的只是匹配分数,还不是最终的信息读取比例。

2. 除以 img

随着向量维度增加,点积结果的数值通常也会增大。如果直接输入 Softmax 计算,可能使输出分布过于集中,导致梯度变小,影响训练稳定性。

因此,Transformer 会把点积结果除以img进行缩放,img 表示当前注意力头中 Query 和 Key 的向量维度。

3. 使用 Softmax 得到注意力权重

缩放后的匹配分数经过 Softmax,被转换成一组总和为 1 的注意力权重:

img

这些权重表示:为了更新 learning 的表示,当前注意力头应该从各个位置读取多少信息。例如,模型可能为 deep 分配较高权重,因为它与 learning 共同构成了 deep learning。

4. 按照权重汇总 Value

得到注意力权重之后,模型会按照相应比例,对所有位置的 Value 进行加权求和:

img

最终得到的 img,就是 learning 在这个注意力头中生成的新表示。它不再只包含 learning 自身的信息,还融合了 I、love、deep 和自身 Value 中与当前 Query 相关的内容。

使用矩阵从一个 Token 扩展到整个序列

序列中的每个 Token 都需要经历相同的过程:

  1. 使用自己的 Query 与所有位置的 Key 计算匹配分数;
  2. 通过 Softmax 把匹配分数转换成注意力权重;
  3. 按照权重对所有位置的 Value 加权求和;
  4. 得到当前位置新的上下文表示。

使用矩阵乘法,可以一次完成整个序列的计算。

首先计算注意力权重矩阵:

img

如果序列中有img个 Token,那么:

img

矩阵img的第img行、第img列,表示第img个位置在更新自身表示时,对第img个位置分配的注意力权重。

接下来模型使用img对 Value 进行加权汇总:

img

合并后,就是我们经常看到的缩放点积注意力公式:

img

输出矩阵img中的每一行,都是一个 Token 融合上下文信息之后的新表示。

因此,Attention 的完整作用不只是判断哪些词更重要,而是先计算不同位置之间的匹配关系,再按照这些关系重新组织信息,生成整个序列新的上下文表示。

掩码自注意力:理解已经生成的内容

Decoder 中的掩码自注意力与 Encoder 自注意力使用相同的计算过程,它的作用是生成目标序列的上下文表示。两者的区别在于 Decoder 在训练时可以一次接收到完整的目标序列。如果不做任何限制,前面的位置就可能直接读取后面的正确答案。

因此,模型需要使用因果掩码遮挡未来位置,使第 img 个位置只能关注自己以及它之前的 Token,不能读取后面的内容。也就是说掩码是为了防止训练时出现目标信息泄漏,使模型训练时每个位置的可见范围与推理时自回归生成时保持一致。

img

假设需要把下面的序列翻译成中文:

I love deep learning

推理刚开始时,Decoder 的输入只有:

<BOS>

经过 Embedding、Positional Encoding 和掩码自注意力之后,Decoder 会得到 <BOS> 对应的表示。

生成“我”以后,Decoder 的输入变为:

<BOS> 我

此时,“我”所在位置可以读取 <BOS> 和自身的信息,从而生成一个包含当前整个输出前缀信息的新表示。

加入掩码后的 Attention 可以简化表示为:

img

其中,img 是因果掩码矩阵。允许关注的位置取 0,需要遮挡的位置取负无穷。经过 Softmax 后,被遮挡位置的注意力权重会变成 0。

需要注意的是,虽然推理时通常使用最新位置的表示预测下一个 Token,但这个表示已经通过掩码自注意力融合了当前整个生成前缀的信息。因此,它不是只表示“我”这个 Token,而是表示模型当前生成到哪里的整体状态。

交叉注意力:根据当前状态读取输入序列

经过掩码自注意力之后,Decoder 已经形成了当前输出序列的上下文表示,但它还需要回到输入序列中,读取预测下一个 Token 所需的信息,这就要进入交叉注意力。

之所以称为交叉注意力,是因为 Query 与 Key、Value 来自两个不同的序列。交叉注意力中 Q、K、V 的来源分别是:

  • Query 来自 Decoder 的当前序列表示;
  • Key 和 Value 来自 Encoder 的最终输出。

img

假设 Encoder 对输入序列生成了上下文表示 img,Decoder 经过掩码自注意力后生成了表示 img,那么交叉注意力中的 Q、K、V 为:

img

随后仍然使用相同的 Attention 公式:

img

这个过程可以理解为:Decoder 根据当前已经生成的内容形成 Query,再用它查询 Encoder 对输入序列的表示,得到预测下一个 Token 所需的源序列信息。

Multi-Head Attention 的工作流程

在单头 Attention 中,输入序列表示img经过三组参数矩阵得到 Query、Key 和 Value:

img

然后计算:

img

Multi-Head Attention 的思路是在同一个输入序列上并行进行多次 Attention,让不同的 Head 从不同较低提取特征,形成自己对序列理解的匹配关系,最后再把多个 Head 得到的结果组合起来。

但如果多个 Head 使用完全相同的 Q、K、V,那么它们计算出来的结果也不会有什么区别。为了让不同 Head 能够学习不同的匹配方式,模型会为每个 Head 分别学习一组独立的投影参数。对于第img个 Head:

img

每个 Head 再使用自己的 Query、Key 和 Value 独立完成一次 Attention:

img

如果模型一共使用img个 Head,就会得到img这些不同的输出。它们随后被拼接到一起,并经过一次线性映射,重新形成统一的序列表示:

img

img

Multi-Head Attention 对同一个输入序列经过多组不同的 Q、K、V 投影,分别完成 Attention,再将多个 Head 的结果合并成一个新的序列表示。

多个 Head 的矩阵维度如何变化

多个 Head 虽然能够从不同的表示空间计算 Attention,但如果每个 Head 都处理完整的img维向量,计算量也会随 Head 数量快速增加。Transformer 并没有简单地复制多份完整的 Attention,而是进一步对每个 Head 的维度进行了拆分。

假设:

img

那么每个 Head 的 Query、Key 和 Value 维度通常为:

img

如果当前序列中有img个 Token,原始输入矩阵为:

img

经过不同 Head 的投影以后,每个 Head 得到的 Query、Key 和 Value 都是:

img

接下来在每个 Head 内部计算 Query 与 Key 的匹配关系:

img

因此,无论每个 Head 的内部维度是多少,它得到的注意力权重矩阵仍然是img。这个矩阵描述的依然是序列中img个位置彼此之间的匹配关系,只是不同 Head 会得到不同的权重分布。

随后,注意力权重与 Value 相乘:

img

所以每个 Head 的最终输出为:

img

8 个 Head 各自得到一个img的结果,拼接之后重新恢复成:

img

img

从这个过程可以看到,Multi-Head Attention 并不是让 8 个 Head 都处理完整的 512 维表示,而是把原来的表示空间划分成多个较小的子空间,让不同 Head 分别完成 Attention,最后再拼接回来。这样既可以获得多组不同的注意力关系,又不会简单地把计算规模扩大 8 倍。

代码实现时,多个 Head 并不会通过循环逐个计算,而是将 Head 作为张量中的一个维度组织起来,利用矩阵运算一次并行完成所有 Head 的 Attention 计算。

位置编码

Embedding 负责表示这是什么 Token,位置编码(Positional Encoding)负责表示这个 Token 出现在什么位置。对于序列中第img个 Token,Transformer 会把它的 Token Embedding 与对应的位置编码相加:

img

其中,img表示第img个 Token,img是它的语义表示,img则是第img个位置对应的位置表示。相加得到的img不再只描述当前 Token 是什么,还包含了它出现在什么位置。

dog bites man
man bites dog

两次出现的dog使用同一个 Token Embedding,但由于它们所在的位置不同,需要叠加的位置编码也不同,因此最终送入模型的表示分别为:

img
img

img

这样一来,即使 Token 本身相同,只要它出现在不同位置,最终得到的输入表示就会不同。后续由img生成的 Query、Key 和 Value 也会受到位置信息影响,使 Self-Attention 在计算 Token 之间的匹配关系时,可以同时利用语义与顺序。

Transformer 论文使用正弦、余弦位置编码完成这种转换。它不需要通过训练学习,而是根据位置编号和向量维度直接计算:

img
img

其中,img表示 Token 在序列中的位置,img表示模型的隐藏维度。这里的img不是单个维度的编号,而是正弦、余弦组合的编号。第img组计算会产生两个数,并分别写入位置向量的第img和第img个维度:

  • 第img个维度使用正弦函数;
  • 第img个维度使用余弦函数。

也就是说,一种频率会占用位置向量中的两个维度。

如果位置编码需要img维,就使用img组频率;如果位置编码需要img维,就使用img组频率。一般来说:

img

因此,如果img,就会使用img组不同频率,每组生成一个正弦值和一个余弦值,最终得到一个img维的位置向量。

位置编码的维度不是由正弦和余弦函数自动决定的,而是先由img确定需要多少个维度,再把这些维度两两分组,为每一组分配一种不同的频率。以img、img为例,

  1. 8 个维度分成 4 组
  2. 分母依次是img、img、img、img
  3. 同一个img分别代入这四组,就得到八个数:
img

把这八个数按维度顺序排好,最终得到的位置编码向量就是:

img

不同频率,辨别远近关系

把这些维度组合起来,每个位置就会得到一组不同的数值:

img

正弦和余弦内部的分母img决定了这一组数值变化的速度:随着img增大,分母会逐渐变大,img每增加img所带来的角度变化就会越来越小,因此不同组合会形成快慢不同的变化频率。

从单个维度观察,位置编码会随着位置变化形成一条周期曲线

  • 分母小的维度每隔几个位置就转完一圈,能够区分相邻位置,但距离拉大后取值会重复;
  • 分母大的维度在相邻位置上几乎看不出差别,要经过很多个位置才转完一圈,因此适合区分隔得较远的位置

快慢搭配起来,模型就可以区分距离远近不同的位置

img

单独观察某一组正弦和余弦,它的取值会随着周期重复;但多组不同频率组合起来后,就可以为不同位置形成具有区别度的编码模式。

不同频率能够让不同位置形成不同的编码,但这还不是选择正弦和余弦的全部原因。前面提到,Attention 并不会主动拿两个位置编号做减法,它接收的是向量,然后进行线性映射和点积。既然点积一定会发生,那就看看两个位置编码点乘之后会得到什么。

把某一组的分母记作img,这一组在位置img和位置img上各有一对正弦、余弦值。它们对应相乘再相加,正好可以合并:

img

等式右边不再含有img,只剩下距离img。把所有组加起来,得到的就是两个位置编码的点积:

img

也就是说,两个位置编码的点积与它们各自处在什么绝对位置无关,只由二者相隔多远决定。

RoPE:从绝对位置到相对位置

正弦、余弦位置编码的思路是为每个 Token 添加一个位置表示,让模型知道当前 Token 位于序列中的哪个位置。它会为每个位置生成一个与 Token 表示维度相同的位置向量,然后与 Embedding 相加。

既然正弦、余弦编码的点积已经只与距离有关,为什么还会出现新的方案?因为这个性质是对位置编码本身成立的。位置编码是加在输入上的,真正进入注意力分数的是img经过img、img投影之后的结果,展开后既包含语义与语义的项,也包含语义与位置的交叉项,只依赖距离的结构不再被保证,能不能用上相对位置,要交给训练过程自己去学。

而很多语言理解任务关注的并不是某个词位于第几个位置,而是两个词之间的距离和顺序关系。例如,dog是否位于bites之前,当前 Token 与相关信息相隔多远,这些相对位置关系往往更加重要。

旋转位置编码(Rotary Position Embedding,RoPE)采用了不同的思路,它不再生成一个额外的位置向量,而是利用 Token 的位置信息,对 Attention 中的 Query 和 Key 向量进行旋转。

img

假设某个 Token 经过线性变换后得到 Query:

q=[q_1,q_2,q_3,q_4,…]

RoPE 会将相邻两个维度组合成二维向量,例如:

(q_1,q_2),(q_3,q_4),…

然后根据该 Token 所处的位置m,为每组二维向量计算一个旋转角度,并使用旋转矩阵改变向量方向:

\begin{bmatrix} q_1’\\ q_2′ \end{bmatrix} = \begin{bmatrix} \cos\theta_m & -\sin\theta_m\\ \sin\theta_m & \cos\theta_m \end{bmatrix} \begin{bmatrix} q_1\\ q_2 \end{bmatrix}

其中\theta_m由 Token 的位置决定。位置越靠后,旋转角度越大;不同维度使用不同的旋转频率,因此可以同时捕捉不同距离范围的位置关系。

Key 也进行同样的旋转。由于旋转发生在W_Q、W_K投影之后,Query 与 Key 做点积时,两边共同的绝对旋转会相互抵消,分数中只剩下与位置差n-m有关的相对角度。

这也是 RoPE 与把位置加在输入上的做法的关键区别,后者的相对性只存在于编码层面,能否保留到分数里取决于训练;而 RoPE 不管语义向量是什么,相对距离都必然出现在注意力分数中。

Attention 最终关注的是 Query 和 Key 之间的匹配关系,而语言中的很多信息也依赖 Token 之间的相对距离和顺序。RoPE 让这种相对位置关系自然体现在注意力分数中,使模型能够更直接地理解不同 Token 之间的位置关系,同时保持原有向量维度,不增加额外参数。目前主流大语言模型普遍采用 RoPE 作为位置编码方案。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇