PyTorch简单手写数字识别的实现过程

PyTorch是一个灵活的深度学习框架,可以帮助我们更简单地实现各类深度学习模型。本篇文章将讲解如何使用PyTorch来实现一个简单的手写数字识别模型。

首先,我们需要准备数据集。在这个例子中,我们将使用MNIST手写数字数据集,它包含了大量的手写数字图片和对应的标签。我们需要将这些数据转换成PyTorch的格式,即torch.Tensor。

1. 加载数据集

1.1 下载数据集

我们可以使用torchvision库中的datasets来下载和准备MNIST数据集,具体方法如下:

import torchvision.datasets as dsets

import torchvision.transforms as transforms

from torch.utils.data import DataLoader

train_dataset = dsets.MNIST(root='./data',

train=True,

transform=transforms.ToTensor(),

download=True)

test_dataset = dsets.MNIST(root='./data',

train=False,

transform=transforms.ToTensor(),

download=True)

其中,ToTensor()方法将数据集中的数据转换为PyTorch的tensor格式。我们可以指定数据集的路径,train=True代表下载的是训练集,train=False代表下载的是测试集。

1.2 准备数据集

我们需要将数据集封装成dataloder,以便我们可以轻松地从数据集中获取批次的数据。 在这个例子中,我们将使用PyTorch的DataLoader来准备数据集,具体方法如下所示:

batch_size = 256

train_dataloader = DataLoader(dataset=train_dataset,

batch_size=batch_size,

shuffle=True)

test_dataloader = DataLoader(dataset=test_dataset,

batch_size=batch_size)

其中batch_size是指定每个批次的大小,shuffle=True表示训练集中的数据将被打乱。

2. 构建模型

我们将使用一个简单的卷积神经网络(CNN)来构建手写数字识别模型。CNN表现得较好是因为它可以提取出图像中的关键特征,这些特征被转化为向量形式,送入全连接层进行分类。具体地,在这里我们将使用两个卷积层 (convolutional layer),后面两个全连接层 (fully connected layer)来构建CNN网络。网络结构如下:

import torch.nn as nn

class CNN(nn.Module):

def __init__(self):

super(CNN, self).__init__()

self.conv1 = nn.Sequential(

nn.Conv2d(in_channels=1, out_channels=32, kernel_size=5, stride=1, padding=2),

nn.ReLU(),

nn.MaxPool2d(kernel_size=2),

)

self.conv2 = nn.Sequential(

nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),

nn.ReLU(),

nn.MaxPool2d(kernel_size=2),

)

self.fc1 = nn.Linear(in_features=64*7*7, out_features=1024)

self.fc2 = nn.Linear(in_features=1024, out_features=10)

def forward(self, x):

out = self.conv1(x)

out = self.conv2(out)

out = out.view(-1, 64*7*7)

out = self.fc1(out)

out = self.fc2(out)

return out

model = CNN()

先定义了一个名为CNN的继承自nn.Module的模型类。在构造函数中声明了网络层以及它们的输入、输出维度。模型的前向传播(forward)函数则负责计算和返回输入张量沿网络的输出。

我们可以使用torchsummary库来查看模型的详细信息。

3. 训练模型

我们已经构建了一个简单的CNN模型,下一步是训练这个模型,以便它可以对手写数字进行分类。我们将使用Adam优化器和交叉熵损失函数来训练模型。

3.1 定义损失函数和优化器

我们将使用交叉熵损失函数来训练我们的CNN模型。同时,我们将使用Adam优化器来更新模型的参数。 具体代码实现如下:

import torch.optim as optim

criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)

其中,lr为Adam优化器的学习率。

3.2 开始训练

我们已经定义了损失函数和优化器,接下来就可以开始训练模型。我们将迭代训练集,每个批次都将输入CNN模型,计算损失和梯度,并通过反向传播方法更新模型的参数。 在训练过程中,我们将跟踪模型的训练和测试损失以及准确度。

具体代码实现如下:

num_epochs = 5

for epoch in range(num_epochs):

# Train

total_loss = 0

correct = 0

total = 0

for i, (images, labels) in enumerate(train_dataloader):

images = images.cuda()

labels = labels.cuda()

optimizer.zero_grad()

outputs = model(images)

loss = criterion(outputs, labels)

loss.backward()

optimizer.step()

total_loss += loss.item()

_, predicted = torch.max(outputs.data, 1)

total += labels.size(0)

correct += (predicted == labels).sum().item()

train_loss = total_loss / len(train_dataloader)

train_acc = 100 * correct / total

# Test

total_loss = 0

correct = 0

total = 0

with torch.no_grad():

for images, labels in test_dataloader:

images = images.cuda()

labels = labels.cuda()

outputs = model(images)

loss = criterion(outputs, labels)

total_loss += loss.item()

_, predicted = torch.max(outputs.data, 1)

total += labels.size(0)

correct += (predicted == labels).sum().item()

test_loss = total_loss / len(test_dataloader)

test_acc = 100 * correct / total

print('Epoch [{}/{}] Train Loss: {:.3f}, Train Acc: {:.3f}%, Test Loss: {:.3f}, Test Acc: {:.3f}%'.

format(epoch + 1, num_epochs, train_loss, train_acc, test_loss, test_acc))

其中,我们使用enumerate()函数从train_dataloader中获取每个批次的数据和对应的标签。然后,我们使用model(images)将每个批次的数据输入CNN模型,并得到输出。接下来,我们使用torch.max()函数获取每个输出向量中值最大的元素的索引,这一索引就是预测的数字。我们计算每个批次的准确度,并将其累加到正确分类的数字的总数。

测试模型与训练模型类似,我们使用torch.no_grad()上下文管理器来关闭梯度计算以加快模型的速度。完成测试后,我们计算每个测试批次的平均损失和准确率。

4. 评估模型

我们已经训练了模型,我们想要知道模型的真实表现如何。为此,我们将使用测试集来评估我们训练出来的模型。具体实现如下:

import numpy as np

from sklearn.metrics import confusion_matrix

y_pred = []

y_true = []

with torch.no_grad():

for images, labels in test_dataloader:

images = images.cuda()

labels = labels.cuda()

outputs = model(images)

_, predicted = torch.max(outputs.data, 1)

y_pred.extend(predicted.cpu().numpy())

y_true.extend(labels.cpu().numpy())

confusion_mtx = confusion_matrix(y_true, y_pred)

print(confusion_mtx)

我们使用torch.no_grad()上下文管理器来关闭梯度计算以加快模型的速度。 在预测每个测试图像时,我们将其输入CNN模型,并使用torch.max()函数获得最终预测输出向量中值最大的元素的索引。这一索引就是预测的数字。 然后,我们将预测值和真实值存储到y_pred, y_true中。最后,我们使用sklearn.metrics.confusion_matrix函数计算模型的混淆矩阵。

5. 结论

在这份教程中,我们介绍了如何使用PyTorch来实现一个简单的手写数字识别模型。 我们下载了MNIST数据集,使用torch.Tensor封装了数据集,定义了一个简单卷积神经网络(CNN)模型,用交叉熵作为损失函数,并用Adam优化器更新模型的参数。最后,我们迭代训练集并评估测试集,得出了模型的准确率。 我们的实现效果对该数据集非常不错,未来还可以通过改进网络结构、调整学习率、使用更复杂的数据增强等方式提升模型性能。

后端开发标签