代码地址
上一篇:Pytorch入门实战(1) - 实现线性回归
涉及知识点
Pytorch nn.Module的基本使用
Pytorch nn.Linear的基本用法
PytorchVision Transforms的基本使用
Pytorch中DataLoader的基本用法
Pytorch详解NLLLoss和CrossEntropyLoss
如何确定神经网络的层数和隐藏层神经元数量
本文内容
本文将会使用BP神经网络(就是最普通的神经网络)实现一个MNIST手写数据集的实现。话不多说,直接开始。
首先先导入需要的包:
import os
import numpy as np
import torch
import torchvision
import matplotlib.pyplot as plt
from time import time
from torchvision import datasets, transforms
from torch import nn, optim
定义transform对象,其定义了数据集中的图片应该做怎样的处理:
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,)),])
加载和下载训练数据集,这里使用pytorch提供的API进行下载:
train_set = datasets.MNIST('train_set', download=not os.path.exists('train_set'), train=True, transform=transform )
train_set
Dataset MNISTNumber of datapoints: 60000Root location: train_setSplit: TrainStandardTransform
Transform: Compose(ToTensor()Normalize(mean=(0.5,), std=(0.5,)))
等待一段时间下载成功后,可以看到训练集中一共有6w个数据,接下来下载测试数据集:
test_set = datasets.MNIST('test_set', download=not os.path.exists('test_set'),train=False, transform=transform)
test_set
Dataset MNISTNumber of datapoints: 10000Root location: test_setSplit: TestStandardTransform
Transform: Compose(ToTensor()Normalize(mean=(0.5,), std=(0.5,)))
测试数据集包含1w条数据
接下来构建训练数据集和测试数据集的DataLoader对象:
train_loader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=64, shuffle=True)dataiter = iter(train_loader)
images, labels = dataiter.next()print(images.shape)
print(labels.shape)
torch.Size([64, 1, 28, 28])
torch.Size([64])
在上面,我们将其分成64个一组的图片,每个图片只有一个通道(灰度图),大小为28x28。抽一张绘制一下:
plt.imshow(images[0].numpy().squeeze(), cmap='gray_r');
到这里,前期准备工作就结束了。
开始定义神经网络
class NerualNetwork(nn.Module):def __init__(self):super().__init__()"""定义第一个线性层,输入为图片(28x28),输出为第一个隐层的输入,大小为128。"""self.linear1 = nn.Linear(28 * 28, 128)self.relu1 = nn.ReLU()"""定义第二个线性层,输入是第一个隐层的输出,输出为第二个隐层的输入,大小为64。"""self.linear2 = nn.Linear(128, 64)self.relu2 = nn.ReLU()"""定义第三个线性层,输入是第二个隐层的输出,输出为输出层,大小为10"""self.linear3 = nn.Linear(64, 10)self.softmax = nn.LogSoftmax(dim=1)self.model = nn.Sequential(nn.Linear(28 * 28, 128),nn.ReLU(),nn.Linear(128, 64),nn.ReLU(),nn.Linear(64, 10),nn.LogSoftmax(dim=1))def forward(self, x):"""定义神经网络的前向传播x: 图片数据, shape为(64, 1, 28, 28)"""x = x.view(x.shape[0], -1)x = self.linear1(x)x = self.relu1(x)x = self.linear2(x)x = self.relu2(x)x = self.linear3(x)x = self.softmax(x)return x
model = NerualNetwork()
神经网络定义完后,开始定义损失函数,这里选用负对数似然损失函数(NLLLoss
, negative log likelihood loss),其常用于分类任务。详情可参考链接
criterion = nn.NLLLoss()
接下来定义优化器,这里使用随机梯度下降法,学习率设置为0.003,momentum取默认的0.9(用于防止过拟合)
optimizer = optim.SGD(model.parameters(), lr=0.003, momentum=0.9)
准备工作完毕,开始训练数据集:
time0 = time()
epochs = 15
for e in range(epochs):running_loss = 0 for images, labels in train_loader:output = model(images) loss = criterion(output, labels) loss.backward()optimizer.step()optimizer.zero_grad() running_loss += loss.item()else:print("Epoch {} - Training loss: {}".format(e, running_loss/len(train_loader)))
print("\nTraining Time (in minutes) =",(time()-time0)/60)
Epoch 0 - Training loss: 0.6462286284117937
Epoch 1 - Training loss: 0.27847810615418056
Epoch 2 - Training loss: 0.21768317640081905
Epoch 3 - Training loss: 0.17949896098088736
Epoch 4 - Training loss: 0.1514430489978874
Epoch 5 - Training loss: 0.12892813527329103
Epoch 6 - Training loss: 0.11302738852882341
Epoch 7 - Training loss: 0.09980541475113235
Epoch 8 - Training loss: 0.08899609394905679
Epoch 9 - Training loss: 0.0805584444001174
Epoch 10 - Training loss: 0.07290568387211323
Epoch 11 - Training loss: 0.06743549962075296
Epoch 12 - Training loss: 0.06314737589380491
Epoch 13 - Training loss: 0.056689855163551565
Epoch 14 - Training loss: 0.05361823974547586Training Time (in minutes) = 2.9436919848124186
最终在我这台机器上,花费了2分多钟完成了训练。可以看到,损失是越来越小的。
接下来进行模型的评估
correct_count, all_count = 0, 0
model.eval()
for images,labels in test_loader:for i in range(len(labels)):logps = model(images[i]) probab = list(logps.detach().numpy()[0]) pred_label = probab.index(max(probab)) true_label = labels.numpy()[i]if(true_label == pred_label): correct_count += 1all_count += 1print("Number Of Images Tested =", all_count)
print("\nModel Accuracy =", (correct_count/all_count))
Number Of Images Tested = 10000Model Accuracy = 0.9741
最终,本次训练在测试数据集上的精准率为97.41%
参考资料
Handwritten Digit Recognition Using PyTorch — Intro To Neural Networks: https://towardsdatascience.com/handwritten-digit-mnist-pytorch-977b5338e627