马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
手写数字辨认:利用PyTorch构建MNIST分类器
在这篇文章中,我将引导你通过利用PyTorch框架构建一个简朴的神经网络模子,用于辨认MNIST数据会合的手写数字。MNIST数据集是一个经典的呆板学习数据集,包罗了60,000张训练图像和10,000张测试图像,每张图像都是28x28像素的灰度手写数字。
数据加载与预处置惩罚
我们起首加载MNIST数据集,并将图像转换为PyTorch张量格式,以便模子可以处置惩罚。- import torch
- from torch import nn
- from torch.utils.data import DataLoader
- from torchvision import datasets
- from torchvision.transforms import ToTensor
- '''下载训练数据集(包含训练图片+标签)'''
- training_data = datasets.MNIST( #跳转到函数的内部源代码,pycharm 按下ctrl+鼠标点击 training_data:Dataset
- root="data",#表示下载的手写数字 到哪个路径。60000
- train=True, #读取下载后的数据 中的 训练集
- download=True,#如果你之前已经下载过了,就不用再下载
- transform=ToTensor(), #张量,图片是不能直接传入神经网络模型
- ) #对于pytorch库能够识别的数据一般是tensor张量。
- '''下载测试数据集(包含训练图片+标签)'''
- test_data = datasets.MNIST(
- root="data",
- train=False,
- download=True,
- transform=ToTensor()
- )
- print(len(training_data))
复制代码 数据可视化
为了更好地明白数据,我们可以展示一些手写数字图像。- ''展示手写字图片,把训练数据集中的前59000张图片展示一下'''
- from matplotlib import pyplot as plt
- figure = plt.figure()
- for i in range(9):
- img, label = training_data[i+59000] #提取第59000张图片
- figure.add_subplot(3, 3, i+1) #图像窗口中创建多个小窗口,小窗口用于显示图片
- plt.title(label) # 设置每个小窗口的标题为对应的标签
- plt.axis("off") ##关闭坐标轴的显示
- plt.imshow(img.squeeze(), cmap="gray") # 显示图片,squeeze()函数用于去除图片张量中长度为1的维度,cmap="gray"表示以灰度模式显示
- a = img.squeeze()# img.squeeze()从张量img中去掉维度为1的。如果该维度的大小不为1则张量不会改变。#cmap="gray
- plt.show()
复制代码 运行结果
创建DataLoader
为了高效地加载数据,我们利用DataLoader来批量加载数据。- # '"创建数据DataLoader(数据加载器)开'
- # 'batch_size:将数据集分成多份,每一份为batch_size个数据'
- # '优点:可以减少内存的使用,提高训练速度。
- train_dataloader = DataLoader(training_data, batch_size=64) #64张图片为一个包,train_dataloader:<torch
- test_dataloader = DataLoader(test_data, batch_size=64)
- '''判断当前设备是否支持GPU,其中mps是苹果m系列芯片的GPU。'''
- device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
- print(f"Using {device} device")
复制代码 模子界说
接下来,我们界说一个简朴的神经网络模子,包罗两个潜伏层和一个输出层。- '''定义神经网络类的继承这种方式'''
- class NeuralNetwork(nn.Module): # 定义一个名为 NeuralNetwork 的类,继承自 PyTorch 的 nn.Module 类
- # 通过继承 nn.Module,NeuralNetwork 类可以使用 PyTorch 提供的模块化网络结构和功能
- def __init__(self): # 类的构造函数,当创建 NeuralNetwork 类的实例时调用
- super().__init__() # 调用父类(nn.Module)的构造函数,确保父类的初始化被正确执行
- self.flatten = nn.Flatten() # 创建一个 Flatten 层,用于将多维输入一维化
- self.hidden1 = nn.Linear(28*28, 128) # 创建第一个隐藏层,输入特征为 28*28(即 784),输出特征为 128
- self.hidden2 = nn.Linear(128, 256) # 创建第二个隐藏层,输入特征为 128,输出特征为 256
- self.out = nn.Linear(256, 10) # 创建输出层,输入特征为 256,输出特征为 10(假设有 10 个类别)
- def forward(self, x): # 定义前向传播函数,x 为输入数据
- x = self.flatten(x) # 将输入数据 x 通过 Flatten 层展开
- x = self.hidden1(x) # 将展开后的数据通过第一个隐藏层
- x = torch.relu(x) # 对第一个隐藏层的输出应用 ReLU 激活函数
- x = self.hidden2(x) # 将激活后的数据通过第二个隐藏层
- x = torch.relu(x) # 对第二个隐藏层的输出再次应用 ReLU 激活函数
- x = self.out(x) # 将数据通过输出层
- return x # 返回最终的输出结果
- model = NeuralNetwork().to(device) # 创建 NeuralNetwork 类的实例,并将其移动到指定的设备(CPU 或 GPU)
- print(model) # 打印模型的结构,以查看各层的参数和连接方式
复制代码 训练与测试
我们界说训练和测试函数,利用交叉熵丧失函数和随机梯度降落优化器。- def train(dataloader, model, loss_fn, optimizer):
- # 将模型设置为训练模式,这将影响某些层(如Dropout和BatchNorm)的行为
- model.train()
-
- batch_size_num = 1 # 初始化批次计数器
- for X, y in dataloader: # 遍历数据加载器,获取每个批次的数据和标签
- X, y = X.to(device), y.to(device) # 将数据和标签移动到指定的设备(CPU或GPU)
- pred = model.forward(X) # 执行模型的前向传播,计算预测结果
- loss = loss_fn(pred, y) # 计算预测结果和真实标签之间的损失
- # 反向传播和优化步骤
- optimizer.zero_grad() # 清除旧的梯度
- loss.backward() # 计算当前梯度
- optimizer.step() # 根据梯度更新模型参数
- # 提取损失值并打印
- loss_value = loss.item() # 从张量中提取损失值
- if batch_size_num % 100 == 0: # 每100个批次打印一次损失值和批次编号
- print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")
- batch_size_num += 1 # 递增批次计数器
- def test(dataloader, model, loss_fn):
- size = len(dataloader.dataset) # 获取测试数据集的大小
- num_batches = len(dataloader) # 获取测试数据加载器中的批次数量
- model.eval() # 将模型设置为评估模式,这将影响某些层(如Dropout)的行为
- test_loss, correct = 0, 0 # 初始化测试损失和正确预测计数器
- with torch.no_grad(): # 关闭梯度计算
- for X, y in dataloader: # 遍历测试数据加载器
- X, y = X.to(device), y.to(device) # 将数据和标签移动到指定的设备(CPU或GPU)
- pred = model.forward(X) # 执行模型的前向传播,计算预测结果
- test_loss += loss_fn(pred, y).item() # 累加测试损失
- correct += (pred.argmax(1) == y).type(torch.float).sum().item() # 计算正确预测的数量
- # 计算平均测试损失和准确率
- test_loss /= num_batches # 计算平均测试损失
- correct /= size # 计算平均准确率
- # 打印测试结果
- print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")
复制代码 训练模子
末了,我们训练模子并测试其性能。- loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
- optimizer = torch.optim.SGD(model.parameters(), lr=0.01) #创建一个优化器,SGD为随机梯度下降算法 #lr:learning_rate学习率,也就是步长
- # #params:要训练的参数,一般我们传入的都是model.parameters()# #lr:learning_rate学习率,也就是步长
- #loss表示模型训练后的输出结果与,样本标签的差距。如果差距越小,就表示模型训练越好,越逼近干真实的模型。
- # train(train_dataloader, model, loss_fn, optimizer)
- # test(test_dataloader, model, loss_fn)
- epochs = 30
- for t in range(epochs):
- print(f"Epoch {t+1}\n")
- train(train_dataloader, model, loss_fn, optimizer) #调用train函数开始一个训练周期,使用训练数据加载器、模型、损失函数和优化器。
- print("Done!") #在所有训练周期完成后,打印"Done!"表示训练结束。
- test(test_dataloader, model, loss_fn)
复制代码 运行结果
结论
通过这篇文章,我们成功构建了一个简朴的神经网络模子来辨认MNIST数据会合的手写数字。这个模子展示了怎样利用PyTorch举行数据处置惩罚、模子界说、训练和测试。盼望这能资助你开始本身的深度学习项目!
|