基于PyTorch的手写数字识别(Python初学练手)

一、基本概念

(一)框架

框架:Pytorch

入门Pytorch框架参考:
http://t.csdnimg.cn/IJvsYicon-default.png?t=N7T8http://t.csdnimg.cn/IJvsY

(二)数据集

 数据集:MNIST

       1.手写数字图片7万张(其中,训练集6万张,测试集1万张)

         2.每张图片是28*28像素,灰度值为0-255

(三)神经网络原理

什么是神经网络?它是如何识别图片的?

1.假设有5*5的矩阵,共25个节点,每个节点的值为0或1,把这25个节点排成1列

2.构造神经网络的第一层节点,这层节点的值是由前一层节点计算得到的

        如何计算?

                假设第0层节点上的数值为X0_0,X0_1,X0_2...,X0_24,

                那么第1层节点上的X1_0是这样计算的:

                        

                同理,可以计算第1层神经网络下,其他节点的数值:

                 

                        这里的i表示前一层节点的数值,j表示这一层节点的序号

               如果要构建多层神经网络,那么公式还可以扩展成:

                其中,字母含义:

                        i:前一层节点的数值

                        j:这一层节点的序号 

                        k:网络层数

               如图所示:

最后一层页脚输出层,一共有10个,因为识别的是数字0-9,共有10种结果

(四)归一化

softmax归一化步骤:

        1.用自然常数e对输出节点的每一个数值做指数运算,这样结果就都为正数了;

        2.再求和,用求和的值当分母,这样就得到了一组大于0,小于1,且总和为1的数组

        

训练的原理:

        神经网络的本质:

                数学函数

        训练的本质:

                调整参数 

(五)激活函数

上面的是线性问题,但很多时候需要解决非线性问题,这个时候就需要套上一层非线性函数,也称激活函数:

常见的激活函数有很多,只要非线性即可:

二、代码

1.安装插件

pip install numpy torch torchvision matplotlib

2.定义一个Net类

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #下面是四个全链接层
        self.fc1 = torch.nn.Linear(28*28,64) #输入是28*28像素尺寸的图像
        self.fc2 = torch.nn.Linear(64,64) #中间第一层:64个节点
        self.fc3 = torch.nn.Linear(64,64) #中间第二层:64个节点
        self.fc4 = torch.nn.Linear(64,10) #中间第三层:64个节点,输出为10个数字类别

    #定义了前向传播过程(参数x:图像输入)
    def forword(self,x):
        # 每层传播中,先执行self.fc(x),做全链接线性计算
        # torch.nn.functional.relu(),这是激活函数
        x = torch.nn.functional.relu(self.fc1(x))
        x = torch.nn.functional.relu(self.fc2(x))
        x = torch.nn.functional.relu(self.fc3(x))
        #输出层通过softmax做归一化,其中,log_softmax是为了提高计算的稳定性,因此在softmax之外又套上了一层对数运算
        x = torch.nn.functional.log_softmax(self.fc4(x),dim=1)
        return x

3.下载MINIST数据集

def get_data_loader(is_train):
    #tensor是一个多维数组,也叫张量
    to_tensor = transforms.Compose([transforms.ToTensor()])
    #下载MNIST数据集,MNIST(参数1:导入的目录,参数2:导入训练集还是测试集,)
    data_set = MNIST("", is_train, transform=to_tensor, download=True)
    #batch_size=15表示一个批次包含15张照片;shuffle=True表示数据是随机打乱的
    #函数的最后返回DataLoader数据加载器
    return DataLoader(data_set, batch_size=15, shuffle=True)

4.评估神经网络的识别正确率

def evaluate(test_data, net):
    n_correct = 0 #正确预测的数量
    n_total = 0 #预测的总数量
    with torch.no_grad():
        for (x, y) in test_data: #从测试集test_data中按批次取出数据
            #计算神经网络的预测值
            outputs = net.forword(x.view(-1, 28*28))
            #对批次中的每个结果进行比较
            for i, output in enumerate(outputs):
                if torch.argmax(output) == y[i]: #argmax():计算一个数列中最大值的序号(也就是预测手写数字的结果)
                    n_correct +=1
                n_total+=1
    #返回正确率
    return n_correct / n_total

5.主函数

def main():
    #1--导入训练集和测试集
    train_data = get_data_loader(is_train=True)
    test_data = get_data_loader(is_train=False)

    #2--初始化神经网络
    net = Net()

    #3--打印初始网络的正确率(接近0.1)
    print("initial accuracy:", evaluate(test_data, net))

    #4--训练神经网络
    optimizer = torch.optim.Adam(net.parameters(), lr=0.001)

    #epoch:有时候需要在一个神经网络上反复训练数据集,这样可以提高数据集的利用率,每一轮就是一个epoch
    for epoch in range(2):
        for(x,y) in train_data:
            # 初始化
            net.zero_grad()
            # 正向传播
            output = net.forword(x.view(-1,28*28))
            #计算差值
            loss = torch.nn.functional.nll_loss(output,y) #nll_loss:对数损失函数,为了匹配前面log_softmax的运算
            #反向误差传播
            loss.backward()
            #优化网络参数
            optimizer.step()
        #打印当前网络的正确率
        print("epoch",epoch,"accuracy:",evaluate(test_data,net))

    #训练结束后,随机抽取三张图像,显示网络预测的结果
    for(n, (x, _)) in enumerate(test_data):
        if n>3:
            break
        predict = torch.argmax(net.forword(x[0].view(-1,28*28)))
        plt.figure(n)
        plt.imshow(x[0].view(28,28))
        plt.title("prediction: " + str(int(predict)))
    plt.show()

