Pytorch实战:手写数字识别

Pytorch实战:手写数字识别

1、数据导入

#实战手写数字识别
#************************************************************导入包*********************************************************************

import  torch , torchvision           #该句中torchvision可省略,torchvision可实现数据的处理、导入和预览等
import  matplotlib.pyplot as plt      #该句可略

from torch.autograd import Variable
from torchvision import datasets, transforms       #torchvision.datasets可实现对自带训练集和测试集的下载
                                                   #torchvision.transforms中提供了丰富的类对载入的数据进行变换
from torch.utils.data import DataLoader            #dataLoader实现对数据的装载      

#**************************************************获取手写数字的训练集和测试集**********************************************************

data_train = torchvision.datasets.MNIST(root = "./data/",     #MNIST是系统自带的手写数字数据集,
                                                              #root指定下载地址,这里是放在根目录下的data文件夹中
                    transform= transforms.ToTensor(),       #对数据进行变换操作
                    train = True ,                #将下载好的数据进行指定数据载入,True--载入的是训练集,False--载入的是测试集
                    download = True)              #确认下载


data_test = datasets.MNIST(root = "./data/",
                      transform= transforms.ToTensor() ,      #对数据进行变换操作
                      train = False)      #无需进行 download = True 的下载操作,反而会报错
 
#pytorch.torch.transforms
transform = transforms.Compose(                            #Compose可以当作一种容器,它能够同时对多种数据变换进行组合
                                [transforms.ToTensor() ,   #类型的转换变换
                                transforms.Normalize(mean = [0.5, 0.5, 0.5],  #(图像去均值)数据标准化变换,这里是将数据变换为标准正太分布                                                  
                                                     std= [0.5, 0.5, 0.5])]   # 归一化可以移除图像的平均亮度值,也有利于学习率的自动选择
                               )                                              #normalize函数:X(normal)=(X-mean(均值))/std(标准差)
                                                                              #这里取巧(偷懒),并没有使用原始的数据集,而是自定义了
                                                                              #一个normalize函数

data_loader_train =DataLoader(dataset = data_train,            #用于指定载入的数据集名称
                                        batch_size = 64,       #每个包中的图像数据个数
                                        shuffle =True)         #true表明装载的过程中将数据随机打乱顺序,并进行打包(写False会报错)

data_loader_test = DataLoader(dataset = data_test,
                              batch_size = 64,
                              shuffle = True)   

2、数据预览

#**********************************************************数据预览******************************************************************

images, labels = next(iter(data_loader_train))  #使用iter和next来获取一个批次的图片数据和其对应的图片标签
                                               #iter()函数获取这些可迭代对象的迭代器
                                               #next()不断的获取下一条数据
                                               #迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素
            
img = torchvision.utils.make_grid(images)  #使用torchvision.utils中的make_grid类方法将一个批次的图片构造成网络模式
                                           #传递给grid的参数就是一个批次的装载数据,每个批次的装载数据都是4维的,维度
                                           #从前往后分别是:batch_size(一个批次中的数据个数),channel(每张图片的色彩通道数),
                                           #height(每张图片的高度),weight(每张图片的宽度)
                                           #经过grid整合后,这个批次的图片全部被整合到一起,图片的维度变成(channel,height,weight)
                                           #channel的值和之前一样,其余值发生了变化
                    
img = img.numpy().transpose(1,2,0)  #transpose实现坐标轴的旋转,原始为(0,1,2)表示(x,y,z)轴,在这里变成(1,2,0)表示(y,z,x)轴,实现了90度翻转
std = [0.5,0.5,0.5]    #标准差
mean = [0.5,0.5,0.5]   #均值
img = img*std + mean   #一种归一化处理
print([labels[i] for i in range(64)])
plt.imshow(img)

数据集

3、模型搭建

#********************************************************* CNN训练模型搭建 ******************************************************************

