1.介绍:
作为深度学习的小白,为了熟悉Pytorch框架,选择了复现手写数字识别的代码。应用的数据集是简单且常用的MNIST手写数字集,应用的模型是最简单的多层感知机模型,最终训练的模型达到了accuracy=97%的预测效果。
2.思路:
MNIST数据集中已经划分好了训练集和测试集,我们实现分类的思路如下:
(1)分别对数据集中的图片和标签进行处理
图片像素为28*28、通道数为1,需要先用totensor()函数将图片转换为张量形式,接着对其进行标准化(std=0.5,mean=0.5),再应用Flatten()函数打平为1*784张量。接着应用四层全连接神经网络将其化为1*10向量。
标签需要用独热编码处理为1*10向量,以保持与模型输出结果相同的形状以便于损失函数的计算。
(2)关于多层感知机模型:
四层节点数分别设置为784、256、128、10,其中输入层和输出层的节点必须是固定的。
第二、三层输出应用激活函数 ReLu:max(0,x),最后一层输出应用softmax()函数输出分类概率。
(3)损失函数:
应用均方差(MSE)函数作为损失函数。应用随机梯度下降进行参数更新。
3.完整代码及详细注释如下:
import torch
import torch.nn as nn
import torch.optim as optim # 引入随机梯度优化器
import torch.nn.functional as F # one_hot_encoding
from torchvision import datasets, transforms
# 构建数据预处理组合---transforms:先化图象为张量,再对张量以(mean,std)=(0.5,0.5)标准化
transforms = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,), )])
# 加载MNIST数据集并对其进行预处理
train_dataset = datasets.MNIST(r"D:\HuaweiMoveData\Users\朱明意\Desktop\MNIST_data", train=True, download=True,
transform=transforms)
test_dataset = datasets.MNIST(r"D:\HuaweiMoveData\Users\朱明意\Desktop\MNIST_data", train=False, download=True,
transform=transforms)
# 创建数据加载器
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True) # 每批次训练样本数量设定为64
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False) # 每批次测试样本数量设定为64
# 定义多层感知机模型类
class MLP(nn.Module): # 继承nn.Model基类
def __init__(self):
super(MLP, self).__init__()
self.flatten = nn.Flatten() # 打平数据
self.fc1 = nn.Linear(784, 256) # 神经网络隐藏层节点数为256
self.relu = nn.ReLU() # relu()激活函数
self.fc2 = nn.Linear(256, 128) # 神经网络输出层节点数为128
self.fc3 = nn.Linear(128, 10) # 神经网络输出层节点数为10
def forward(self, x): # 正向传播计算
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.relu(x)
x = self.fc3(x)
x = torch.softmax(x, dim=1) # 在最后一层使用softmax()函数
return x
# 定义训练函数(用于模型参数更新)
def train(model, train_loader, optimizer, criterion, device):
model.train() # 将模型设置为训练模式(可有可无,最好有)
for batch_idx, (data, target) in enumerate(train_loader): # batch_idx为当前批次索引,从0开始递增;
data, target = data.to(device), target.to(device) # (data,target)为当前批次数据及对应目标值(label)
optimizer.zero_grad() # 清空优化器的累计梯度
output = model(data) # 进行正向传播计算:输入data,得到output
target_one_hot = F.one_hot(target, num_classes=10).float() # 运用独热编码函数,总类别数为10
loss = criterion(output, target_one_hot) # 根据输入的损失函数参数计算损失
loss.backward() # 反向传播
optimizer.step() # 根据反向传播计算的梯度更新优化模型参数()
# 定义测试函数(用于检验模型效果)
def test(model, test_loader, device):
model.eval() # 将模型设置为评估模式
correct=0 # 正确分类样本数量
with torch.no_grad():
for data, target in test_loader: # 遍历测试数据集
data, target = data.to(device), target.to(device) # 将数据和目标移动到指定的设备(cpu)
output = model(data) # 使用模型预测得到输出
_, predicted = torch.max(output.data, 1) # 获得模型最大预测概率(softmax函数)的索引值,存储到predicted
correct += (predicted == target).sum().item() # 统计预测正确的样本数量
accuracy = 100. * correct / len(test_loader.dataset)
print('Test set: Accuracy: {}/{} ({:.2f}%)'.format(correct, len(test_loader.dataset), accuracy))
model = MLP() # 创建MLP实例
optimizer = optim.Adam(model.parameters(), lr=0.001) # 创建优化器,其中model.parameters()源自继承的基类
criterion = nn.MSELoss() # 创建损失函数
for epoch in range(10):
# 训练
train(model, train_loader, optimizer, criterion, torch.device('cpu'))
# 测试
test(model, test_loader, torch.device('cpu'))
# 保存模型参数状态
torch.save(model.state_dict(), 'model.pth') # 保存模型参数状态
4.运行结果如下:
D:\Anaconda\python.exe D:\HuaweiMoveData\Users\朱明意\Desktop\MLorDL代码实现\手写数字识别(Minst.py
Test set: Accuracy: 9443/10000 (94.43%)
Test set: Accuracy: 9599/10000 (95.99%)
Test set: Accuracy: 9559/10000 (95.59%)
Test set: Accuracy: 9653/10000 (96.53%)
Test set: Accuracy: 9704/10000 (97.04%)
Test set: Accuracy: 9705/10000 (97.05%)
Test set: Accuracy: 9630/10000 (96.30%)
Test set: Accuracy: 9739/10000 (97.39%)
Test set: Accuracy: 9772/10000 (97.72%)
Test set: Accuracy: 9676/10000 (96.76%)