# 利用Pytorch实战手写数字识别
# 1 首先导入相关的包
import torch
# torchvision包的主要功能是实现数据的处理,导入和预览
from torchvision import datasets, transforms
import torchvision
# torch.autograd包的主要功能是完成反向传播中的链式求导,并且使用Variable类对定义的各个tensor进行封装
# 注意X.grad指的是梯度这个对象,要想访问梯度值必须用tensor.grad.data
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt
# 2 获取手写数字的训练集和测试集
# 数据集为图片类型,而Pytorch中处理的是Tensor类型的变量,首先就要进行数据类型的转化,如果数据格式和大小
# 不一样,还需要进行归一化和大小缩放等操作
# torchvision.transforms.Compose类可以看作是一个容器,它能够同时对多种数据变换进行组合,传入的参数是
# 一个列表,列表中的元素就是对数据进行的各种变换
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean = [0.5], std = [0.5])])
# torchvision.datasets可以轻易实现对这些训练集和测试集的下载
# root用于指定下载之后的存放路径,transform用于指定导入数据集时需要对数据进行哪种变换操作,train用于
# 指定下载完成后需要载入哪部分数据,如果参数设置为True说明载入的是训练集,如果参数设置为False说明载入
# 是测试集
data_train = datasets.MNIST(root = "./data/", transform = transform, train = True, download = True)
data_test = datasets.MNIST(root = "./data/", transform = transform, train = False, download = True)
##############################################
# 3 数据预览与装载
# 选取其中一个批次的数据进行预览
# batch_size 是每次喂入神经网络的图片数量,shuffle 是判断是否打乱次序
data_loader_train = torch.utils.data.DataLoader(dataset = data_train, batch_size = 64, shuffle = True)
data_loader_test = torch.utils.data.DataLoader(dataset = data_test, batch_size = 64, shuffle = True)
# 分别用 iter 和 next 来获取一个批次的图片和其对应的图片标签
images, labels = next(iter(data_loader_train))
# make_grid类方法就是将一个批次的图片构造成网格模式,需要传入的参数就是一个批次的装载数据,都是4维的,fen
# 别是batch_size, channel, height, weight,经过make_grid后就变成了3维的,分别是channel, height, weight
img = torchvision.utils.make_grid(images)
# 如果想要用matplotlib将数据显示成正常的模式, 就需要传入数组数据, transpose就是将原始数据的维度进行调换
# 使得height, weight, channel
img = img.numpy().transpose(1, 2, 0)
std = [0.5]
mean = [0.5]
img = img*std+mean
print(labels[i] for i in range(64))
plt.imshow(img)
###############################################
# 4 模型搭建与参数优化
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv1 = torch.nn.Sequential(
# torch.nn.Conv2d用于搭建卷积神经网络的卷积层,主要参数有输入通道数,输出通道数
# 卷积核大小,步长,padding值
torch.nn.Conv2d(1, 64, kernel_size = 3, stride = 1, padding = 1),
torch.nn.ReLU(),
torch.nn.Conv2d(64, 128, kernel_size = 3, stride = 1, padding = 1),
torch.nn.ReLU(),
# torch.nn.Maxpool 实现最大池化层,输入参数为池化窗口大小,步长,padding值
torch.nn.MaxPool2d(stride = 2, kernel_size = 2))
self.dense = torch.nn.Sequential(
# torch.nn.Linear定义的参数有三个,输入特征数,输出特征数,是否使用偏置
# 实际上只要输入输入特征数,输出特征数就会自动生成维度对应的权重和偏置
torch.nn.Linear(14*14*128, 1024),
torch.nn.ReLU(),
# torch.nn.Dropout 用于防止过拟合,默认值为0.5
torch.nn.Dropout(p = 0.5),
torch.nn.Linear(1024, 10))
def forward(self,x):
x = self.conv1(x)
# 对参数实现扁平化
x = x.view(-1,14*14*128)
x = self.dense(x)
return x
################################################
# 5 训练之前先定义使用哪种损失函数和优化函数
model = Model()
# 计算交叉熵作为损失函数,不需要传入任何参数
cost = torch.nn.CrossEntropyLoss()
# 使用Adam类作为优化函数,如果没有设置学习率的初始值,那么默认使用0.001
# 由于需要优化的是所有参数,所以把model.parameters传入
optimizer = torch.optim.Adam(model.parameters())
# 打印出构造好的模型
print(model)
###############################################
# 6 进行训练和参数优化
# 设置训练次数
epoch_n = 5
# 设置学习率,如果不设置就使用默认值
# 最外层的大循环保证训练次数,循环内代表着前向传播和方向传播方法,参数优化使用梯度下降来完成
for epoch in range (epoch_n):
running_loss = 0
running_correct =0
print("Epoch {}/{}".format(epoch,epoch_n))
print("-"*10)
for data in data_loader_train:
X_train, y_train = data
X_train, y_train = Variable(X_train), Variable(y_train)
outputs = model(X_train)
# 这句代码木有搞懂 呜呜
_, pred = torch.max(outputs.data,1)
# 使得各参数节点的梯度值全部置0
optimizer.zero_grad()
loss = cost(outputs, y_train)
# 反向传播,可以让模型根据构造出的计算图自动计算每个节点的梯度值并根据需求进行保留
loss.backward()
# 使用计算得到的梯度值对各个节点的参数进行梯度更新
optimizer.step()
running_loss += loss.data
running_correct += torch.sum(pred == y_train.data)
testing_correct = 0
for data in data_loader_test:
X_test, y_test = data
X_test, y_test = Variable(X_test), Variable(y_test)
outputs = model(X_test)
_, pred = torch.max(outputs.data, 1)
testing_correct +=torch.sum(pred == y_test.data)
print("Loss is :{:.4f}, "
"Train Accuracy is:{:.4f}%,"
"Test Accuracy is :{:.4f}%".format(running_loss/len(data_train),100*running_correct/len(data_train),100*testing_correct/len(data_test)))
# 选取测试集其中一个批次的数据进行测试
data_loader_test = torch.utils.data.DataLoader(dataset = data_test, batch_size = 4, shuffle = True)
X_test, y_test = next(iter(data_loader_train))
inputs = Variable(X_test)
pred = model(inputs)
_, pred = torch.max(pred, 1)
print("Predict Label is:", [i for i in pred.data])
print("Real label is :",[i for i in y_test])
img = torchvision.utils.make_grid(X_test)
img = img.numpy().transpose(1, 2, 0)
std = [0.5, 0.5, 0.5]
mean = [0.5, 0.5, 0.5]
img = img*std+mean
plt.imshow(img)
利用Pytorch实战手写数字识别
最新推荐文章于 2024-07-11 09:41:13 发布