今天運(yùn)行TensorFlow的代碼,沒(méi)運(yùn)行完一個(gè)epoch就直接報(bào)錯(cuò)崩掉了,然后定位錯(cuò)誤,發(fā)現(xiàn)了一個(gè)警告信息如下:
_2_index/fraction_of_32_full/fraction_of_32_full:Skipping cancelled enqueue attempt with queue not closed
接著代碼到后面就崩掉了,報(bào)錯(cuò)的信息如下:
tensorflow.python.framework.errors_impl.OutOfRangeError:FIFOQueue '_0_batch_join/fifo_queue' is closed and has insufficient elements(requested 64, current size 59)
[[Node: batch_join =QueueDequeueManyV2[component_types=[DT_FLOAT, DT_INT64], timeout_ms=-1,_device="/job:localhost/replica:0/task:0/cpu:0"](batch_join/fifo_queue,batch_join/n)]]
[[Node: batch_join/_2179 =_Recv[client_terminated=false,recv_device="/job:localhost/replica:0/task:0/gpu:0",send_device="/job:localhost/replica:0/task:0/cpu:0",send_device_incarnation=1, tensor_name="edge_12_batch_join",tensor_type=DT_INT64,_device="/job:localhost/replica:0/task:0/gpu:0"]()]]
大致的意思是,在調(diào)用batch_join的時(shí)候,隊(duì)列需要64個(gè)元素(一個(gè)batch_size大?。?,但是隊(duì)列中只有59個(gè)元素,導(dǎo)致了OutOffRangeError。設(shè)置tf.train.batch_join函數(shù)中的allow_smaller_final_batch為True可以避免這樣的錯(cuò)誤發(fā)生,不過(guò)這會(huì)到導(dǎo)致batch_join函數(shù)獲得的數(shù)據(jù)的size是不確定的,會(huì)帶來(lái)一系列其他的影響。
在追蹤錯(cuò)誤發(fā)生的過(guò)程中,我注意到上述的警告信息,其整個(gè)報(bào)錯(cuò)和警告關(guān)聯(lián)的業(yè)務(wù)代碼簡(jiǎn)化版大致如下:
indices_que =tf.train.range_input_producer(range_size, name='index')
deque_op =indices_que.dequeue_many(self.batch_size*self.batch_num,'index_dequeue')
input_queue = tf.FIFOQueue(capacity=100000,dtypes=[tf.string, tf.int64], shapes=[(1,), (1,)], name='input_que')
enque_op = input_queue.enqueue_many([samples],name='enque_op')
batch_sample= tf.train.batch_join(input_queue_list,batch_size= batch_size,enqueue_many=False,capacity=4*num_threads*self.batch_size,allow_smaller_final_batch=False)
其中input_queue_list與input_queue相關(guān),是從input_queue中獲取元素處理的一個(gè)list(涉及每個(gè)線程處理的具體業(yè)務(wù)邏輯,因此省略)。
而警告信息來(lái)自于其中某一個(gè)隊(duì)列,可以看出其enqueue的入隊(duì)操作沒(méi)有完成,然后在運(yùn)行中我嘗試打印出deueu_op的結(jié)果,其結(jié)果無(wú)誤,每次出對(duì)的索引數(shù)量都是batch_size*batch_num個(gè),因而問(wèn)題出現(xiàn)在enque_op部分,猜測(cè)是enqueue_many過(guò)程沒(méi)有完成,隊(duì)列就關(guān)閉了。
經(jīng)過(guò)反復(fù)檢查代碼,發(fā)現(xiàn)可能導(dǎo)致隊(duì)列關(guān)閉的代碼如下:
run_config= tf.ConfigProto()
run_config.operation_timeout_in_ms= 10000
這段代碼為TensorFlow所有的阻塞操作定義了一個(gè)毫秒級(jí)別的超時(shí)時(shí)間,猜測(cè)由于是非主線程的其他線程進(jìn)行enqueue_many操作,然后入隊(duì)過(guò)程中超時(shí),導(dǎo)致了隊(duì)列被關(guān)閉,但是沒(méi)有拋出異常到主線程,導(dǎo)致主線程繼續(xù)運(yùn)行直至報(bào)錯(cuò)。
解決辦法也很簡(jiǎn)單,就是不設(shè)置超時(shí)時(shí)間即可。
上述的問(wèn)題解決過(guò)程中可以看到幾點(diǎn):
1.雖然調(diào)用的是enqueue_many操作,但是具體實(shí)現(xiàn)的時(shí)候,enqueue_many也可能是一個(gè)一個(gè)元素往隊(duì)列中存放的。
2.TensorFlow有可能忽略掉非主線程的異常的拋出,因而在運(yùn)行調(diào)試中,要注意一些警告信息,或者自己指定處理非主線程的其他線程的異常信息。
最后,如果上述無(wú)法解決你的Skipping cancelled enqueue attempt with queue not closed的問(wèn)題,那么嘗試在Session結(jié)束的地方,加入
coord.request_stop()
coord.joint(thread)
這個(gè)解決辦法來(lái)自:http://qiita.com/7of9/items/3b9364444418e128c92a
或者是嘗試更新TensorFlow的版本,有人提及這個(gè)可能涉及到TensorFlow的版本BUG,詳情見(jiàn):https://github.com/TensorBox/TensorBox/issues/25