class Model (torch.nn.Module): #继承Module
    def __init__(self):
        super(Model , self).__init__( )
        self.conv1 = torch.nn.Sequential(  #Sequential是一个容器,将一些模块装入其中
                     torch.nn.Conv2d(1,64,kernel_size = 3 , stride = 1 , padding = 1),#(1是输入图像的深度,64是输出图像的深度)
                     torch.nn.ReLU(),
                     torch.nn.Conv2d(64, 128, kernel_size = 3 ,stride = 1 , padding = 1),
                     torch.nn.ReLU(),
                     torch.nn.MaxPool2d(stride = 2 , kernel_size = 2))
        
        self.dence = torch.nn.Sequential(
                     torch.nn.Linear(14*14*128 , 1024), #(14*14*128是输入层,1024是隐藏层)
                     torch.nn.ReLU(),
                     torch.nn.Dropout(p=0.5), #将所有元素按概率P=0.5进行置0,以防止过拟合
                     torch.nn.Linear(1024,10)) 
     
    def forward(self , x):          #前向传播forward函数中的内容,首先经过self.conv1进行卷积处理,然后进行x.view(-1,14*14*128),对参数实现扁平化,
        x = self.conv1(x)           #/因为之后紧接着的就是全连接层,所以如果不进行扁平化,则全连接层的实际输出的参数维度和其定义输入的维度将不匹配,
        x = x.view(-1 , 14*14*128)  #/程序将会报错,最后通过self.dense定义的全连接层进行最后的分类。   view中的-1表示一个不确定的数
        x = self.dence(x)           #/输入-1会使计算机进行自我计算,view返回的数据和传入的tensor一样,只是形状不同
        return x   
        

4、定义在训练之前使用哪种损失函数和优化函数

model = Model()
cost = torch.nn.CrossEntropyLoss()  #损失函数使用的是交叉熵
optimizer = torch.optim.Adam(model.parameters())  #优化函数使用的是Adam自适应算法,优化参数范围是所有参数
print(model)

5、导入CNN模型与优化函数,进行后向传播

n_epochs = 5
 
for epoch in range (n_epochs):
    running_loss = 0.0   #损失个数初始化为0
    running_correct = 0  #命中个数初始化为0
    print("Epoch {}/{}".format(epoch , n_epochs))
    print("-"*20)
    for data in data_loader_train :   #逐一读取训练集中的数据
        X_train , y_train = data   
        X_train , y_train = Variable(X_train),Variable(y_train)  #使用Variable将Tensor数据变量进行封装,以便自动梯度的实现
        outputs = model(X_train)      #输出卷积后的训练集
        _,pred = torch.max(outputs.data , 1) 
        optimizer.zero_grad()         #自适应下的梯度清零
        loss = cost(outputs , y_train)  #损失函数的计算:将训练后的参数与目标数进行 交叉熵 的计算        
        loss.backward()    #后向传播
        optimizer.step()   #自适应算法下的梯度更新
        running_loss += loss.data.item()    #识别失败数据统计,.item()等同于data[0]
        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),#len求字符串长度
                                                                                      100*running_correct/len(data_train), #百分比样式
                                                                                      100*testing_correct/len(data_test))) #百分比样式

6、最终结果

Epoch 0/5
--------------------
Loss is : 0.0021 , Train Accuracy is : 95.0000% , Test Accuracy is :98.0000
Epoch 1/5
--------------------
Loss is : 0.0007 , Train Accuracy is : 98.0000% , Test Accuracy is :99.0000
Epoch 2/5
--------------------
Loss is : 0.0004 , Train Accuracy is : 99.0000% , Test Accuracy is :99.0000
Epoch 3/5
--------------------
Loss is : 0.0003 , Train Accuracy is : 99.0000% , Test Accuracy is :99.0000
Epoch 4/5
--------------------
Loss is : 0.0002 , Train Accuracy is : 99.0000% , Test Accuracy is :99.0000

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值