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=)