精华内容
下载资源
问答
  • 主要介绍了详解PyTorch手写数字识别(MNIST数据集),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 今天小编就为大家分享一篇pytorch 利用lstm做mnist手写数字识别分类的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • pytorch识别手写数字成功
  • 本篇文章主要介绍了PyTorch CNN实战之MNIST手写数字识别示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了Pytorch实现的手写数字mnist识别功能,结合完整实例形式分析了Pytorch模块手写字识别具体步骤与相关实现技巧,需要的朋友可以参考下
  • 手写数字识别Mnist的Pytorch实现

    千次阅读 2020-07-02 23:20:09
    手写数字识别Mnist的Pytorch实现 注:该内容为校内课程实验,仅供参考,请勿抄袭! 源码地址: 一、引言(Introduction)   手写数字识别时经典的图像分类任务,也是经典的有监督学习任务,经常被用于测试图像的...

    手写数字识别Mnist的Pytorch实现

    注:该内容为校内课程实验,仅供参考,请勿抄袭!
    源码地址:Gray-scale-Hand-Written-Digits-Pytorch

    一、引言(Introduction)

      手写数字识别时经典的图像分类任务,也是经典的有监督学习任务,经常被用于测试图像的特征提取效果、分类器性能度量等方面,本文将通过应用机器学习和深度学习算法实现手写数字识别。
      图像分类任务是指给定一张图像来对其进行分类,常见的图像分类任务有手写数字识别、猫狗分类、物品识别等,图像分类也是计算机视觉基本的分类任务。而对于手写数字识别任务来说,可以当做图像分类问题,也可以当做目标检测与分类。其中图像分类即输入整个图像并预测其类别,例如含有6的数字的图像我们希望最大化预测为6的概率;另外也可以视为目标检测任务,即提取图像中的目标并将目标提取出后进行预测,例如OCR对字符进行识别。因为手写数字是被预处理后的图像,且一张图像中只包含一个数字,因此本文则将手写数字识别视为整个图像的分类。

    二、任务分析

    2.1 形式化描述
      给定一个图像数据集,其中图像记做,是一个宽为,高为,通道数为的图像,是图像对应的类标,任务的目标是寻找一个由图像数据到类别的映射。
    2.2 任务分析
      传统的方法是对图像进行序列化,即使用一组向量来对图像进行表示。例如本文处理的手写数字识别是灰度图像,即通道数为1,宽高均为28像素的图像,因此可以直接将图像的每个像素使用0-255整型数进行表示,并形成784维度的向量,然后使用包括SVM(支持向量机)、LR(逻辑回归)、DT(决策树)等机器学习学习多个超平面将假设空间中的样本正确的分类。另外也可以使用聚类算法,例如KNN、K-means、DBSCAN等算法自动将样本聚到10个类别上。
      另外由于手写数字相同类别之间会存在相关性,因此也有基于图像压缩方法进行特征提取工作。通常使用PCA等降维技术将784维度的图像降维到较低空间,形成潜在的特征向量,且这些向量每一个维度之间是不相关;其次对压缩后的特征向量在使用机器学习算法进行分类,这种方法可以大大提高对重要特征的学习,忽略噪声对分类的影响。
      随着深度学习的发展,基于深度学习神经网络可以自动地对特征进行提取以及分类成为图像分类的主流方法。常规有直接将图像对应的矩阵(或张量)进行展开后直接喂入一个前馈神经网络,或使用卷积神经网络或胶囊网络对特征进行提取,并使用一层前馈神经网络进行分类。基于深度学习的方法通常可以有效的提升分类的性能和精度。
    本文主要进行了简单的对比实验,对比方案包括机器学习算法(KNN算法和决策树算法)以及深度学习算法(神经网络、CNN),并进行可视化展示。机器学习算法在实验1和2中有所介绍,因此本节主要介绍CNN网络:
      CNN为两层卷积层以及池化层。第一层卷积层为32个大小为33的卷积核,第二层卷积层为64个22的卷积核,两个池化层均为2值最大池化,卷积网络则为3136维度的向量,输出层为两层神经网络,网络中使用正则化防止过拟合,输出部分为softmax。

    三、数据描述

      本次实验使用MNIST数据集进行实验,其中我们用6000张图像作为训练集,1000张图像作为测试集,图像的示例如图所示:

    在这里插入图片描述
      由于数据集已经集成于一些深度学习框架中,因此我们直接使用pytorch的torchvision中的datasets库下载相应数据集。数据集包括如下几个文件,如下所示:

    train-images-idx3-ubyte 训练集图像数据二进制文件
    train-labels-idx1-ubyte 训练集对应类标二进制文件
    t10k-images-idx3-ubyte 测试集10K图像数据二进制文件
    t10k-labels-idx1-ubyte 测试集10K对应类标二进制文件

      数据集是二进制文件,因此我们使用Pytorch读取数据集,并直接转换为张量,其次将每张图像与类标存入JSON数据中,保存为“{‘img’: img, ‘label’: label}”格式。另外我们使用min_batch方法进行训练,因此使用Pytorch提供的DataLoader方法自动生成batch。

    四、实验

      实验中,首先使用Sklearn调用了包括KNN(K近邻)和DT(决策树)两个算法并对训练集进行训练,其次在测试集上进行实验:。其次使用Pytorch实现只有一层隐层的神经网络以及含有多层卷积核池化层的CNN网络进行实验,程序划分为基于机器学习的训练入口函数(ml_main.py),机器学习算法类为Classifier.py;基于深度学习的训练入口函数(dl_main.py)以及模型为Network.py。使用机器学习的算法实验结果如表所示:

    算法精确度
    KNN97.50%
    DT75.96%
    SVM97.92%

      在使用深度学习训练时,相关超参数如表2所示:

    超参数取值
    Epoch20
    Batch_size30
    Learn_rate0.01
    Hidden_size196

    基于深度学习的实验结果如表4所示:

    算法精确度
    单隐层神经网络93.86%
    CNN98.86%

      下图展示了在CNN模型下训练和测试过程中的损失与精度的变化曲线,以展示最优的CNN的收敛情况。
    在这里插入图片描述

      其中横坐标表示统计的次数,训练集的loss和acc则是每训练20个batch统计一次,测试集的loss和test则是每1000个batch记录一次。

    五、总结

      通过使用几个简单的机器学习和深度学习算法实现了对手写数字识别数据集MNIST的分类,可以发现机器学习算法中SVM模型表现最优,在深度学习模型中CNN分类效果最优。另外通过对模型训练过程中的收敛情况可知,当训练第3轮时模型以及基本达到收敛,因此可知模型的收敛速度和收敛性得以保证。在今后的拓展实验中,我们还将会对彩色图像以及场景图像进行识别,以提升模型的鲁棒性。

    参考文献
    [1]Simonyan K, Zisserman A. VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION[C]. computer vision and pattern recognition, 2014.
    [2]He K, Zhang X, Ren S, et al. Deep Residual Learning for Image Recognition[C]. computer vision and pattern recognition, 2016: 770-778.
    [3]张黎;刘争鸣;唐军;;基于BP神经网络的手写数字识别方法的实现[J];自动化与仪器仪表;2015年06期

    展开全文
  • PyTorch实现-使用MNIST数据集的GAN模型生成/识别手写数字 项目目标 目标是使用在MNIST数据集上训练的生成对抗网络(GAN)生成新的手写数字。 GAN(生成对抗网络) GAN最早是在2014年由Ian Goodfellow和Yoshua ...
  • PyTorch从入门到实战一次学会

    千人学习 2019-12-29 13:44:33
    【超实用课程内容】 本课程从pytorch安装开始讲起,从基本计算结构到深度学习各大神经网络,全程案例代码实战,一步步带大家入门如何使用深度学习框架pytorch,玩转pytorch模型训练等所有知识点。最后通过 kaggle ...
  • 使用Pytor## 标题ch实现手写数字识别 思路和流程分析 准备数据,这些需要准备DataLoader 构建模型,这里可以使用torch构造一个深层的神经网络 模型的训练 模型的保存,保存模型,后续持续使用 模型的评估,使用测试...

    使用Pytorch实现手写数字识别

    思路和流程分析

    1. 准备数据,这些需要准备DataLoader
    2. 构建模型,这里可以使用torch构造一个深层的神经网络
    3. 模型的训练
    4. 模型的保存,保存模型,后续持续使用
    5. 模型的评估,使用测试集,观察模型的好坏

    准备训练集和测试集

    准备数据集的方法前面已经讲过,但是通过前面的内容可知,调用MNIST返回的结果中图像数据是一个image对象,需要对其进行处理。

    为了进行数据的处理,我们需要学习torchvision.transform的方法

    torchvision.transform的图形数据处理API

    torchvision.transform.ToTensor

    把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloatTensor

    其中(H,W,C)意思为(高,宽,通道数),黑白图片的通道数只有1,其中每个像素点的取值为[0,255],彩色图片的通道数为[R,G,B],每个通道的每个像素点的取值为[0,255],三个通道的颜色互相叠加,形成了各种颜色

    实例如下:

    from torchvision import transforms
    import numpy as np
    
    data = np.random.randint(0,255,size=12)#随机生成12个0-255的数字
    img = data.reshape(2,2,3)#将这12个数字的形状改成2 2 3
    print(img.shape)
    img_tensor = transforms.ToTensor()(img)#转化成tensor
    print(img_tensor)
    print(img_tensor.shape)
    

    输出如下:

    (2, 2, 3)
    tensor([[[ 22,  78],
             [ 13, 167]],
    
            [[153, 107],
             [102, 100]],
    
            [[ 10,  64],
             [  9,  89]]], dtype=torch.int32)
    torch.Size([3, 2, 2])
    

    可见,使用transforms.ToTensor()(img)转化成tensor类型后,这个新对象的形状变成[3,2,2](原来是(2,2,3)),相当于torch.tensor(img).permute(2,0,1)

    即:

    from torchvision import transforms
    import numpy as np
    import torch
    
    data = np.random.randint(0,255,size=12)
    img = data.reshape(2,2,3)
    print(img)
    print(img.shape)
    img_tensor = transforms.ToTensor()(img)#转化成tensor
    print(img_tensor)
    print(img_tensor.shape)
    img_t = torch.tensor(img)
    print(img_t.permute(2,0,1))
    print(img_t.permute(2,0,1).shape)
    

    对应输出如下:

    [[[154 131   6]
      [113 149   7]]
    
     [[ 11  19 163]
      [112 111  97]]]
    (2, 2, 3)
    tensor([[[154, 113],
             [ 11, 112]],
    
            [[131, 149],
             [ 19, 111]],
    
            [[  6,   7],
             [163,  97]]], dtype=torch.int32)
    torch.Size([3, 2, 2])
    tensor([[[154, 113],
             [ 11, 112]],
    
            [[131, 149],
             [ 19, 111]],
    
            [[  6,   7],
             [163,  97]]], dtype=torch.int32)
    torch.Size([3, 2, 2])
    

    对应应用于MNIST中:

    import torchvision
    from torchvision import transforms
    dataset = torchvision.datasets.MNIST(root='./data',train=True,download=True,transform=None)
    print(dataset[0])
    ret = transforms.ToTensor()(dataset[0][0])
    print(ret.size())
    #print(ret) 输出这个1*28*28的数组,内容太多不展示了
    

    输出如下:

    (<PIL.Image.Image image mode=L size=28x28 at 0x19FF2B2C7B8>, 5)
    torch.Size([1, 28, 28])
    

    可见通过transforms.ToTensor方法,把dataset[0]元组中第一个img对象转换成了[1,28,28]的tensor类型的数组(对应[通道,高,宽])

    注意:transforms.ToTensor对象中有__calll__方法,所以可以对其示例能传入数据获取结果。

    torchvision.transform.Normalize(mean,std)

    给定均值:mean,shape(形状)和图片的通道数相同(指的是每个通道的均值)。

    方差:std,和图片的通道数相同(指的是每个通道的方差)

    将会把Tensor规范化处理,即:Normalize_image = (image - mean) / std

    例如:

    from torchvision import transforms
    import numpy as np
    import torchvision
    data = np.random.randint(0,255,size=12)
    img = data.reshape(2,2,3)
    img = transforms.ToTensor()(img) #转化成tensor
    print(img)
    print('*' * 50)
    norm_img = transforms.Normalize((10,10,10),(1,1,1))(img)#进行规范化处理
    print(norm_img)
    

    输出如下:

    tensor([[[103,   6],
             [157, 226]],
    
            [[ 17, 119],
             [176,  37]],
    
            [[  6, 137],
             [173, 193]]], dtype=torch.int32)
    **************************************************
    tensor([[[ 93,  -4],
             [147, 216]],
    
            [[  7, 109],
             [166,  27]],
    
            [[ -4, 127],
             [163, 183]]], dtype=torch.int32)
    

    其中,93=(103-10)/1,10是均值,1是方差

    torchvision.transforms.Compose(transforms)

    将多个transform组合起来使用

    1. 传入一个list
    2. 数据经过list中的每一个方法挨个进行处理

    例如:

    transforms.Compose([
        torchvision.transforms.ToTensor(),#先转化为Tensor
        torchvision.transforms.Normalize(mean,std) #再进行正则化
    ])
    
    准备训练集和测试集的代码实现
    from torch.utils.data import DataLoader
    from torchvision.transforms import Compose,ToTensor,Normalize
    from torchvision.datasets import MNIST
    
    #准备数据集
    transform_fn = Compose([ #定义数据处理函数,完成对数据的totorch处理和标准化
        ToTensor(),
        Normalize(mean=(0.1307,),std=(0.3081,)) #mean 和std的形状要和数据通道数相同
    ])
    dataset = MNIST(root='./data',train=True,transform=transform_fn) #设置数据集
    data_Loader = DataLoader(dataset,batch_size=2,shuffle=True)#设置加载器
    
    for i in enumerate(data_Loader):
        print(i)
    

    构建模型

    补充:全连接层:当前一层的神经元和前一层的神经元相互链接,其核心操作就是y=wx,即矩阵的乘法,实现对前一层数据的变换。

    模型的构建使用了一个三层的神经网络,其中包含两个全连接层和一个输出层,第一个全连接层会经过激活函数的处理,将处理后的结果交给下一个全连接层,进行变换后输出结果。

    那么在这个模型中有三个地方需要注意:

    • 激活函数如何使用

    • 每一层数据的形状

    • 模型的损失函数

    激活函数如何使用

    常见的激活函数Relu,它实现对数据中所有的负数置为零,其余0和正数原样输出的效果,它由import torch.nn.functional as F提供(这个包提供了很多激活函数),F.relu(x)即可对x进行处理。

    例如:

    b = torch.tensor([-2,-1,0,1,2])
    print(F.relu(b))
    

    运行结果:

    tensor([0, 0, 0, 1, 2])
    

    模型中数据的形状(【添加形状变化图形】)

    1. 原数输入数据的形状:[batch_size,1,28,28]
    2. 进行数据的修改:[batch_size,28*28](全连接层是在进行矩阵的乘法操作)
    3. 第一个全连接层的输出形状:[batch_size,28],这里的28因个人设定,也可以设置为别的
    4. 激活函数不会修改数据的形状
    5. 第二个全连接层的输出形状:[batch_size,10],因为手写数字有十个类别

    构建模型的代码如下:

    class MnistModel(nn.Module):
        def __init__(self):
            super(MnistModel,self).__init__()
            # 定义f1方法,使用Linear方法,Linear(输入的形状,输出的形状),将输入的28*28输出为28
            self.fc1 = nn.Linear(in_features=28*28,out_features=28)
            # 将输入的28输出为10,因为预期输出是10个数字
            self.fc2 = nn.Linear(28,10)
    
    
        def forward(self,input):
            '''
            :param input: [batch_size,1,28*28] 我们获得的原始数据的样子,即input[0]=batchsize,input[1]=1,input[2]=28*28
            :return: 
            '''
            #更改形状,view函数相当于resize的功能,将原来的tensor变换成指的维度,input.size(0)指batchsize的值
            x = input.view(input.size(0),28*28) #这里实现把形状转化为[batch_size,28*28]
            # x = input.view(-1,28*28) #二者实现效果相同
            # x = input.view(input.size(0),-1)#实现效果与未注释的那句等价
            #进行全连接操作
            x = self.fc1(x)
            #使用激活函数处理数据,不会使形状发生变化
            x = F.relu(x)
            #输出层
            out = self.fc2(x)
            return out
    

    可见,pytorch在构建模型的时候形状上并不会考虑batch_size。

    补充知识

    view()函数的功能根reshape类似,用来转换size大小。x = x.view(batchsize, -1)中batchsize指转换后有几行,而-1指在不告诉函数有多少列的情况下,根据原tensor数据和batchsize自动分配列数。x = x.view(x.size(0), -1)相当于2x = x.view(batchsize, -1)。

    模型的损失函数

    需要知道,手写数字识别是一个多分类问题,所谓多分类是对比之前的二分类。

    回顾一下二分类:
    在这里插入图片描述

    sigmoid函数表达式如下:
    1 1 + e − Z \frac{1}{1+e^{-Z}} 1+eZ1

    图像如下:

    在这里插入图片描述

    可以看到在趋于正无穷或负无穷时,函数趋近平滑状态,sigmoid函数因为输出范围(0,1),所以二分类的概率常常用这个函数,特点:

    1. 值域在0和1之间

    2. 函数具有非常好的对称性

    3. 函数对输入超过一定范围就会不敏感

    现在我们使用多分类应该如何处理呢?

    • 多分类应该使用softmax模型,而不是继续使用二分类的sigmoid模型
    • softmax和sigmoid的区别在于我们需要去计算样本属于每个类别的概率,需要计算多次,而sigmoid只需要计算一次。

    softmax的公式如下:在这里插入图片描述

    例如下图:

    在这里插入图片描述

    在这里插入图片描述

    我们把softmax概率传入对数似然损失的损失函数称为交叉熵损失

    在pytorch中有两种方法实现交叉熵损失

    criterion = nn.CrossEntropyLoss()
    loss = criterion(input.taget)
    
    #对输出值计算softmax和取对数
    output = = F.log_softmax(x,dim=-1)
    #使用torch中带权损失
    loss = F.nll_loss(output,target)
    

    带权损失定义为:
    l n = − ∑ w i x i l_n=-\sum w_ix_i ln=wixi
    其实就是把log(P)作为x_i,把真实值Y作为权重

    模型的训练

    训练流程:

    1. 实例化模型,设置模型为训练模式
    2. 实例化优化器模型,实例化损失函数
    3. 获取、遍历dataloader
    4. 梯度置为0
    5. 进行前向计算
    6. 计算损失
    7. 反向传播
    8. 更新参数
    model = MnistModel()#实例化模型,设置模型为训练模式(默认)
    optimizer = Adam(model.parameters(),lr=0.001)#实例化优化器模型
    
    def train(epoch):#epoch 轮的意思
        '''实现训练的过程'''
        data_loader = get_dataLoader()#获取dataloader
        for idx,(input,target) in enumerate(data_loader):
            optimizer.zero_grad()#梯度置为零
            out_put = model(input)#进行前向计算,调用模型,得到预测值
            loss = F.nll_loss(out_put,target)#带权损失
            loss.backward()#反向传播(记得梯度置为0),计算梯度
            optimizer.step()#梯度更新
            if idx%100 == 0:
                print(loss.item())
    

    模型的保存和加载

    模型的保存
    #模型的保存
    if idx%100 ==0:
        torch.save(model.state_dict(),'./model/model.pkl')
        torch.save(optimizer.state_dict(), './model/optimizer.pkl')
    
    模型的加载
    if os.path.exists('./model/model.pkl'):#判断路径是否存在
        model.load_state_dict(torch.load('./model/model.pkl'))
        optimizer.load_state_dict(torch.load('./model/optimizer.pkl'))
    

    模型的评估

    评估的过程和训练的过程相似,但是:

    1. 不需要计算梯度
    2. 需要收集损失和转化率,用来计算平均损失和平均准确率
    3. 损失的计算和训练时候损失的计算方法相同
    4. 准确率的计算:
      • 模型的输出为[batch_size]的形状
      • 其中最大值的位置就是其预测的目标值(预测值进行过softmax后为概率,softmax中分母都是相同的,分子越大,概率越大)
      • 最大值的位置的获取方法可以使用torch.max返回最大值和最大值的位置
      • 返回最大值的位置后,和真实值([batch_size])进行对比,相同表示预测成功。
    def test():
        loss_list = []
        acc_list = []
        test_dataLoader = get_dataLoader(train=False,batch_size=TEST_BATCH_SIZE)
        for idx,(input,target) in enumerate(test_dataLoader):
            with torch.no_grad():
                output = model(input)
                cur_loss = F.nll_loss(output,target)
                loss_list.append(cur_loss)
                #计算准确率
                # output [batch_size] target:[batch_size]
                pred = output.max(dim=-1)[-1] #第一个-1表示在最后一个维度(行上)取得最大值,第二个-1表示同时输出对应位置
                cur_acc = pred.eq(target).float().mean()
                acc_list.append(cur_acc)
        print('平均准确率:',np.mean(acc_list),'平均损失',np.mean(loss_list))
    

    Pytorch实现手写识别完整代码

    '''
    该算法的核心思想是通过对比训练值和测试值中的最大值是否相同,来评估该项目的好坏
    '''
    import numpy as np
    import os
    from torch.utils.data import DataLoader
    from torchvision.transforms import Compose,ToTensor,Normalize
    from torchvision.datasets import MNIST
    import torch
    import torch.nn.functional as F
    import torch.nn as nn
    from torch.optim import Adam
    
    BATCH_SIZE = 128
    TEST_BATCH_SIZE = 1000
    
    #准备数据集
    def get_dataLoader(train = True,batch_size = BATCH_SIZE):
        transform_fn = Compose([  # 定义数据处理函数,完成对数据的totorch处理和标准化
            ToTensor(),
            Normalize(mean=(0.1307,), std=(0.3081,))  # mean 和std的形状要和数据通道数相同
        ])
        dataset = MNIST(root='./data', train=True, transform=transform_fn)  # 设置数据集
        data_Loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)  # 设置加载器
        return data_Loader
    
    #构建数据模型
    class MnistModel(nn.Module):
        def __init__(self):
            super(MnistModel,self).__init__()
            # 定义f1方法,使用Linear方法,Linear(输入的形状,输出的形状),将输入的28*28输出为28
            self.fc1 = nn.Linear(in_features=28*28,out_features=28)
            # 将输入的28输出为10,因为预期输出是10个数字
            self.fc2 = nn.Linear(28,10)
    
    
        def forward(self,input):
            '''
            :param input: [batch_size,1,28*28] 我们获得的原始数据的样子,即input[0]=batchsize,input[1]=1,input[2]=28*28
            :return: 
            '''
            #更改形状,view函数相当于resize的功能,将原来的tensor变换成指的维度,input.size(0)指batchsize的值
            x = input.view(input.size(0),28*28) #这里实现把形状转化为[batch_size,28*28]
            # x = input.view(-1,28*28) #二者实现效果相同
            # x = input.view(input.size(0),-1)#实现效果与未注释的那句等价
            #进行全连接操作
            x = self.fc1(x)
            #使用激活函数处理数据,不会使形状发生变化
            x = F.relu(x)
            #输出层
            out = self.fc2(x)
            return F.log_softmax(out,dim=-1) #在最后一个维度上进行操作,dim是维度的意思
    
    model = MnistModel()#实例化模型,设置模型为训练模式(默认)
    optimizer = Adam(model.parameters(),lr=0.001)#实例化优化器模型
    if os.path.exists('./model/model.pkl'):#判断路径是否存在
        model.load_state_dict(torch.load('./model/model.pkl'))
        optimizer.load_state_dict(torch.load('./model/optimizer.pkl'))
    
    def train(epoch):#epoch 轮的意思
        '''实现训练的过程'''
        data_loader = get_dataLoader()#获取dataloader
        for idx,(input,target) in enumerate(data_loader):
            optimizer.zero_grad()#梯度置为零
            out_put = model(input)#进行前向计算,调用模型,得到预测值
            loss = F.nll_loss(out_put,target)#带权损失
            loss.backward()#反向传播(记得梯度置为0),计算梯度
            optimizer.step()#梯度更新
            # if idx%100 == 0:
            #     print(loss.item())
            #模型的保存
            if idx%100 ==0:
                torch.save(model.state_dict(),'./model/model.pkl')
                torch.save(optimizer.state_dict(), './model/optimizer.pkl')
    
    def test():
        loss_list = []
        acc_list = []
        test_dataLoader = get_dataLoader(train=False,batch_size=TEST_BATCH_SIZE)
        for idx,(input,target) in enumerate(test_dataLoader):
            with torch.no_grad():
                output = model(input)
                cur_loss = F.nll_loss(output,target)
                loss_list.append(cur_loss)
                #计算准确率
                # output [batch_size] target:[batch_size]
                pred = output.max(dim=-1)[-1] #第一个-1表示在最后一个维度(行上)取得最大值,第二个-1表示同时输出对应位置
                cur_acc = pred.eq(target).float().mean()
                acc_list.append(cur_acc)
        print('平均准确率:',np.mean(acc_list),'平均损失',np.mean(loss_list))
    
    if __name__ == '__main__':
        # for i in range(3):#训练三轮
        #     train(i)
    
        # loader = get_dataLoader(False)
        # for input,lable in loader:
        #     print(lable.size())
        #     break
    
        test()
        for i  in range(5):
            train(i)
            test()
    

    更多Pytorch知识梳理,请参考: pytorch学习笔记

    有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

    展开全文
  • 普通图片都是三通道的为(3, x, y),手写数字的图为单通道的。 class MyDataset ( Dataset ) : def __init__ ( self , df , transform , train = True ) : self . df = df . values self . ...

    题目地址
    之前学svm时候就做了一下,pca+svm也有0.98左右,这次试试cnn吧。在本地跑完提交需要搭梯子,就直接在kaggle的kernel上运行了,kernel上也有很多大佬分享自己的代码,可以学到很多。

    先导入一堆包进来:

    import numpy as np # linear algebra
    import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
    import torch
    import torch.nn as nn
    import torch.utils.data as Data
    import torchvision
    from torch.autograd import Variable
    import matplotlib.pyplot as plt
    from torchvision import transforms
    from torch.utils.data import Dataset, DataLoader
    from sklearn.model_selection import train_test_split
    # Input data files are available in the "../input/" directory.
    # For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory
    import os
    print(os.listdir("../input"))
    

    读取训练集和测试,同时将训练集再分成训练集和验证集:

    data = pd.read_csv('../input/train.csv')
    test = pd.read_csv('../input/test.csv')
    train, valid = train_test_split(data, stratify=data.label, test_size=0.2)
    

    定义一个自己的数据集,原本每张图为(1,784),需变成(28,28),再加一维,得到(1,28,28)
    刚开始没加最后那一维,然后后面报错维度不对啥的。。。普通图片都是三通道的为(3, x, y),手写数字的图为单通道的。

    class MyDataset(Dataset):
        def __init__(self, df, transform, train=True):
            self.df = df.values
            self.transform = transform
            self.train = train  
    
        def __len__(self):
            return len(self.df)
    
        def __getitem__(self, index):
            if self.train == True: # 训练集or验证集
                label = self.df[index, 0]
                image = torch.FloatTensor(self.df[index, 1:]).view(28, 28).unsqueeze(0)
                image = self.transform(image)
                return image, label
            else: # 测试集,没有标签
                image = torch.FloatTensor(self.df[index, :]).view(28, 28).unsqueeze(0)
                image = self.transform(image)
                return image
    

    加载数据:

    EPOCH = 30  # 训练整批数据多少次
    BATCH_SIZE = 64 
    LR = 0.002  # 学习率
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    
    tranf = transforms.Compose([
        transforms.ToPILImage(),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.5,), std=(0.5,)),
    ])
    train_dataset = MyDataset(df=train, transform=tranf)
    train_dataloader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
    valid_dataset = MyDataset(df=valid, transform=tranf)
    valid_dataloader = DataLoader(valid_dataset, batch_size=BATCH_SIZE)
    

    构建网络:

    class CNN(nn.Module):
        def __init__(self):
            super(CNN, self).__init__()
            self.conv1 = nn.Sequential(  # (1, 28, 28)
                nn.Conv2d(
                    in_channels=1, # 输入通道数,若图片为RGB则为3通道
                    out_channels=32, # 输出通道数,即多少个卷积核一起卷积
                    kernel_size=3, # 卷积核大小
                    stride=1, # 卷积核移动步长
                    padding=1, # 边缘增加的像素,使得得到的图片长宽没有变化
                ),# (32, 28, 28)
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
            )
            self.conv2 = nn.Sequential(
                nn.Conv2d(32, 32, 3, 1, 1), # (32, 28, 28)
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2), # 池化 (32, 14, 14)
            )
            self.conv3 = nn.Sequential(# (32, 14, 14)
                nn.Conv2d(32, 64, 3, 1, 1),# (64, 14, 14)
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True),
            )
            self.conv4 = nn.Sequential(
                nn.Conv2d(64, 64, 3, 1, 1),# (64, 14, 14)
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(2),# (64, 7, 7)
            )
            self.out = nn.Sequential(
                nn.Dropout(p = 0.5), # 抑制过拟合
                nn.Linear(64 * 7 * 7, 512),
                nn.BatchNorm1d(512),
                nn.ReLU(inplace=True),
                nn.Dropout(p = 0.5),
                nn.Linear(512, 512),
                nn.BatchNorm1d(512),
                nn.ReLU(inplace=True),
                nn.Dropout(p = 0.5),
                nn.Linear(512, 10),
            )
        def forward(self, x):
            x = self.conv1(x)
            x = self.conv2(x)
            x = self.conv3(x)
            x = self.conv4(x)
            x = x.view(x.size(0), -1) # (batch_size, 64*7*7)
            output = self.out(x)
            return output
    

    训练过程:

    cnn = CNN().to(device)
    print(cnn)
    # 训练
    optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)
    loss_func = nn.CrossEntropyLoss()
    
    for epoch in range(EPOCH):
        for step, (x, y) in enumerate(train_dataloader):
            b_x = x.to(device)
            b_y = y.to(device)
            output = cnn(b_x)
            loss = loss_func(output, b_y)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
    
            if step % 100 == 0:
                print('epoch:[{}/{}], loss:{:.4f}'.format(epoch, EPOCH, loss))
    

    验证:

    cnn.eval()
    with torch.no_grad():
        total = 0
        cor = 0
        for x, y in valid_dataloader:
            x = x.to(device)
            y = y.to(device)
            out = cnn(x)
            pred = torch.max(out, 1)[1]
            total += len(y)
            cor += (y == pred).sum().item()
    print('acc:{:.4f}'.format(cor/total))
    

    得到结果,感觉这次还行
    在这里插入图片描述
    测试集提交一发试试:

    test_dataset = MyDataset(df=test, transform=tranf, train=False)
    test_dataloader = DataLoader(test_dataset, batch_size=BATCH_SIZE)
    cnn.eval()
    pred = []
    for x in test_dataloader:
        x = x.to(device)
        out = cnn(x)
        pre = torch.max(out, 1)[1].cpu().numpy()
        pred += list(pre)
    submit = pd.read_csv('../input/sample_submission.csv')
    submit['Label'] = pred
    submit.to_csv('submission_cnn99.csv', index=False)
    

    分数:
    在这里插入图片描述总结:
    刚开始学,也碰到了好多问题,特别是数据集那里。后面构建网络时,刚开始就建了两层,结果还不如svm,然后在kernel上参考了好多国外的大佬,准确率才提高了点,感觉就跟炼丹一样。之后还可以采用对图片进行平移旋转等操作扩大数据集来提高准确率,继续加油吧。

    展开全文
  • 数据集介绍 使用的是MNIST手写数字识别数据集,torchvision中自带有数据集的下载地址。 定义网络结构 就按照网络结构图中一层一层的定义就行,其中第1,2,5层卷积层后面接有Max pooling层和Relu激活函数,五层卷积...

    网络介绍:

    Alexnet网络是CV领域最经典的网络结构之一了,在2012年横空出世,并在当年夺下了不少比赛的冠军,下面是Alexnet的网络结构:
    image.png

    网络结构较为简单,共有五个卷积层和三个全连接层,原文作者在训练时使用了多卡一起训练,具体细节可以阅读原文得到。
    Alexnet文章链接:http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf
    作者在网络中使用了Relu激活函数和Dropout等方法来防止过拟合,更多细节看文章。

    数据集介绍

    使用的是MNIST手写数字识别数据集,torchvision中自带有数据集的下载地址。

    定义网络结构

    就按照网络结构图中一层一层的定义就行,其中第1,2,5层卷积层后面接有Max pooling层和Relu激活函数,五层卷积之后得到图像的特征表示,送入全连接层中进行分类。

    # !/usr/bin/python3
    # -*- coding:utf-8 -*-
    # Author:WeiFeng Liu
    # @Time: 2021/11/2 下午3:25
    
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torchvision.transforms as transforms
    import torch.optim as optim
    
    class AlexNet(nn.Module):
        def __init__(self,width_mult=1):
            super(AlexNet,self).__init__()
            #定义每一个就卷积层
            self.layer1 = nn.Sequential(
                #卷积层  #输入图像为1*28*28
                nn.Conv2d(1,32,kernel_size=3,padding=1),
                #池化层
                nn.MaxPool2d(kernel_size=2,stride=2)  ,   #池化层特征图通道数不改变,每个特征图的分辨率变小
                #激活函数Relu
                nn.ReLU(inplace=True),
            )
    
            self.layer2 = nn.Sequential(
                nn.Conv2d(32,64,kernel_size=3,padding=1),
                nn.MaxPool2d(kernel_size=2,stride=2),
                nn.ReLU(inplace=True),
            )
    
            self.layer3 = nn.Sequential(
                nn.Conv2d(64,128,kernel_size=3,padding=1),
            )
    
            self.layer4 = nn.Sequential(
                nn.Conv2d(128,256,kernel_size=3,padding=1),
            )
            self.layer5 = nn.Sequential(
                nn.Conv2d(256,256,kernel_size=3,padding=1),
                nn.MaxPool2d(kernel_size=3, stride=2),
                nn.ReLU(inplace=True),
            )
    
            #定义全连接层
            self.fc1 = nn.Linear(256 * 3 * 3,1024)
            self.fc2 = nn.Linear(1024,512)
            self.fc3 = nn.Linear(512,10)
            #对应十个类别的输出
    
    
        def forward(self,x):
            x = self.layer1(x)
            x = self.layer2(x)
            x = self.layer3(x)
            x = self.layer4(x)
            x = self.layer5(x)
            x = x.view(-1,256*3*3)
            x = self.fc1(x)
            x = self.fc2(x)
            x = self.fc3(x)
    
            return x
    
    
    
    
    

    训练

    # !/usr/bin/python3
    # -*- coding:utf-8 -*-
    # Author:WeiFeng Liu
    # @Time: 2021/11/2 下午3:38
    
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torchvision
    import torch.optim as optim
    import torchvision.transforms as transforms
    from alexnet import AlexNet
    import cv2
    from utils import plot_image,plot_curve,one_hot
    #定义使用GPU
    
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    
    #设置超参数
    epochs = 30
    batch_size = 256
    lr = 0.01
    
    train_loader = torch.utils.data.DataLoader(
        torchvision.datasets.MNIST('mnist_data',train=True,download=True,
                                   transform = torchvision.transforms.Compose([
                                       torchvision.transforms.ToTensor(),
                                       #数据归一化
                                       torchvision.transforms.Normalize(
                                           (0.1307,),(0.3081,))
                                   ])),
        batch_size = batch_size,shuffle = True
    )
    
    test_loader = torch.utils.data.DataLoader(
        torchvision.datasets.MNIST('mnist_data/',train=False,download=True,
                                   transform = torchvision.transforms.Compose([
                                       torchvision.transforms.ToTensor(),
                                       torchvision.transforms.Normalize(
                                           (0.1307,),(0.3081,))
                                   ])),
        batch_size = 256,shuffle = False
    )
    
    #定义损失函数
    criterion = nn.CrossEntropyLoss()
    
    #定义网络
    net = AlexNet().to(device)
    
    #定义优化器
    optimzer = optim.SGD(net.parameters(),lr=lr,momentum = 0.9)
    
    
    #train
    train_loss = []
    for epoch in range(epochs):
        sum_loss = 0.0
        for batch_idx,(x,y) in enumerate(train_loader):
            print(x.shape)
            x = x.to(device)
            y = y.to(device)
    
            #梯度清零
            optimzer.zero_grad()
    
            pred = net(x)
            loss = criterion(pred, y)
            loss.backward()
            optimzer.step()
            train_loss.append(loss.item())
    
            sum_loss += loss.item()
    
            if batch_idx % 100 == 99:
                print('[%d, %d] loss: %.03f'
                      % (epoch + 1, batch_idx + 1, sum_loss / 100))
                sum_loss = 0.0
    torch.save(net.state_dict(),'/home/lwf/code/pytorch学习/alexnet图像分类/model/model.pth')
    plot_curve(train_loss)
    
    
    

    使用交叉熵损失函数和SGD优化器来训练网络,训练后保存模型至本地。

    训练过程中损失函数的收敛过程:
    image.png

    测试准确率

    image.png

    完整代码:https://github.com/SPECTRELWF/pytorch-cnn-study/tree/main/Alexnet-MNIST
    个人主页:http://liuweifeng.top:8090/

    展开全文
  • PyTorch实现MNIST手写数字识别(非常详细)

    万次阅读 多人点赞 2020-04-30 22:25:58
    hello大家好!我又来搬文章了!我就不信还有比这更详细的?...在本文中,我们将在PyTorch中构建一个简单的卷积神经网络,并使用MNIST数据集训练它识别手写数字。在MNIST数据集上训练分类器可以看作是...
  • 卷积神经网络的结构 #定义网络结构 #不是le-net5的结构 class Net(nn.Module): def __init__(self): super(Net, self).__init__() # Sequential表示...写下数字之后,便会自动识别。几乎是0延迟,预测结果非常的快! 
  • CNN 手写数字识别 (pytorch代码实现)

    千次阅读 2020-05-23 17:51:02
    1、pytorch 手写数字识别步骤 (1)加载minist数据 (2)搭建网络 (3)模型训练 (4)结果可视化 2、代码实现 # library # standard library import os # third-party library import torch import torch.nn as nn...
  • 先写resnet18.py,代码如下: import torch from torch import nn from torch.nn import functional as F class ResBlk(nn.Module): """ resnet block """ ... def __init__(self, ch_in, ch_out, stride=1): ...
  • Pytorch实战:手写数字识别 1、数据导入 #实战手写数字识别 #************************************************************导入包********************************************************************* import...
  • Debug经验总结 一、常规ResBlock的输出尺寸与输入尺寸相同,否则需要进行尺寸变换; 二、在数据集较大时设置num_work进行多线程处理,可以很大提高训练效率; 三、较复杂的网络在搭建前可以先用草图计算每个输出位置...
  • PyTorch手写数字识别

    千次阅读 2019-04-18 22:09:54
    手写数字识别是经典数据集 最后一次任务我们来搞一下 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import matplotlib.pyplot as plt from torchvision...
  • PyTorch resnet18实现MNIST手写数字识别 Warning: 这是一个学习笔记及分享向的文章, 对于初学者可能不太友好 最近突然出现了一个疑问, 用了ResNet等主流主干网络这么久, 也知道每个网络最基本的原理, 比如ResNet...
  • PyTorch完成手写数字识别

    千次阅读 2019-08-20 18:53:46
    PyTorch完成手写数字识别 数据集为MNIST import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms import torchvision ...
  • pytorch实现mnist手写数字识别(一)

    千次阅读 2020-03-30 18:46:09
    深度学习的神经网络往往是庞大的,有几十层或几百层...PyTorch有一个很好的模块nn,它提供了一种有效构建大型神经网络的好方法。 # Import necessary packages %matplotlib inline %config InlineBackend.figure_fo...
  • CNN实现手写数字识别卷积神经网络介绍什么是卷积paddingstride(步长)三维卷积池化层LeNet-5卷积神经网络LeNet-5实现(pytorch) 卷积神经网络介绍 卷积神经网络它的优点在于,需要调优的参数比全连接神经网络少的多...
  • PyTorch】GPU实现cnn手写数字识别

    千次阅读 2019-07-18 22:02:36
    核心思想: ...#gpu方式的mnist手写数字识别 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.autograd import Variable import torch.uti...
  • 主要介绍了pytorch cnn 识别手写的字实现自建图片数据,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 目录PyTorch 学习 —— 手写数字识别Ⅰ. 数据读取器1. 训练集2. 验证集和测试集Ⅱ. 搭建网络Ⅲ. 模型训练1. 开始训练2. 模型验证Ⅲ. 模型测试Ⅳ. 绘制图像Ⅴ. 完整代码 PyTorch 学习 —— 手写数字识别   MNIST ...
  • 本文学习自莫烦教程 import torch import torch.nn as nn from torch.autograd import Variable import torchvision.datasets as dsets import torchvision.transforms as transforms from torch.utils.data import ...
  • PyTorch手写数字识别(MNIST数据集)

    万次阅读 多人点赞 2019-06-05 08:27:40
    MNIST 手写数字识别是一个比较简单的入门项目,相当于深度学习中的 Hello World,可以让我们快速了解构建神经网络的大致过程。虽然网上的案例比较多,但还是要自己实现一遍。代码采用 PyTorch 1.0 编写并运行...
  • 下面是用全连接网络实现手写数字识别。主要对数据的输入输出做了相关笔记。 import torch import torch . nn as nn import torchvision import torchvision . transforms as transforms # 如果gpu...
  • grad() output=model(data) # pred=output.argmax(dim=1)#找到每行中数值最大的索引 # #[0,0.1,0.2,0.3,0.4]返回为5表示数字5 loss = F.nll_loss(output, target) # train_loss=train_loss.append(loss.item())#注意...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,853
精华内容 1,541
关键字:

手写数字识别pytorch