利用Tensorflow的隊列多線程讀取數(shù)據(jù)

在tensorflow中马昙,有三種方式輸入數(shù)據(jù)

1. 利用feed_dict送入numpy數(shù)組

2. 利用隊列從文件中直接讀取數(shù)據(jù)

3. 預(yù)加載數(shù)據(jù)

其中第一種方式很常用,在tensorflow的MNIST訓練源碼中可以看到攒暇,通過feed_dict={}子房,可以將任意數(shù)據(jù)送入tensor中池颈。

第二種方式相比于第一種,速度更快每币,可以利用多線程的優(yōu)勢把數(shù)據(jù)送入隊列琢歇,再以batch的方式出隊李茫,并且在這個過程中可以很方便地對圖像進行隨機裁剪、翻轉(zhuǎn)秸侣、改變對比度等預(yù)處理宠互,同時可以選擇是否對數(shù)據(jù)隨機打亂,可以說是非常方便搏色。該部分的源碼在tensorflow官方的CIFAR-10訓練源碼中可以看到券册,但是對于剛學習tensorflow的人來說垂涯,比較難以理解航邢,本篇博客就當成我調(diào)試完成后寫的一篇總結(jié)翠忠,以防自己再忘記具體細節(jié)。

-------------------------

## 讀取CIFAR-10數(shù)據(jù)集##

按照第一種方式的話当娱,CIFAR-10的讀取只需要寫一段非常簡單的代碼即可將測試集與訓練集中的圖像分別讀瓤颊ァ:

```python

path = 'E:\Dataset\cifar-10\cifar-10-batches-py'

# extract train examples

num_train_examples = 50000

x_train = np.empty((num_train_examples, 32, 32, 3), dtype='uint8')

y_train = np.empty((num_train_examples), dtype='uint8')

for i in range(1, 6):

fpath = os.path.join(path, 'data_batch_' + str(i))

(x_train[(i - 1) * 10000: i * 10000, :, :, :], y_train[(i - 1) * 10000: i * 10000]) = load_and_decode(fpath)

# extract test examples

fpath = os.path.join(path, 'test_batch')

x_test, y_test = load_and_decode(fpath)

return x_train, y_train, x_test, np.array(y_test)

```

其中l(wèi)oad_and_decode函數(shù)只需要按照CIFAR-10官網(wǎng)給出的方式decode就行河质,最終返回的x_train是一個[50000, 32, 32, 3]的ndarray,但對于ndarray來說散休,進行預(yù)處理就要麻煩很多乐尊,為了取mini-SGD的batch扔嵌,還自己寫了一個類,通過調(diào)用train_set.next_batch()函數(shù)來取胁勺,總而言之就是什么都要自己動手独旷,效率確實不高

但對于第二種方式势告,讀取起來就要麻煩很多抚恒,但使用起來,又快又方便

首先回溺,把CIFAR-10的測試集文件讀取出來遗遵,生成文件名列表

```python

path = 'E:\Dataset\cifar-10\cifar-10-batches-py'

filenames = [os.path.join(path, 'data_batch_%d' % i) for i in range(1, 6)]

```

有了列表以后,利用tf.train.string_input_producer函數(shù)生成一個讀取隊列

```python

filename_queue = tf.train.string_input_producer(filenames)

```

接下來允粤,我們調(diào)用read_cifar10函數(shù)翼岁,得到一幅一幅的圖像琅坡,該函數(shù)的代碼如下:

```python

def read_cifar10(filename_queue):

label_bytes = 1

IMAGE_SIZE = 32

CHANNELS = 3

image_bytes = IMAGE_SIZE*IMAGE_SIZE*3

record_bytes = label_bytes+image_bytes

# define a reader

reader = tf.FixedLengthRecordReader(record_bytes)

key, value = reader.read(filename_queue)

record_bytes = tf.decode_raw(value, tf.uint8)

label = tf.strided_slice(record_bytes, [0], [label_bytes])

depth_major = tf.reshape(tf.strided_slice(record_bytes, [label_bytes],

[label_bytes + image_bytes]),

[CHANNELS, IMAGE_SIZE, IMAGE_SIZE])

image = tf.transpose(depth_major, [1, 2, 0])

return image, label

```

