手写数字识别

594次阅读
没有评论

共计 2926 个字符,预计需要花费 8 分钟才能阅读完成。

提醒:本文最后更新于 2023-10-07 17:37,文中所关联的信息可能已发生改变,请知悉!

数据集

MNIST 是一个大型数据库,其中包含手写数字。它通常被用作图像处理机器学习的基准测试。该数据库包含 60,000 个训练图像和 10,000 个测试图像。每个图像都是 28×28 的灰度图像,表示 0 到 9 之间的数字。

数据预处理

首先,我们需要将图像数据转换为可以被神经网络接受的格式。我们可以使用 torchvision 库中的 transforms 模块来进行数据预处理。我们将图像转换为张量,并将其归一化以使其具有零均值和单位方差。

import torch
from torchvision import datasets, transforms

# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.5,), (0.5,))])

# 加载数据集
trainset = datasets.MNIST('./data', download=True, train=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

testset = datasets.MNIST('./data', download=True, train=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=True)

定义神经网络模型

我们可以使用 PyTorch 中的 nn 模块来定义神经网络模型。在这里,我们将使用一个简单的卷积神经网络(CNN)来处理 MNIST 数据集。该模型包含两个卷积层、两个池化层和两个全连接层。

import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output

训练模型

训练模型的关键步骤如下:

import torch.optim as optim

# 定义优化器和损失函数
model = Net()

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

# 训练模型
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

num_epochs = 10
for epoch in range(num_epochs):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()

    print(f"Epoch {epoch + 1}, Loss: {running_loss / len(trainloader)}")

print("Finished Training")

在这个代码片段中,我们使用 Adam 优化器来更新模型的权重和偏差,以最小化交叉熵损失。我们迭代训练数据集多个周期(这里选择了 10 个周期),在每个周期内对所有的批次进行训练。在每个批次中,我们计算损失、执行反向传播和权重更新,最后计算并输出每个周期的平均损失。

评估模型

评估模型的代码已经在之前提到的代码片段中给出,但是为了更全面,这里再次列出:

test_loss = 0
correct = 0
with torch.no_grad():  # 禁止梯度计算
    for data, target in testloader:
        images, labels = data.to(device), target.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        test_loss += criterion(outputs, labels).item()
        correct += (predicted == labels).sum().item()

test_loss /= len(testloader.dataset)
print('Test Loss: {:.4f}'.format(test_loss))

print('Test Accuracy: {}/{} ({:.2f}%)\n'.format(correct, len(testloader.dataset),
                                                100 * correct / len(testloader.dataset)))

在这段代码中,我们遍历测试数据集,计算模型在每个图像上的损失和预测标签。然后,我们汇总这些信息来计算平均损失和准确率,以评估模型的性能。最后,我们输出测试集上的损失和准确率。这些指标可以帮助我们判断模型是否有效地泛化到新数据。

运行结果

Epoch 1, Loss: 0.23964141234844874
Epoch 2, Loss: 0.09505011013218526
Epoch 3, Loss: 0.07344594778967643
Epoch 4, Loss: 0.05976587735257471
Epoch 5, Loss: 0.05009076422531414
Epoch 6, Loss: 0.044607697039664385
Epoch 7, Loss: 0.040750773838482426
Epoch 8, Loss: 0.03625520611176456
Epoch 9, Loss: 0.033343519127966445
Epoch 10, Loss: 0.03101113824747073
Finished Training
Test Loss: 0.0009
Test Accuracy: 9838/10000 (98.38%)    

正文完
 0
历史的配角
版权声明:本站原创文章,由 历史的配角 于2023-08-20发表,共计2926字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码

您无法复制此页面的内容

了解 未来日记 的更多信息

立即订阅以继续阅读并访问完整档案。

Continue reading