欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

程序员文章站 2022-04-30 20:13:00
...

废话不多说,先上效果图

机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
整体来看,效果是非常不错的,模型的训练,参照官方代码mnist_deep.py,准确率是高达99.2%
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)


那么,我是怎么实现的呢?

一.读懂卷积神经网络代码(至少得把程序跑通)

首先参照Tensorflow中文社区教程传送门:
http://www.tensorfly.cn/tfdoc/tutorials/mnist_pros.html
能在自己的环境中成功运行代码,具体代码的实现我就不在这里具体赘述了,因为关于代码的文章太多了,百度都能一大堆。博主是参照了Tensorflow中社区教程如图:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
(注意一点:关于教程的print函数)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
在博主用的Python3.6版本中,print已经成为了一个函数,而在Python2.7当中print不是一个函数,这里博主是需要加上括号。
所以根据自己所用的版本,更改这里,例如

print"Hello")  python3.6
print "Hello"   python2.7

如果你按照教程,将代码跑通之后,可以进行下一步了。那就是将模型保存,只需调用一个简单的函数,以下就是博主根据教程敲得完整代码:

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

mnist = input_data.read_data_sets('F:/DEEPLEARN/Anaconda/Lib/site-packages/tensorflow/examples/tutorials/mnist/MNIST_data', one_hot=True) #MNIST数据集所在路径

x = tf.placeholder(tf.float32, [None, 784])

y_ = tf.placeholder(tf.float32, [None, 10])


def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev = 0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1,shape = shape)
    return tf.Variable(initial)

def conv2d(x,W):
    return tf.nn.conv2d(x, W, strides = [1,1,1,1], padding = 'SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

x_image = tf.reshape(x,[-1,28,28,1])

h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])

h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

saver = tf.train.Saver() #定义saver

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(20000):
        batch = mnist.train.next_batch(50)
        if i % 100 == 0:
            train_accuracy = accuracy.eval(feed_dict={
                x: batch[0], y_: batch[1], keep_prob: 1.0})
            print('step %d, training accuracy %g' % (i, train_accuracy))
        train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
    saver.save(sess, 'C:/Users/考拉拉/Desktop/SAVE/model.ckpt') #模型储存位置

    print('test accuracy %g' % accuracy.eval(feed_dict={
        x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

以上,是我的mnistdeep.py代码,用于导入MNIST数据集-创建模型-保存模型到指定路径。
保存的路径会出现四个文件,具体每个文件是干嘛的,自己百度吧,我不在这里赘述了:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

二.测试自己的刚才保存的模型

整体来看,和刚才的代码相似度很高,也是将需要测试的图片进行卷积,池化,softmax回归等等。
这里关于图片数字化,并将每个像素值限定在0~1种的代码参照了大佬博客:
http://blog.csdn.net/sparta_117/article/details/66965760

from PIL import Image, ImageFilter
import tensorflow as tf
import matplotlib.pyplot as plt

def imageprepare(): 
    im = Image.open('C:/Users/考拉拉/Desktop/4.png') #读取的图片所在路径,注意是28*28像素
    plt.imshow(im)  #显示需要识别的图片
    plt.show()
    im = im.convert('L')
    tv = list(im.getdata()) 
    tva = [(255-x)*1.0/255.0 for x in tv] 
    return tva

result=imageprepare()
x = tf.placeholder(tf.float32, [None, 784])

y_ = tf.placeholder(tf.float32, [None, 10])

def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev = 0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1,shape = shape)
    return tf.Variable(initial)

def conv2d(x,W):
    return tf.nn.conv2d(x, W, strides = [1,1,1,1], padding = 'SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

x_image = tf.reshape(x,[-1,28,28,1])

h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])

h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

saver = tf.train.Saver()

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    saver.restore(sess, "C:/Users/考拉拉/Desktop/SAVE/model.ckpt") #使用模型,参数和之前的代码保持一致

    prediction=tf.argmax(y_conv,1)
    predint=prediction.eval(feed_dict={x: [result],keep_prob: 1.0}, session=sess)

    print('识别结果:')
    print(predint[0])

这是我的test.py代码,用于读取刚才保存的模型-导入测试图片-测试输出结果

三.制作测试图片

我们的模型需要输入的是28 X 28像素的手写体数字图片,如果图片尺寸不等于28 X 28,可以参照上一篇博客用opencv进行处理。
这里,为了方便,我使用PS制作。

这里,需要大家按照我的步骤进行绘制,不然会出现一些问题,在文章末尾我会为大家总结避坑。

第一步:打开ps创建像素为28 X 28的画布,填充白色如图
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
第二步:找到画笔工具,使用柔边画笔,三像素,进行图片绘制(前景色黑/背景色白)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
第三步:绘制的图片另存为格式png(png相对jpg,储存信息更完整)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
第四步:更改test.py读取为要测试图片的路径,然后运行
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

大功告成

问题总结:

一.为什么要用3像素柔边画笔?(不一定要3,随便你)
之前我用的小方块绘制测试图片,做了很多测试,可是发现正确率很低,很容易出错,我做的图片如图:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

困扰了我很久,我忽然想到MNIST是手写体文字,那么手写体和我画的图有什么区别呢?我将处理后的每个像素储存的值输出:
手写体:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
我做的图:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

显而易见,错误率是由于测试图片不对导致的!
我们训练的MNIST注意是手写体,手写体并不是我画的图那样只存在0和1两个数值,而是处在0~1之间的一个值如图:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)

而如果,训练数据是二值图(MNIST数据集也可以通过阈值处理转化为二值图)。那么我输出这种二值图图片,当然,机器是不会出错的啦。

二.关于西方手写体和东方手写体


但我解决了上一个问题后,我发现准确率还是不能保证上去,特别是5,6傻傻分不清如图:
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
于是,我搜索部分了训练用的MNIST数据集(仔细看6):
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
我他娘的意大利。。。。。。面呢。。。。
于是乎,我重新画了许多张西方手写体的6
机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
基本不会出错了


三.关于3.6和2.7的print上面已经介绍了

四.其他关于识别率的问题,大多都是尺寸,格式之类的问题了

其他什么地方有问题,欢迎评论区指正

成功之后别忘了点赞~