import torch
import torch.nn as nn
import numpy as np
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
'''
确定当前环境是否支持 GPU 运行
'''
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
'''
加载 PyTorch 中的自带数据集合
该数据集合存在于 torchvision.datasets 中,可以直接利用 torchvision.datasets.MNIST 获得
'''
# 将数据集合下载到指定目录下,这里的transform表示,数据加载时所需要做的预处理操作
# 加载训练集合
train_dataset = torchvision.datasets.MNIST(root='./data',
train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
# 加载测试集合
test_dataset = torchvision.datasets.MNIST(root='./data',
train=False,
transform=transforms.ToTensor())
print(train_dataset, test_dataset)
print("-------------------------------")
'''
把数据放入数据加载器中
'''
batch_size = 100
# 根据数据集定义数据加载器
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=False)
print(train_loader, test_loader)
'''
在定义完 PyTorch 能够识别的数据加载器后
我们可以加载几张图片,观察一下图片效果:
'''
# 加载测试集中的前 6 张图片
examples = iter(test_loader)
example_data, example_targets = examples.next()
for i in range(6):
plt.subplot(2, 3, i+1)
plt.imshow(example_data[i][0], cmap='gray')
plt.show()
# 输入节点数就为图片的大小:28×28×1
input_size = 784
# 由于数字为 0-9,因此是10分类问题,因此输出节点数为 10
num_classes = 10
'''
利用 PyTorch 建立一个简单的神经网络模型用于手写字符的识别
第一层为输入层,节点数量和图像大小相同。
第二次为隐藏层,节点数为 500 。
第三层为输出层,节点大小为 10 ,节点数大小和类别相同。
'''
# 包含了一个隐含层的全联机神经网络
class NeuralNet(nn.Module):
# 输入数据的维度,中间层的节点数,输出数据的维度
def __init__(self, input_size, hidden_size, num_classes):
super(NeuralNet, self).__init__()
self.input_size = input_size
self.l1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.l2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.l1(x)
out = self.relu(out)
out = self.l2(out)
return out
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 建立了一个中间层为 500 的三层神经网络,且将模型转为当前环境支持的类型(CPU 或 GPU)
model = NeuralNet(input_size, 500, num_classes).to(device)
print(model)
'''
损失和优化器的定义
'''
criterion = nn.CrossEntropyLoss()
'''
利用 PyTorch 中定义的梯度下降算法的优化算法,Adam 算法,来进行模型的训练
'''
# 此时学习率为 0.001 ,你也可以根据实际情况,自行设置
learning_rate = 0.001
# 定义 Adam 优化器用于梯度下降
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
print(optimizer)
'''
模型的训练
通过 模型的正向传播,输出预测结果。
通过 预测结果和真实标签计算损失。
通过 后向传播,获得梯度。
通过 梯度更新模型的权重。
进行 梯度的清空。
循环上面操作,直到损失较小为止。
'''
num_epochs = 2
# 数据总长度
n_total_steps = len(train_loader)
for epoch in range(num_epochs):
for i, (images, labels) in enumerate(train_loader):
# 因为全连接会把一行数据当做一条数据,因此我们需要将一张图片转换到一行上
# 原始数据集的大小: [100, 1, 28, 28]
# 将每一张图片都转为一行向量,
# resize 后的向量大小: [100, 784]
images = images.reshape(-1, 28*28).to(device)
labels = labels.to(device)
# 正向传播以及损失的求取
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播
# 下面三句话固定:梯度清空,反向传播,权重更新
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i+1) % 100 == 0:
print(
f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{n_total_steps}], Loss: {loss.item():.4f}')
print("模型训练完成")
'''
模型已经训练完毕。
接下来,让我们先放入几张图片观察一下,预测结果是否和真实一致:
'''
# 测试样例
examples = iter(test_loader)
example_data, example_targets = examples.next()
# 图片的展示
for i in range(3):
plt.subplot(1, 3, i+1)
plt.imshow(example_data[i][0], cmap='gray')
plt.show()
# 结果的预测
images = example_data
images = images.reshape(-1, 28*28).to(device)
labels = labels.to(device)
# 正向传播以及损失的求取
outputs = model(images)
# 将 Tensor 类型的变量 example_targets 转为 numpy 类型的,方便展示
print("上面三张图片的真实结果:", example_targets[0:3].detach().numpy())
# 将得到预测结果
# 由于预测结果是 N×10 的矩阵,因此利用 np.argmax 函数取每行最大的那个值,最为预测值
not print("上面三张图片的预测结果:", np.argmax(outputs[0:3].detach().cpu().numpy(), axis=1))
'''
模型的测试
在训练完模型后,我们将导入测试数据集,对模型进行测试,对比模型的预测结果和实际结果,进而得到模型的识别准确率。
模型的测试代码很简单,其实就是将数据传入模型之中,并进行一次正向传播即可。
简单的说,就是复制上面的模型训练代码,然后更换数据集,删除后面的梯度下降相关的代码即可。
'''
# I测试数据,计算模型的识别准确率
with torch.no_grad():
n_correct = 0
n_samples = 0
for images, labels in test_loader:
# 和训练代码一致
images = images.reshape(-1, 28*28).to(device)
labels = labels.to(device)
outputs = model(images)
# 进行模型训练
_, predicted = torch.max(outputs.data, 1)
n_samples += labels.size(0)
n_correct += (predicted == labels).sum().item()
acc = 100.0 * n_correct / n_samples
print(f'Accuracy of the network on the 10000 test images: {acc} %')
手写字符的识别+pytorch
于 2021-04-09 11:12:40 首次发布