tensorflow笔记06:实现对自己输入的手写图片的检测及对制造数据集的总结。
前面我们已经实现了模块化训练神经网络,并保存训练模型,实现对mnist数据集的训练与检查。
今天,我们利用已经搭建好的神经网络模型,实现检查自己在画板的写的手写图片。
1.实现对自己手写数字的检测
第一步:将自己的图片转化为mnist的图片格式
我们需要一个py文件将自己输入的图片预先处理,使之能够变成mnist格式喂入神经网络mnist_app.py
思路是:
1.先把图片转化28×28大小的shape
2.因为mnist图片是黑底白字,我们必须对图片进行取化反,然后二值化。
3.将图片的像素值转化到(0,1)范围的浮点型。,因为mnist数据集里面像素值都是(0~1)
像素点:0-1 之间的浮点数(接近 0 越黑,接近 1 越白)
4.图片转化为为1×784的np.array
代码:(用到的模块numpy,Image,当然也可以使用opencv)
#定义一个函数,用于处理输入的图片,转化为值是在[0,1]的1×784的一维数组
def pre_picture(Picture_Path):
#打开图片
img = Image.open(Picture_Path)
reIm = img.resize((28,28),Image.ANTIALIAS)
#图片转化为单通道,并转化为数组
img_array = np.array(reIm.convert('L'))
#因为mnist图片中纯黑色像素值为 0,纯白色像素值为 1
#我们必须将图片也转化成这样,即二值化
threshold = 50
for i in range(28):
for j in range(28):
#因为我们图片背景是白色,mnist是黑底白字,所以得反转前景,取反
img_array[i,j] = 255 - img_array[i,j]
if img_array[i,j]<threshold:
img_array[i,j] = 0
else: img_array[i,j] = 255
#然后转化图为一维数组[1,784]
pre_array = img_array.reshape((1,784))
#转化为浮点型
pre_array = pre_array.astype(np.float32)
#按比例缩放值到[0,1]
img_ready = np.multiply(pre_array,1.0/255.0)
return img_ready
python
使用opencv预先处理:
#定义一个函数,用于处理输入的图片,转化为值是在[0,1]的1×784的一维数组
def pre_picture(Picture_Path):
#打开图片
img = imread(Picture_Path)
img = resize(img,(28,28),INTER_AREA)
#imshow("img",img);#
#cvtColor the picture
gray = cvtColor(img,COLOR_BGR2GRAY)
#imshow("gray",gray);
#bitwrise_not
gray_not = bitwise_not(gray)
#imshow("gray_not",gray_not)#
#dilate the picture
kernel = np.array([[3,3,3],
[3,3,3],[3,3,3]])
dst = dilate(gray_not,kernel);
#imshow("dilate",dst);
#threshold picture
_,dst = threshold(dst,120,255,THRESH_BINARY)
#imshow("THRESHOLD",dst)#
img_array = np.array(dst)
pre_array = img_array.reshape((1,784))
#转化为浮点型
pre_array = pre_array.astype(np.float32)
#按比例缩放值到[0,1]
img_ready = np.multiply(pre_array,1.0/255.0)
return img_ready
第二步加载训练好的模型,将符合神经网络输入要求的图片喂给复现的神经网络模型,输出预测值
函数是:
#定义函数,批量加载图片并喂入神经网络,并返回预测的值
def restore_model(testPicArray):
#创建默认的计算图,在该图中执行预测步骤
with tf.Graph().as_default() as g:
#输入的x占位
x = tf.placeholder(tf.float32,shape=[None,forward.INPUT_NODE])
#获取输出y
y = forward.forward(x,None)
#返回最大值为1的索引,并赋值给preValue
preValue = tf.argmax(y,1)
#实现滑动平均,参数MOVING_AVERAGE_DECAY用于控制模型更新的速度
#训练过程中会对每个变量维护一个影子,这个影子的初始值就是相应变量的初始值
variable_averages = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
#加载滑动平均
variables_to_restore = variable_averages.variables_to_restore()
#实例化saver对象
saver = tf.train.Saver(variables_to_restore)
with tf.Session() as sess:
#加载训练好的模型文件
ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
#判断
if ckpt and ckpt.model_checkpoint_path:
#加载训练的模型
saver.restore(sess,ckpt.model_checkpoint_path)
#计算预测值
preValue = sess.run(preValue,feed_dict={x:testPicArray})
return preValue
else:
print "No checkpoint file found"
return -1
#定义一个应用的函数
def application():
test_Number = int(input("input the number of the test pictures:"))
#循环输入图片,输入一张,预测一张
for i in range(test_Number):
Path =raw_input("input the image's path:")
#图片预处理
testPicArray = pre_picture(Path)
#预测图片,返回预测值
preValue = restore_model(testPicArray)
print "the preValue number is ",preValue
第三步测试图片
用到的图片,有以一些是手写的,有一些是从网上找的,主要数字的轮廓(字迹粗细)一定的大,因为mnist数据集就是这个样子
打开终端,运行:python mnist_app.py
发现全部预测成功
附上整个代码:
#coding:utf-8
import tensorflow as tf
from PIL import Image
import numpy as np
import forward
import mnist_backward
import mnist_test
#这是修改图片的格式,使其能够直接输入神经网络,执行预判
#定义一个函数,用于处理输入的图片,转化为值是在[0,1]的1×784的一维数组
def pre_picture(Picture_Path):
#打开图片
img = Image.open(Picture_Path)
reIm = img.resize((28,28),Image.ANTIALIAS)
#图片转化为单通道,并转化为数组
img_array = np.array(reIm.convert('L'))
#因为mnist图片中纯黑色像素值为 0,纯白色像素值为 1
#我们必须将图片也转化成这样,即二值化
threshold = 50
for i in range(28):
for j in range(28):
#因为我们图片背景是白色,mnist是黑底白字,所以得反转前景,取反
img_array[i,j] = 255 - img_array[i,j]
if img_array[i,j]<threshold:
img_array[i,j] = 0
else: img_array[i,j] = 255
#然后转化图为一维数组[1,784]
pre_array = img_array.reshape((1,784))
#转化为浮点型
pre_array = pre_array.astype(np.float32)
#按比例缩放值到[0,1]
img_ready = np.multiply(pre_array,1.0/255.0)
return img_ready
#定义函数,批量加载图片并喂入神经网络,并返回预测的值
def restore_model(testPicArray):
#创建默认的计算图,在该图中执行预测步骤
with tf.Graph().as_default() as g:
#输入的x占位
x = tf.placeholder(tf.float32,shape=[None,forward.INPUT_NODE])
#获取输出y
y = forward.forward(x,None)
#返回最大值为1的索引,并赋值给preValue
preValue = tf.argmax(y,1)
#实现滑动平均,参数MOVING_AVERAGE_DECAY用于控制模型更新的速度
#训练过程中会对每个变量维护一个影子,这个影子的初始值就是相应变量的初始值
variable_averages = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
#加载滑动平均
variables_to_restore = variable_averages.variables_to_restore()
#实例化saver对象
saver = tf.train.Saver(variables_to_restore)
with tf.Session() as sess:
#加载模型文件
ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
#判断
if ckpt and ckpt.model_checkpoint_path:
#加载训练的模型
saver.restore(sess,ckpt.model_checkpoint_path)
#计算预测值
preValue = sess.run(preValue,feed_dict={x:testPicArray})
return preValue
else:
print "No checkpoint file found"
return -1
#定义一个应用的函数
def application():
test_Number = int(input("input the number of the test pictures:"))
#循环输入图片,输入一张,预测一张
for i in range(test_Number):
Path =raw_input("input the image's path:")
#图片预处理
testPicArray = pre_picture(Path)
preValue = restore_model(testPicArray)
print "the preValue number is ",preValue
def main():
application()
if __name__ == '__main__':
main()
2.对制造数据集的总结
2_1.将自己的图片整理为数据集文件,用于神经网络的训练
1、数据集生成读取文件(mnist_generateds.py)
先介绍tfRecord文件:
- tfrecords:是一种二进制文件,可先将图片和标签制作成该格式的文件。使用 tfrecords 进行数据读取,会提高内存利用率。
- tf.train.Example: 用来存储训练数据。训练数据的特征用键值对的形式表示。
如:‘ img_raw ’ :值 ‘ label ’ :值,值是 Byteslist/FloatList/Int64List类型 - SerializeToString( ):把数据序列化成字符串存储。
现在介绍生成 tfrecords 文件:
#coding:utf-8
import tensorflow as tf
import numpy as np
import Image
#设置数据集合生成的路径,以及保存路径。
tfRecord_train = ""
tfRecord_test = ""
data_path = ""
image_train_path =""
label_train_path = ""
image_test_path = ""
label_test_path = ""
def write_tfRecord(tfRecordName,image_Path,label_Path):
#定义一个writer:
writer = tf.python_io.TFRecordWriter(tfRecordName)
#定义一个变量记录读取的图片的数量
num_pic = 0
#利用自带的函数,打开图片,读取的方式
f = open(image_Path,'r')
#一行一行的读取,存为列表
contents = f.readlines()
#关闭文件
f.close()
#遍历文件
for content in contents:
value = content.split()
#获取图片的路径
img_path = img_Path+valu[0]
#读取图片
img = Image.open(img_path)
img_raw = img.tobytes()
#创建标签,元素个数是10的列表
labels = [0]*10
#设置正确的标签
labels[int(value[1])] = 1
#转化为正确的样本文件,example,是把每张图片与标签封装到example
example = tf.train.Example(features=tf.train.Features(feature={'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),'label':tf.train.Feature(int64_list=tf.train.Int64List(value=labels))}))
#把example序列化
writer.write(example.SerializeToString())
#数量加一
num_pic +=1
print "the number of the picture:",num_pic
#关闭writer
writer.close()
#写入成功
print "write tfRecord successful"
解析 tfrecords 文件:
def generate_tfRecord():
isExists = os.path.exists(data_path)
if not isExists:
#建立对应的目录保存数据样本集合
os.makedirs(data_path)
print"The directory was created successfully"
else:
print"the directory already exists"
#开始转化tfRecord二进制文件
write_tfRecord = (tfRecord_train,image_train_path,label_train_path)
write_tfRecord = (tfTecord_test,image_test_path,label_test_path)
#定义一个函数解析tfRecord文件
def read_tfRecord(tfRecord_path):
#下面这个函数:生成一个先入先出的队列,文本阅读器会用它来读取数据
filename_queue = tf.train.string_input_producer([tfRecord_path])
reader = tf.TFRecordReader()
#把读出的样本保存在serialized_example中解序列化
_,serialized_example = reader.read(filename_queue)
#函数可以将tfl.train.Example协议块(protocol buffer 解析为张量)
features = tf.parse_single_example(serialized_example,features={'label':tf.FixedLenFeature([10],tf.int64),'img_raw':tf.train.FixedLenFeature([],tf.string)})
#将img_raw字符串转化为8位无字符号整数
img = tf.decode_raw(features['img_raw'],tf.uint8)
#设置形状
img.set_shape([784])
#将像素值转化到0,1之间
img = tf.cast(img,tf.float32)*(1./255.0)
#标签转化为浮点型
label = tf.cast(features['label'],tf.float32)
return img,label
#定义一个函数实现获取tfTecord文件
def get_tfRecord(num,isTrain=True):
if isTrain:
tfRecord_path = tfRecord_train
else:
tfRecord_path = tfRecord_test
img,label = read_tfRecord(tfRecord_path)
#随机读取便签与图片
img_batch,label_batch = tf.train.shuffle_batch([img,label],batch_size=num,num_threads=2,capacity=1000,min_after_dequeue=700)
return img_batch,label_batch
def main():
generate_tfRecord()
if __name__ =='__main__':
main()
一些函数的解析:
注解:
-
filename_queue = tf.train.string_input_producer([tfRecord_path])
tf.train.string_input_producer( string_tensor,
num_epochs=None,
shuffle=True,
seed=None,
capacity=32,
shared_name=None,
name=None,
cancel_op=None)
该函数会生成一个先入先出的队列,文件阅读器会使用它来读取数据。
参数说明:string_tensor: 存储图像和标签信息的 TFRecord 文件名列表
num_epochs: 循环读取的轮数(可选)
shuffle:布尔值(可选),如果为 True,则在每轮随机打乱读取顺序
seed:随机读取时设置的种子(可选)
capacity:设置队列容量
shared_name:(可选) 如果设置,该队列将在多个会话中以给定名
称共享。所有具有此队列的设备都可以通过 shared_name 访问它。在分布式设置
中使用这种方法意味着每个名称只能被访问此操作的其中一个会话看到。
name:操作的名称(可选)
cancel_op:取消队列(None) -
reader = tf.TFRecordReader()#新建一个 reader
-
_, serialized_example = reader.read(filename_queue)
features = tf.parse_single_example(serialized_example,features={
‘img_raw’: tf.FixedLenFeature([ ], tf.string) ,
‘label’: tf.FixedLenFeature([10], tf.int64)})#把读出的每个样本保存在 serialized_example 中进行解序列化,标签和图片的键名应该和制作 tfrecords 的键名相同,其中标签给出几分类。
tf.parse_single_example(serialized,
features,
name=None,
example_names=None)
该函数可以将 tf.train.Example 协议内存块(protocol buffer)解析为张量。
参数说明:serialized: 一个标量字符串张量
features: 一个字典映射功能键 FixedLenFeature 或 VarLenFeature
值,也就是在协议内存块中储存的
name:操作的名称(可选)
example_names: 标量字符串联的名称(可选) -
img = tf.decode_raw(features[‘img_raw’], tf.uint8)
#将 img_raw 字符串转换为 8 位无符号整型 -
img.set_shape([784])
#将形状变为一行 784 列 -
img = tf.cast(img, tf.float32) * (1. / 255) #变成 0 到 1 之间的浮点数
-
label = tf.cast(features[‘label’], tf.float32)#把标签列表变为浮点数
-
return image,label #返回图片和标签(跳回到 get_tfrecord)
-
tf.train.shuffle_batch( tensors,batch_size,
capacity,
min_after_dequeue,
num_threads=1,
seed=None,
enqueue_many=False,
shapes=None,
allow_smaller_final_batch=False,
shared_name=None,
name=None)
这个函数随机读取一个 batch 的数据。
参数说明:tensors: 待乱序处理的列表中的样本(图像和标签)
batch_size: 从队列中提取的新批量大小
capacity:队列中元素的最大数量
min_after_dequeue: 出队后队列中的最小数量元素,用于确保元素
的混合级别
num_threads: 排列 tensors 的线程数
seed:用于队列内的随机洗牌
enqueue_many: tensor 中的每个张量是否是一个例子
shapes: 每个示例的形状
allow_smaller_final_batch: (可选)布尔值。 如果为 True,则在
队列中剩余数量不足时允许最终批次更小。
shared_name:(可选)如果设置,该队列将在多个会话中以给定名称
共享。
name:操作的名称(可选) -
return img_batch,label_batch
#返回的图片和标签为随机抽取的 batch_size 组
2_2.反向传播文件修改图片标签获取的接口(mnist_backward.py),获取自己制造的数据集,测试文件修改图片标签获取的接口,获取自己生成的测试数据集(mnist_test.py)
这里只记录一些函数
关键操作:利用多线程提高图片和标签的批获取效率方法:将批获取的操作放到线程协调器开启和关闭之间
- 开启线程协调器:
coord = tf.train.Coordinator( )
threads = tf.train.start_queue_runners(sess=sess, coord=coord) - 关闭线程协调器:
coord.request_stop( )
coord.join(threads)
注解:
tf.train.start_queue_runners( sess=None,
coord=None,
daemon=True,
start=True,
collection=tf.GraphKeys.QUEUE_RUNNERS)
这个函数将会启动输入队列的线程,填充训练样本到队列中,以便出队操作可以
从队列中拿到样本。这种情况下最好配合使用一个 tf.train.Coordinator ,这
样可以在发生错误的情况下正确地关闭这些线程。
参数说明:sess:用于运行队列操作的会话。 默认为默认会话。
coord:可选协调器,用于协调启动的线程。
daemon: 守护进程,线程是否应该标记为守护进程,这意味着它们不
会阻止程序退出。
start:设置为 False 只创建线程,不启动它们。
collection : 指 定 图 集 合 以 获 取 启 动 队 列 的 GraphKey 。 默 认 为
GraphKeys.QUEUE_RUNNERS。