深度学习RNNLSTMGRU 网络使用教程
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习RNNLSTMGRU 网络使用教程 相关的知识,希望对你有一定的参考价值。
前言
- 在 RNN实战-姓名分类 中介绍了最基础 RNN 网络结构的搭建,个人感觉对 RNN 网络结构的理解与使用远远不够,缺乏普遍性。
- 本文将对 pytorch 中的 RNN 网络结构的使用进行介绍,力求在代码逻辑层面达到普遍性。
- 本文暂不涉及网络结构的数学理论基础。
- 【深度学习】RNN、LSTM、GRU 网络使用教程 (一)
1. 数据处理
无论是 RNN、LSTM、GRU 的哪一种网络结构,它们对于输入都有统一的要求,输入的数据都是序列数据。格式必须是 (batch, time_step, input_size) 。
- batch:该批次样本数,可以为1.
- time_step: 样本的序列长度。(对于 pytorch, 不同样本之间,序列长度可以不相同,这点后面会说)
- input_size: 样本每条序列的特征数目。(无论是样本还是序列之间,input_size 必须相同)
由于它对于输入数据格式的特殊性,个人感觉这也是使用 RNN 的一个难点,我们要想办法把我们的训练数据处理成 RNN 网络能够接收的格式。对于这点,会在后面的实战教程中具体操作,仅供参考。
在 RNN实战-姓名分类 实战中定义的RNN网络模型,输入的文本张量的one-hot
表示形式。
class RNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size, num_layers=1):
"""
:param input_size:代表RNN输入的最后一个维度
:param hidden_size:代表RNN隐藏层的最后一个维度
:param output_size:代表RNN网络最后线性层的输出维度
:param num_layers:代表RNN网络的层数
"""
super(RNN, self).__init__()
self._input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
self.num_layers = num_layers
# 实例化预定义的RNN,三个参数分别是input_size,hidden_size,num_layers
self.rnn = nn.RNN(input_size, hidden_size, num_layers)
# 实例化全连接线形层,作用是将RNN的输出维度转化成指定的输出维度
self.linear = nn.Linear(hidden_size, output_size)
# 实例化nn中预定义的softmax层,用于从输出层中获得类别的结果
self.softmax = nn.LogSoftmax(dim=-1)
def forward(self, input1, hidden):
# input1:代表人名分类器中的输入张量,形状是 1 * n_letters
# hidden:代表RNN的隐藏层张量,形状是 self.num_layers * 1 * self.hidden_size
# 注意:输入到RNN中的张量要求是三维张量,所以要用unsqueeze()函数扩充维度
input1 = input1.unsqueeze(0)
# 将input1和hidden输入到RNN的实例化对象中,如果num_layers=1,rr恒等于hn
rr, hn = self.rnn(input1, hidden)
# 将从RNN中获得的结果通过线形层的变换和softmax层的处理,最终返回
return self.softmax(self.linear(rr)), hn
def initHidden(self):
# 本函数的作用是用来初始化一个全零的隐藏层张量,维度是3
return torch.zeros(self.num_layers, 1, self.hidden_size)
在本文中我们选取的是 手写数字识别的例子,这样一张图片就可以看作是一个长度为 28 的序列,每个序列的特征数是 28。(我们的图片是 28 * 28 )。
# 整个数据集上训练次数
EPOCH = 1
# 分批次训练
BATCH_SIZE = 64
# image height
TIME_STEP = 28
# image width
INPUT_SIZE = 28
LR = 0.01
DOWNLOAD_MNIST = False
train_data = dsets.MNIST(
root='./mnist/',
train=True,
# 我们可以使用 transforms.ToTensor() 将 PIL.Image/numpy.ndarray 数据进转化为torch.FloadTensor,并且在训练的时候,归一化到[0, 1.0]
transform=transforms.ToTensor(),
download=DOWNLOAD_MNIST,
)
print(train_data.train_data.size())
print(train_data.train_labels.size())
# 分批次训练
train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
# 这里测试数据我们只取前 2000
test_data = dsets.MNIST(root='./mnist/', train=False)
test_x = test_data.test_data.type(torch.FloatTensor)[:2000]/255.
test_y = test_data.test_labels.numpy()[:2000]
2. 定义网络结构
class LSTM(nn.Module):
def __init__(self):
super(LSTM, self).__init__()
self.rnn = nn.LSTM(
input_size=INPUT_SIZE,
hidden_size=128,
num_layers=1,
batch_first=True
)
self.out = nn.Linear(128, 10)
def forward(self, x):
# None 表示 hidden state 会用全0的 state
r_out, h_state = self.rnn(x, None)
""" 因为是分类,这里我们只要最后一个预测结果 """
out = self.out(r_out[:,-1,:])
return out
lstm = LSTM()
3. 定义损失函数
loss_func = nn.CrossEntropyLoss()
4. 定义优化器
optimizer = torch.optim.Adam(rnn.parameters(), lr=LR)
5. 模型训练
all_losses = []
for epoch in range(EPOCH):
for step, (train_x, train_y) in enumerate(train_loader):
# reshape x to (batch, time_step, input_size)
train_x = train_x.view(-1, 28, 28)
output = lstm(train_x)
loss = loss_func(output, train_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
all_losses.append(loss)
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure()
plt.plot(all_losses)
模型效果:
可以看到,随着模型的迭代,loss 越来越小,说明模型的训练是有价值的。
6. 验证模型效果
模型训练完成之后,我们在测试集上验证下模型的准确率
test_output = lstm(test_x.view(-1, 28, 28))
pred_y = torch.max(test_output, 1)[1].data.numpy()
accuracy = float((pred_y == test_y).astype(int).sum()) / float(test_y.size)
print(accuracy)
最后模型的准确率为 0.962,对于 EPOCH 为 1 来说,这个准确率要比之前的 CNN 好很多了。
7. LSTM —> GRU
我们注意到对于 LSTM 来说,返回结果格式和 RNN 一样,也是两个部分 output 和 hidden。其实 LSTM 返回的 hidden 由两部分构成: hidden 0、hidden 1。了解 LSTM 原理的同学应该清楚,这里不在此篇介绍。 GRU 作为 LSTM 的一个变体。在我们的项目工程使用上几乎没有区别,只需要在 nn 模块调用 GRU 即可。
网络结构定义如下:
class GRU(nn.Module):
def __init__(self):
super(GRU, self).__init__()
self.rnn = nn.GRU(
input_size=INPUT_SIZE,
hidden_size=128,
num_layers=1,
batch_first=True
)
self.out = nn.Linear(128, 10)
def forward(self, x):
# None 表示 hidden state 会用全0的 state
r_out, h_state = self.rnn(x, None)
""" 因为是分类,这里我们只要最后一个预测结果 """
out = self.out(r_out[:,-1,:])
return out
gru = GRU()
之后的模型训练 和前面的 LSTM 完全一样,这里不再具体展示。
在相同条件下使用 GRU 替换 LSTM 训练之后模型的准确率为 0.952。当然通过一次简单的测试并不能说明模型的优劣,本文的重点也是在于介绍 LSTM 和 GRU 的使用,对于算法的差异性,后续再补。
原文链接:Link
加油!
感谢!
努力!
以上是关于深度学习RNNLSTMGRU 网络使用教程 的主要内容,如果未能解决你的问题,请参考以下文章