Python代码实现简单的MNIST手写数字识别(适合初学者看)

补充:由于很多同学找我要原数据集和代码,所以我上传到了资源里,https://download.csdn.net/download/zugexiaodui/10913834

初学机器学习,第一步是做一个简单的手写数字识别,我选用的是MNIST数据集(用其他数据集也可以,原理都差不多),算法是KNN(下载库直接调用函数,算法的具体实现没有过多关心)。在网上也看到过MNIST数据集的Python代码,但是感觉有些复杂,作为初学者见到那么多代码就头大……这里分享一下我的代码,虽然并不完善,但是可以为其他初学者提供一点简单的思路吧。

首先明确一下我的思路:解析图片和标签——处理图片和标签——加载KNN分类器训练——读入处理后的测试图片和标签——得出正确率。

我写了两个程序,第一个用来解析并保存图片,第二个对图片进行处理、解析标签、训练、预测、得出结果。

准备工作:

0.安装Python:最好默认安装位置,安装的时候勾上Add Path......,下一步还有个为所有Users安装,也勾上。win7以上如果默认安装到C盘某个目录下,需要更改一下文件夹的权限,在python文件夹上点击右键>>属性>>安全>>编辑,把Users和ALL APPLICATION PACKAGES的权限的“完全控制”都打上勾,确定。

1.Python做数字手写识别需要用到的库:numpy,scipy,scikit_learn,也可以再加上openCV,因为我把图片都解析出来保存下来了。点击这里可以寻找并下载这些库(.whl文件),注意要对应自己的python版本。下载后放在python安装目录的Scripts下,按着shift点鼠标右键,点击”在此处打开命令窗口”,输入pip install ****** ,这里******代表要安装的文件名,注意不要更改那些文件名,直接把文件名带着后缀.whl复制粘贴在命令行里就行,粘贴的时候不可以使用ctrl+v,直接鼠标右键粘贴就行。要先安装numpy和scipy,再安装scikit_learn和openCV。安装成功会有提示的,失败的话……当然也会有提示,如果有错误就百度一下。如果你安装的是python3.5或者3.6的话,联网的情况下不用下载.whl文件直接输入pip install ******应该程序就会自己在网上下载安装,特别方便。但是下载的numpy只有numpy,而在我提供的那个网址上下载的都是numpy+mkl,后续安装一些库需要用到mkl,所以建议numpy还是自己下载。

2.下载MNIST数据集,网上很好搜到(很久前下载的了,这里就不贴链接了)。下载后有四个文件,两个.idx3-ubyte文件,分别是训练用和测试用的图像文件,还有两个.idx1-ubyte文件,分别是训练和测试用的标签文件。这些文件都是二进制文件,没办法直接打开,需要在Python 里写程序解析。

正式开始:

为了验证我的解析结果是否正确,我把解析出的图片进行了保存(这里用到了openCV),然后处理的是保存后的图片,其实不保存就可以,解析出来直接用,反而会节省很多步骤。

解析图片:解析图片和标签的原理在这里我就不多说了,网上可以搜到,介绍的很详细。直接上代码(如果你不用openCV的话,就要修改一下代码了,可以不转换成图片)。

 

import numpy as np
import struct
import cv2

def readfile():#读取源图片文件
    with open('E:\\t10k-images.idx3-ubyte','rb') as f1:
        buf1 = f1.read()
    return buf1

def get_image(buf1):#解析并保存图片
    image_index = 0
    image_index += struct.calcsize('>IIII')
    magic,numImages,imgRows,imgCols=struct.unpack_from(">IIII",buf1,0)
    im = []
    for i in range(numImages):
        temp = struct.unpack_from('>784B', buf1, image_index)
        im=np.array(temp)
        im2=im.reshape(28,28)
        cv2.imwrite("E:\\testImages\\testIM"+str(i)+".jpg",im2)#保存路径自己设置
        image_index += struct.calcsize('>784B')  # 28*28=784(B)
        if i%20==0:#知道图片保存的进度
            print i
        else:
            print i,

if __name__ == "__main__":
    image_data = readfile()
    get_image(image_data)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

