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()
文章图片
前面的脚本显示了示例图像数据集的样子。为了训练深度学习模型,我们需要将整个训练数据集转换成小批量,这有助于我们平均模型的最终精度。通过数据加载器,我们可以加载训练数据,并准备小批量数据。在小批量中进行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库中的神经网络模块包含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】
文章图片
推荐阅读
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- pytorch|使用pytorch从头实现多层LSTM
- Pytorch|Pytorch AlexNet Fashion-MNIST
- 用npm发布一个包的教程并编写一个vue的插件发布
- 20180322【w4复盘日志】
- 狗狗定点大小便视频教程下载地址
- SwiftUI|SwiftUI iOS 瀑布流组件之仿CollectionView不规则图文混合(教程含源码)
- 【实用教程】4种获取无水印视频素材的方法
- 【糯米糖藕】教程