这个是接着上一个文章从零实现GRU门控循环单元写的,如果你没看上篇文章也没事,本篇文章是讲如何用pytorch直接实现GRU,和上一篇文章除了思路一样,其他没有任何参考意义。
import torch
from torch import nn
from d2l import torch as d2l
from torch.nn import functional as F
依旧是熟悉的配方熟悉的导包操作。
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
这里和之前没区别,设定一些超参数并加载数据集。
- 设定batch-size批量大小和时间步的长度num_step。这里需要注意时间步的长度是你一个要处理的序列的时间步有多少个。
- 使用之前我们实现过的加载时光机器数据集。获得数据集的迭代器和词汇表的长度,这里为了方便,使用的是char进行分割,也就是说词汇表是a~z以及空格和<unk>。
class GRUModel(nn.Module):
def __init__(self, gru_layer, vocab_size, <strong>kwargs):
super(GRUModel, self).__init__(</strong>kwargs)
self.gru = gru_layer
self.vocab_size = vocab_size
self.num_hiddens = self.gru.hidden_size
if not self.gru.bidirectional:
self.num_directions = 1
self.linear = nn.Linear(self.num_hiddens,
self.vocab_size)
else:
self.num_directions = 2
self.linear = nn.Linear(self.num_hiddens * 2,
self.vocab_size)
def forward(self, inputs, state):
X = F.one_hot(inputs.T.long(), self.vocab_size)
X = X.to(torch.float32)
Y, state = self.gru(X, state)
output = self.linear(Y.reshape((-1, Y.shape[-1])))
return output, state
def begin_state(self, device, batch_size=1):
return torch.zeros((
self.num_directions * self.gru.num_layers,
batch_size, self.num_hiddens),
device=device)
RNN、GRU、LSTM一脉相承,用的类的都差不多,这个是适用于RNN和GRU的,但是不适用于LSTM。LSTM可以看我之后的文章,或者看前边的简洁实现RNN循环神经网络实现的那个RNNModule类,那个类是涵盖了RNN、GRU、LSTM的通用模型。
-
__init__
初始化这个类,这个类是继承了nn.Module
的。
-
self.gru
设定计算层是GRU层,这里是需要参数的,你在下一段代码中会传入nn.GRU
。 -
self.vocab_size
设定字典的大小,这里大小是28,因为我们使用的是字母进行分词,所以其中只有a~z
26个字母外加和<unk>
(空格和unknown)。 -
self.num_hiddens
设置隐藏层的大小。普通的RNN是隐藏层,在这里是带隐状态的隐藏层。不是说有隐状态之后就没隐藏层了。 - if-else语句是设定GRU是单双向的。
-
forward
定义前向传播网络。
这里不用我们自己来实现计算过程了,nn.GRU
会直接给我们计算。但是我们依旧需要对数据进行一下才操作。
- 首先是将输入转化为对应的one-hot向量,这里
F
看前边导包部分,是使用nn.functional
。 -
torch.float32
再将其类型转化为float。 -
Y
和state
是计算隐状态的,注意 在这里Y
不是 输出。这里Y是输出全部的隐状态,state是输出最后一个时间步的隐状态。
-
output
是用于存储输出的。
-
begin_state
是进行初始化。
这里初始化和RNN初始化一样,都是初始化为一个零张量。之后可以留意一下LSTM,LSTM是返回一个元组,元组中有两个张量。
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 100, 1
num_inputs = vocab_size
gru_layer = nn.GRU(num_inputs, num_hiddens)
model = GRUModel(gru_layer, len(vocab))
model = model.to(device)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
设定一些基础数值:
-
vocab_size
词典长度 -
num_hiddens
隐藏层向量的长度 -
device
在CPU还是GPU上执行 -
num_epochs
训练的epoch数量 -
lr
学习率learning rate
GRU层直接使用nn.GRU
。
之后对其进行训练并测试。输出训练集的困惑度和前缀“time traveler”和“traveler”的预测序列结果。