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 npimport structimport 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 cv2import osimport numpy as npfrom sklearn import neighborsimport structprint "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,运行完一次我再也不想运行了,心疼我电脑……

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

点这里可以跳转到人工智能网站

发表评论