然后是主要程序了(我的程序有点啰嗦,见谅)。

 

 

import cv2
import os
import numpy as np
from sklearn import neighbors
import struct
print "Now start,please wait..."#程序运行时间灰常漫长……
#当时脑抽用了四个自定义函数,其实用两个就够了,玩家可以自定义

def getImages():#处理训练图片
    imgs=np.zeros([60000,784],int)#建立一个60000*784的0矩阵
    for i in range(60000):
        img1=cv2.imread("E:\\Images\\IM"+str(i)+".jpg",0)#读取每一张图片(路径自定义)
        for rows in range(28):
            for cols in range(28):#访问每张图片的每个像素,这种方法简单易懂但是效率比较低
                if img1[rows,cols]>=127:#二值化处理,把一整张图片的像素处理成只有0和1
                    img1[rows,cols]=1
                else:
                    img1[rows,cols]=0#这里选择的临界点是127,正好是0-255的中间值
                imgs[i,rows*28+cols]=img1[rows,cols]#把每张图片(28*28)展开成一行(1*784),
                                                    #然后把每张图片的像素逐行放到(60000*784)的大矩阵中

    return imgs#返回所有图片的像素重构的矩阵

def getLabels():#解析训练标签(解析出来的标签和图片顺序是一一对应的)
    f1=open("E:\\train-labels.idx1-ubyte",'rb')
    buf1=f1.read()
    f1.close()
    index=0
    magic,num=struct.unpack_from(">II",buf1,0)
    index+=struct.calcsize('>II')
    labs=[]
    labs=struct.unpack_from('>'+str(num)+'B',buf1,index)
    return labs#返回训练标签。之前没有单独解析出来保存在文本文件中,因为解析标签比较简单。

def getTestImages():#处理测试图片,和处理训练图片是一样的
    imgs=np.zeros([10000,784],int)#
    for i in range(10000):#
        img1=cv2.imread("E:\\testImages\\testIM"+str(i)+".jpg",0)
        for rows in range(28):
            for cols in range(28):
                if img1[rows,cols]>=127:
                    img1[rows,cols]=1
                else:
                    img1[rows,cols]=0
                imgs[i,rows*28+cols]=img1[rows,cols]
    return imgs

def getTestLabels():#处理测试标签,和处理训练标签是一样的
    f1=open("E:\\t10k-labels.idx1-ubyte",'rb')
    buf1=f1.read()
    f1.close()
    index=0
    magic,num=struct.unpack_from(">II",buf1,0)
    index+=struct.calcsize('>II')
    labs=[]
    labs=struct.unpack_from('>'+str(num)+'B',buf1,index)
    return labs

if __name__=="__main__":#主函数

    print "Getting train_imgs..."#print的目的就是知道进度
    train_imgs=getImages()#train_imgs保存60000*784的大矩阵
    print "Getting train_labels..."
    train_labels=getLabels()#train_labels保存60000个训练标签
    print "Creating KNN classifier..."
    knn=neighbors.KNeighborsClassifier(algorithm='kd_tree',n_neighbors=3)#重点来了,这里就是加载KNN分类器,具体的用法可以上网搜索
    print "Training..."
    knn.fit(train_imgs,train_labels)#读入训练图片和标签进行训练
    print "Getting test_images..."
    test_imgs=getTestImages()#test_imgs保存10000*784的大矩阵
    print "Getting test_labels..."
    test_labels=getTestLabels()#test_labels保存10000个训练标签
    print "Predicting..."
    result=knn.predict(test_imgs)#对测试图片进行预测
    wrongNum=np.sum(result!=test_labels)#得出错误个数
    num=len(test_imgs)#训练图片的总数
    print "Total number:",num
    print "Wrong number:",wrongNum
    print "RightRate:",1-wrongNum/float(num)#得出正确率
    #英语部分可能有些表述错误,能理解就好~_~

 

我第一次运行用了大约半个小时的时间,这个程序使用的内存升到了几乎700M,运行完一次我再也不想运行了,心疼我电脑……

在下初学者,不足之处甚多,恳请批评指正。

  • 43
    点赞
  • 339
    收藏
    觉得还不错? 一键收藏
  • 184
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值