AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我这样读懂了Transformer中的位置编码
发布日期:2024-12-27 08:14:16 浏览次数: 1578 来源:码农随心笔记


在自然语言处理 (NLP) 领域中,Transformer 模型从根本上重塑了我们处理序列到序列任务的方法。然而,与传统的递归神经网络 (RNN) 或卷积神经网络 (CNN) 不同,Transformer 缺乏对令牌顺序的固有感知。在本篇文章中,我们将了解到位置编码(Positional Encoding)在Transformer 模型中的重要性,它是把序列顺序嵌入 Transformer 模型的关键技术。

01
位置编码的由来


什么是位置编码,在模型的输入输出时,为什么我们首先需要它呢?

首先,我们明白单词的位置和顺序是任何语言的重要组成部分。它们定义了句子的语法,从而定义了句子的实际语义。递归神经网络 (RNN)本质上会考虑单词的顺序,他们按顺序逐字解析句子。这会将单词的顺序集成到 RNN 的主干中。

但是 Transformer 架构放弃了递归机制,转而采用多头自注意力机制。避免 RNN 的递归方法将导致训练时间的大幅加快。从理论上讲,它可以在句子中捕获更长的依赖项。

由于句子中的每个单词同时流经 Transformer 的编码器/解码器堆栈,因此模型本身对每个单词没有任何位置和顺序感。因此,仍然需要一种方法将单词的顺序合并到我们的模型中。位置编码的引入就是为了解决这个问题,它为每个词加入位置信息,让模型知道每个词在句子中的位置。


02
作用


让我们通过一个简单的例子来说明Transformer框架中位置编码的作用:

假设我们有一个英文句子:"The cat sat on the mat",并且我们使用Transformer模型来处理这个句子。Transformer模型的输入是一个词嵌入(word embedding)的序列,其中每个词都被转换成了一个固定维度的向量。如果没有位置编码,模型将无法区分这些词的顺序,因为它的自注意力机制在理论上是无序的。

步骤1:词嵌入 

首先,我们将句子中的每个词转换成词嵌入向量。假设每个词嵌入的维度是4维(实际中通常是几百维),我们得到以下6个词嵌入向量(每个词一个):

The: [0.25, 0.50, 0.75, 1.00]cat: [0.60, 0.40, 0.20, 0.00]sat: [0.90, 0.10, 0.30, 0.70]on:  [0.45, 0.55, 0.65, 0.35]the: [0.25, 0.50, 0.75, 1.00]mat: [0.80, 0.20, 0.10, 0.90]


步骤2:添加位置编码

接下来,我们为每个词嵌入向量添加位置编码。假设我们使用正弦/余弦位置编码,对于4维的词嵌入,我们可能得到以下位置编码:

Position 1: [0.000, 0.100, 0.200, 0.300]  (The的位置编码)Position 2: [0.100, 0.200, 0.000, 0.100]  (cat的位置编码)Position 3: [0.200, 0.000, 0.100, 0.200]  (sat的位置编码)Position 4: [0.300, 0.100, 0.200, 0.000]  (on的位置编码)Position 5: [0.400, 0.000, 0.300, 0.100]  (the的位置编码)Position 6: [0.500, 0.100, 0.000, 0.300]  (mat的位置编码)


步骤3:结合词嵌入和位置编码

我们将每个词嵌入与其对应的位置编码相加,得到最终的输入向量:

The: [0.25+0.000, 0.50+0.100, 0.75+0.200, 1.00+0.300] = [0.25, 0.60, 0.95, 1.30]cat: [0.60+0.100, 0.40+0.200, 0.20+0.000, 0.00+0.100] = [0.70, 0.60, 0.20, 0.10]sat: [0.90+0.200, 0.10+0.000, 0.30+0.100, 0.70+0.200] = [1.10, 0.10, 0.40, 0.90]on:  [0.45+0.300, 0.55+0.100, 0.65+0.200, 0.35+0.000] = [0.75, 0.65, 0.85, 0.35]the: [0.25+0.400, 0.50+0.000, 0.75+0.300, 1.00+0.100] = [0.65, 0.50, 1.05, 1.10]mat: [0.80+0.500, 0.20+0.100, 0.10+0.000, 0.90+0.300] = [1.30, 0.30, 0.10, 1.20]


步骤4:自注意力机制

在自注意力机制中,模型会计算每个词与其他所有词的注意力分数。由于我们已经为每个词添加了位置编码,模型现在可以区分不同词的位置,并据此计算注意力分数。例如,"cat"这个词的编码会告诉模型它紧随"The"之后,而"sat"则在"cat"之后,这种顺序信息对于理解句子结构至关重要。

步骤5:输出

经过多层Transformer处理后,模型最终输出每个词的表示,这些表示包含了词义和它们在句子中的位置信息,这对于后续的任务(如翻译、文本摘要等)是非常重要的。

通过以上例子,我们可以看到位置编码在Transformer模型中的作用是为模型提供词序信息,使得模型能够捕捉到句子的结构和语义,这对于处理序列数据是非常关键的。


03
如何构建


以下是使用PyTorch创建Transformer模型中的位置编码的代码示例。这里我们将使用正弦和余弦函数来生成位置编码。
import torchimport torch.nn as nnimport mathclass PositionalEncoding(nn.Module):    def __init__(self, d_model, max_len=5000):        super(PositionalEncoding, self).__init__()               # 创建一个足够大的位置编码矩阵,以避免位置超出范围        pe = torch.zeros(max_len, d_model)        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))        pe[:, 0::2] = torch.sin(position * div_term)        pe[:, 1::2] = torch.cos(position * div_term)        pe = pe.unsqueeze(0).transpose(01)                # 将位置编码矩阵注册为模型的缓冲区,这样它就不会被视为模型参数        self.register_buffer('pe', pe)        def forward(self, x):        # 将位置编码添加到输入的嵌入向量中        x = x + self.pe[:x.size(0), :]        return x
# 假设我们的词嵌入维度是512,最大序列长度是100d_model = 512max_len = 100positional_encoding = PositionalEncoding(d_model, max_len)
# 假设我们有一个随机生成的词嵌入张量,形状为[seq_len, batch_size, d_model]seq_len, batch_size = 6032x = torch.randn(seq_len, batch_size, d_model)
# 将位置编码添加到词嵌入中x = positional_encoding(x)print(x.shape)  # 输出的形状应该是[seq_len, batch_size, d_model]

在这段代码中,我们定义了一个`PositionalEncoding`类,它继承自`nn.Module`。这个类的构造函数接受模型的维度`d_model`和最大序列长度`max_len`。在`forward`方法中,我们将位置编码添加到输入的词嵌入张量`x`中。

请注意,这个位置编码是可学习的,但在实际的Transformer模型中,位置编码通常是固定的,不参与训练。这里为了简化,我们将位置编码作为模型的一部分,但在实际应用中,你可能会将位置编码作为一个固定的张量添加到词嵌入中。



53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询