[云云怪]项目11:自制手写数字识别系统(MNIST、深度学习)

【创作背景】

我入坑围棋的时候,正逢“李世石vs Alpha Go”人机大战。这么几年下来,学棋不成总被吊打的我,就一直有个梦想:写一个围棋AI,拿去暴打包子,报仇雪恨。于是,学完python基础语法之后,我就开始朝着深度学习方向去了。

哪吒给我推荐了《深度学习入门》这本书,他说对新手极其友好,容易看懂,于是我就从这里入坑了。全书围绕MNIST手写数据集的识别,讲解深度学习的底层理论和代码实现,确实非常友好。除了一些数学公式和理论我已经忘光光之外,啃完书的我,自认为对深度学习有了基本概念。

然后就应该上手练习了吧!我的第一个小目标:

【目标】

封装一个完整的程序,实现手写数字拍照识别。

【目标实现】

1,《深度学习入门》自带了sample_weight.kpl文件,但我找不到这个文件,权重只能自己训练。好在啃完全书,照抄代码之后,我也能自己训练出一个权重了。把这个权重存下来,留待后用。

2,官方的MNIST数据集里的图片文件是封装好的,本小白也不知道怎么拆解它。对于自己拍的照片文件,只能想办法转换成适合MNIST模型的输入数据。

3,没了,就前面两条属于新知识。

【上代码】

# 第一段:用MNIST数据集训练权重,并把权重存起来,留待后用.

这一段需要引用之前编写好的:
two_layer_net.py
mnist.py
my_fn.py(书里叫funtions.py)

这几个文件在网上都很容易找到。

# 用MNIST数据集训练权重,并把权重存起来

import numpy as np
from two_layer_net import TwoLayerNet
from mnist import load_mnist
import matplotlib.pylab as plt
from my_fn import *
import pickle

# 读取MNIST数据集

(x_train,t_train),(x_test,t_test)=load_mnist(one_hot_label=True,normalize=True)
train_loss_list=[]
train_acc_list=[]
test_acc_list=[]
epoch=0

#超参数
iters_num=5000
train_size=x_train.shape[0]
batch_size=100
learning_rate=0.1
network=TwoLayerNet(784,50,10)

# 平均每个epoch的重复次数
iter_per_epoch=max(train_size/batch_size,1)

for i in range(iters_num):
    #print(i)  #进程监督
    batch_mask=np.random.choice(train_size,batch_size)
    x_batch=x_train[batch_mask]
    t_batch=t_train[batch_mask]

    # 计算梯度
    #grad=network.numerical_gradient(x_batch,t_batch)
    grad=network.gradient(x_batch,t_batch) # 高速版

    for key in ('W1','b1','W2','b2'):
        network.params[key]-=learning_rate * grad[key]

    loss=network.loss(x_batch,t_batch)
    train_loss_list.append(loss)

    if i%iter_per_epoch==0: # 每经历一个epoch(训练次数整除epoch)
        epoch+=1
        train_acc=network.accuracy(x_train,t_train)
        test_acc=network.accuracy(x_test,t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print('epoch: '+str(epoch)+' train acc, test acc | '+str(train_acc)+', '+str(test_acc))

# 训练好的权重存起来
file_name='sample_weight.pkl'
with open (file_name,'wb') as f:
    pickle.dump(network.params,f,-1)

进入第二段之前,我们可以先看看这个权重的质量:

# 画损失函数
x=range(iters_num)
y=train_loss_list
plt.plot(x,y)
plt.xlabel('learning time')
plt.ylabel('value of loss function')
plt.show()

[云云怪]项目11:自制手写数字识别系统(MNIST、深度学习)_第1张图片

# 画出识别精度
x=range(len(train_acc_list))
y1=train_acc_list
y2=test_acc_list
plt.plot(x,y1,label='train_acc')
plt.plot(x,y2,linestyle='--',label='test_acc')
plt.xlabel('epochs')
plt.ylabel('accurancy')
plt.legend()
plt.show()

 [云云怪]项目11:自制手写数字识别系统(MNIST、深度学习)_第2张图片

 嗯,看上去很不错的样子。

#第二段:处理手写数字图片(可以自己写)

from PIL import Image

with open('sample_weight.pkl','rb') as f:
    network0=pickle.load(f)
    
#使用sample_weight里存好的数据
W1,W2,b1,b2=network0['W1'],network0['W2'],network0['b1'],network0['b2']

# 读取图片,调整为正确格式,转换成 1*784 的数列
def load_pic(fn):
    img0=Image.open(fn).convert('L')
    if img0.size[0] !=28 or img0.size[1]!=28:
        img0.resize((28,28))

    arr = []
    for i in range(28):
        for j in range(28):
            pixel = 1-float(img0.getpixel((j, i)))/255.0
            arr.append(pixel)
    arr1=np.array(arr)
    return arr1

# 调用刚才存好的权重,识别输入的图片(数列),返回识别结果
def read_pic(x):
    with open('sample_weight.pkl','rb') as f:
        network=pickle.load(f)
    W1,W2,b1,b2=network['W1'],network['W2'],network['b1'],network['b2']

    a1=np.dot(x,W1)+b1
    z1=sigmoid(a1)
    a2=np.dot(z1,W2)+b2
    y=softmax(a2)

    max=np.max(y)
    n=0
    for i in y:
        if i!=max:
            n+=1
        else:
            print('晕晕狗识别结果:'+str(n),end='  ')
            break
    return n

# 识别单张图片
k=input('输入文件名,不带后缀:')
fn='C:/Users/Echo/Desktop/test_pic/'+k+'.png'
x=load_pic(fn)
read_pic(x)

效果(截图):

看上去很不错!!!然而——

# 小规模图片测试

acc=0
for k in range(10):
    fn='C:/Users/Echo/Desktop/test_pic/'+str(k)+'.png'
    print('正解:'+str(k)+'  ',end='')
    x=load_pic(fn)
    res=read_pic(x)
    if k==res:
        print('正确')
        acc+=1
    else:
        print('错误')
        
acc=acc/10 *100
print('总体正确率:'+str(acc)+'%')

我把我自己手写的0-9全部测试了一遍,喜提50%的惨淡正确率 (爆哭。。。)

[云云怪]项目11:自制手写数字识别系统(MNIST、深度学习)_第3张图片

[云云怪]项目11:自制手写数字识别系统(MNIST、深度学习)_第4张图片

【感想】

不管怎么说,经过了一上午的努力,把书本里的知识封装成了自己的程序,这中间,也去百度学习了很多之前并不会的知识点(比如图片转像素,比如自制权重PKL文件)。

为什么训练完毕的权重在测试图片(1w张)里的表现很好——识别精确度达到97%,但用在我自制的手写数字图片上准确度只有50%呢?不知道是我的权重出了问题,还是程序里其他代码出了问题。——这个问题,就留给饭后解决吧!(啊,肚子好饿)

你可能感兴趣的:(深度学习,python)