PyTorch实例Ⅱ(卷积神经网络)

★ 利用CNN再现MNIST手写数字分类

前提:GPU版PyTorch已安装

查看方法:

import torch
print(torch.__version__) # 查看Pytorch版本
# 1.7.1
print(torch.cuda.is_available()) # 验证GPU版是否可用
# True

Part 1/3 定义网络

netCNN.py —— 定义的神经网络,单独的一个脚本文件,供后期调用

  • 注意:在Jupyter notebook中,建立.py文件的方法,可以先建立一个.txt文件,编辑完成后,改后缀为.py即可。

import torch.nn as nn
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3), # b, 16, 26, 26 卷积层 1/4
nn.BatchNorm2d(16),
nn.ReLU(inplace=True)
)
self.layer2 = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=3), # b, 32, 24, 24 卷积层 2/4
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2) # b, 32, 12, 12 最大池化层1/2
)
self.layer3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=3), # b, 64, 10, 10 卷积层 3/4
nn.BatchNorm2d(64),
nn.ReLU(inplace=True)
)
self.layer4 = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=3), # b, 128, 8, 8 卷积层 4/4
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2) # b, 128, 4, 4 最大池化层2/2
)
self.fc = nn.Sequential(
nn.Linear(128 * 4 * 4, 1024),
nn.ReLU(inplace=True),
nn.Linear(1024, 128),
nn.ReLU(inplace=True),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x

Part 2/3 载入数据和模型

# 预处理 -> 将各种预处理组合在一起
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)
# batch_size是一个参数,可以提前定义
train_data = DataLoader(train_set,batch_size=64,shuffle=True)
test_data = DataLoader(test_set,batch_size=128,shuffle=False)
net = netCNN.CNN()
# net = CNN()
if torch.cuda.is_available():
print("GPU Available")
net = net.cuda()
# learning_rate = 1e-1 # 可以提前定义,也可以直接指定
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),1e-1)

Part 3/3 Version 1.0

代码参考网络,训练和测试同时进行。

nums_epoch = 20
# 开始训练
losses =[]
acces = []
eval_losses = []
eval_acces = []
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))
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
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)))

Part 3/3 Version 1.0 输出结果

训练和测试同时进行的代码输出结果

1.Epoch 1 Train Loss 0.1200949283268825 Train Accuracy 0.9624033848614072 Test Loss 0.03021998926547733 Test Accuracy 0.9894185126582279
2.Epoch 2 Train Loss 0.03246538862835483 Train Accuracy 0.9897054904051172 Test Loss 0.02885316127356395 Test Accuracy 0.990506329113924
3.Epoch 3 Train Loss 0.022931524569345916 Train Accuracy 0.9926872334754797 Test Loss 0.021938524580220956 Test Accuracy 0.9924841772151899
4.Epoch 4 Train Loss 0.016952382484600178 Train Accuracy 0.9947694562899787 Test Loss 0.022626916710163918 Test Accuracy 0.9923852848101266
5.Epoch 5 Train Loss 0.012722379837827043 Train Accuracy 0.9958855277185501 Test Loss 0.02963682129401478 Test Accuracy 0.9887262658227848
6.Epoch 6 Train Loss 0.00933914151214313 Train Accuracy 0.9971515191897654 Teat Loss 0.016077996881098375 Test Accuracy 0.9943631329113924
7.Epoch 7 Train Loss 0.0073814120018459725 Train Accuracy 0.9978011727078892 Test Loss 0.020331518359456176 Test Accuracy 0.9937697784810127
8.Epoch 8 Train Loss 0.006885198775323313 Train Accuracy 0.9978011727078892 Test Loss 0.018373859318625698 Test Accuracy 0.993868670886076
9.Epoch 9 Train Loss 0.0038942436833549476 Train Accuracy 0.9990005330490405 Test Loss 0.016592746393847606 Test Accuracy 0.9956487341772152
10.Epoch 10 Train Loss 0.002232599869024773 Train Accuracy 0.9994003198294243 Test Loss 0.015350714311217657 Test Accuracy 0.995253164556962
11.Epoch 11 Train Loss 0.0017868314392756248 Train Accuracy 0.9995169243070362 Test Loss 0.018393577383369466 Test Accuracy 0.9948575949367089
12.Epoch 12 Train Loss 0.0016904843163558175 Train Accuracy 0.9995668976545842 Test Loss 0.016470837249351892 Test Accuracy 0.9956487341772152
13.Epoch 13 Train Loss 0.0009593032377107248 Train Accuracy 0.9997168176972282 Test Loss 0.017069807002093356 Test Accuracy 0.9956487341772152
14.Epoch 14 Train Loss 0.0005009614711480778 Train Accuracy 0.9999167110874201 Test Loss 0.017695282020998935 Test Accuracy 0.9951542721518988
15.Epoch 15 Train Loss 0.000283710520967615 Train Accuracy 0.999950026652452 Test Loss 0.017179816710221504 Test Accuracy 0.9956487341772152
16.Epoch 16 Train Loss 0.000170343950114149 Train Accuracy 1.0 Test Loss 0.01801280932005637 Test Accuracy 0.9954509493670886
17.Epoch 17 Train Loss 0.0001393258903054915 Train Accuracy 0.999983342217484 Test Loss 0.01771450764791116 Test Accuracy 0.9958465189873418
18.Epoch 18 Train Loss 0.00018152690381616592 Train Accuracy 0.999950026652452 Test Loss 0.018631271707387376 Test Accuracy 0.9958465189873418
19.Epoch 19 Train Loss 9.018222667412523e-05 Train Accuracy 1.0 Test Loss 0.018682040436009194 Test Accuracy 0.9957476265822784
20.Epoch 20 Train Loss 7.264835773966668e-05 Train Accuracy 1.0 Test Loss 0.01840561395100387 Test Accuracy 0.9956487341772152