第9行榆俺,定義一個reader,來讀取固定長度的數(shù)據(jù)陪捷,這個固定長度是由CIFAR-10數(shù)據(jù)集圖片的存儲格式?jīng)Q定的诺擅,1byte的標簽加上32 *32 *3長度的圖像掀虎,3代表RGB三通道,由于圖片的是按[channel, height, width]的格式存儲的烹玉,為了變?yōu)槌S玫腫height, width, channel]維度二打,需要在17行reshape一次圖像,最終我們提取出了一副完整的圖像與對應(yīng)的標簽

## 對圖像進行預(yù)處理

我們?nèi)〕龅膇mage與label均為tensor格式症杏,因此預(yù)處理將變得非常簡單

```python

if not distortion:

IMAGE_SIZE = 32

else:

IMAGE_SIZE = 24

# 隨機裁剪為24*24大小

distorted_image = tf.random_crop(tf.cast(image, tf.float32), [IMAGE_SIZE, IMAGE_SIZE, 3])

# 隨機水平翻轉(zhuǎn)

distorted_image = tf.image.random_flip_left_right(distorted_image)

# 隨機調(diào)整亮度

distorted_image = tf.image.random_brightness(distorted_image, max_delta=63)

# 隨機調(diào)整對比度

distorted_image = tf.image.random_contrast(distorted_image, lower=0.2, upper=1.8)

# 對圖像進行白化操作厉颤,即像素值轉(zhuǎn)為零均值單位方差

float_image = tf.image.per_image_standardization(distorted_image)

```

distortion是定義的一個輸入布爾型變量凡简,默認為True,表示是否對圖像進行處理

## 填充隊列與隨機打亂

調(diào)用tf.train.shuffle_batch或tf.train.batch函數(shù)司抱,以tf.train.shuffle_batch為例黎烈,函數(shù)的定義如下:

```python

def 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):

```

tensors表示輸入的張量(tensor)照棋,batch_size表示要輸出的batch的大小,capacity表示隊列的容量肉拓,即大小梳庆,min_after_dequeue表示出隊操作后隊列中的最小元素數(shù)量膏执,這個值是要小于隊列的capacity的,通過調(diào)整min_after_dequeue與capacity兩個變量欺栗,可以改變數(shù)據(jù)被隨機打亂的程度征峦,num_threads表示使用的線程數(shù)栏笆,只要取大于1的數(shù),隊列的效率就會高很多蚜枢。

通常情況下针饥,我們只需要輸入以上幾個變量即可丁眼,在CIFAR-10_input.py中,谷歌給出的代碼是這樣寫的:

```python

if shuffle:

images, label_batch = tf.train.shuffle_batch([image, label], batch_size,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? min_queue_examples+3*batch_size,

min_queue_examples, num_preprocess_threads)

else:

images, label_batch = tf.train.batch([image, label], batch_size,

num_preprocess_threads,

min_queue_examples + 3 * batch_size)

```

min_queue_examples由以下方式得到:

```python

min_fraction_of_examples_in_queue = 0.4

min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN

*min_fraction_of_examples_in_queue)

```

當然嵌施,這些值均可以自己隨意設(shè)置,

最終得到的images吗伤,labels(label_batch)硫眨,即為shape=[128, 32, 32, 3]的tensor礁阁,其中128為默認batch_size。

## 激活隊列與處理異常

得到了images和labels兩個tensor后丹鸿,我們便可以把這兩個tensor送入graph中進行運算了

```python

# input tensor

img_batch, label_batch = cifar10_input.tesnsor_shuffle_input(batch_size)

# build graph that computes the logits predictions from the inference model

logits, predicts = train.inference(img_batch, keep_prob)

# calculate loss

loss = train.loss(logits, label_batch)

```

定義sess=tf.Session()后靠欢,運行sess.run()铜跑,然而你會發(fā)現(xiàn)并沒有輸出锅纺,程序直接掛起了,仿佛死掉了一樣

原因是這樣的坦弟,雖然我們在數(shù)據(jù)流圖中加入了隊列官地,但只有調(diào)用tf.train.start_queue_runners()函數(shù)后区丑,數(shù)據(jù)才會動起來,被負責輸入管道的線程填入隊列可霎,否則隊列將會掛起宴杀。

