Step 0:導入必要的庫
import tensorflow as tfimport os
Step 1:獲取圖片文件名以及對應的標簽
首先是讀取給定路徑下所有圖片的名稱以及對應的標簽。os.listdir(file_dir)可以列出file_dir路徑下所有文件名;str.split(sep='.')將字符串str以點(.)分割。
# you need to change this to your data directory train_dir = 'E:\\data\\Dog_Cat\\train\\'#Windows #train_dir = '/home/kevin/tensorflow/cats_vs_dogs/data/train/'#linux #獲取給定路徑下圖片名及其對應的標簽 def get_files(file_dir): ''' Args: file_dir: file directory Returns: list of images and labels ''' images=[] labels=[] for file in os.listdir(file_dir): name = file.split(sep='.') if name[0]=='cat': images.append(file_dir + file) labels.append(0) else: images.append(file_dir + file) labels.append(1) return images, labels
step3:分批次讀取圖片
由於圖片數量太多,如果一次性將全部圖片讀入內存的話,可能會造成內存不夠用的情況,因此需要分批次地將圖片讀入內存中。我們可以利用tensorflow的tf.train.slice_input_producer函數,利用隊列的思想實現。
def get_batch(image, label, image_W, image_H, batch_size, capacity): ''' Args: image: list type label: list type image_W: image width image_H: image height batch_size: batch size capacity: the maximum elements in queue Returns: image_batch: 4D tensor [batch_size, width, height, 3], dtype=tf.float32 label_batch: 1D tensor [batch_size], dtype=tf.int32 ''' #將python的list數據類型轉換為tensorflow的數據類型 #image = tf.cast(image, tf.string) #label = tf.cast(label, tf.int32) image = tf.convert_to_tensor(image, dtype=tf.string) label = tf.convert_to_tensor(label, dtype=tf.int32) # make an input queue 生成一個隊列,shuffle=True即將圖片打亂放入隊列中 input_queue = tf.train.slice_input_producer([image, label],shuffle=True) label = input_queue[1] #獲取label對應的隊列 image_contents = tf.read_file(input_queue[0])#讀取圖片 image = tf.image.decode_jpeg(image_contents, channels=3)#解碼jpg格式圖片 ###################################### # data argumentation should go to here ###################################### #圖片resize image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H) # if you want to test the generated batches of images, you might want to comment the following line. # 如果想看到正常的圖片,請注釋掉111行(標准化)和 126行(image_batch = tf.cast(image_batch, tf.float32)) # 訓練時不要注釋掉! #數據標准化 image = tf.image.per_image_standardization(image) #Creates batches of tensors in tensors. image_batch, label_batch = tf.train.batch([image, label], batch_size= batch_size, num_threads= 2, #線程數設置 capacity = capacity) #隊列中最多能容納的元素 #you can also use shuffle_batch # image_batch, label_batch = tf.train.shuffle_batch([image,label], # batch_size=BATCH_SIZE, # num_threads=64, # capacity=CAPACITY, # min_after_dequeue=CAPACITY-1) image_batch = tf.cast(image_batch, tf.float32) return image_batch, label_batch
首先,我們需要先把image和label轉換成tensorflow的tensor相關數據類型;其次,我們需要將images和labels放入隊列中,需要注意的是要設置shuffle=True將順序打亂(默認shuffle=True)。然后通過tf.read_file和tf.image.decode_jpeg函數讀取圖片已經將其進行解碼。接下來就是重新調整圖片大小(通過crop或者pad的方式實現)和將圖像歸一化。最后就是利用tf.train.batch讀取隊列中batch_size個數的圖像及其對應的標簽。
測試:
接下來就是測試上面寫的代碼是否正確。
import matplotlib.pyplot as plt BATCH_SIZE = 4 CAPACITY = 256 #圖片resize后的大小 IMG_W = 208 IMG_H = 208 #train_dir = '/home/kevin/tensorflow/cats_vs_dogs/data/train/' train_dir = 'E:\\data\\Dog_Cat\\train\\' image_list, label_list = get_files(train_dir) image_batch, label_batch = get_batch(image_list, label_list, IMG_W, IMG_H, BATCH_SIZE, CAPACITY) with tf.Session() as sess:#在會話中運行程序 i = 0 coord = tf.train.Coordinator()#線程協調者 threads = tf.train.start_queue_runners(coord=coord) try: # Check if stop was requested. while not coord.should_stop() and i<1: img, label = sess.run([image_batch, label_batch]) print(img[0,:,:,:]) # just test one batch for j in range(BATCH_SIZE): print('label: %d' %label[j]) plt.imshow(img[j,:,:,:]) plt.show() i+=1 except tf.errors.OutOfRangeError:#當讀取完列隊中所有數據時,拋出異常 print('done!') finally: #Request that the threads stop.After this is called, calls to should_stop() will return True. coord.request_stop() coord.join(threads)
首先是一些參數的設置,然后通過get_files和get_batch建立等下需要運行的Graph。由於讀取圖片時,涉及到隊列已經多線程,因此需要tf.train.Coordinator來產生一個線程協調者,主要作用是協調線程是否終止(This class implements a simple mechanism to coordinate the termination of a set of threads.),更詳細的用法可以參考下文的函數介紹和官網的說明。然后調用tf.train.start_queue_runners來啟動之前定義好的Graph中所有的線程。
最后的效果:
函數注釋:
1)np.hstack:
函數原型:numpy.hstack(tup)
tup可以是python中的元組(tuple)、列表(list),或者numpy中數組(array),函數作用是將tup在水平方向上(按列順序)合並。
舉例:
a=[1,2,3]
b=[4,5,6]
print(np.hstack((a,b)))
輸出:[1 2 3 4 5 6 ]
2)transpose()
函數原型:numpy.transpose(a, axes=None)
作用:將輸入的array轉置,並返回轉置后的array
舉例:
>>> x = np.arange(4).reshape((2,2))
>>> x
array([[0, 1],
[2, 3]])
>>> np.transpose(x)
array([[0, 2],
[1, 3]])
注:
image_list = ["D:\\1.jpg","D:\\2.jpg","D:\\3.jpg"] label_list = [1,0,1] temp = np.array([image_list, label_list]) print(temp) #輸出: #[['D:\\1.jpg' 'D:\\2.jpg' 'D:\\3.jpg'] # ['1' '0' '1']] temp = temp.transpose() print(temp) #輸出: #[['D:\\1.jpg' '1'] # ['D:\\2.jpg' '0'] # ['D:\\3.jpg' '1']] np.random.shuffle(temp) print(temp) #輸出: #[['D:\\2.jpg' '0'] # ['D:\\1.jpg' '1'] # ['D:\\3.jpg' '1']]
3)tf.cast
cast(
x,
dtype,
name=None
)
將x轉換為dtype數據類型的張量。
舉例:
x = tf.constant([1.8, 2.2], dtype=tf.float32) tf.cast(x, tf.int32) # [1, 2], dtype=tf.int32
4)tf.train.slice_input_producer
slice_input_producer(
tensor_list,
num_epochs=None,
shuffle=True,
seed=None,
capacity=32,
shared_name=None,
name=None
)
Produces a slice of each Tensor in tensor_list.
Implemented using a Queue -- a QueueRunner for the Queue is added to the current Graph's QUEUE_RUNNERcollection.
Args:
- tensor_list: A list of Tensor objects. Every Tensor in tensor_list must have the same size in the first dimension.
- num_epochs: An integer (optional). If specified, slice_input_producer produces each slice num_epochs times before generating an OutOfRange error. If not specified, slice_input_producer can cycle through the slices an unlimited number of times.
- shuffle: Boolean. If true, the integers are randomly shuffled within each epoch.
- seed: An integer (optional). Seed used if shuffle == True.
- capacity: An integer. Sets the queue capacity.
- shared_name: (optional). If set, this queue will be shared under the given name across multiple sessions.
- name: A name for the operations (optional).
Returns:
A list of tensors, one for each element of tensor_list. If the tensor in tensor_list has shape [N, a, b, .., z], then the corresponding output tensor will have shape [a, b, ..., z].
Raises:
- ValueError: if slice_input_producer produces nothing from tensor_list.
簡單說來,就是生成一個隊列,該隊列的容量為capacity。
5)tf.read_file
作用:讀取輸入文件的內容並輸出
6)tf.image.decode_jpeg
作用:將JPEG格式編碼的圖片解碼成uint8數據類型的tensor。
7)tf.image.resize_image_with_crop_or_pad
resize_image_with_crop_or_pad(
image,
target_height,
target_width
)
將圖片大小調整為target_height和target_width大小。若原圖像比較大,則以中心點為裁剪。若原圖像比較小,則在短邊補零,使得大小為target_height和target_width。
8)tf.image.per_image_standardization
線性尺度變化,使得原圖像具有零均值,單位范數( zero mean and unit norm)。
也就是計算(x - mean) / adjusted_stddev,其中mean是圖像中所有像素的平均值,adjusted_stddev = max(stddev, 1.0/sqrt(image.NumElements()))
。
adjusted_stddev
是圖像中所有像素的標准差,max作用為防止stddev的值為0。
9)tf.train.batch
batch(
tensors,
batch_size,
num_threads=1,
capacity=32,
enqueue_many=False,
shapes=None,
dynamic_pad=False,
allow_smaller_final_batch=False,
shared_name=None,
name=None
)
作用:Creates batches of tensors in tensors
.即從輸入的tensors
獲取
batch_size
大小的數據。
該函數是利用隊列實現的。因此在使用的時候需要使用QueueRunner啟動隊列。
10)tf.train.Coordinator()
作用:線程協調者
任意一個線程可以調用coord.request_stop()來使所有線程停止。為了達到這一目的,每個線程必須定期檢查coord.should_stop()。只要coord.request_stop()一被調用,那么coord.should_stop()馬上返回True。
因此,一個典型的 thread running with a coordinator如下:
while not coord.should_stop(): ...do some work...
11)tf.train.start_queue_runners
作用:啟動graph中所有的隊列。
說明:
代碼來自:https://github.com/kevin28520/My-TensorFlow-tutorials,略有修改
函數作用主要參考tensorflow官網。https://www.tensorflow.org/versions/master/api_docs/
本文中修改后的代碼可以在這里下載:https://github.com/hjl240/dog_vs_cat