PyTorch|PyTorch教程(3)RNN

如何使用MNIST数据集建立递归神经网络?
递归神经网络(RNN)被认为是一种记忆网络。我们使用epoch为1,每次使用64个样品的批量大小来建立输入和输出之间的联系。利用RNN模型,我们可以预测图像中存在的数字。
让我们看看下面的例子。递归神经网络在输入层取一个向量序列,在输出层产生一个向量序列。信息序列在递归层中通过内部状态转换进行处理。有时输出值长期依赖于过去的历史值。这是RNN模型的另一种变体:长短期记忆(LSTM)模型。这适用于以顺序方式使用信息的任何类型的领域 。例如,在一个时间序列中,当前股票价格由历史股票价格决定,依赖关系可以是短的或长的。类似地,使用文本输入向量的长范围和短范围的上下文预测。还有其他行业用例,如噪声分类,其中噪声也是一个信息序列。
分类问题 下面的代码片段解释了使用PyTorch模块执行RNN模型。
权值有三组:U、V、W。权值向量集合,用W表示,表示网络中存储单元之间的信息传递,显示隐藏状态之间的通信。RNN使用Word2vec表示的嵌入层。例如,如果你有20,000个单词和1000个隐藏单位,矩阵的嵌入层大小为20,000×1000。新的表示被传递给LSTM,LSTM输出经过sigmoid函数输出。

import torch import torchvision.datasets as dsets import torchvision.transforms as transforms import matplotlib.pyplot as plt torch.manual_seed(1) # 超参数 EPOCH=1 BATCH_SIZE=64 TIME_STEP=28 INPUT_SIZE=28 LR=0.01 DOWNLOAD=True

RNN模型具有超参数,如迭代次数(EPOCH); 批大小取决于单个机器中可用的内存; 记忆信息序列的时间步长; 输入大小和学习率。这些值的选择是指示性的; 我们不能在其他用例中依赖它们。超参数的取值选择是一个迭代过程; 您可以选择多个参数并决定哪个参数有效,或者对模型进行并行训练并决定哪个参数有效。
train_data = https://www.it610.com/article/dsets.MNIST(root="./mnist", train=True, transform=transforms.ToTensor(),download=DOWNLOAD) print(train_data.train_data.size()) print(train_data.train_labels.size()) plt.imshow(train_data.train_data[0].numpy(), cmap="gray") plt.title("%i"%train_data.train_labels[0]) plt.show()

PyTorch|PyTorch教程(3)RNN
文章图片

前面的脚本显示了示例图像数据集的样子。为了训练深度学习模型,我们需要将整个训练数据集转换成小批量,这有助于我们平均模型的最终精度。通过数据加载器,我们可以加载训练数据,并准备小批量数据。在小批量中进行shuffle选择的目的是确保模型捕获实际数据集中的所有变化。
# 数据加载器返回训练数据的mini-batch train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True) # 选择测试集中的前2000个元素 test_data = https://www.it610.com/article/dsets.MNIST(root="./mnist", train=False, transform=transforms.ToTensor()) # shape(2000, 28, 28) test_x = test_data.test_data.type(torch.FloatTensor)[:2000]/255. # convert to numpy test_y = test_data.test_labels.numpy().squeeze()[:2000]