OK旺罢,我們調(diào)用函數(shù)绢记,讓隊列運行起來

```python

with tf.Session(config=run_config) as sess:

sess.run(init_op) # intialization

queue_runner = tf.train.start_queue_runners(sess)

for i in range(10):

b1, b2 = sess.run([img_batch, label_batch])

print(b1.shape)

```

在這里為了測試蠢熄,我們?nèi)?0次輸出炉旷,看看輸出的batch1的維度是否正確

![console_output](E:\blog\1\微信截圖_20171219164138.png)

10個batch的維度均為正確的签孔,但是tensorflow卻報了錯,錯誤的文字內(nèi)容如下:

> 2017-12-19 16:40:56.429687: W C:\tf_jenkins\home\workspace\rel-win\M\windows-gpu\PY\36\tensorflow\core\kernels\queue_base.cc:295]? _ 0 _ input_producer: **Skipping cancelled enqueue attempt with queue not closed**

簡單地看一下窘行,大致意思是說我們的隊列里還有數(shù)據(jù)饥追,但是程序結(jié)束了,拋出了異常罐盔,因此但绕,我們還需要定義一個Coordinator,也就是協(xié)調(diào)器來處理異常

Coordinator有3個主要方法:

1. tf.train.Coordinator.should_stop() 如果線程應(yīng)該停止惶看,返回True

2. tf.train.Coordinator.request_stop() 請求停止線程

3. tf.train.Coordinator.join() 等待直到指定線程停止

首先捏顺,定義協(xié)調(diào)器

```python

coord = tf.train.Coordinator()

```

將協(xié)調(diào)器應(yīng)用于QueueRunner

```python

queue_runner = tf.train.start_queue_runners(sess, coord=coord)

```

結(jié)束數(shù)據(jù)的訓練或測試后,關(guān)閉線程

```python

coord.request_stop()

coord.join(queue_runner)

```

最終的sess代碼段如下:

```python

coord = tf.train.Coordinator()

with tf.Session(config=run_config) as sess:

sess.run(init_op)

queue_runner = tf.train.start_queue_runners(sess, coord=coord)

for i in range(10):

b1, b2 = sess.run([img_batch, label_batch])

print(b1.shape)

coord.request_stop()

coord.join(queue_runner)

```

得到的輸出結(jié)果為:

![console_output](E:\blog\1\微信截圖_20171219165409.png)

完美解決草丧,利用img_batch與label_batch,把tensor送入graph中莹桅,就可以享受tensorflow帶來的訓練樂趣了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昌执,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诈泼,更是在濱河造成了極大的恐慌懂拾,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铐达,死亡現(xiàn)場離奇詭異岖赋,居然都是意外死亡,警方通過查閱死者的電腦和手機瓮孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門唐断,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杭抠,你說我怎么就攤上這事脸甘。” “怎么了偏灿?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵丹诀,是天一觀的道長。 經(jīng)常有香客問我,道長铆遭,這世上最難降的妖魔是什么硝桩? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮枚荣,結(jié)果婚禮上碗脊,老公的妹妹穿的比我還像新娘。我一直安慰自己棍弄,他們只是感情好望薄,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布疟游。 她就那樣靜靜地躺著呼畸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颁虐。 梳的紋絲不亂的頭發(fā)上蛮原,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音另绩,去河邊找鬼儒陨。 笑死,一個胖子當著我的面吹牛笋籽,可吹牛的內(nèi)容都是我干的蹦漠。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼车海,長吁一口氣:“原來是場噩夢啊……” “哼笛园!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侍芝,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤研铆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后州叠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棵红,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年咧栗,在試婚紗的時候發(fā)現(xiàn)自己被綠了逆甜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡致板,死狀恐怖交煞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情可岂,我是刑警寧澤错敢,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響稚茅,放射性物質(zhì)發(fā)生泄漏纸淮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一亚享、第九天 我趴在偏房一處隱蔽的房頂上張望咽块。 院中可真熱鬧,春花似錦欺税、人聲如沸侈沪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亭罪。三九已至,卻和暖如春歼秽,著一層夾襖步出監(jiān)牢的瞬間应役,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工燥筷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留箩祥,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓肆氓,卻偏偏與公主長得像袍祖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谢揪,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容