机器学习Tensorflow基于MNIST数据集识别自己的手写数字(读取和测试自己的模型)
废话不多说,先上效果图
整体来看,效果是非常不错的,模型的训练,参照官方代码mnist_deep.py,准确率是高达99.2%
那么,我是怎么实现的呢?
一.读懂卷积神经网络代码(至少得把程序跑通)
首先参照Tensorflow中文社区教程传送门:
http://www.tensorfly.cn/tfdoc/tutorials/mnist_pros.html
能在自己的环境中成功运行代码,具体代码的实现我就不在这里具体赘述了,因为关于代码的文章太多了,百度都能一大堆。博主是参照了Tensorflow中社区教程如图:
(注意一点:关于教程的print函数)
在博主用的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数据集-创建模型-保存模型到指定路径。
保存的路径会出现四个文件,具体每个文件是干嘛的,自己百度吧,我不在这里赘述了:
二.测试自己的刚才保存的模型
整体来看,和刚才的代码相似度很高,也是将需要测试的图片进行卷积,池化,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的画布,填充白色如图
第二步:找到画笔工具,使用柔边画笔,三像素,进行图片绘制(前景色黑/背景色白)
第三步:绘制的图片另存为格式png(png相对jpg,储存信息更完整)
第四步:更改test.py读取为要测试图片的路径,然后运行
大功告成
问题总结:
一.为什么要用3像素柔边画笔?(不一定要3,随便你)
之前我用的小方块绘制测试图片,做了很多测试,可是发现正确率很低,很容易出错,我做的图片如图:
困扰了我很久,我忽然想到MNIST是手写体文字,那么手写体和我画的图有什么区别呢?我将处理后的每个像素储存的值输出:
手写体:
我做的图:
显而易见,错误率是由于测试图片不对导致的!
我们训练的MNIST注意是手写体,手写体并不是我画的图那样只存在0和1两个数值,而是处在0~1之间的一个值如图:
而如果,训练数据是二值图(MNIST数据集也可以通过阈值处理转化为二值图)。那么我输出这种二值图图片,当然,机器是不会出错的啦。
二.关于西方手写体和东方手写体
但我解决了上一个问题后,我发现准确率还是不能保证上去,特别是5,6傻傻分不清如图:
于是,我搜索部分了训练用的MNIST数据集(仔细看6):
我他娘的意大利。。。。。。面呢。。。。
于是乎,我重新画了许多张西方手写体的6:
基本不会出错了
三.关于3.6和2.7的print上面已经介绍了
四.其他关于识别率的问题,大多都是尺寸,格式之类的问题了
其他什么地方有问题,欢迎评论区指正
成功之后别忘了点赞~
上一篇: 文件上传和下载