TensorFlow数据读取机制:文件队列 tf.train.slice_input_producer和 tf.data.Dataset机制
TensorFlow數據讀取機制:文件隊列 tf.train.slice_input_producer和tf.data.Dataset機制
? ? 之前寫了一篇博客,關于《Tensorflow生成自己的圖片數據集TFrecord》,項目做多了,你會發現將數據轉為TFrecord格式,實在是太麻煩了,靈活性太差!后面就總結一下TensorFlow數據讀取機制,主要還是介紹tf.data.Dataset的數據讀取機制(Pipeline機制)。
? ? TensorFlow數據讀取機制主要是兩種方法:
(1)一種是使用文件隊列方式,如使用slice_input_producer和string_input_producer;這種方法既可以將數據轉存為TFrecord數據格式,也可以直接讀取文件圖片數據,當然轉存為TFrecord數據格式進行讀取,會更高效點
(2)另一種是TensorFlow 1.4版本后出現的tf.data.Dataset的數據讀取機制(Pipeline機制)。這是TensorFlow強烈推薦的方式,是一種更高效的讀取方式。使用tf.data.Dataset模塊的pipline機制,可實現CPU多線程處理輸入的數據,如讀取圖片和圖片的一些的預處理,這樣GPU可以專注于訓練過程,而CPU去準備數據。
? ? ? 本博客Github源碼:https://github.com/PanJinquan/tensorflow-learning-tutorials?->tf_record_demo文件夾(覺得可以,還請給個“Star”哦
? ? ?之前專門寫了一篇博客關于《?Tensorflow生成自己的圖片數據集TFrecords(支持多標簽label)》https://blog.csdn.net/guyuealian/article/details/80857228,主要實現的是使用自己的數據集制作TensorFlow的TFrecord數據格式。
目錄
目錄
TensorFlow數據讀取機制:文件隊列 tf.train.slice_input_producer和tf.data.Dataset機制
1. 文件隊列讀取方式:slice_input_producer和string_input_producer
1.1.生成圖片數據集TFrecords
(1)生成單個record文件 (單label)
(2)生成單個record文件 (多label)
(3)生成多個record文件的方法
1.2. 直接文件讀取方式?
2.tf.data.Dataset數據讀取機制:Pipeline機制
prefetch(必須放在最后)
map
repeat
實例代碼1:dataset.make_initializable_iterator()
實例代碼2:dataset.make_one_shot_iterator()
實例代碼3:產生用于訓練的圖和label
實例代碼4:產生用于訓練的原始圖和target目標圖
實例代碼5: tf.data.Dataset.from_generator
3.?用Python循環產生批量數據batch
4.參考資料:
1. 文件隊列讀取方式:slice_input_producer和string_input_producer
? ? TensorFlow可以采用tf.train.slice_input_producer或者tf.train.string_input_producer兩種方法產生文件隊列,其區別就是:前者是輸入是tensor_list,因此,可以將多個list組合成一個tensorlist作為輸入;而后者只能是一個string_tensor了,例子如下:
image_dir ='path/to/image_dir/*.jpg'image_list = glob.glob(image_dir)label_list=...image_list = tf.convert_to_tensor(image_list, dtype=tf.string)# 可以將image_list,label_list多個list組合成一個tensor_listimage_que, label_que = tf.train.slice_input_producer([image_list,label_list], num_epochs=1)# 只能時string_tensor,所以不能組合多個listimage = tf.train.string_input_producer(image_list, num_epochs=1)1.1.生成圖片數據集TFrecords
? ? 假設train.txt保存圖片的路徑和標簽信息,如下,以空格分割,第一項的圖片的路徑名,第二項是圖片對應的labels
dog/1.jpg 0 dog/2.jpg 0 dog/3.jpg 0 dog/4.jpg 0 cat/1.jpg 1 cat/2.jpg 1 cat/3.jpg 1 cat/4.jpg 1? ? 這里提供三種方法將圖像數據轉存為TFrecords數據格式,當然也包含TFrecords解析的方法,詳細的用法都會在函數參數說明,已經封裝了很簡單了,你只需要改變你圖片的路徑就可以。
- 生成單個record文件 (單label)
? ? 這種方法會將所有圖片數據和單labels轉存為一個record文件,合適單labels小批量的數據
- 生成單個record文件 (多label)
? ? 這種方法將所有圖片數據和多個labels轉存為一個record文件,合適多labels的小批量的數據
- 生成多個record文件的方法
? ? 這種方法將圖片數據和labels,切分一個batch_size的大小,并轉存為多個record文件,合適大批量的數據
(1)生成單個record文件 (單label)
? ? ?下面是封裝好的py文件,可以直接生成單個record文件 ,當然這里假設只有一個label情況。其中get_batch_images函數會產生一個batch的數據,這個batch的數據就可以用于CNN的網絡訓練的數據。
# -*-coding: utf-8 -*- """@Project: create_tfrecord@File : create_tfrecord.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-07-27 17:19:54@desc : 將圖片數據保存為單個tfrecord文件 """##########################################################################import tensorflow as tf import numpy as np import os import cv2 import matplotlib.pyplot as plt import random from PIL import Image########################################################################## def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) # 生成字符串型的屬性 def _bytes_feature(value):return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) # 生成實數型的屬性 def float_list_feature(value):return tf.train.Feature(float_list=tf.train.FloatList(value=value))def get_example_nums(tf_records_filenames):'''統計tf_records圖像的個數(example)個數:param tf_records_filenames: tf_records文件路徑:return:'''nums= 0for record in tf.python_io.tf_record_iterator(tf_records_filenames):nums += 1return numsdef show_image(title,image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def load_labels_file(filename,labels_num=1,shuffle=False):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1 標簽2,如:test_image/1.jpg 0 2:param filename::param labels_num :labels個數:param shuffle :是否打亂順序:return:images type->list:return:labels type->list'''images=[]labels=[]with open(filename) as f:lines_list=f.readlines()if shuffle:random.shuffle(lines_list)for lines in lines_list:line=lines.rstrip().split(' ')label=[]for i in range(labels_num):label.append(int(line[i+1]))images.append(line[0])labels.append(label)return images,labelsdef read_image(filename, resize_height, resize_width,normalization=False):'''讀取圖片數據,默認返回的是uint8,[0,255]:param filename::param resize_height::param resize_width::param normalization:是否歸一化到[0.,1.0]:return: 返回的圖片數據'''bgr_image = cv2.imread(filename)if len(bgr_image.shape)==2:#若是灰度圖則轉為三通道print("Warning:gray image",filename)bgr_image = cv2.cvtColor(bgr_image, cv2.COLOR_GRAY2BGR)rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)#將BGR轉為RGB# show_image(filename,rgb_image)# rgb_image=Image.open(filename)if resize_height>0 and resize_width>0:rgb_image=cv2.resize(rgb_image,(resize_width,resize_height))rgb_image=np.asanyarray(rgb_image)if normalization:# 不能寫成:rgb_image=rgb_image/255rgb_image=rgb_image/255.0# show_image("src resize image",image)return rgb_imagedef get_batch_images(images,labels,batch_size,labels_nums,one_hot=False,shuffle=False,num_threads=1):''':param images:圖像:param labels:標簽:param batch_size::param labels_nums:標簽個數:param one_hot:是否將labels轉為one_hot的形式:param shuffle:是否打亂順序,一般train時shuffle=True,驗證時shuffle=False:return:返回batch的images和labels'''min_after_dequeue = 200capacity = min_after_dequeue + 3 * batch_size # 保證capacity必須大于min_after_dequeue參數值if shuffle:images_batch, labels_batch = tf.train.shuffle_batch([images,labels],batch_size=batch_size,capacity=capacity,min_after_dequeue=min_after_dequeue,num_threads=num_threads)else:images_batch, labels_batch = tf.train.batch([images,labels],batch_size=batch_size,capacity=capacity,num_threads=num_threads)if one_hot:labels_batch = tf.one_hot(labels_batch, labels_nums, 1, 0)return images_batch,labels_batchdef read_records(filename,resize_height, resize_width,type=None):'''解析record文件:源文件的圖像數據是RGB,uint8,[0,255],一般作為訓練數據時,需要歸一化到[0,1]:param filename::param resize_height::param resize_width::param type:選擇圖像數據的返回類型None:默認將uint8-[0,255]轉為float32-[0,255]normalization:歸一化float32-[0,1]standardization:標準化float32-[0,1],再減均值中心化:return:'''# 創建文件隊列,不限讀取的數量filename_queue = tf.train.string_input_producer([filename])# create a reader from file queuereader = tf.TFRecordReader()# reader從文件隊列中讀入一個序列化的樣本_, serialized_example = reader.read(filename_queue)# get feature from serialized example# 解析符號化的樣本features = tf.parse_single_example(serialized_example,features={'image_raw': tf.FixedLenFeature([], tf.string),'height': tf.FixedLenFeature([], tf.int64),'width': tf.FixedLenFeature([], tf.int64),'depth': tf.FixedLenFeature([], tf.int64),'label': tf.FixedLenFeature([], tf.int64)})tf_image = tf.decode_raw(features['image_raw'], tf.uint8)#獲得圖像原始的數據tf_height = features['height']tf_width = features['width']tf_depth = features['depth']tf_label = tf.cast(features['label'], tf.int32)# PS:恢復原始圖像數據,reshape的大小必須與保存之前的圖像shape一致,否則出錯# tf_image=tf.reshape(tf_image, [-1]) # 轉換為行向量tf_image=tf.reshape(tf_image, [resize_height, resize_width, 3]) # 設置圖像的維度# 恢復數據后,才可以對圖像進行resize_images:輸入uint->輸出float32# tf_image=tf.image.resize_images(tf_image,[224, 224])# [3]數據類型處理# 存儲的圖像類型為uint8,tensorflow訓練時數據必須是tf.float32if type is None:tf_image = tf.cast(tf_image, tf.float32)elif type == 'normalization': # [1]若需要歸一化請使用:# 僅當輸入數據是uint8,才會歸一化[0,255]# tf_image = tf.cast(tf_image, dtype=tf.uint8)# tf_image = tf.image.convert_image_dtype(tf_image, tf.float32)tf_image = tf.cast(tf_image, tf.float32) * (1. / 255.0) # 歸一化elif type == 'standardization': # 標準化# tf_image = tf.cast(tf_image, dtype=tf.uint8)# tf_image = tf.image.per_image_standardization(tf_image) # 標準化(減均值除方差)# 若需要歸一化,且中心化,假設均值為0.5,請使用:tf_image = tf.cast(tf_image, tf.float32) * (1. / 255) - 0.5 # 中心化# 這里僅僅返回圖像和標簽# return tf_image, tf_height,tf_width,tf_depth,tf_labelreturn tf_image,tf_labeldef create_records(image_dir,file, output_record_dir, resize_height, resize_width,shuffle,log=5):'''實現將圖像原始數據,label,長,寬等信息保存為record文件注意:讀取的圖像數據默認是uint8,再轉為tf的字符串型BytesList保存,解析請需要根據需要轉換類型:param image_dir:原始圖像的目錄:param file:輸入保存圖片信息的txt文件(image_dir+file構成圖片的路徑):param output_record_dir:保存record文件的路徑:param resize_height::param resize_width:PS:當resize_height或者resize_width=0是,不執行resize:param shuffle:是否打亂順序:param log:log信息打印間隔'''# 加載文件,僅獲取一個labelimages_list, labels_list=load_labels_file(file,1,shuffle)writer = tf.python_io.TFRecordWriter(output_record_dir)for i, [image_name, labels] in enumerate(zip(images_list, labels_list)):image_path=os.path.join(image_dir,images_list[i])if not os.path.exists(image_path):print('Err:no image',image_path)continueimage = read_image(image_path, resize_height, resize_width)image_raw = image.tostring()if i%log==0 or i==len(images_list)-1:print('------------processing:%d-th------------' % (i))print('current image_path=%s' % (image_path),'shape:{}'.format(image.shape),'labels:{}'.format(labels))# 這里僅保存一個label,多label適當增加"'label': _int64_feature(label)"項label=labels[0]example = tf.train.Example(features=tf.train.Features(feature={'image_raw': _bytes_feature(image_raw),'height': _int64_feature(image.shape[0]),'width': _int64_feature(image.shape[1]),'depth': _int64_feature(image.shape[2]),'label': _int64_feature(label)}))writer.write(example.SerializeToString())writer.close()def disp_records(record_file,resize_height, resize_width,show_nums=4):'''解析record文件,并顯示show_nums張圖片,主要用于驗證生成record文件是否成功:param tfrecord_file: record文件路徑:return:'''# 讀取record函數tf_image, tf_label = read_records(record_file,resize_height,resize_width,type='normalization')# 顯示前4個圖片init_op = tf.initialize_all_variables()with tf.Session() as sess:sess.run(init_op)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(show_nums):image,label = sess.run([tf_image,tf_label]) # 在會話中取出image和label# image = tf_image.eval()# 直接從record解析的image是一個向量,需要reshape顯示# image = image.reshape([height,width,depth])print('shape:{},tpye:{},labels:{}'.format(image.shape,image.dtype,label))# pilimg = Image.fromarray(np.asarray(image_eval_reshape))# pilimg.show()show_image("image:%d"%(label),image)coord.request_stop()coord.join(threads)def batch_test(record_file,resize_height, resize_width):''':param record_file: record文件路徑:param resize_height::param resize_width::return::PS:image_batch, label_batch一般作為網絡的輸入'''# 讀取record函數tf_image,tf_label = read_records(record_file,resize_height,resize_width,type='normalization')image_batch, label_batch= get_batch_images(tf_image,tf_label,batch_size=4,labels_nums=5,one_hot=False,shuffle=False)init = tf.global_variables_initializer()with tf.Session() as sess: # 開始一個會話sess.run(init)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(coord=coord)for i in range(4):# 在會話中取出images和labelsimages, labels = sess.run([image_batch, label_batch])# 這里僅顯示每個batch里第一張圖片show_image("image", images[0, :, :, :])print('shape:{},tpye:{},labels:{}'.format(images.shape,images.dtype,labels))# 停止所有線程coord.request_stop()coord.join(threads)if __name__ == '__main__':# 參數設置resize_height = 224 # 指定存儲圖片高度resize_width = 224 # 指定存儲圖片寬度shuffle=Truelog=5# 產生train.record文件image_dir='dataset/train'train_labels = 'dataset/train.txt' # 圖片路徑train_record_output = 'dataset/record/train.tfrecords'create_records(image_dir,train_labels, train_record_output, resize_height, resize_width,shuffle,log)train_nums=get_example_nums(train_record_output)print("save train example nums={}".format(train_nums))# 產生val.record文件image_dir='dataset/val'val_labels = 'dataset/val.txt' # 圖片路徑val_record_output = 'dataset/record/val.tfrecords'create_records(image_dir,val_labels, val_record_output, resize_height, resize_width,shuffle,log)val_nums=get_example_nums(val_record_output)print("save val example nums={}".format(val_nums))# 測試顯示函數# disp_records(train_record_output,resize_height, resize_width)batch_test(train_record_output,resize_height, resize_width)(2)生成單個record文件 (多label)
? ? 對于多label的情況,你可以在單label的基礎上增加多個“label': tf.FixedLenFeature([], tf.int64)“,但每次label個數不一樣時,都需要修改,挺麻煩的。這里提供一個方法:label數據也可以像圖像數據那樣,轉為string類型來保存:labels_raw = np.asanyarray(labels,dtype=np.float32).tostring() ,解析時也跟圖像數據一樣進行解析:tf_label = tf.decode_raw(features['labels'],tf.float32) ,這樣,不管多少個label,我們都可以保存為record文件了:
? ?多label的TXT文件:
0.jpg 0.33 0.55 1.jpg 0.42 0.73 2.jpg 0.16 0.75 3.jpg 0.78 0.66 4.jpg 0.46 0.59 5.jpg 0.46 0.09 6.jpg 0.89 0.93 7.jpg 0.42 0.82 8.jpg 0.39 0.76 9.jpg 0.46 0.40 # -*-coding: utf-8 -*- """@Project: create_tfrecord@File : create_tf_record_multi_label.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-07-27 17:19:54@desc : 將圖片數據,多label,保存為單個tfrecord文件 """##########################################################################import tensorflow as tf import numpy as np import os import cv2 import matplotlib.pyplot as plt import random from PIL import Image########################################################################## def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))def _float_feature(value):return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))# 生成字符串型的屬性 def _bytes_feature(value):return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) # 生成實數型的屬性 def float_list_feature(value):return tf.train.Feature(float_list=tf.train.FloatList(value=value))def get_example_nums(tf_records_filenames):'''統計tf_records圖像的個數(example)個數:param tf_records_filenames: tf_records文件路徑:return:'''nums= 0for record in tf.python_io.tf_record_iterator(tf_records_filenames):nums += 1return numsdef show_image(title,image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def load_labels_file(filename,labels_num=1,shuffle=False):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1 標簽2,如:test_image/1.jpg 0 2:param filename::param labels_num :labels個數:param shuffle :是否打亂順序:return:images type->list:return:labels type->list'''images=[]labels=[]with open(filename) as f:lines_list=f.readlines()if shuffle:random.shuffle(lines_list)for lines in lines_list:line=lines.rstrip().split(' ')label=[]for i in range(labels_num):label.append(float(line[i+1]))images.append(line[0])labels.append(label)return images,labelsdef read_image(filename, resize_height, resize_width,normalization=False):'''讀取圖片數據,默認返回的是uint8,[0,255]:param filename::param resize_height::param resize_width::param normalization:是否歸一化到[0.,1.0]:return: 返回的圖片數據'''bgr_image = cv2.imread(filename)if len(bgr_image.shape)==2:#若是灰度圖則轉為三通道print("Warning:gray image",filename)bgr_image = cv2.cvtColor(bgr_image, cv2.COLOR_GRAY2BGR)rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)#將BGR轉為RGB# show_image(filename,rgb_image)# rgb_image=Image.open(filename)if resize_height>0 and resize_width>0:rgb_image=cv2.resize(rgb_image,(resize_width,resize_height))rgb_image=np.asanyarray(rgb_image)if normalization:# 不能寫成:rgb_image=rgb_image/255rgb_image=rgb_image/255.0# show_image("src resize image",image)return rgb_imagedef get_batch_images(images,labels,batch_size,labels_nums,one_hot=False,shuffle=False,num_threads=1):''':param images:圖像:param labels:標簽:param batch_size::param labels_nums:標簽個數:param one_hot:是否將labels轉為one_hot的形式:param shuffle:是否打亂順序,一般train時shuffle=True,驗證時shuffle=False:return:返回batch的images和labels'''min_after_dequeue = 200capacity = min_after_dequeue + 3 * batch_size # 保證capacity必須大于min_after_dequeue參數值if shuffle:images_batch, labels_batch = tf.train.shuffle_batch([images,labels],batch_size=batch_size,capacity=capacity,min_after_dequeue=min_after_dequeue,num_threads=num_threads)else:images_batch, labels_batch = tf.train.batch([images,labels],batch_size=batch_size,capacity=capacity,num_threads=num_threads)if one_hot:labels_batch = tf.one_hot(labels_batch, labels_nums, 1, 0)return images_batch,labels_batchdef read_records(filename,resize_height, resize_width,type=None):'''解析record文件:源文件的圖像數據是RGB,uint8,[0,255],一般作為訓練數據時,需要歸一化到[0,1]:param filename::param resize_height::param resize_width::param type:選擇圖像數據的返回類型None:默認將uint8-[0,255]轉為float32-[0,255]normalization:歸一化float32-[0,1]standardization:歸一化float32-[0,1],再減均值中心化:return:'''# 創建文件隊列,不限讀取的數量filename_queue = tf.train.string_input_producer([filename])# create a reader from file queuereader = tf.TFRecordReader()# reader從文件隊列中讀入一個序列化的樣本_, serialized_example = reader.read(filename_queue)# get feature from serialized example# 解析符號化的樣本features = tf.parse_single_example(serialized_example,features={'image_raw': tf.FixedLenFeature([], tf.string),'height': tf.FixedLenFeature([], tf.int64),'width': tf.FixedLenFeature([], tf.int64),'depth': tf.FixedLenFeature([], tf.int64),'labels': tf.FixedLenFeature([], tf.string)})tf_image = tf.decode_raw(features['image_raw'], tf.uint8)#獲得圖像原始的數據tf_height = features['height']tf_width = features['width']tf_depth = features['depth']# tf_label = tf.cast(features['labels'], tf.float32)tf_label = tf.decode_raw(features['labels'],tf.float32)# PS:恢復原始圖像數據,reshape的大小必須與保存之前的圖像shape一致,否則出錯# tf_image=tf.reshape(tf_image, [-1]) # 轉換為行向量tf_image=tf.reshape(tf_image, [resize_height, resize_width, 3]) # 設置圖像的維度tf_label=tf.reshape(tf_label, [2]) # 設置圖像的維度# 恢復數據后,才可以對圖像進行resize_images:輸入uint->輸出float32# tf_image=tf.image.resize_images(tf_image,[224, 224])# [3]數據類型處理# 存儲的圖像類型為uint8,tensorflow訓練時數據必須是tf.float32if type is None:tf_image = tf.cast(tf_image, tf.float32)elif type == 'normalization': # [1]若需要歸一化請使用:# 僅當輸入數據是uint8,才會歸一化[0,255]# tf_image = tf.cast(tf_image, dtype=tf.uint8)# tf_image = tf.image.convert_image_dtype(tf_image, tf.float32)tf_image = tf.cast(tf_image, tf.float32) * (1. / 255.0) # 歸一化elif type == 'standardization': # 標準化# tf_image = tf.cast(tf_image, dtype=tf.uint8)# tf_image = tf.image.per_image_standardization(tf_image) # 標準化(減均值除方差)# 若需要歸一化,且中心化,假設均值為0.5,請使用:tf_image = tf.cast(tf_image, tf.float32) * (1. / 255) - 0.5 # 中心化# 這里僅僅返回圖像和標簽# return tf_image, tf_height,tf_width,tf_depth,tf_labelreturn tf_image,tf_labeldef create_records(image_dir,file, output_record_dir, resize_height, resize_width,shuffle,log=5):'''實現將圖像原始數據,label,長,寬等信息保存為record文件注意:讀取的圖像數據默認是uint8,再轉為tf的字符串型BytesList保存,解析請需要根據需要轉換類型:param image_dir:原始圖像的目錄:param file:輸入保存圖片信息的txt文件(image_dir+file構成圖片的路徑):param output_record_dir:保存record文件的路徑:param resize_height::param resize_width:PS:當resize_height或者resize_width=0是,不執行resize:param shuffle:是否打亂順序:param log:log信息打印間隔'''# 加載文件,僅獲取一個labellabels_num=2images_list, labels_list=load_labels_file(file,labels_num,shuffle)writer = tf.python_io.TFRecordWriter(output_record_dir)for i, [image_name, labels] in enumerate(zip(images_list, labels_list)):image_path=os.path.join(image_dir,images_list[i])if not os.path.exists(image_path):print('Err:no image',image_path)continueimage = read_image(image_path, resize_height, resize_width)image_raw = image.tostring()if i%log==0 or i==len(images_list)-1:print('------------processing:%d-th------------' % (i))print('current image_path=%s' % (image_path),'shape:{}'.format(image.shape),'labels:{}'.format(labels))# 這里僅保存一個label,多label適當增加"'label': _int64_feature(label)"項# label=labels[0]# labels_raw="0.12,0,15"labels_raw = np.asanyarray(labels,dtype=np.float32).tostring()example = tf.train.Example(features=tf.train.Features(feature={'image_raw': _bytes_feature(image_raw),'height': _int64_feature(image.shape[0]),'width': _int64_feature(image.shape[1]),'depth': _int64_feature(image.shape[2]),'labels': _bytes_feature(labels_raw),}))writer.write(example.SerializeToString())writer.close()def disp_records(record_file,resize_height, resize_width,show_nums=4):'''解析record文件,并顯示show_nums張圖片,主要用于驗證生成record文件是否成功:param tfrecord_file: record文件路徑:return:'''# 讀取record函數tf_image, tf_label = read_records(record_file,resize_height,resize_width,type='normalization')# 顯示前4個圖片init_op = tf.initialize_all_variables()with tf.Session() as sess:sess.run(init_op)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(show_nums):image,label = sess.run([tf_image,tf_label]) # 在會話中取出image和label# image = tf_image.eval()# 直接從record解析的image是一個向量,需要reshape顯示# image = image.reshape([height,width,depth])print('shape:{},tpye:{},labels:{}'.format(image.shape,image.dtype,label))# pilimg = Image.fromarray(np.asarray(image_eval_reshape))# pilimg.show()show_image("image:{}".format(label),image)coord.request_stop()coord.join(threads)def batch_test(record_file,resize_height, resize_width):''':param record_file: record文件路徑:param resize_height::param resize_width::return::PS:image_batch, label_batch一般作為網絡的輸入'''# 讀取record函數tf_image,tf_label = read_records(record_file,resize_height,resize_width,type='normalization')image_batch, label_batch= get_batch_images(tf_image,tf_label,batch_size=4,labels_nums=2,one_hot=False,shuffle=True)init = tf.global_variables_initializer()with tf.Session() as sess: # 開始一個會話sess.run(init)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(coord=coord)for i in range(4):# 在會話中取出images和labelsimages, labels = sess.run([image_batch, label_batch])# 這里僅顯示每個batch里第一張圖片show_image("image", images[0, :, :, :])print('shape:{},tpye:{},labels:{}'.format(images.shape,images.dtype,labels))# 停止所有線程coord.request_stop()coord.join(threads)if __name__ == '__main__':# 參數設置resize_height = 224 # 指定存儲圖片高度resize_width = 224 # 指定存儲圖片寬度shuffle=Truelog=1000# 產生train.record文件image_dir='dataset_regression/images'train_labels = 'dataset_regression/train.txt' # 圖片路徑train_record_output = 'dataset_regression/record/train.tfrecords'create_records(image_dir,train_labels, train_record_output, resize_height, resize_width,shuffle,log)train_nums=get_example_nums(train_record_output)print("save train example nums={}".format(train_nums))# 測試顯示函數# disp_records(train_record_output,resize_height, resize_width)# 產生val.record文件image_dir='dataset_regression/images'val_labels = 'dataset_regression/val.txt' # 圖片路徑val_record_output = 'dataset_regression/record/val.tfrecords'create_records(image_dir,val_labels, val_record_output, resize_height, resize_width,shuffle,log)val_nums=get_example_nums(val_record_output)print("save val example nums={}".format(val_nums))## # 測試顯示函數# # disp_records(train_record_output,resize_height, resize_width)# batch_test(val_record_output,resize_height, resize_width)(3)生成多個record文件的方法
? ? ? 上述該代碼只能保存為單個record文件,當圖片數據很多時候,會導致單個record文件超級巨大的情況,解決方法就是,將數據分成多個record文件保存,讀取時,只需要將多個record文件的路徑列表交給“tf.train.string_input_producer”。可以設置參數batchSize的大小,比如batchSize=2000,表示每2000張圖片保存為一個*.tfrecords,這樣可以避免單個record文件過大的情況。
? ? ? 完整代碼如下:
# -*-coding: utf-8 -*- """@Project: tf_record_demo@File : tf_record_batchSize.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-07-27 17:19:54@desc : 將圖片數據保存為多個record文件 """##########################################################################import tensorflow as tf import numpy as np import os import cv2 import math import matplotlib.pyplot as plt import random from PIL import Image########################################################################## def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) # 生成字符串型的屬性 def _bytes_feature(value):return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) # 生成實數型的屬性 def float_list_feature(value):return tf.train.Feature(float_list=tf.train.FloatList(value=value))def show_image(title,image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def load_labels_file(filename,labels_num=1):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1 標簽2,如:test_image/1.jpg 0 2:param filename::param labels_num :labels個數:return:images type->list:return:labels type->list'''images=[]labels=[]with open(filename) as f:for lines in f.readlines():line=lines.rstrip().split(' ')label=[]for i in range(labels_num):label.append(int(line[i+1]))images.append(line[0])labels.append(label)return images,labelsdef read_image(filename, resize_height, resize_width):'''讀取圖片數據,默認返回的是uint8,[0,255]:param filename::param resize_height::param resize_width::return: 返回的圖片數據是uint8,[0,255]'''bgr_image = cv2.imread(filename)if len(bgr_image.shape)==2:#若是灰度圖則轉為三通道print("Warning:gray image",filename)bgr_image = cv2.cvtColor(bgr_image, cv2.COLOR_GRAY2BGR)rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)#將BGR轉為RGB# show_image(filename,rgb_image)# rgb_image=Image.open(filename)if resize_height>0 and resize_width>0:rgb_image=cv2.resize(rgb_image,(resize_width,resize_height))rgb_image=np.asanyarray(rgb_image)# show_image("src resize image",image)return rgb_imagedef create_records(image_dir,file, record_txt_path, batchSize,resize_height, resize_width):'''實現將圖像原始數據,label,長,寬等信息保存為record文件注意:讀取的圖像數據默認是uint8,再轉為tf的字符串型BytesList保存,解析請需要根據需要轉換類型:param image_dir:原始圖像的目錄:param file:輸入保存圖片信息的txt文件(image_dir+file構成圖片的路徑):param output_record_txt_dir:保存record文件的路徑:param batchSize: 每batchSize個圖片保存一個*.tfrecords,避免單個文件過大:param resize_height::param resize_width:PS:當resize_height或者resize_width=0是,不執行resize'''if os.path.exists(record_txt_path):os.remove(record_txt_path)setname, ext = record_txt_path.split('.')# 加載文件,僅獲取一個labelimages_list, labels_list=load_labels_file(file,1)sample_num = len(images_list)# 打亂樣本的數據# random.shuffle(labels_list)batchNum = int(math.ceil(1.0 * sample_num / batchSize))for i in range(batchNum):start = i * batchSizeend = min((i + 1) * batchSize, sample_num)batch_images = images_list[start:end]batch_labels = labels_list[start:end]# 逐個保存*.tfrecords文件filename = setname + '{0}.tfrecords'.format(i)print('save:%s' % (filename))writer = tf.python_io.TFRecordWriter(filename)for i, [image_name, labels] in enumerate(zip(batch_images, batch_labels)):image_path=os.path.join(image_dir,batch_images[i])if not os.path.exists(image_path):print('Err:no image',image_path)continueimage = read_image(image_path, resize_height, resize_width)image_raw = image.tostring()print('image_path=%s,shape:( %d, %d, %d)' % (image_path,image.shape[0], image.shape[1], image.shape[2]),'labels:',labels)# 這里僅保存一個label,多label適當增加"'label': _int64_feature(label)"項label=labels[0]example = tf.train.Example(features=tf.train.Features(feature={'image_raw': _bytes_feature(image_raw),'height': _int64_feature(image.shape[0]),'width': _int64_feature(image.shape[1]),'depth': _int64_feature(image.shape[2]),'label': _int64_feature(label)}))writer.write(example.SerializeToString())writer.close()# 用txt保存*.tfrecords文件列表# record_list='{}.txt'.format(setname)with open(record_txt_path, 'a') as f:f.write(filename + '\n')def read_records(filename,resize_height, resize_width):'''解析record文件:param filename:保存*.tfrecords文件的txt文件路徑:return:'''# 讀取txt中所有*.tfrecords文件with open(filename, 'r') as f:lines = f.readlines()files_list=[]for line in lines:files_list.append(line.rstrip())# 創建文件隊列,不限讀取的數量filename_queue = tf.train.string_input_producer(files_list,shuffle=False)# create a reader from file queuereader = tf.TFRecordReader()# reader從文件隊列中讀入一個序列化的樣本_, serialized_example = reader.read(filename_queue)# get feature from serialized example# 解析符號化的樣本features = tf.parse_single_example(serialized_example,features={'image_raw': tf.FixedLenFeature([], tf.string),'height': tf.FixedLenFeature([], tf.int64),'width': tf.FixedLenFeature([], tf.int64),'depth': tf.FixedLenFeature([], tf.int64),'label': tf.FixedLenFeature([], tf.int64)})tf_image = tf.decode_raw(features['image_raw'], tf.uint8)#獲得圖像原始的數據tf_height = features['height']tf_width = features['width']tf_depth = features['depth']tf_label = tf.cast(features['label'], tf.int32)# tf_image=tf.reshape(tf_image, [-1]) # 轉換為行向量tf_image=tf.reshape(tf_image, [resize_height, resize_width, 3]) # 設置圖像的維度# 存儲的圖像類型為uint8,這里需要將類型轉為tf.float32# tf_image = tf.cast(tf_image, tf.float32)# [1]若需要歸一化請使用:tf_image = tf.image.convert_image_dtype(tf_image, tf.float32)# 歸一化# tf_image = tf.cast(tf_image, tf.float32) * (1. / 255) # 歸一化# [2]若需要歸一化,且中心化,假設均值為0.5,請使用:# tf_image = tf.cast(tf_image, tf.float32) * (1. / 255) - 0.5 #中心化return tf_image, tf_height,tf_width,tf_depth,tf_labeldef disp_records(record_file,resize_height, resize_width,show_nums=4):'''解析record文件,并顯示show_nums張圖片,主要用于驗證生成record文件是否成功:param tfrecord_file: record文件路徑:param resize_height::param resize_width::param show_nums: 默認顯示前四張照片:return:'''tf_image, tf_height, tf_width, tf_depth, tf_label = read_records(record_file,resize_height, resize_width) # 讀取函數# 顯示前show_nums個圖片init_op = tf.initialize_all_variables()with tf.Session() as sess:sess.run(init_op)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(show_nums):image,height,width,depth,label = sess.run([tf_image,tf_height,tf_width,tf_depth,tf_label]) # 在會話中取出image和label# image = tf_image.eval()# 直接從record解析的image是一個向量,需要reshape顯示# image = image.reshape([height,width,depth])print('shape:',image.shape,'label:',label)# pilimg = Image.fromarray(np.asarray(image_eval_reshape))# pilimg.show()show_image("image:%d"%(label),image)coord.request_stop()coord.join(threads)def batch_test(record_file,resize_height, resize_width):''':param record_file: record文件路徑:param resize_height::param resize_width::return::PS:image_batch, label_batch一般作為網絡的輸入'''tf_image,tf_height,tf_width,tf_depth,tf_label = read_records(record_file,resize_height, resize_width) # 讀取函數# 使用shuffle_batch可以隨機打亂輸入:# shuffle_batch用法:https://blog.csdn.net/u013555719/article/details/77679964min_after_dequeue = 100#該值越大,數據越亂,必須小于capacitybatch_size = 4# capacity = (min_after_dequeue + (num_threads + a small safety margin?batchsize)capacity = min_after_dequeue + 3 * batch_size#容量:一個整數,隊列中的最大的元素數image_batch, label_batch = tf.train.shuffle_batch([tf_image, tf_label],batch_size=batch_size,capacity=capacity,min_after_dequeue=min_after_dequeue)init = tf.global_variables_initializer()with tf.Session() as sess: # 開始一個會話sess.run(init)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(coord=coord)for i in range(4):# 在會話中取出images和labelsimages, labels = sess.run([image_batch, label_batch])# 這里僅顯示每個batch里第一張圖片show_image("image", images[0, :, :, :])print(images.shape, labels)# 停止所有線程coord.request_stop()coord.join(threads)if __name__ == '__main__':# 參數設置image_dir='dataset/train'train_file = 'dataset/train.txt' # 圖片路徑output_record_txt = 'dataset/record/record.txt'#指定保存record的文件列表resize_height = 224 # 指定存儲圖片高度resize_width = 224 # 指定存儲圖片寬度batchSize=8000 #batchSize一般設置為8000,即每batchSize張照片保存為一個record文件# 產生record文件create_records(image_dir=image_dir,file=train_file,record_txt_path=output_record_txt,batchSize=batchSize,resize_height=resize_height,resize_width=resize_width)# 測試顯示函數disp_records(output_record_txt,resize_height, resize_width)# batch_test(output_record_txt,resize_height, resize_width)1.2. 直接文件讀取方式?
? ? 上面介紹的是如何將數據轉存為TFrecord文件,訓練時再解析TFrecord。這種轉存為TFrecord數據格式的方法,雖然高效,但也喪失了靈活性,特別是新增數據或者刪除相關數據時,這時就不得不重新制作TFrecord數據了。這就挺麻煩啦,如果不想轉為TFrecord文件,可以直接讀取圖像文件進行訓練。
? ? 這種方法比較簡單,靈活性很強,但效率很低,因為每次迭代訓練,GPU/CPU都要等待數據讀取I/O操作,圖像文件讀取以及預處理過程本身就很耗時,甚至比你迭代一次網絡還耗時。解決的方法,就是采用tf.data.Dataset數據讀取機制。
? ? 直接文件讀取方式的完整代碼可以參考如下:
? ? 假設我們有train.txt的文件數據如下:
0.jpg 0
1.jpg 0
2.jpg 0
3.jpg 0
4.jpg 0
5.jpg 1
6.jpg 1
7.jpg 1
8.jpg 1
9.jpg 1
? ? 可以使用下面的方法直接讀取圖像數據,并產生一個batch的訓練數據:
# -*-coding: utf-8 -*- """@Project: tf_record_demo@File : tf_read_files.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-10-14 10:44:06 """ import tensorflow as tf import glob import numpy as np import os import matplotlib.pyplot as pltimport cv2 def show_image(title, image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.imshow(image, cmap='gray')plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def tf_read_image(filename, resize_height, resize_width):'''讀取圖片:param filename::param resize_height::param resize_width::return:'''image_string = tf.read_file(filename)image_decoded = tf.image.decode_jpeg(image_string, channels=3)# tf_image = tf.cast(image_decoded, tf.float32)tf_image = tf.cast(image_decoded, tf.float32) * (1. / 255.0) # 歸一化if resize_width>0 and resize_height>0:tf_image = tf.image.resize_images(tf_image, [resize_height, resize_width])# tf_image = tf.image.per_image_standardization(tf_image) # 標準化[0,1](減均值除方差)return tf_imagedef get_batch_images(image_list, label_list, batch_size, labels_nums, resize_height, resize_width, one_hot=False, shuffle=False):''':param image_list:圖像:param label_list:標簽:param batch_size::param labels_nums:標簽個數:param one_hot:是否將labels轉為one_hot的形式:param shuffle:是否打亂順序,一般train時shuffle=True,驗證時shuffle=False:return:返回batch的images和labels'''# 生成隊列image_que, tf_label = tf.train.slice_input_producer([image_list, label_list], shuffle=shuffle)tf_image = tf_read_image(image_que, resize_height, resize_width)min_after_dequeue = 200capacity = min_after_dequeue + 3 * batch_size # 保證capacity必須大于min_after_dequeue參數值if shuffle:images_batch, labels_batch = tf.train.shuffle_batch([tf_image, tf_label],batch_size=batch_size,capacity=capacity,min_after_dequeue=min_after_dequeue)else:images_batch, labels_batch = tf.train.batch([tf_image, tf_label],batch_size=batch_size,capacity=capacity)if one_hot:labels_batch = tf.one_hot(labels_batch, labels_nums, 1, 0)return images_batch, labels_batchdef load_image_labels(filename):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1,如:test_image/1.jpg 0:param filename::return:'''images_list = []labels_list = []with open(filename) as f:lines = f.readlines()for line in lines:# rstrip:用來去除結尾字符、空白符(包括\n、\r、\t、' ',即:換行、回車、制表符、空格)content = line.rstrip().split(' ')name = content[0]labels = []for value in content[1:]:labels.append(int(value))images_list.append(name)labels_list.append(labels)return images_list, labels_listdef batch_test(filename, image_dir):labels_nums = 2batch_size = 4resize_height = 200resize_width = 200image_list, label_list = load_image_labels(filename)image_list=[os.path.join(image_dir,image_name) for image_name in image_list]image_batch, labels_batch = get_batch_images(image_list=image_list,label_list=label_list,batch_size=batch_size,labels_nums=labels_nums,resize_height=resize_height, resize_width=resize_width,one_hot=False, shuffle=True)with tf.Session() as sess: # 開始一個會話sess.run(tf.global_variables_initializer())coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(coord=coord)for i in range(4):# 在會話中取出images和labelsimages, labels = sess.run([image_batch, labels_batch])# 這里僅顯示每個batch里第一張圖片show_image("image", images[0, :, :, :])print('shape:{},tpye:{},labels:{}'.format(images.shape, images.dtype, labels))# 停止所有線程coord.request_stop()coord.join(threads)if __name__ == "__main__":image_dir = "./dataset/train"filename = "./dataset/train.txt"batch_test(filename, image_dir)2.tf.data.Dataset數據讀取機制:Pipeline機制
? ? 要執行訓練步驟,您必須首先提取并轉換訓練數據,然后將其提供給在加速器上運行的模型。然而,在一個簡單的同步執行中,當 CPU 正在準備數據時,加速器則處于空閑狀態。相反,當加速器正在訓練模型時,CPU 則處于空閑狀態。因此,訓練步驟時間是 CPU 預處理時間和加速器訓練時間的總和。
prefetch(必須放在最后)
? ? ?TensorFlow引入了tf.data.Dataset模塊,使其數據讀入的操作變得更為方便,而支持多線程(進程)的操作,也在效率上獲得了一定程度的提高。使用tf.data.Dataset模塊的pipline機制,可實現CPU多線程處理輸入的數據,如讀取圖片和圖片的一些的預處理,這樣GPU可以專注于訓練過程,而CPU去準備數據。
? ? 參考資料:
https://blog.csdn.net/u014061630/article/details/80776975
(五星推薦)TensorFlow全新的數據讀取方式:Dataset API入門教程:http://baijiahao.baidu.com/s?id=1583657817436843385&wfr=spider&for=pc
? ? Pipelining 將一個訓練步驟的預處理和模型執行重疊。當加速器正在執行訓練步驟 N 時,CPU 正在準備步驟 N + 1 的數據。這樣做的目的是可以將步驟時間縮短到極致,包含訓練以及提取和轉換數據所需時間(而不是總和)。
? ? 如果沒有使用 pipelining,則 CPU 和 GPU / TPU 在大部分時間處于閑置狀態:
? ? 而使用 pipelining 技術后,空閑時間顯著減少:
? ? tf.data?API 通過 tf.data.Dataset.prefetch 轉換提供了一個軟件 pipelining 操作機制,該轉換可用于將數據生成的時間與所消耗時間分離。特別是,轉換使用后臺線程和內部緩沖區,以便在請求輸入數據集之前從輸入數據集中預提取元素。因此,為了實現上面說明的 pipelining 效果,您可以將 prefetch(1) 添加為數據集管道的最終轉換(如果單個訓練步驟消耗 n 個元素,則添加 prefetch(n))。
? ? tf.data.Dataset.prefetch 提供了 software pipelining 機制。該函數解耦了 數據產生的時間 和 數據消耗的時間。具體來說,該函數有一個后臺線程和一個內部緩存區,在數據被請求前,就從 dataset 中預加載一些數據(進一步提高性能)。prefech(n) 一般作為最后一個 transformation,其中 n 為 batch_size。?prefetch 的使用方法如下:? ?
? ? 要將此更改應用于我們的運行示例,請將:
dataset = dataset.batch(batch_size=FLAGS.batch_size) return?dataset? ? 更改為:
dataset = dataset.batch(batch_size=FLAGS.batch_size) dataset = dataset.prefetch(buffer_size=FLAGS.prefetch_buffer_size) return?dataset? ? 請注意,在任何時候只要有機會將 “制造者” 的工作與 “消費者” 的工作重疊,預取轉換就會產生效益。前面的建議只是最常見的應用程序。
map
? ? 使用?tf.data.Dataset.map,我們可以很方便地對數據集中的各個元素進行預處理。因為輸入元素之間時獨立的,所以可以在多個 CPU 核心上并行地進行預處理。map?變換提供了一個?num_parallel_calls參數去指定并行的級別。
? ? 準備批處理時,可能需要預處理輸入元素。為此,tf.data?API 提供了 tf.data.Dataset.map 轉換,它將用戶定義的函數(例如,運行示例中的 parse_fn)應用于輸入數據集的每個元素。由于輸入元素彼此獨立,因此可以跨多個 CPU 內核并行化預處理。為了實現這一點,map 轉換提供了 thenum_parallel_calls 參數來指定并行度。例如,下圖說明了將 num_parallel_calls = 2 設置為 map 轉換的效果:
dataset = dataset.map(map_func=parse_fn, num_parallel_calls=FLAGS.num_parallel_calls)repeat
? ? repeat的功能就是將整個序列重復多次,主要用來處理機器學習中的epoch,假設原先的數據是一個epoch,使用repeat(5)就可以將之變成5個epoch:
? ? 如果直接調用repeat()的話,生成的序列就會無限重復下去,沒有結束,因此也不會拋出tf.errors.OutOfRangeError異常
實例代碼1:dataset.make_initializable_iterator()
# -*-coding: utf-8 -*- """@Project: fine tuning@File : pipeline.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-11-17 20:18:54 """ import tensorflow as tf import numpy as np import glob import matplotlib.pyplot as pltwidth=0 height=0 def show_image(title, image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def tf_read_image(filename, label):image_string = tf.read_file(filename)image_decoded = tf.image.decode_jpeg(image_string, channels=3)image = tf.cast(image_decoded, tf.float32)if width>0 and height>0:image = tf.image.resize_images(image, [height, width])image = tf.cast(image, tf.float32) * (1. / 255.0) # 歸一化return image, labeldef input_fun(files_list, labels_list, batch_size, shuffle=True):''':param files_list::param labels_list::param batch_size::param shuffle::return:'''# 構建數據集dataset = tf.data.Dataset.from_tensor_slices((files_list, labels_list))if shuffle:dataset = dataset.shuffle(100)dataset = dataset.repeat() # 空為無限循環dataset = dataset.map(tf_read_image, num_parallel_calls=4) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.batch(batch_size)dataset = dataset.prefetch(2) # software pipelining 機制return datasetif __name__ == '__main__':data_dir = 'dataset/image/*.jpg'# labels_list = tf.constant([0,1,2,3,4])# labels_list = [1, 2, 3, 4, 5]files_list = glob.glob(data_dir)labels_list = np.arange(len(files_list))num_sample = len(files_list)batch_size = 1dataset = input_fun(files_list, labels_list, batch_size=batch_size, shuffle=False)# 需滿足:max_iterate*batch_size <=num_sample*num_epoch,否則越界max_iterate = 3with tf.Session() as sess:iterator = dataset.make_initializable_iterator()init_op = iterator.make_initializer(dataset)sess.run(init_op)iterator = iterator.get_next()for i in range(max_iterate):images, labels = sess.run(iterator)show_image("image", images[0, :, :, :])print('shape:{},tpye:{},labels:{}'.format(images.shape, images.dtype, labels))實例代碼2:dataset.make_one_shot_iterator()
? ? ?上面的迭代器是使用dataset.make_initializable_iterator(),當然一個更簡單的方法是使用dataset.make_one_shot_iterator(),下面的代碼,可把dataset.make_one_shot_iterator()放在input_fun函數中,直接返回一個迭代器iterator:
# -*-coding: utf-8 -*- """@Project: fine tuning@File : pipeline.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-11-17 20:18:54 """ import tensorflow as tf import numpy as np import glob import matplotlib.pyplot as pltwidth = 224 height = 224def show_image(title, image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def tf_read_image(filename, label):image_string = tf.read_file(filename)image_decoded = tf.image.decode_jpeg(image_string, channels=3)image = tf.cast(image_decoded, tf.float32)if width > 0 and height > 0:image = tf.image.resize_images(image, [height, width])image = tf.cast(image, tf.float32) * (1. / 255.0) # 歸一化return image, labeldef input_fun(files_list, labels_list, batch_size, shuffle=True):''':param files_list::param labels_list::param batch_size::param shuffle::return:'''# 構建數據集dataset = tf.data.Dataset.from_tensor_slices((files_list, labels_list))if shuffle:dataset = dataset.shuffle(100)dataset = dataset.repeat() # 空為無限循環dataset = dataset.map(tf_read_image, num_parallel_calls=4) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.batch(batch_size)dataset = dataset.prefetch(2) # software pipelining 機制iterator = dataset.make_one_shot_iterator()return iteratorif __name__ == '__main__':data_dir = './data/demo_data/*.jpg'# labels_list = tf.constant([0,1,2,3,4])# labels_list = [1, 2, 3, 4, 5]files_list = glob.glob(data_dir)labels_list = np.arange(len(files_list))num_sample = len(files_list)batch_size = 4iterator = input_fun(files_list, labels_list, batch_size=batch_size, shuffle=False)# 需滿足:max_iterate*batch_size <=num_sample*num_epoch,否則越界max_iterate = 3with tf.Session() as sess:# iterator = dataset.make_initializable_iterator()# init_op = iterator.make_initializer(dataset)# sess.run(init_op)iterator = iterator.get_next()for i in range(max_iterate):images, labels = sess.run(iterator)show_image("image", images[0, :, :, :])print('shape:{},tpye:{},labels:{}'.format(images.shape, images.dtype, labels))實例代碼3:產生用于訓練的圖和label
假設train.txt的數據如下:
0_8354.jpg 8 3 5 4 1_3621.jpg 3 6 2 1 2_4326.jpg 4 3 2 6 3_7711.jpg 7 7 1 1 # -*-coding: utf-8 -*- """@Project: verification_code@File : dataset.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2019-03-03 18:45:13 """ import tensorflow as tf import numpy as np import glob import os import matplotlib.pyplot as plt from utils import file_processing,image_processingprint("TF Version:{}".format(tf.__version__))resize_height = 0 # 指定存儲圖片高度 resize_width = 0 # 指定存儲圖片寬度def load_image_labels(filename):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1 標簽1,如:test_image/1.jpg 0 2:param filename::return:'''images_list=[]labels_list=[]with open(filename) as f:lines = f.readlines()for line in lines:#rstrip:用來去除結尾字符、空白符(包括\n、\r、\t、' ',即:換行、回車、制表符、空格)content=line.rstrip().split(' ')name=content[0]labels=[]for value in content[1:]:labels.append(int(value))images_list.append(name)labels_list.append(labels)return images_list,labels_listdef show_image(title, image):'''顯示圖片:param title: 圖像標題:param image: 圖像的數據:return:'''# plt.figure("show_image")# print(image.dtype)plt.imshow(image)plt.axis('on') # 關掉坐標軸為 offplt.title(title) # 圖像題目plt.show()def tf_resize_image(image, width=0, height=0):if (width is None) or (height is None): # 錯誤寫法:resize_height and resize_width is Nonereturn imageimage = tf.image.resize_images(image, [height, width])return imagedef tf_read_image(file, width, height):image_string = tf.read_file(file)image_decoded = tf.image.decode_jpeg(image_string, channels=3)image = tf.cast(image_decoded, tf.float32)image=tf_resize_image(image, width, height)image = tf.cast(image, tf.float32) * (1. / 255.0) # 歸一化return imagedef map_read_image(files_list, labels_list):tf_image=tf_read_image(files_list,resize_width,resize_height)return tf_image,labels_listdef input_fun(files_list, labels_list, batch_size, shuffle=True):''':param orig_image::param dest_image::param batch_size::param num_epoch::param shuffle::return:'''# 構建數據集dataset = tf.data.Dataset.from_tensor_slices((files_list, labels_list))#TF version>=1.4# dataset = tf.contrib.data.Dataset.from_tensor_slices((files_list, labels_list))#TF version<1.4if shuffle:dataset = dataset.shuffle(100)dataset = dataset.repeat() # 空為無限循環# dataset = dataset.map(map_read_image, num_parallel_calls=4) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.map(map_read_image) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.batch(batch_size)dataset = dataset.prefetch(2) # software pipelining 機制dataset = dataset.make_one_shot_iterator()return datasetdef get_image_data(images_list, image_dir,labels_list, batch_size, re_height, re_width, shuffle=False):global resize_heightglobal resize_widthresize_height = re_height # 指定存儲圖片高度resize_width = re_width # 指定存儲圖片寬度image_list = [os.path.join(image_dir, name) for name in images_list]dataset = input_fun(image_list, labels_list, batch_size, shuffle)return datasetif __name__ == '__main__':filename='../dataset/train.txt'image_dir="E:/TensoFlow/verification_code/dataset/train"images_list, labels_list=load_image_labels(filename)batch_size = 4dataset=get_image_data(images_list, image_dir,labels_list, batch_size, re_height=None, re_width=None, shuffle=False)# 需滿足:max_iterate*batch_size <=num_sample*num_epoch,否則越界max_iterate = 3with tf.Session() as sess:# dataset = dataset.make_initializable_iterator()# init_op = dataset.make_initializer(dataset)# sess.run(init_op)dataset = dataset.get_next()for i in range(max_iterate):images, labels = sess.run(dataset)print('shape:{},tpye:{},labels:{}'.format(images.shape, images.dtype, labels))show_image("image", images[0, :, :, :])實例代碼4:產生用于訓練的原始圖和target目標圖
# -*-coding: utf-8 -*- """@Project: triple_path_networks@File : load_data.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-11-29 11:40:37 """import tensorflow as tfimport glob import numpy as np import utils.image_processing as image_processing import os print("TF Version:{}".format(tf.__version__))resize_height = 0 # 指定存儲圖片高度 resize_width = 0 # 指定存儲圖片寬度def write_data(file, content_list, model):with open(file, mode=model) as f:for line in content_list:f.write(line + "\n")def read_data(file):with open(file, mode="r") as f:content_list = f.readlines()content_list = [content.rstrip() for content in content_list]return content_listdef read_train_val_data(filename,factor=0.8):image_list = read_data(filename)trian_num=int(len(image_list)*factor)train_list = image_list[:trian_num]val_list = image_list[trian_num:]print("data info***************************")print("--train nums:{}".format(len(train_list)))print("--val nums:{}".format(len(val_list)))print("************************************")return train_list,val_listdef tf_resize_image(image,width=0,height=0):if height>0 and width>0:image = tf.image.resize_images(image, [height, width])return imagedef tf_read_image(file,width=224,height=224):image_string = tf.read_file(file)image_decoded = tf.image.decode_jpeg(image_string, channels=3)image = tf.cast(image_decoded, tf.float32)if height>0 and width>0:image = tf.image.resize_images(image, [height, width])image = tf.cast(image, tf.float32) * (1. / 255.0) # 歸一化return imagedef map_read_image(orig_file, dest_file):orig_image=tf_read_image(orig_file,resize_width,resize_height)dest_image=tf_read_image(dest_file,resize_width,resize_height)return orig_image,dest_imagedef input_fun(orig_image, dest_image, batch_size, shuffle=True):''':param orig_image::param dest_image::param batch_size::param num_epoch::param shuffle::return:'''# 構建數據集# dataset = tf.data.Dataset.from_tensor_slices((orig_image, dest_image))dataset = tf.contrib.data.Dataset.from_tensor_slices((orig_image, dest_image))if shuffle:dataset = dataset.shuffle(100)dataset = dataset.repeat() #空為無限循環# dataset = dataset.map(map_read_image, num_parallel_calls=4) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.map(map_read_image) # num_parallel_calls一般設置為cpu內核數量dataset = dataset.batch(batch_size)# dataset = dataset.prefetch(2) # software pipelining 機制return datasetdef get_image_data(file_list,orig_dir,dest_dir,batch_size,re_height,re_width,shuffle=False):global resize_heightglobal resize_widthresize_height = re_height # 指定存儲圖片高度resize_width = re_width # 指定存儲圖片寬度orig_image_list=[os.path.join(orig_dir,name) for name in file_list]dest_image_list=[os.path.join(dest_dir,name) for name in file_list]dataset = input_fun(orig_image_list, dest_image_list, batch_size=batch_size,shuffle=shuffle)return datasetif __name__ == '__main__':orig_dir="../dataset/blackberry/blackberry"dest_dir="../dataset/blackberry/canon"filename="../dataset/blackberry/filelist.txt"batch_size = 1file_list=read_data(filename)dataset = get_image_data(file_list,orig_dir, dest_dir, batch_size=batch_size,shuffle=False)# 迭代次數:max_iterate=10# 需滿足:max_iterate*batch_size <=num_sample*num_epoch,否則越界max_iterate = 5with tf.Session() as sess:iterator = dataset.make_initializable_iterator()init_op = iterator.make_initializer(dataset)sess.run(init_op)iterator = iterator.get_next()for i in range(max_iterate):orig_image, dest_image = sess.run(iterator)image_processing.show_image("orig_image", orig_image[0, :, :, :])image_processing.show_image("dest_image", dest_image[0, :, :, :])print('orig_image:{},dest_image:{}'.format(orig_image.shape, dest_image.shape))實例代碼5: tf.data.Dataset.from_generator
? ??tf.data.Dataset.from_tensor_slices并不支持輸入長度不同list,比如以下代碼
t = [[4,2], [3,4,5]] dataset = tf.data.Dataset.from_tensor_slices(t)? ? 將會報錯:
ValueError: Argument must be a dense tensor: [[4, 2], [3, 4, 5]] - got shape [2], but wanted [2, 2].? ? 一種決解的方法,采用? tf.data.Dataset.from_generator生成器:
import tensorflow as tf import numpy as np data1 = np.array([[1], [2, 3], [3, 4]]) data2 = np.array([[10], [20, 30], [30, 40]])def data_generator():for el, e2 in zip(data1, data2):yield el, e2dataset = tf.data.Dataset.from_generator(data_generator,output_types=(tf.int32, tf.int32),output_shapes=(None, None)) #或者output_shapes=(tf.TensorShape([None]), tf.TensorShape([None]))iterator = dataset.make_one_shot_iterator() next_element = iterator.get_next() max_iter = 3 with tf.Session() as sess:for i in range(max_iter):d1, d2 = sess.run(next_element)print("d1:{}".format(d1))print("d2:{}".format(d2))print("******************************")? 輸出:
d1:[1]
d2:[10]
******************************
d1:[2 3]
d2:[20 30]
******************************
d1:[3 4]
d2:[30 40]
******************************
參考資料:
https://stackoverflow.com/questions/47580716/how-to-input-a-list-of-lists-with-different-sizes-in-tf-data-dataset
https://blog.csdn.net/foreseerwang/article/details/80572182
https://blog.csdn.net/dqcfkyqdxym3f8rb0/article/details/79342369(五星推薦)
3.?用Python循環產生批量數據batch
? ? ?這部分請參考本人的博客《Python循環產生批量數據batch》??https://blog.csdn.net/guyuealian/article/details/83473298
? ? 上面提到的方法都是在TensorFlow提高API接口完成的,數據預處理也必須依賴TensorFlow的API接口。當遇到一些特殊處理,而TensorFlow沒有相應的接口時,就比較尷尬。比如要對輸入的圖像進行邊緣檢測處理時,這時能想到就是用OpenCV的Canny算法,一種簡單的方法就是,每次sess.run()獲得圖像數據后,再調用OpenCV的Canny算法……是的,有的麻煩!
? ? ?這里提供一個我自己設計方法,不依賴TensorFlow,靈活性很強,你可以對數據進行任意的操作,可以使用OpenCV,numpy等任意的庫函數。
? ?TXT文本如下,格式:圖片名 label1 label2 ,注意label可以多個
1.jpg 1 11 2.jpg 2 12 3.jpg 3 13 4.jpg 4 14 5.jpg 5 15 6.jpg 6 16 7.jpg 7 17 8.jpg 8 18? ? 要想產生batch數據,關鍵是要用到Python的關鍵字yield,實現一個batch一個batch的返回數據,代碼實現主要有兩個方法:
def get_data_batch(inputs, batch_size=None, shuffle=False):'''循環產生批量數據batch:param inputs: list數據:param batch_size: batch大小:param shuffle: 是否打亂inputs數據:return: 返回一個batch數據''' def get_next_batch(batch):return batch.__next__()? ? 使用時,將數據傳到?get_data_batch( )方法,然后使用get_next_batch( )獲得一個batch數據,完整的Python代碼如下:
# -*-coding: utf-8 -*- """@Project: create_batch_data@File : create_batch_data.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2017-10-27 18:20:15 """ import math import random import os import glob import numpy as npdef get_data_batch(inputs, batch_size=None, shuffle=False):'''循環產生批量數據batch:param inputs: list類型數據,多個list,請[list0,list1,...]:param batch_size: batch大小:param shuffle: 是否打亂inputs數據:return: 返回一個batch數據'''rows = len(inputs[0])indices = list(range(rows))# 如果輸入是list,則需要轉為listif shuffle:random.seed(100)random.shuffle(indices)while True:batch_indices = np.asarray(indices[0:batch_size]) # 產生一個batch的indexindices = indices[batch_size:] + indices[:batch_size] # 循環移位,以便產生下一個batchbatch_data = []for data in inputs:data = np.asarray(data)temp_data=data[batch_indices] #使用下標查找,必須是ndarray類型類型batch_data.append(temp_data.tolist())yield batch_datadef get_data_batch2(inputs, batch_size=None, shuffle=False):'''循環產生批量數據batch:param inputs: list類型數據,多個list,請[list0,list1,...]:param batch_size: batch大小:param shuffle: 是否打亂inputs數據:return: 返回一個batch數據'''# rows,cols=inputs.shaperows = len(inputs[0])indices = list(range(rows))if shuffle:random.seed(100)random.shuffle(indices)while True:batch_indices = indices[0:batch_size] # 產生一個batch的indexindices = indices[batch_size:] + indices[:batch_size] # 循環移位,以便產生下一個batchbatch_data = []for data in inputs:temp_data = find_list(batch_indices, data)batch_data.append(temp_data)yield batch_datadef find_list(indices, data):out = []for i in indices:out = out + [data[i]]return outdef get_list_batch(inputs, batch_size=None, shuffle=False):'''循環產生batch數據:param inputs: list數據:param batch_size: batch大小:param shuffle: 是否打亂inputs數據:return: 返回一個batch數據'''if shuffle:random.shuffle(inputs)while True:batch_inouts = inputs[0:batch_size]inputs = inputs[batch_size:] + inputs[:batch_size] # 循環移位,以便產生下一個batchyield batch_inoutsdef load_file_list(text_dir):text_dir = os.path.join(text_dir, '*.txt')text_list = glob.glob(text_dir)return text_listdef get_next_batch(batch):return batch.__next__()def load_image_labels(finename):'''載圖txt文件,文件中每行為一個圖片信息,且以空格隔開:圖像路徑 標簽1 標簽1,如:test_image/1.jpg 0 2:param test_files::return:'''images_list = []labels_list = []with open(finename) as f:lines = f.readlines()for line in lines:# rstrip:用來去除結尾字符、空白符(包括\n、\r、\t、' ',即:換行、回車、制表符、空格)content = line.rstrip().split(' ')name = content[0]labels = []for value in content[1:]:labels.append(float(value))images_list.append(name)labels_list.append(labels)return images_list, labels_listif __name__ == '__main__':filename = './training_data/test.txt'images_list, labels_list = load_image_labels(filename)# 若輸入為np.arange數組,則需要tolist()為list類型,如:# images_list = np.reshape(np.arange(8*3), (8,3))# labels_list = np.reshape(np.arange(8*3), (8,3))# images_list=images_list.tolist()# labels_list=labels_list.tolist()iter = 5 # 迭代3次,每次輸出一個batch個# batch = get_data_batch([images_list, labels_list], batch_size=3, shuffle=False)batch = get_data_batch2(inputs=[images_list,labels_list], batch_size=5, shuffle=True)for i in range(iter):print('**************************')batch_images, batch_labels = get_next_batch(batch)print('batch_images:{}'.format(batch_images))print('batch_labels:{}'.format(batch_labels))? ?運行輸出結果為:
**************************
batch_images:['1.jpg', '2.jpg', '3.jpg']
batch_labels:[[1.0, 11.0], [2.0, 12.0], [3.0, 13.0]]
**************************
batch_images:['4.jpg', '5.jpg', '6.jpg']
batch_labels:[[4.0, 14.0], [5.0, 15.0], [6.0, 16.0]]
**************************
batch_images:['7.jpg', '8.jpg', '1.jpg']
batch_labels:[[7.0, 17.0], [8.0, 18.0], [1.0, 11.0]]
**************************
batch_images:['2.jpg', '3.jpg', '4.jpg']
batch_labels:[[2.0, 12.0], [3.0, 13.0], [4.0, 14.0]]
**************************
batch_images:['5.jpg', '6.jpg', '7.jpg']
batch_labels:[[5.0, 15.0], [6.0, 16.0], [7.0, 17.0]]
Process finished with exit code 0
?
4.參考資料:
[1]https://blog.csdn.net/happyhorizion/article/details/77894055? (五星推薦)
[2]https://blog.csdn.net/ywx1832990/article/details/78462582
[3]https://blog.csdn.net/csuzhaoqinghui/article/details/51377941
[4]《tf.data API,構建高性能 TensorFlow 輸入管道》
?
?
總結
以上是生活随笔為你收集整理的TensorFlow数据读取机制:文件队列 tf.train.slice_input_producer和 tf.data.Dataset机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV图像缩放resize各种插值
- 下一篇: Dilated/Atrous conv