1. 程式人生 > >tensorflow的數據輸入

tensorflow的數據輸入

bat res 數據 1-1 ner PE 結果 produce ice

tensorflow有兩種數據輸入方法,比較簡單的一種是使用feed_dict,這種方法在畫graph的時候使用placeholder來站位,在真正run的時候通過feed字典把真實的輸入傳進去。比較簡單不再介紹。

比較惱火的是第二種方法,直接從文件中讀取數據(其實第一種也可以我們自己從文件中讀出來之後使用feed_dict傳進去,但方法二tf提供很完善的一套類和函數形成一個類似pipeline一樣的讀取線):
1.使用tf.train.string_input_producer函數把我們需要的全部文件打包為一個tf內部的queue類型,之後tf開文件就從這個queue中取目錄了,要註意一點的是這個函數的shuffle參數默認是True,也就是你傳給他文件順序是1234,但是到時候讀就不一定了,我一開始每次跑訓練第一次叠代的樣本都不一樣,還納悶了好久,就是這個原因。

files_in = ["./data/data_batch%d.bin" % i for i in range(1, 6)]
files = tf.train.string_input_producer(files_in)

2.搞一個reader,不同reader對應不同的文件結構,比如度bin文件tf.FixedLengthRecordReader就比較好,因為每次讀等長的一段數據。如果要讀什麽別的結構也有相應的reader。

reader = tf.FixedLengthRecordReader(record_bytes=1+32*32*3)

3.用reader的read方法,這個方法需要一個IO類型的參數,就是我們上邊string_input_producer輸出的那個queue了,reader從這個queue中取一個文件目錄,然後打開它經行一次讀取,reader的返回是一個tensor(這一點很重要,我們現在寫的這些讀取代碼並不是真的在讀數據,還是在畫graph,和定義神經網絡是一樣的,這時候的操作在run之前都不會執行,這個返回的tensor也沒有值,他僅僅代表graph中的一個結點)。

key, value = reader.read(files)

4.對這個tensor做些數據與處理,比如CIFAR1-10中label和image數據是糅在一起的,這裏用slice把他們切開,切成兩個tensor(註意這個兩個tensor是對應的,一個image對一個label,對叉了後便訓練就完了),然後對image的tensor做data augmentation。

data = tf.decode_raw(value, tf.uint8)
label = tf.cast(tf.slice(data, [0], [1]), tf.int64)
raw_image = tf.reshape(tf.slice(data, [1], [32*32*3]), [3, 32, 32])
image = tf.cast(tf.transpose(raw_image, [1, 2, 0]), tf.float32)

lr_image = tf.image.random_flip_left_right(image)
br_image = tf.image.random_brightness(lr_image, max_delta=63)
rc_image = tf.image.random_contrast(br_image, lower=0.2, upper=1.8)

std_image = tf.image.per_image_standardization(rc_image)

5.這時候可以發現,這個tensor代表的是一個樣本([高管道]),但是訓練網絡的時候的輸入一般都是一推樣本([樣本數寬*管道]),我們就要用tf.train.batch或者tf.train.shuffle_batch這個函數把一個一個小樣本的tensor打包成一個高一維度的樣本batch,這些函數的輸入是單個樣本,輸出就是4D的樣本batch了,其內部原理似乎是創建了一個queue,然後不斷調用你的單樣本tensor獲得樣本,直到queue裏邊有足夠的樣本,然後一次返回一堆樣本,組成樣本batch。

images, labels = tf.train.batch([std_image, label],
                           batch_size=100,
                           num_threads=16,
                           capacity=int(50000* 0.4 + 3 * batch_size))

5.事實上一直到上一部的images這個tensor,都還沒有真實的數據在裏邊,我們必須用Session run一下這個4D的tensor,才會真的有數據出來。這個原理就和我們定義好的神經網絡run一下出結果一樣,你一run這個4D tensor,他就會順著自己的operator找自己依賴的其他tensor,一路最後找到最開始reader那裏。

除了上邊講的原理,其中還要註意幾點
1.tf.train.start_queue_runners(sess=sess)這一步一定要運行,且其位置要在定義好讀取graph之後,在真正run之前,其作用是把queue裏邊的內容初始化,不跑這句一開始string_input_producer那裏就沒用,整個讀取流水線都沒用了。

training_images = tf.train.batch(XXXXXXXXXXXXXXX)
tf.train.start_queue_runners(sess=self.sess)
real_images = sess.run(training_images)

2.image和label一定要一起run,要記清楚我們的image和label是在一張graph裏邊的,跑一次那個graph,這兩個tensor都會出結果,且同一次跑出來的image和label才是對應的,如果你run兩次,第一次為了拿image第二次為了拿label,那整個就叉了,因為第一次跑出來第0到100號image和0到100號label,第二次跑出來第100到200的image和第100到200的label,你拿到了0~100的image和100~200的label,整個樣本分類全不對,最後網絡肯定跑不出結果。

training_images, training_labels = read_image()
tf.train.start_queue_runners(sess=self.sess)
real_images = sess.run(training_images) # 讀出來是真的圖片,但是和label對不上
real_labels = sess.run(training_labels) # 讀出來是真的label,但是和image對不上

# 正確調用方法,通過跑一次graph,將成套的label和image讀出來
real_images, real_labels = sess.run([training_images, training_labels])

tensorflow的數據輸入