TensorFlow三種常用的數據加載方式(附python演練)

簡介

TensorFlow系列後期部分正在整理,整理好後會繼續更新。在此段時間大家有什麼疑問的,可以留言,我看見了會為您解答。

今天主要說下一些在TensorFlow讀取數據部分的內容,希望對大家有幫助。文章內容參考了一篇博客:https://blog.csdn.net/lujiandong1/article/details/53376802,尊重該博主原創。

TensorFlow讀取數據有三種方式:

  • Preloaded data: 預加載數據
  • Feeding: Python: 產生數據,再把數據餵給後端
  • Reading from file: 從文件中直接讀取

注意我們這裡說的讀取數據的三種方式不是針對有多少種不同的數據格式(比如像字典結構數據;bin file 讀取數據;CSV讀取數據,從原圖讀取數據等),而是指讀取數據的不同方式。

一 預加載數據

Import tensorflow as tf
# 設計Graph
x1 = tf.constant([2,3,4])
x2 = tf.constant([4,0,1])
y = tf.add(x1,x2)
# 打開一個session,計算y
with tf.Session() as sess:
print(sess.run(y))

可以看見預加載數據的讀取方式是直接讀取定義好的數據,直接嵌入至Graph,然後將Graph傳入Session中運行。

Feeding方式加載數據

import tensorflow as tf
# 設計Graph
x1 = tf.placeholder(tf.int16)
x2 = tf.placeholder(tf.int16)
y = tf.add(x1, x2)
# 用Python產生數據
li1 = [2, 3, 4]
li2 = [4, 0, 1]
with tf.Session() as sess:
print sess.run(y, feed_dict={x1: li1, x2: li2})

Feeding方式加載數據時,是事先不知道傳進來的數據是什麼,只需要先用tf.placeholder方法定義好準備放入的數據的類型等特徵。然後同預加載數據比較,在打開一個session後將具體的數據比如這裡的li1,li2餵給我們提前用tf.placeholder定義好的位置x1,x2佔位符。這樣x1,x2這時候就會被傳入li1,li2用於進行計算了。用佔位符代替數據,待運行的時候填充數據。

前兩種方法很方便,但是如果遇到大型數據時候會很吃力。最好的辦法是在Graph定義好文件讀取的辦法,讓tensorflow自己從文件中讀取數據,並解碼成可用的樣本。

這麼說可能大家會疑惑,難道前兩種不也是讀取好文件後才傳的數據嗎?

舉個例子,預加載數據一般是定義tensorflow中的Graph裡所需要的常量,我們不會將所有的數據都像這樣去定義,只會定義graph中所需要的一些常量而已。

而Feeding讀取數據是這個樣子的:假設讀入的時間是0.1s,計算的時間是0.9s。那麼Feeding方式讀取數據,在我們之前說的識別Mnist手寫數據集例子中,先讀取一個batch的數據,假設讀取數據後計算,其中讀取數據花費0.1s,計算花費0.9s。那麼當我們進行下一次batch個數據的的讀取時,又要先花費0.1s讀取數據,再花費0.9s計算。這就意味在,在每次讀取新的數據的那個0.1s時,CPU是處於空閒狀態的。這樣就會大大降低了與運行的效率。

Reading from file方式載入數據

Reading from file方式通過將讀取數據和計算這兩個過程分別放入兩個線程中來解決CPU在讀取數據時處於閒置狀態而導致的低效率問題。

TensorFlow三種常用的數據加載方式(附python演練)

圖一

讀取線程將文件系統中的數據陸續讀入進內存的隊列中,而另外計算是另外一個線程。這樣這兩個線程同時工作,就能保證CPU一直在計算,而不會因為IO階段而閒置的問題。

TensorFlow三種常用的數據加載方式(附python演練)

圖二

$ echo -e "Alpha1,A1\nAlpha2,A2\nAlpha3,A3" > A.csv
$ echo -e "Bee1,B1\nBee2,B2\nBee3,B3" > B.csv
$ echo -e "Sea1,C1\nSea2,C2\nSea3,C3" > C.csv
#單個Reader,單個樣本
#-*- coding:utf-8 -*-
import tensorflow as tf
# 生成一個先入先出隊列和一個QueueRunner,生成文件名隊列
filenames = ['A.csv', 'B.csv', 'C.csv']
filename_queue = tf.train.string_input_producer(filenames, shuffle=False)
# 定義Reader
reader = tf.TextLineReader()
key, value = reader.read(filename_queue)
# 定義Decoder
example, label = tf.decode_csv(value, record_defaults=[['null'], ['null']])
#example_batch, label_batch = tf.train.shuffle_batch([example,label], batch_size=1, capacity=200, min_after_dequeue=100, num_threads=2)
# 運行Graph
with tf.Session() as sess:
coord = tf.train.Coordinator() #創建一個協調器,管理線程
threads = tf.train.start_queue_runners(coord=coord) #啟動QueueRunner, 此時文件名隊列已經進隊。
for i in range(10):
print example.eval(),label.eval()
coord.request_stop()
coord.join(threads)

讀取步驟:

1.創建文件名列表list (filenames)

2.創建文件名隊列創建文件名隊列,調用tf.train.string_input_producer(),參數包含:文件名列表,num_epochs(定義重複次數),shuffle(定義是否打亂文件的順序)

3.定義對應文件的閱讀器。(針對不同類型的數據文件有不同的閱讀器,如tf.ReaderBase、tf.TFRecordReader 、tf.TextLineReader 、tf.WholeFileReader 、tf.IdentityReader 、tf.FixedLengthRecordReader)

4.解析器 (同理針對不同類型的數據,如csv,圖片,bin數據等,有不同的解析器如tf.decode_csv 、tf.decode_raw 、 tf.image.decode_image)

5.預處理,對原始數據進行處理,以適應network輸入所需

6.生成batch,調用tf.train.batch() 或者 tf.train.shuffle_batch()

7.prefetch(可選)使用預加載隊列slim.prefetch_queue.prefetch_queue()

8.啟動填充隊列的線程,調用tf.train.start_queue_runners

這個函數需要傳入一個文件名list,系統會自動將它轉為一個文件名隊列。tf.train.string_input_producer還有兩個重要的參數,一個是num_epochs,表示epoch數。另外一個就是shuffle是指在一個epoch內文件的順序是否被打亂。在tensorflow中,內存隊列不需要我們自己建立,我們只需要使用reader對象從文件名隊列中讀取數據就可以了。

在我們使用tf.train.string_input_producer創建文件名隊列後,整個系統其實還是處於"停滯狀態"的,也就是說,我們文件名並沒有真正被加入到隊列中,此時如果我們開始計算,因為內存隊列中什麼也沒有,計算單元就會一直等待,導致整個系統被阻塞。使用tf.train.start_queue_runners之後,才會啟動填充隊列的線程,這時系統就不再"停滯"。此後計算單元就可以拿到數據並進行計算,整個程序也就跑起來了。

這次就說到這裡,大致介紹了tensorflow讀取數據的三種不同方式,尤其是最後一種,在針對大型數據時普遍採用的方法,內容是參考了原博主的內容。下次會著重介紹第三種數據加載方式更細節的內容。關於shuffle的執行和線程thread的使用方法。希望此次分享對大家用tensorflow處理數據讀取上有所幫助。

---

對深度學習感興趣,熱愛Tensorflow的小夥伴,歡迎關注我們的網站http://www.panchuang.net 我們的公眾號:磐創AI。


分享到:


相關文章: