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。