★ 利用
RNN实现MNIST手写数字分类(图片类型的数据)前提:GPU版PyTorch已安装
查看方法:
import torch
print(torch.__version__) # 查看Pytorch版本
# 1.7.1
print(torch.cuda.is_available()) # 验证GPU版是否可用
# True
参考书目:深度学习入门之PyTorch@page127
参考网页:https://www.jb51.net/article/178199.htm
import torch
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision.datasets import mnist
from torchvision import transforms
from torch.autograd import Variable
import matplotlib.pyplot as plt
import datetime
解说
该网络定义主要由LSTM网络和线性网络构成,LSTM网络接受图片序列,线性网络将它输出成最后的概率向量
定义一个用于图片分类的循环神经网络
class Rnn(nn.Module):
def __init__(self, in_dim = 28, hidden_dim = 100, n_layer = 2, n_class = 10): # tao, 指定了参数的数值,参考网页↑
super(Rnn, self).__init__()
self.n_layer = n_layer
self.hidden_dim = hidden_dim
self.lstm = nn.LSTM(in_dim, hidden_dim, n_layer) # LSTM网络:接受图片序列 # tao, delete postfix ->【, batch_first = True】
self.classifier = nn.Linear(hidden_dim, n_class) # 线性网络:将它输出成最后的概率向量
def forward(self, x):
# h0 = Variable(torch.zeros(self.n_layer, x.size(1), self.hidden_dim)).cuda()
# c0 = Variable(torch.zeros(self.n_layer, x.size(1), self.hidden_dim)).cuda()
# tao修改代码块(参考自网页 https://www.jb51.net/article/178199.htm)
x = x.squeeze() #去掉(batch,1,28,28)中的1,变成(batch, 28,28)
x = x.permute(2, 0, 1)#将最后一维放到第一维,变成(batch,28,28)
out, _ = self.lstm(x) #使用默认的隐藏状态,得到的out是(28, batch, hidden_feature)
out = out[-1,:,:]#取序列中的最后一个,大小是(batch, hidden_feature)
out = self.classifier(out) #得到分类结果
return out
# # 原书代码
# out, _ = self.lstm(x)
# # 注意这个细节,这是因为循环神经网络的输出也是一个序列
# out = out[:, -1, :] # 这一行代码是取出输出序列中的最后一个,在应用线性层作为最后的输出结果
# out = self.classifier(out)
# return out
Indispensable code block 【数据准备1/2】
# 预处理=>将各种预处理组合在一起
data_tf = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize([0.5],[0.5])])
train_set = mnist.MNIST('./data',train=True,transform=data_tf,download=True)
test_set = mnist.MNIST('./data',train=False,transform=data_tf,download=True)
Skip or Not 【中间变量/图形图像查看】
# 查看数据详情
print(train_set.data.size())
print(train_set.targets.size())
# 图片数据,打印一张出来看看
plt.imshow(train_set.data[0].numpy(),cmap='gray')
plt.title('%i' % train_set.targets[0]) # 图片名称,显示真实标签,%i %d十进制整数,有区别,深入请查阅资料
plt.show()
Output
torch.Size([60000, 28, 28])
torch.Size([60000])