6.启动主函数

if __name__ == '__main__':
    main()

7.完整代码

import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
import matplotlib.pyplot as plt

# 定义一个Net类
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #下面是四个全链接层
        self.fc1 = torch.nn.Linear(28*28,64) #输入是28*28像素尺寸的图像
        self.fc2 = torch.nn.Linear(64,64) #中间第一层:64个节点
        self.fc3 = torch.nn.Linear(64,64) #中间第二层:64个节点
        self.fc4 = torch.nn.Linear(64,10) #中间第三层:64个节点,输出为10个数字类别

    #定义了前向传播过程(参数x:图像输入)
    def forword(self,x):
        # 每层传播中,先执行self.fc(x),做全链接线性计算
        # torch.nn.functional.relu(),这是激活函数
        x = torch.nn.functional.relu(self.fc1(x))
        x = torch.nn.functional.relu(self.fc2(x))
        x = torch.nn.functional.relu(self.fc3(x))
        #输出层通过softmax做归一化,其中,log_softmax是为了提高计算的稳定性,因此在softmax之外又套上了一层对数运算
        x = torch.nn.functional.log_softmax(self.fc4(x),dim=1)
        return x

def get_data_loader(is_train):
    #tensor是一个多维数组,也叫张量
    to_tensor = transforms.Compose([transforms.ToTensor()])
    #下载MNIST数据集,MNIST(参数1:导入的目录,参数2:导入训练集还是测试集,)
    data_set = MNIST("", is_train, transform=to_tensor, download=True)
    #batch_size=15表示一个批次包含15张照片;shuffle=True表示数据是随机打乱的
    #函数的最后返回DataLoader数据加载器
    return DataLoader(data_set, batch_size=15, shuffle=True)


#evaluate用于评估神经网络的识别正确率
def evaluate(test_data, net):
    n_correct = 0 #正确预测的数量
    n_total = 0 #预测的总数量
    with torch.no_grad():
        for (x, y) in test_data: #从测试集test_data中按批次取出数据
            #计算神经网络的预测值
            outputs = net.forword(x.view(-1, 28*28))
            #对批次中的每个结果进行比较
            for i, output in enumerate(outputs):
                if torch.argmax(output) == y[i]: #argmax():计算一个数列中最大值的序号(也就是预测手写数字的结果)
                    n_correct +=1
                n_total+=1
    #返回正确率
    return n_correct / n_total

def main():
    #1--导入训练集和测试集
    train_data = get_data_loader(is_train=True)
    test_data = get_data_loader(is_train=False)

    #2--初始化神经网络
    net = Net()

    #3--打印初始网络的正确率(接近0.1)
    print("initial accuracy:", evaluate(test_data, net))

    #4--训练神经网络
    optimizer = torch.optim.Adam(net.parameters(), lr=0.001)

    #epoch:有时候需要在一个神经网络上反复训练数据集,这样可以提高数据集的利用率,每一轮就是一个epoch
    for epoch in range(2):
        for(x,y) in train_data:
            # 初始化
            net.zero_grad()
            # 正向传播
            output = net.forword(x.view(-1,28*28))
            #计算差值
            loss = torch.nn.functional.nll_loss(output,y) #nll_loss:对数损失函数,为了匹配前面log_softmax的运算
            #反向误差传播
            loss.backward()
            #优化网络参数
            optimizer.step()
        #打印当前网络的正确率
        print("epoch",epoch,"accuracy:",evaluate(test_data,net))

    #训练结束后,随机抽取三张图像,显示网络预测的结果
    for(n, (x, _)) in enumerate(test_data):
        if n>3:
            break
        predict = torch.argmax(net.forword(x[0].view(-1,28*28)))
        plt.figure(n)
        plt.imshow(x[0].view(28,28))
        plt.title("prediction: " + str(int(predict)))
    plt.show()

if __name__ == '__main__':
    main()

三、运行结果

 可以看出,初始预测的准确率为0.0958,第一个epoch后,准确率达到了0.0562,第二个epoch下准确率达到了0.9665,故实验完毕。

四、本文参考来源

【10分钟入门神经网络 PyTorch 手写数字识别】https://www.bilibili.com/video/BV1GC4y15736?vd_source=7e977d0187273d77005659cdd86927dficon-default.png?t=N7T8http://【10分钟入门神经网络 PyTorch 手写数字识别】https://www.bilibili.com/video/BV1GC4y15736?vd_source=7e977d0187273d77005659cdd86927df

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值