现代循环神经网络实战:机器翻译( 四 )


编码器 代码详解
#@saveclass Seq2SeqEncoder(Encoder):"""用于序列到序列学习的循环神经网络编码器"""def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,dropout=0, **kwargs):super(Seq2SeqEncoder, self).__init__(**kwargs)# 嵌入层self.embedding = nn.Embedding(vocab_size, embed_size)self.rnn = nn.GRU(embed_size, num_hiddens, num_layers,dropout=dropout)def forward(self, X, *args):# 输出'X'的形状:(batch_size,num_steps,embed_size)X = self.embedding(X)# 在循环神经网络模型中,第一个轴对应于时间步X = X.permute(1, 0, 2)# 如果未提及状态,则默认为0output, state = self.rnn(X)# output的形状:(num_steps,batch_size,num_hiddens)# state的形状:(num_layers,batch_size,num_hiddens)return output, state
这段代码定义了一个用于序列到序列学习的循环神经网络编码器 。该编码器由嵌入层和多层循环神经网络组成 。具体解释如下:
class ()::定义了一个名为的类,该类继承自类 。
def init(self, , , , , =0, **)::定义了类的初始化函数,该函数接受以下参数:
:词汇表大小 。
:嵌入向量的维度 。
:循环神经网络中隐藏状态的维度 。

现代循环神经网络实战:机器翻译

文章插图
:循环神经网络中的层数 。
:概率,默认为0 。
**:其他参数 。
super(, self).init(**):调用父类的初始化函数并传入参数 。
self. = nn.(, ):定义一个嵌入层,用于将输入序列中的每个单词转换为嵌入向量 。
self.rnn = nn.GRU(, , , =):定义一个多层循环神经网络,其中包含个GRU层 。GRU层的输入维度为,输出维度为,同时还包括层,的概率为 。
def (self, X, *args)::定义了类的前向传播函数,该函数接受输入序列X和其他参数(*args) 。
X = self.(X):将输入序列X中的每个单词转换为嵌入向量 。
X = X.(1, 0, 2):将输入序列X的维度从(, , )转换为(, , ) 。这样做是为了在循环神经网络模型中,第一个轴对应于时间步 。
, state = self.rnn(X):将转换后的输入序列X传入多层循环神经网络中进行计算,并返回输出和状态 。其中,的形状为(, , ),表示每个时间步的输出;state的形状为(, , ),表示最后一个时间步的状态 。
, state:返回输出和状态 。
X.
在中,X.(dims)是一个张量的方法,它可以用来对张量的维度进行重新排列 。dims是一个整数元组,表示对于原始张量中的每个维度,新张量中应该放置的位置 。例如,如果一个张量的维度是(3,4,5),并且dims=(1,0,2),则表示在新张量中第一个维度是原始张量的第二个维度,第二个维度是原始张量的第一个维度,第三个维度是原始张量的第三个维度 。
具体来说,X.(1, 0, 2)表示将张量X的第一个维度和第二个维度交换,第三个维度不变 。在代码中,这个操作被用于将形状为(, , )的输入序列张量X的维度进行调整,使得第一个维度是时间步,第二个维度是批量大小,从而符合循环神经网络的输入要求 。
为什么X = X.(1, 0, 2)
在循环神经网络中,输入数据的维度需要满足以下要求:
第一个维度是时间步 。第二个维度是批量大小 。
因此,对于一个形状为(, , )的输入序列X,需要将它的维度调整为(, , ) 。
在代码中,通过调用X.(1, 0, 2)来实现维度的调整 。具体地,X.(1, 0, 2)表示将X的维度从(, , )转换为(, , ),即将第一个维度()和第二个维度()进行交换 。这样做的目的是为了将输入序列X中的每个时间步作为输入,而每个时间步中的所有样本(个)作为批量进行处理 。这样做可以充分利用GPU的并行计算能力,提高训练效率 。