Indispensable code block 【数据准备2/2】
train_data = DataLoader(train_set,batch_size=64,shuffle=True)
test_data = DataLoader(test_set,batch_size=128,shuffle=False)
Skip or Not
print(train_set)
print(test_set)
print("------------")
print(type(train_set))
print(type(train_data))
Output
Dataset MNIST
Number of datapoints: 60000
Root location: ./data
Split: Train
StandardTransform
Transform: Compose(
ToTensor()
Normalize(mean=[0.5], std=[0.5])
)
Dataset MNIST
Number of datapoints: 10000
Root location: ./data
Split: Test
StandardTransform
Transform: Compose(
ToTensor()
Normalize(mean=[0.5], std=[0.5])
)
------------
torchvision.datasets.mnist.MNIST
torch.utils.data.dataloader.DataLoader
Skip or Not 【
iter,next】
dataiter= iter(train_data)
imgs,labs = next(dataiter)
print(imgs)#imgs.size()=torch.Size([64, 1, 28, 28])
print(labs)#图片的标签,就是类别,mnist一共有10个类别,故其取值分布在[0,9]之间
Output
tensor([[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]],
[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]],
[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]],
...,
[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]],
[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]],
[[[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]]]])
tensor([1, 6, 3, 9, 6, 8, 3, 0, 0, 4, 5, 8, 2, 7, 2, 2, 4, 5, 9, 4, 1, 7, 4, 4,
5, 7, 6, 4, 8, 0, 6, 7, 7, 7, 1, 0, 9, 4, 5, 6, 2, 6, 3, 1, 1, 8, 1, 1,
1, 8, 8, 0, 0, 8, 3, 6, 0, 3, 8, 9, 6, 3, 7, 7])
Skip or Not 【
enumerate,next】
# 一批测试数据组成内容
examples = enumerate(test_data)
batch_idx, (example_data, example_targets) = next(examples)
print(example_targets)
print(example_data.shape)
Output
tensor([7, 2, 1, 0, 4, 1, 4, 9, 5, 9, 0, 6, 9, 0, 1, 5, 9, 7, 3, 4, 9, 6, 6, 5,
4, 0, 7, 4, 0, 1, 3, 1, 3, 4, 7, 2, 7, 1, 2, 1, 1, 7, 4, 2, 3, 5, 1, 2,
4, 4, 6, 3, 5, 5, 6, 0, 4, 1, 9, 5, 7, 8, 9, 3, 7, 4, 6, 4, 3, 0, 7, 0,
2, 9, 1, 7, 3, 2, 9, 7, 7, 6, 2, 7, 8, 4, 7, 3, 6, 1, 3, 6, 9, 3, 1, 4,
1, 7, 6, 9, 6, 0, 5, 4, 9, 9, 2, 1, 9, 4, 8, 7, 3, 9, 7, 4, 4, 4, 9, 2,
5, 4, 7, 6, 7, 9, 0, 5])
torch.Size([128, 1, 28, 28])
Skip or Not 【绘图:
plt@import matplotlib.pyplot as plt】
# 取一部分查看
fig = plt.figure()
for i in range(6):
plt.subplot(2,3,i+1)
plt.tight_layout()
plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
plt.title("Ground Truth: {}".format(example_targets[i]))
plt.xticks([])
plt.yticks([])
plt.show()
Output

