- import torch
- from torch import nn
- from torch.nn import functional as F
- import dltools
- batch_size, num_steps = 32, 35
- # 更改了默认的文件下载方式,需要将 article 文件放入该文件夹
- train_iter, vocab = dltools.load_data_time_machine(batch_size, num_steps)
- num_hiddens = 256
- # 构造了一个具有256个隐藏神经单元的单隐藏层的循环神经网络
- rnn_layer = nn.RNN(len(vocab), num_hiddens)
构造了一个 循环神经网络 (RNN) 层,该 RNN 层具有以下特性:
num_hiddens = 256
: 这行代码定义了 RNN 层中的隐藏单元数量,即 RNN 层内部神经元的数量。在这个例子中,设置为 256,意味着 RNN 层将有 256 个隐藏神经单元。
nn.RNN(len(vocab), num_hiddens)
: 这行代码 创建了一个 RNN 层 的实例。它的参数如下:
len(vocab)
: 这是 输入数据的特征维度。在循环神经网络中,输入数据通常是一个序列,每个时间步的输入是一个向量。len(vocab)
表示词汇表的大小,它代表了序列中的每个时间步可能的输入的数量。在自然语言处理任务中,词汇表的大小通常对应于词汇表中不同词汇的数量。
num_hiddens
: 这是 RNN 层内部的 隐藏单元数量,根据之前定义的值为 256。
综上所述,这段代码创建了一个 具有 256 个隐藏神经单元的单隐藏层的循环神经网络层。这个 RNN 层可以用来处理序列数据,例如文本数据,在文本数据中,每个时间步可以对应一个词汇表中的一个词或一个词的嵌入表示。
- # 初始化隐藏状态
- state = torch.zeros((1, batch_size, num_hiddens))
创建了一个 全零的张量作为隐藏状态。张量的形状是 (1, batch_size, num_hiddens)
,其中:
1
表示时间步的数量,这里初始化的是一个初始时间步的隐藏状态。batch_size
表示批量大小,即一次处理的样本数量。num_hiddens
表示每个时间步的隐藏单元数量,即隐藏状态的维度。- # 构建一个完整的循环神经网络
- class RNNModel(nn.Module):
- def __init__(self, rnn_layer, vocab_size, **kwargs):
- super().__init__(**kwargs)
- self.rnn = rnn_layer
- self.vocab_size = vocab_size
- self.num_hiddens = self.rnn.hidden_size
-
- if not self.rnn.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.rnn(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.rnn.num_layers, batch_size, self.num_hiddens), device=device)
该部分定义了一个名为 RNNModel
的 PyTorch 模型类,该模型是一个循环神经网络 (RNN) 模型,用于处理序列数据。
__init__
方法:这是类的构造函数,用于初始化模型的各个组件。在这里,做了以下工作:
super().__init__(**kwargs)
调用了父类的构造函数,确保正确初始化模型。self.rnn = rnn_layer
存储了 传入的 RNN 层。self.vocab_size = vocab_size
存储了 词汇表的大小。self.num_hiddens = self.rnn.hidden_size
获取了 RNN 层的隐藏状态大小。forward
方法:这个方法定义了 前向传播 过程。它接受输入 inputs
和当前的隐藏状态 state
。在前向传播中,它执行以下操作:
F.one_hot
将输入 inputs
转化为 独热编码,以便与词汇表大小匹配。然后将其转换为浮点数张量。Y
和新的 隐藏状态 state
。Y
重塑成 二维张量,然后通过线性层 self.linear
将其映射到词汇表大小的空间,并返回输出结果。begin_state
方法:这个方法用于 初始化隐藏状态,返回一个全零的张量,其形状取决于 RNN 的层数、方向数、隐藏单元数以及批量大小。
- # 在训练前,跑下模型
- device = dltools.try_gpu()
- net = RNNModel(rnn_layer, vocab_size=len(vocab))
- net = net.to(device)
创建了一个 RNNModel对象,该对象接受一个rnn_layer和一个词汇表大小作为参数。最后,它将模型移动到之前确定的设备上
- # 训练
- num_epochs, lr = 200, 0.1
- dltools.train_ch8(net, train_iter, vocab, lr, num_epochs, device)
dltools.predict_ch8('time traveller', 10, net, vocab, device)