Part 3/3 Version 2.0 - Train

代码修改自网络,将训练部分和测试部分分开。这里是训练部分

nums_epoch = 20
# 开始训练
losses =[]
acces = []
eval_losses = []
eval_acces = []
for epoch in range(nums_epoch):
train_loss = 0
train_acc = 0
epoch_bar = 0 # t
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
# epoch_bar += 1 # t
# if epoch_bar % 100 == 0:
# print('epoch: {}, loss: {:.4}'.format(epoch_bar, loss.data.item())) # t
# 注意对齐方式,和第二个for循环对齐
losses.append(train_loss / len(train_data))
acces.append(train_acc / len(train_data))
print('Epoch {} Train Loss {} Train Accuracy {}'.format(
epoch+1, train_loss / len(train_data), train_acc / len(train_data)))

Part 3/3 Version 2.0 - Train 输出结果

训练部分的输出结果

1.Epoch 1 Train Loss 3.330065098466196e-05 Train Accuracy 1.0
2.Epoch 2 Train Loss 3.848856647202233e-05 Train Accuracy 1.0
3.Epoch 3 Train Loss 3.249672247295006e-05 Train Accuracy 1.0
4.Epoch 4 Train Loss 3.181019142470626e-05 Train Accuracy 1.0
5.Epoch 5 Train Loss 2.7420538388295905e-05 Train Accuracy 1.0
6.Epoch 6 Train Loss 2.7395371789663205e-05 Train Accuracy 1.0
7.Epoch 7 Train Loss 2.3074768167839898e-05 Train Accuracy 1.0
8.Epoch 8 Train Loss 2.5261873254028975e-05 Train Accuracy 1.0
9.Epoch 9 Train Loss 2.3468322291219845e-05 Train Accuracy 1.0
10.Epoch 10 Train Loss 2.5787879148294842e-05 Train Accuracy 1.0
11.Epoch 11 Train Loss 2.2100263572805158e-05 Train Accuracy 1.0
12.Epoch 12 Train Loss 2.1043419593538925e-05 Train Accuracy 1.0
13.Epoch 13 Train Loss 1.919428202949172e-05 Train Accuracy 1.0
14.Epoch 14 Train Loss 2.0986426386100698e-05 Train Accuracy 1.0
15.Epoch 15 Train Loss 1.882315135082913e-05 Train Accuracy 1.0
16.Epoch 16 Train Loss 1.8170344417382568e-05 Train Accuracy 1.0
17.Epoch 17 Train Loss 1.8023049316377245e-05 Train Accuracy 1.0
18.Epoch 18 Train Loss 1.893510798163638e-05 Train Accuracy 1.0
19.Epoch 19 Train Loss 1.5729498005578122e-05 Train Accuracy 1.0
20.Epoch 20 Train Loss 1.623870315189797e-05 Train Accuracy 1.0

Part 3/3 Version 2.0 - Test

代码修改自网络,将训练部分和测试部分分开。这里是测试部分

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
eval_losses.append(eval_loss / len(test_data))
eval_acces.append(eval_acc / len(test_data))
print('Test Loss {} Test Accuracy {}'.format(
eval_loss / len(test_data), eval_acc / len(test_data)))

Part 3/3 Version 2.0 - Test 输出结果

测试部分的输出结果

1.Test Loss 0.02094335074422509 Test Accuracy 0.9949564873417721

Part 3/3 Version 3.0 Train

参考实例Ⅰ部分的代码——训练部分

epoch = 0
for data in train_data:
img, label = data
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()
epoch += 1
if epoch % 100 == 0:
print('epoch: {}, loss: {:.4}'.format(epoch, loss.data.item()))

Part 3/3 Version 3.0 Train 输出结果

训练部分的输出结果

1.epoch: 100, loss: 0.1181
2.epoch: 200, loss: 0.03296
3.epoch: 300, loss: 0.0591
4.epoch: 400, loss: 0.04722
5.epoch: 500, loss: 0.08721
6.epoch: 600, loss: 0.06054
7.epoch: 700, loss: 0.05327
8.epoch: 800, loss: 0.03804
9.epoch: 900, loss: 0.06624

Part 3/3 Version 3.0 Test

参考实例Ⅰ部分的代码——测试部分

# 测试
net.eval()
eval_loss = 0
eval_acc = 0
for data in test_data:
img, label = data
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)
# # code block: run OK
# # 记录误差
# eval_loss += loss.item()
# _ , pred = out.max(1)
# num_correct = (pred==label).sum().item()
# acc = num_correct / img.shape[0]
# eval_acc += acc
# 记录误差
eval_loss += loss.data.item() # different
_ , pred = torch.max(out, 1)
num_correct = (pred==label).sum()
acc = num_correct / img.shape[0] # different
eval_acc += acc
print('Test Loss: {:.6f}, Acc: {:.6f}'.format(
eval_loss / (len(test_data)),
eval_acc / (len(test_data))
))

Part 3/3 Version 3.0 Test 输出结果

测试部分的输出结果

1.Test Loss: 0.028490, Acc: 0.991495

目录