位置编码代码示例

embedding+随索引位置波动矩阵=位置编码矩阵

 
单词维度:偶数-正弦,奇数-余弦
单词位置:某个单词在一句话中的索引位置,与三角函数的参数相关

每句话都会得到一个相同的 位置编码矩阵,
该矩阵与经过embedding的句子矩阵相加,就是最终的位置编码矩阵

cos,sin函数范围[-1,1]

 
import torch 
from torch import nn
import math 
torch.manual_seed(73)

# 位置编码层
class PositionEmbedding(nn.Module):
    def __init__(self,num_embeddings=39,seq_len=50,embedding_dim=32):
        super().__init__()

        # pos是第几个词,i是第几个维度,d_model是维度总数
        def get_pe(pos, i, d_model):
            temp = 1e4 ** (i / d_model)
            pe = pos / temp

            if i % 2 == 0:
                return math.sin(pe)
            return math.cos(pe)

        # 初始化位置编码矩阵
        pe = torch.empty(seq_len, embedding_dim)
        for i in range(seq_len):#第几个词
            for j in range(embedding_dim):#第几个维度
                pe[i, j] = get_pe(i, j, embedding_dim)

        pe = pe.unsqueeze(0)

        # 定义为不更新的常量
        self.register_buffer('pe', pe)

        # 词编码层,39=26+10+3
        self.embed = torch.nn.Embedding(num_embeddings, embedding_dim)
        
        # 初始化参数
        self.embed.weight.data.normal_(0, 0.1)

    def forward(self, x):
        # [8, 50] -> [8, 50, 32]
        embed = self.embed(x)

        # 词编码和位置编码相加
        # [8, 50, 32] + [1, 50, 32] -> [8, 50, 32]
        embed = embed + self.pe
        return embed
        

 
#[batch_size=2,seq_len=3]
X = torch.tensor([[1,2,3],[4,2,7]])
# num_embeddings为连续的索引的个数,也可看作索引个数=最大索引值+1
embed = PositionEmbedding(num_embeddings=8,seq_len=3,embedding_dim=3)
embed(X)

 
tensor([[[ 0.0788,  0.8416, -0.1078],
    [ 0.8597,  0.9252,  0.0572],
    [ 0.9962,  0.8905,  0.0526]],

   [[ 0.0153,  0.9039,  0.0861],
    [ 0.8597,  0.9252,  0.0572],
    [ 0.8809,  1.0006,  0.1205]]], grad_fn=)
参考