Indispensable code block【模型调用】
net = Rnn()
print(net) # 可以查看模型结构
if torch.cuda.is_available():
print("GPU Available")
net = net.cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),1e-1)
Output
Rnn(
(lstm): LSTM(28, 100, num_layers=2)
(classifier): Linear(in_features=100, out_features=10, bias=True)
)
GPU Available
Indispensable code block【训练&测试】
代码运行时间记录方法 -> 记录时间消耗4步 @
import datetime
nums_epoch = 20
# 开始训练
losses =[]
acces = []
eval_losses = []
eval_acces = []
# 记录时间消耗 1/4
prev_time = datetime.datetime.now() # time
for epoch in range(nums_epoch):
train_loss = 0
train_acc = 0
net = net.train()
for img, label in train_data:
#img = img.reshape(img.size(0),-1)
if torch.cuda.is_available():
img = Variable(img).cuda()
label = Variable(label).cuda()
else:
img = Variable(img)
label = Variable(label)
# 前向传播
out = net(img)
loss = criterion(out,label)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 记录误差
train_loss += loss.item()
# 计算分类的准确率
_,pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
train_acc += acc
losses.append(train_loss / len(train_data))
acces.append(train_acc / len(train_data))
# 记录时间消耗 2/4
cur_time = datetime.datetime.now() # time
hhh, remainder = divmod((cur_time - prev_time).seconds, 3600) # time
mmm, sss = divmod(remainder, 60) # time
time_str = "Time %02d:%02d:%02d" % (hhh, mmm, sss) # time
eval_loss = 0
eval_acc = 0
# 测试集不训练
for img , label in test_data:
#img = img.reshape(img.size(0),-1)
if torch.cuda.is_available():
img = Variable(img).cuda()
label = Variable(label).cuda()
else:
img = Variable(img)
label = Variable(label)
out = net(img)
loss = criterion(out,label)
# 记录误差
eval_loss += loss.item()
_ , pred = out.max(1)
num_correct = (pred==label).sum().item()
acc = num_correct / img.shape[0]
eval_acc += acc
# 记录时间消耗 3/4
prev_time = cur_time
eval_losses.append(eval_loss / len(test_data))
eval_acces.append(eval_acc / len(test_data))
print('Epoch {} Train Loss {} Train Accuracy {} Test Loss {} Test Accuracy {}'.format(
epoch+1, train_loss / len(train_data),train_acc / len(train_data), eval_loss / len(test_data), eval_acc / len(test_data)))
print(cur_time) # 记录时间消耗 4/4
结果输出
1.Epoch 1 Train Loss 1.7209380644597987 Train Accuracy 0.36350613006396587 Test Loss 0.674197974838788 Test Accuracy 0.7854034810126582
2.2021-04-11 11:27:40.920542
3.Epoch 2 Train Loss 0.30949205364277366 Train Accuracy 0.9076492537313433 Test Loss 0.17407198870389523 Test Accuracy 0.950059335443038
4.2021-04-11 11:27:56.628108
5.Epoch 3 Train Loss 0.13884762286055666 Train Accuracy 0.9594216417910447 Test Loss 0.13562022487904074 Test Accuracy 0.9610363924050633
6.2021-04-11 11:28:12.395561
7.Epoch 4 Train Loss 0.101547363801484 Train Accuracy 0.9693663379530917 Test Loss 0.09922966387276125 Test Accuracy 0.9707278481012658
8.2021-04-11 11:28:28.192915
9.Epoch 5 Train Loss 0.0815562306389983 Train Accuracy 0.9756629797441365 Test Loss 0.09412724761398439 Test Accuracy 0.9709256329113924
10.2021-04-11 11:28:44.020164
11.Epoch 6 Train Loss 0.0687523225897244 Train Accuracy 0.9792610607675906 Test Loss 0.07506146606741639 Test Accuracy 0.9765625
12.2021-04-11 11:28:59.820516
13.Epoch 7 Train Loss 0.05848293340102688 Train Accuracy 0.9826759061833689 Test Loss 0.06827540622870851 Test Accuracy 0.9798259493670886
14.2021-04-11 11:29:15.627318
15.Epoch 8 Train Loss 0.049010571555918585 Train Accuracy 0.9849913379530917 Test Loss 0.06305017933850707 Test Accuracy 0.9811115506329114
16.2021-04-11 11:29:31.420040
17.Epoch 9 Train Loss 0.043739378950851504 Train Accuracy 0.9866404584221748 Test Loss 0.06487459723861251 Test Accuracy 0.9788370253164557
18.2021-04-11 11:29:47.206276
19.Epoch 10 Train Loss 0.03890312307671622 Train Accuracy 0.9879231076759062 Test Loss 0.08851856838460846 Test Accuracy 0.974881329113924
20.2021-04-11 11:30:02.971917
21.Epoch 11 Train Loss 0.035701624276776756 Train Accuracy 0.9890058635394456 Test Loss 0.058823986216212466 Test Accuracy 0.9832871835443038
22.2021-04-11 11:30:18.733420
23.Epoch 12 Train Loss 0.032145718470087216 Train Accuracy 0.9898554104477612 Test Loss 0.05840251735806512 Test Accuracy 0.9840783227848101
24.2021-04-11 11:30:34.496777
25.Epoch 13 Train Loss 0.02828378130949022 Train Accuracy 0.9912046908315565 Test Loss 0.055727175945309994 Test Accuracy 0.9831882911392406
26.2021-04-11 11:30:50.290992
27.Epoch 14 Train Loss 0.024952145273621475 Train Accuracy 0.9922208155650319 Test Loss 0.09268021784115676 Test Accuracy 0.9747824367088608
28.2021-04-11 11:31:06.054200
29.Epoch 15 Train Loss 0.024101163034447964 Train Accuracy 0.9924373667377399 Test Loss 0.04986062547088088 Test Accuracy 0.9848694620253164
30.2021-04-11 11:31:21.813121
31.Epoch 16 Train Loss 0.021454994980583904 Train Accuracy 0.9932369402985075 Test Loss 0.06417481121319771 Test Accuracy 0.9817049050632911
32.2021-04-11 11:31:37.632915
33.Epoch 17 Train Loss 0.01850110391111571 Train Accuracy 0.9944363006396588 Test Loss 0.05086001321799387 Test Accuracy 0.9862539556962026
34.2021-04-11 11:31:53.919065
35.Epoch 18 Train Loss 0.016031143488548595 Train Accuracy 0.9951525852878464 Test Loss 0.04880191164041127 Test Accuracy 0.9863528481012658
36.2021-04-11 11:32:10.174033
37.Epoch 19 Train Loss 0.014600724598591668 Train Accuracy 0.9956023454157783 Test Loss 0.051668307816634056 Test Accuracy 0.9861550632911392
38.2021-04-11 11:32:25.947818
39.Epoch 20 Train Loss 0.01331954812350522 Train Accuracy 0.995985474413646 Test Loss 0.05343886803516225 Test Accuracy 0.986056170886076
40.2021-04-11 11:32:41.710178