transformer中的positional encoding(位置编码)

transformer模型是当前大红大热的语言模型,今天要讲解的是transformer中的positional encoding(位置编码).
我们知道,transformer模型的attention机制并没有包含位置信息,即一句话中词语在不同的位置时在transformer中是没有区别的,这当然是不符合实际的。因此,在transformer中引入位置信息相比CNN, RNN等模型有更加重要的作用。
作者添加位置编码的方法是:构造一个跟输入embedding维度一样的矩阵,然后跟输入embedding相加得到multi-head attention 的输入。
在paper中,作者使用的positional encoding如下:
在这里插入图片描述
其中,PE为二维矩阵,大小跟输入embedding的维度一样,行表示词语,列表示词向量;pos 表示词语在句子中的位置; d m o d e l d_{model} dmodel表示词向量的维度;i表示词向量的位置。因此,上述公式表示在每个词语的词向量的偶数位置添加sin变量,奇数位置添加cos变量,以此来填满整个PE矩阵,然后加到input embedding中去,这样便完成位置编码的引入了。
使用sin编码和cos编码的原因是可以得到词语之间的相对位置,因为:
s i n ( α + β ) = s i n α c o s β + c o s α s i n β 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 β cos(\alpha+\beta)= cos\alpha cos\beta - sin\alpha sin\beta cos(α+β)=cosαcosβsinαsinβ
即由 s i n ( p o s + k ) sin(pos+k) sin(pos+k)可以得到,通过线性变换获取后续词语相对当前词语的位置关系。
positional encoding 的源代码如下:

class PositionalEncoding(nn.Module):
    "Implement the PE function."

    def __init__(self, d_model, dropout, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)

        # Compute the positional encodings once in log space.
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) *
                             -(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)
        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + Variable(self.pe[:, :x.size(1)],
                         requires_grad=False)
        return self.dropout(x)

其中,div_term是上述公式经过简单的数学变换得到的,具体如下:
1 / 1000 0 2 i / d m o d e l = e l o g 1000 0 − 2 i / d m o d e l = e − 2 i / d m o d e l ∗ l o g 10000 = e 2 i ∗ ( − l o g 10000 / d m o d e l ) 1/10000^{2i/d_{model}}=e^{log^{10000^{-2i/d_{model}}}}=e^{{-2i/d_{model}}*{log^{10000}}}=e^{{2i}*(-log^{10000}/d_{model})} 1/100002i/dmodel=elog100002i/dmodel=e2i/dmodellog10000=e2i(log10000/dmodel)
我在执行过程中,出现了如下错误:
RuntimeError: “exp” not implemented for ‘torch.LongTensor’
估计原因是pytorch的版本问题,解决方法为将torch.arange(0, d_model, 2)中的整型改为浮点型,即torch.arange(0.0, d_model, 2)
在这里插入图片描述

添加于2020.10.22:
我在实验中尝试将position_embeddings这个向量注释掉,重新跑一遍生成模型,效果下降很明显,具体表现为容易生成重复的字/词。所以,这个位置编码相对于transformer来说是非常重要的。

参考:
attention is all you need
自然语言处理N天-使用Pytorch实现Transformer第一节
RuntimeError: “exp” not implemented for ‘torch.LongTensor’

### 位置编码Transformer 模型中的作用 Transformer 是一种基于自注意力机制的神经网络架构,在处理序列数据时表现出色。然而,由于其设计不依赖于循环或卷积操作,因此无法像 RNN 或 CNN 那样自然地捕捉输入序列的位置信息。为了弥补这一缺陷,引入了 **位置编码 (Positional Encoding)** 来显式表示令牌在其序列中的相对或绝对位置。 位置编码的作用在于为模型提供关于序列顺序的信息,使得自注意力机制能够区分相同内容但在不同位置上的标记[^1]。具体来说: - 自注意力机制本身不具备感知位置的能力,它仅关注特征之间的关系而忽略它们的实际排列。 - 通过将位置编码加入到词嵌入向量中,可以赋予每个单词额外的空间维度属性,从而帮助模型更好地理解上下文语境以及时间步长间的关联性[^2]。 --- ### 实现方法:Sinusoidal Positional Encoding 最常用的一种形式化方式是采用正弦函数余弦函数来定义固定长度的位置编码矩阵。这种方法具有如下特点: #### 数学表达 对于给定的一个 token 所处的位置 \(pos\) embedding 维度 \(i\): \[ PE_{(\text{pos}, 2i)} = \sin\left(\frac{\text{pos}}{10000^{2i/d}}\right) \] \[ PE_{(\text{pos}, 2i+1)} = \cos\left(\frac{\text{pos}}{10000^{2i/d}}\right) \] 其中: - \(d\) 表示 embedding 的总维数; - 此公式交替使用 sine cosine 函数生成偶数索引 (\(2i\)) 及奇数索引 (\(2i+1\)) 上对应的值。 这种周期性的特性允许模型推断任意距离的关系,即使这些距离超出了训练期间遇到的最大句长范围之外[^3]。 #### Python 实现代码 以下是利用上述公式的简单实现例子: ```python import numpy as np import torch def sinusoidal_position_encoding(max_len, d_model): pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2) * -(np.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) # Even indices pe[:, 1::2] = torch.cos(position * div_term) # Odd indices return pe.unsqueeze(0) # Example usage: max_length = 512 embedding_dim = 768 pe_matrix = sinusoidal_position_encoding(max_length, embedding_dim) print(pe_matrix.shape) # Output shape should be [1, max_length, embedding_dim] ``` 此代码片段展示了如何构建一个形状为 `[batch_size, sequence_length, hidden_dimension]` 的张量作为附加信息供后续计算所用[^4]。 --- ### 总结 综上所述,位置编码不仅解决了 Transformer 对序列次序无感的问题,还增强了模型捕获长期依赖性局部模式的能力。借助精心设计的位置编码方案,我们可以显著提升 NLP 应用场景下的性能表现。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值