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