当前位置: 首页 > news >正文

手写数字识别与卷积神经网络

手写数字识别与卷积神经网络的探索之旅

在当今数字化时代,机器学习和深度学习技术正以惊人的速度改变着我们的生活。其中,手写数字识别作为一个经典的应用场景,不仅具有重要的学术研究价值,还在许多实际应用中发挥着关键作用。本文将通过两个具体的代码示例,深入探讨手写数字识别技术以及卷积神经网络(CNN)在图像分类任务中的应用。

一、手写数字识别:从基础到实践

(一)数据集与预处理

手写数字识别任务通常使用 MNIST 数据集,这是一个包含 60,000 个训练样本和 10,000 个测试样本的标准数据集,每个样本是一个 28×28 的灰度图像,对应一个 0 到 9 的数字。在第一个代码示例中,我们使用 PyTorch 的 torchvision.datasets 模块轻松加载了 MNIST 数据集,并对其进行了标准化处理。通过 transforms.Compose,我们将图像转换为张量并进行了归一化,这有助于提高模型的训练效率和准确性。

import torch
import torchvision
import torchvision.transforms as transforms# 数据预处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])# 下载数据,并对数据进行预处理
train_dataset = torchvision.datasets.MNIST('../data/', train=True, transform=transform, download=True)
test_dataset = torchvision.datasets.MNIST('../data/', train=False, transform=transform)# 得到一个生成器
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=128, shuffle=False)

(二)模型构建

为了实现手写数字识别,我们构建了一个简单的全连接神经网络模型。该模型包含两个隐藏层,分别有 300 和 100 个神经元,输出层有 10 个神经元,对应 10 个数字类别。模型使用了 ReLU 激活函数和 Softmax 输出层,以确保输出的概率分布。此外,我们还定义了交叉熵损失函数和随机梯度下降(SGD)优化器,用于模型的训练和参数更新。

import torch.nn as nn
import torch.optim as optimclass Net(nn.Module):def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):super(Net, self).__init__()self.flatten = nn.Flatten()self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1), nn.BatchNorm1d(n_hidden_1))self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2), nn.BatchNorm1d(n_hidden_2))self.out = nn.Sequential(nn.Linear(n_hidden_2, out_dim))def forward(self, x):x = self.flatten(x)x = torch.relu(self.layer1(x))x = torch.relu(self.layer2(x))x = torch.softmax(self.out(x), dim=1)return x# 实例化模型
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = Net(28 * 28, 300, 100, 10).to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

(三)训练与评估

在训练过程中,我们动态调整学习率,以加速模型的收敛。通过 20 个 epoch 的训练,模型在训练集上的损失逐渐降低,准确率不断提高。同时,我们在测试集上评估了模型的性能,结果显示模型具有较高的准确率,能够较好地识别手写数字。

num_epochs = 20
for epoch in range(num_epochs):model.train()for img, label in train_loader:img, label = img.to(device), label.to(device)optimizer.zero_grad()out = model(img)loss = criterion(out, label)loss.backward()optimizer.step()print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

二、卷积神经网络:图像分类的强大工具

(一)CNN 的优势

卷积神经网络(CNN)在图像分类任务中表现出色,这主要得益于其能够自动提取图像的局部特征。与传统的全连接网络相比,CNN 通过卷积层和池化层有效地减少了参数数量,提高了模型的泛化能力。

(二)CNN 模型实现

在第二个代码示例中,我们定义了多个 CNN 模型,包括 CNNNetNetLeNet。这些模型都使用了卷积层、池化层和全连接层的组合,以实现对输入图像的特征提取和分类。特别是 LeNet,它是一个经典的 CNN 架构,通过多次卷积和池化操作,能够有效地提取图像的层次化特征。

class CNNNet(nn.Module):def __init__(self):super(CNNNet, self).__init__()self.conv1 = nn.Conv2d(3, 16, 5)self.pool1 = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(16, 30, 5)self.pool2 = nn.MaxPool2d(2, 2)self.fc3 = nn.Linear(30, 10)def forward(self, x):x = self.pool1(torch.relu(self.conv1(x)))x = self.pool2(torch.relu(self.conv2(x)))x = x.view(x.shape[0], -1)x = self.fc3(x)return xclass LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = torch.relu(self.conv1(x))x = self.pool1(x)x = torch.relu(self.conv2(x))x = self.pool2(x)x = x.view(-1, 16 * 5 * 5)x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)return x

(三)模型训练与测试

1. 训练过程的监控

在训练过程中,监控模型的性能是非常重要的。我们通常会记录每个epoch的训练损失和验证损失,以便观察模型是否在收敛。此外,我们还可以记录训练准确率和验证准确率,以确保模型不仅在训练数据上表现良好,而且在验证数据上也能保持良好的性能。