上述脚本准备训练数据集。使用标志train=False捕获测试数据。使用测试数据中的2000个随机样本进行模型测试。测试标签向量以NumPy数组格式表示。
class RNN(nn.Module): def __init__(self): super(RNN, self).__init__() self.rnn = nn.LSTM(# 如果使用nn.RNN(),很难学习 input_size=INPUT_SIZE,# hidden_size=64, # 隐藏神经元 num_layers=1, # rnn 层的数目 batch_first=True, # input & output中batc size作为第一维 ) self.out = nn.Linear(64, 10) def forward(self, x): # x形状为(batch, time_step, input_size) # r_out形状为(batch, time_step, output_size) # h_n形状(n_layers, batch, hidden_size) # h_c形状(n_layers, batch, hidden_size) # None表示0初始化隐藏层 r_out, (h_n, h_c) = self.rnn(x, None) # choose r_out at the last time step out = self.out(r_out[:,-1,:]) return out

在之前的RNN课程中,我们训练了一个LSTM网络,它被证明对长时间保持记忆有效,从而有助于学习。如果我们使用nn.RNN()模型,它很难学习参数,因为RNN的普通实现不能长时间保持或记住信息。在LSTM网络中,图像的宽度被认为是输入的大小,隐藏的大小被决定为隐藏层神经元的数量,num_layers表示网络中RNN层的数量。
RNN模块,在LSTM模块中,产生的输出为64×10的向量大小,因为输出层的数字被分类为0到9。最后一个前向函数说明了如何在RNN网络中进行前向传播。
下面的脚本显示了如何在RNN类下处理LSTM模型。在LSTM函数中,输入长度为28,隐层神经元数为64,从隐层的64个神经元到输出的10个神经元。
rnn = RNN() print(rnn) # RNN( #(rnn): LSTM(28, 64, batch_first=True) #(out): Linear(in_features=64, out_features=10, bias=True) # ) optimizer = torch.optim.Adam(rnn.parameters(),lr=LR) loss_func = nn.CrossEntropyLoss()# 标签你不是独热编码

为了优化所有RNN参数,我们使用Adam优化器。在函数内部,我们也使用了学习率。本例中使用的损失函数是交叉熵损失函数。我们需要提供多个epoch来获得最好的参数。
在下面的脚本中,我们打印了训练损失和测试准确性。经过一个epoch后,测试准确率提高到95%,训练损耗降低到0.19。
# 训练和测试 for epoch in range(EPOCH): for step, (x,y) in enumerate(train_loader): b_x = x.view(-1, 28, 28) b_y = y output = rnn(b_x) loss = loss_func(output, b_y) optimizer.zero_grad() loss.backward() optimizer.step() if step % 50 == 0: test_output=rnn(test_x) pred_y = torch.max(test_output,1)[1].data.numpy().squeeze() accuracy = sum(pred_y==test_y)/float(test_y.size) print("Epoch:", epoch, "| train loss: %.4f" % loss.item(), "|test accuracy: %.4f"% accuracy) # Epoch: 0 | train loss: 2.3178 |test accuracy: 0.0995 # Epoch: 0 | train loss: 1.1102 |test accuracy: 0.5300 # Epoch: 0 | train loss: 0.7031 |test accuracy: 0.7100 # Epoch: 0 | train loss: 0.6014 |test accuracy: 0.7930 # Epoch: 0 | train loss: 0.7127 |test accuracy: 0.8575 # Epoch: 0 | train loss: 0.3254 |test accuracy: 0.8860 # Epoch: 0 | train loss: 0.3258 |test accuracy: 0.8835 # Epoch: 0 | train loss: 0.3760 |test accuracy: 0.9280 # Epoch: 0 | train loss: 0.2738 |test accuracy: 0.9330 # Epoch: 0 | train loss: 0.1623 |test accuracy: 0.9240 # Epoch: 0 | train loss: 0.1836 |test accuracy: 0.9240 # Epoch: 0 | train loss: 0.3307 |test accuracy: 0.9220 # Epoch: 0 | train loss: 0.1129 |test accuracy: 0.9205 # Epoch: 0 | train loss: 0.0855 |test accuracy: 0.9440 # Epoch: 0 | train loss: 0.1522 |test accuracy: 0.9450 # Epoch: 0 | train loss: 0.2400 |test accuracy: 0.9430 # Epoch: 0 | train loss: 0.2307 |test accuracy: 0.9365 # Epoch: 0 | train loss: 0.1162 |test accuracy: 0.9435 # Epoch: 0 | train loss: 0.1968 |test accuracy: 0.9515

一旦模型训练完毕,下一步就是使用RNN模型进行预测。然后我们比较实际输出和实际输出,以评估模型的执行情况。
test_output = rnn(test_x[:10].view(-1, 28, 28)) pred_y = torch.max(test_output,1)[1].data.numpy().squeeze() print(pred_y, "prediction number") print(test_y[:10], "real number") # [7 2 1 0 4 1 4 9 5 9] prediction number # [7 2 1 0 4 1 4 9 5 9] real number

回归问题 我们如何为基于回归的问题建立一个递归神经网络?
回归模型需要一个目标函数和一个特征集,然后再用一个函数来建立输入和输出之间的关系。在本例中,我们将使用递归神经网络(RNN)进行回归任务。回归问题似乎很简单; 它们确实效果最好,但仅限于显示明确线性关系的数据。当预测输入和输出之间的非线性关系时,它们是相当复杂的。
让我们看一下下面的示例,它显示了输入和输出数据之间的非线性循环模式。在前面的教程中,我们研究了RNN用于分类相关问题的一般示例,预测输入图像的类别。然而,在回归中,RNN的结构会改变,因为目标是预测真实值输出。输出层将有一个神经元处于与回归相关的问题中。
import torch from torch import nn import numpy as np import matplotlib.pyplot as plt torch.manual_seed(1) # 超参数 TIME_STEP=10 INPUT_SIZE=1 LR=0.02

下面的脚本显示了一些样本序列,其中目标cos函数近似于sin函数.
# 显示数据 steps = np.linspace(0, np.pi*2, 100, dtype=np.float32) x_np = np.sin(steps) y_np = np.cos(steps) plt.plot(steps, y_np, "r-", label="target (cos)") plt.plot(steps, x_np, "b-", label="input (sin)") plt.legend(loc="best") plt.show()

PyTorch|PyTorch教程(3)RNN
文章图片

让我们看看下面的例子。PyTorch库中的神经网络模块包含RNN函数。在下面的脚本中,我们使用了输入矩阵的大小,隐含层神经元的数量,以及网络中隐藏层的数量。
class RNN(nn.Module): def __init__(self): super(RNN, self).__init__() self.rnn = nn.LSTM(# 如果使用nn.RNN(),很难学习 input_size=INPUT_SIZE,# hidden_size=32, # 隐藏神经元 num_layers=1, # rnn 层的数目 batch_first=True, # input & output中batc size作为第一维 # (batch, time_step, input_size) ) self.out = nn.Linear(32, 1) def forward(self, x, h_state): # x形状为(batch, time_step, input_size) # h_state形状(n_layers, batch, hidden_size) # r_out形状为(batch, time_step, hidden_size) r_out, h_state = self.rnn(x, h_state)outs = []# save all predictions for time_step in range(r_out.size(1)): # 为每一个time step计算output outs.append(self.out(r_out[:,time_step, :])) return torch.stack(outs, dim=1), h_state

在创建RNN类函数之后,我们需要提供优化函数,即Adam,这次的损失函数是均方损失函数。由于目标是对一个连续变量进行预测,所以我们在优化层使用MSELoss函数。
rnn = RNN() print(rnn) # RNN( #(rnn): LSTM(28, 32, batch_first=True) #(out): Linear(in_features=32, out_features=1, bias=True) # ) optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) loss_func = nn.MSELoss() h_state = None plt.figure(1, figsize=(12,5)) plt.ion()for step in range(100): start, end = step * np.pi, (step+1)*np.pi # 使用sin预测cos steps = np.linspace(start, end, TIME_STEP, dtype=np.float32) x_np = np.sin(steps) y_np = np.cos(steps) x = torch.from_numpy(x_np[np.newaxis,:,np.newaxis]) # shape(batch, time_step, input_size) y = torch.from_numpy(y_np[np.newaxis,:,np.newaxis]) optimizer.zero_grad()# 清除梯度值 prediction,_ = rnn(x, h_state) loss = loss_func(prediction, y)# cross entropy loss loss.backward()# 反向传播,计算梯度 optimizer.step()# 更新参数 # 绘图 plt.plot(steps, y_np.flatten(), "r-") plt.plot(steps, prediction.detach().numpy().flatten(), "b-") plt.draw() plt.pause(0.05)

【PyTorch|PyTorch教程(3)RNN】PyTorch|PyTorch教程(3)RNN
文章图片

    推荐阅读