小白学Pytorch使用(1):Mnist手写数字集分类---全连接

小白学Pytorch使用(1):Mnist手写数字集分类

任务背景

使用Pytorch框架搭建神经网络进行Mnist手写数字集分类。数据可以自行下载进行本地链接,也可直接通过代码下载。
mnist数据集下载链接

一、导入库

# pathlib路径操作模块
from pathlib import Path
# requests是⽤Python语⾔编写,基于urllib,采⽤Apache2 Licensed开源协议的 HTTP 库
import requests
# 持续化模块:把Python对象直接保存到文件里,而不需要先把它们转化为字符串再保存,也不需要用底层的文件访问操作,直接把它们写入到一个二进制文件里
import pickle
# 压缩和解压缩模块
import gzip
# 数组及数组运算函数库
import numpy as np
# 2D绘图库
from matplotlib import pyplot
# Pytorch框架
import torch
import torch.nn.functional as F
from torch import nn
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
from torch import optim

二、下载数据集

# 下载mnist手写数字集,Path中更换自己的文件路径
DATA_PATH = Path("D:/咕泡人工智能-配套资料/配套资料/4.第四章 深度学习核⼼框架PyTorch/第二,三章:神经网络实战分类与回归任务/神经网络实战分类与回归任务/data")
# Mnist数据集存储文件夹(可舍去)
PATH = DATA_PATH/'mnist'
# 建立PATH路径,若自己手动建立也可注释掉
PATH.mkdir(parents=True, exist_ok=True)
# Mnist数据集下载网页
# "http://deeplearning.net/data/mnist/"是老师给的下载网页,但我这无法连接
URL = "https://resources.oreilly.com/live-training/inside-unsupervised-learning/-/tree/master/data/mnist_data/"	
# 数据集名称mnist.pkl.gz,可打开网页验证
FILENAME = 'mnist.pkl.gz'
# 若本地没有相应文件则进行下载
if not (PATH/FILENAME).exists():
    content = requests.get(URL + FILENAME).content      # requests.get()请求指定的页面信息,并返回实体主体
    (PATH/FILENAME).open('wb').write(content)

三、处理数据集

# 打开压缩包获取训练集、测试集,gzip进行解压
with gzip.open((PATH/FILENAME).as_posix(), 'rb') as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
# Mnist数据集中训练集50000个,验证集10000个。x为数据,y为对应标签。
# print(x_train.shape, y_train.shape)     #(50000, 784) (50000,)  784是mnist数据集每个样本的像素点个数,训练集中50000个784像素点的样本
# print(x_valid.shape, y_valid.shape)     #(10000, 784) (10000,)

# 展示训练集中第一张图,尺寸28*28,灰度
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")

# 数据需要转换为tensor参与后续建模训练
# map()函数的原型是map(function,iterable,……),将function应用于iterable的每一个元素,结果以列表的形式返回。function一般是数据类型,如int、str、tensor等
x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid))
# n数据个数,c像素点个数
n, c = x_train.shape
# print(x_train.shape)    #torch.Size([50000, 784])

# torch.utils.data 中的 TensorDataset 基于一系列张量构建数据集。这些张量的形状可以不尽相同,但第一个维度必须具有相同大小,这是为了保证在使用DataLoader时可以正常地返回一个批量的数据。
train_ds = TensorDataset(x_train, y_train)
valid_ds = TensorDataset(x_valid, y_valid)

def get_data(train_ds, valid_ds, bs):
    return (
    	# DataLoader()数据加载,shuffle是否打乱,batch_size分割尺寸。相当于数据打乱后每次随机抽取batch_size个数据作为一个batch
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )

#batch size
bs = 64

四、建立网络结构

#神经网络结构
class Mnist_NN(nn.Module):
    def __init__(self):
        super().__init__()
        #隐藏层1,784*128
        self.hidden1 = nn.Linear(784, 128)
        #隐藏层2,128*256
        self.hidden2 = nn.Linear(128, 256)
        #输出层全连接,256*10
        self.out = nn.Linear(256, 10)
	
	#前向传播
    def forward(self, x):
    	#relu激活函数,f(x)=max(0,x)
        x = F.relu(self.hidden1(x))
        x = F.relu(self.hidden2(x))
        x = self.out(x)
        return x

#net = Mnist_NN()
# print(net)
'''
Mnist_NN(
  (hidden1): Linear(in_features=784, out_features=128, bias=True)
  (hidden2): Linear(in_features=128, out_features=256, bias=True)
  (out): Linear(in_features=256, out_features=10, bias=True)
)
'''
# 打印神经网络每一层名字、权重和偏置
# for name, parameter in net.named_parameters():      
#     print(name, parameter, parameter.size())

五、优化函数及损失迭代

#传递网络,选择优化器
def get_model():
    model = Mnist_NN()
    #SGD和Adam两种优化器,SGD随机梯度下降法。本分类任务中Adam效果优于SGD,以下附Pytorch常用优化器介绍链接:"https://www.jianshu.com/p/1a1339c4acd7"
    #lr学习率,学习率太小,则收敛得慢。学习率太大,则损失会震荡甚至变大。
    # return model, optim.SGD(model.parameters(), lr=0.001)   
    return model, optim.Adam(model.parameters(), lr=0.001)

# 损失函数
loss_func = F.cross_entropy
# 损失迭代函数
def loss_batch(model, loss_func, xb, yb, opt=None):
	# 计算损失值
    loss = loss_func(model(xb), yb)
    # 若优化器不为空
    if opt is not None:
    	# 反向传播
        loss.backward()
        # 更新权重参数
        opt.step()
        # 梯度归零。Pytorch默认梯度叠加,因此将前一轮梯度归零
        opt.zero_grad()
    # loss.item()损失值
    # print(loss)		#tensor(2.3090, grad_fn=<NllLossBackward0>)
    # print(loss.item(), len(xb))		#2.309035062789917 64
    return loss.item(), len(xb)

六、训练/验证函数

#steps训练轮数,model神经网络,loss_func损失函数,opt优化器
def fit(steps, model, loss_func, opt, train_dl, valid_dl):
    for step in range(steps):
    	#训练
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)
            
		#验证
        model.eval()
        #验证过程不进行梯度更新
        with torch.no_grad():
            losses, nums = zip(*[loss_batch(model, loss_func, xb, yb)for xb, yb in valid_dl])
            val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
            print('当前step:'+str(step), '验证集损失:'+str(val_loss))
      
    #计算分类准确率      
	correct = 0
    total = 0
    for xb, yb in valid_dl:
        outputs = model(xb)
        _, predicted = torch.max(outputs.data, 1)
        total += yb.size(0)
        correct += (predicted == yb).sum().item()
    print('准确率是:%d%%'%(100*correct/total))

七、主函数

if __name__ == '__main__':
    train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
    model, opt = get_model()
    #迭代25轮
    fit(25, model, loss_func, opt, train_dl, valid_dl)

训练结果展示:
在这里插入图片描述
三层全连接网络训练三轮,准确率在97%。
Alt
初学者水平,如有不妥请指出,不胜感激!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值