# 定义训练过程
def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=20):model.train()  # 将模型设置为训练模式train_losses = []val_losses = []train_accuracies = []val_accuracies = []for epoch in range(num_epochs):running_loss = 0.0correct = 0total = 0for images, labels in train_loader:images, labels = images.to(device), labels.to(device)  # 将数据移动到设备上optimizer.zero_grad()  # 清空之前的梯度outputs = model(images)  # 前向传播loss = criterion(outputs, labels)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新参数running_loss += loss.item() * images.size(0)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()epoch_loss = running_loss / len(train_loader.dataset)epoch_accuracy = 100 * correct / totaltrain_losses.append(epoch_loss)train_accuracies.append(epoch_accuracy)# 验证过程val_loss, val_accuracy = validate_model(model, val_loader, criterion)val_losses.append(val_loss)val_accuracies.append(val_accuracy)print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {epoch_loss:.4f}, Train Acc: {epoch_accuracy:.2f}%, Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.2f}%')return train_losses, val_losses, train_accuracies, val_accuracies# 定义验证过程
def validate_model(model, val_loader, criterion):model.eval()  # 将模型设置为评估模式running_loss = 0.0correct = 0total = 0with torch.no_grad():  # 在验证过程中不需要计算梯度for images, labels in val_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)loss = criterion(outputs, labels)running_loss += loss.item() * images.size(0)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()epoch_loss = running_loss / len(val_loader.dataset)epoch_accuracy = 100 * correct / totalreturn epoch_loss, epoch_accuracy
2. 模型验证

为了确保模型不会过拟合,我们通常会使用一个验证集来监控模型的性能。验证集是从训练数据中分离出来的一部分数据,用于在每个epoch结束时评估模型的性能。如果验证损失开始增加,而训练损失继续下降,这可能表明模型正在过拟合。

在上述代码中,我们在每个epoch结束时调用了 validate_model 函数,该函数计算了验证集上的损失和准确率,并将这些值记录下来。这样,我们可以在训练结束后绘制训练损失、验证损失、训练准确率和验证准确率的图表,以直观地观察模型的性能。

3. 模型性能优化

在训练过程中,我们可以通过多种方式优化模型性能,包括调整学习率、使用学习率调度器、增加正则化项(如Dropout)等。以下是一些常见的优化方法:

  • 学习率调度器:动态调整学习率,通常在训练过程中逐渐减小学习率,以帮助模型更好地收敛。

  • 正则化:使用Dropout或L2正则化(权重衰减)来防止过拟合。

  • 数据增强:通过数据增强技术(如随机裁剪、水平翻转等)增加训练数据的多样性,提高模型的泛化能力。

# 使用学习率调度器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)# 在训练循环中添加学习率调度器
for epoch in range(num_epochs):# 训练过程for images, labels in train_loader:images, labels = images.to(device), labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 更新学习率scheduler.step()# 验证过程val_loss, val_accuracy = validate_model(model, val_loader, criterion)print(f'Epoch [{epoch+1}/{num_epochs}], Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.2f}%')
4. 测试模型

在模型训练和验证完成后,我们使用测试集来最终评估模型的性能。测试集是模型在训练过程中从未见过的数据,因此它可以提供一个公正的性能评估。

# 测试模型
def test_model(model, test_loader):model.eval()  # 将模型设置为评估模式correct = 0total = 0with torch.no_grad():  # 在测试过程中不需要计算梯度for images, labels in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = 100 * correct / totalprint(f'Accuracy of the model on the test images: {accuracy:.2f}%')
http://www.dtcms.com/a/480337.html

相关文章:

  • 自学做网站的浦东新区网站推广公司
  • 天津公司网站怎样制作网站是什么意思例如
  • 佘山做网站公司石家庄建站优化公司
  • 重庆永川网站建设报价知名做网站费用
  • 成都网站制作培训怀化市鹤城区建设局网站
  • 苏州园区建设网站首页免费网站建设 百度一下
  • 做物品租赁网站楼盘推荐排行榜
  • 个人网站当企业网站用win优化大师官网
  • 关于百度网站的优缺点如何查网站的icp备案
  • 手机网站 优化seo工具包括
  • 站长工具里查看的网站描述和关键词都不显示网站技术解决
  • 免费html网页模板素材网站网站开发基本构成
  • html5手机商城网站模板做VIP视频网站赚钱
  • 网站建设及政务公开工作seo智能优化公司
  • 江苏省质量建设厅网站网络工程师报名时间
  • 中国矿山建设网站网站被人抄袭怎么办
  • JavaScript 时间转换
  • 学做网站需要贵州建设厅网站办事大厅
  • 白云区网站开发公司电话百度推广开户需要多少钱
  • 做网站如何调字体格式程序小程序开发公司
  • 哪个网站可以做高数题项目总结报告怎么写
  • 网站要素如何进行网站推广?网站推广的基本手段有哪些
  • 西宁建设网站佛山新网站建设市场
  • 福安做网站最好上海网站建设推广
  • 嵩县网站开发新宁县建设局网站
  • 企业网站推广的方法有哪些wordpress 时尚主题
  • seo网站改版统计二级域名的网站流量有什么用
  • 设计网站推荐视频网上建设银行网站首页
  • 网站海外推广多少钱福建泉州曾明军的网站
  • 南京建站公司网站新赣州房产网