输入层代码:
import torch
import torch.nn as nn
import math
from torch.autograd import Variable
# 构建Embedding类来实现文本嵌入层
class Embedding(nn.Module):
def __init__(self, d_model, vocab):
"""类的初始化函数,有两个函数d_model:指词的维度,vocab:指词表的大小,"""
"""接着使用super的方式指明继承nn.module的初始化函数,我们自己实现的所有层都会这样去继承super(Embedding,self).__init__()"""
super(Embedding, self).__init__()
# 之后就是调用nn中的预定义层Embedding,获得一个词的嵌入对象self.lut
self.lut = nn.Embedding(vocab, d_model)
# 最后就是将d_model传入类中
self.d_model = d_model
# 前馈神经网络
def forward(self, x):
"""可以将其理解为该层的前向传播逻辑,所有层都会有此函数
当传给该类的实例化对象参数时,自动调用该类该函数
参数x:因为Embeddeding层是首层,所以代表输入给模型的文本通过词汇映射后的张量
"""
# 将x传给self.lut并与根号下self.d_model相乘作为结果返回
return self.lut(x) * math.sqrt(self.d_model)
# 测试Embedding层的功能
d_model = 512
vocab = 1000
x = Variable(torch.LongTensor([[100, 2, 421, 508], [491, 998, 1, 221]]))
emb = Embedding(d_model, vocab)
embr = emb(x)
print("embr:", embr)
print(embr.shape)
# 构建位置编码器的类
class PostitionalEncoding(nn.Module):
def __init__(self, d_model, dropout, max_len=5000):
# d_model:代表词嵌入的维度
# dropout:代表drouput的置零比率
# max_len:代表每个句子的最大长度
super(PostitionalEncoding, self).__init__()
# 实例Drouput层
self.dropout = nn.Dropout(p=dropout)
# 初始化一个位置编码矩阵,大小是max_len*d_model
pe = torch.zeros(max_len, d_model)
# 初始化一个绝对位置矩阵,max_len*1
position = torch.arange(0, max_len).unsqueeze(1)
# 定义一个变化矩阵div_term,跳跃式的初始化
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代表的是Embedding层的输出
# x:代表文本序列的词嵌入表示
# 首先明确pe的编码太长了,将第二个维度,也就是max_len对应的那个维度缩小为x的句子大小
x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)
return self.dropout(x)
# 位置编码器的测试部分
d_model = 512
dropout = 0.1
max_len = 60
x = embr
pe = PostitionalEncoding(d_model, dropout, max_len)
pe_result = pe(x)
print(pe_result)
print("pe_result:", pe_result.shape)