TensorFlow:Skipping cancelled en
今天运行TensorFlow的代码,没运行完一个epoch就直接报错崩掉了,然后定位错误,发现了一个警告信息如下:
_2_index/fraction_of_32_full/fraction_of_32_full:Skipping cancelled enqueue attempt with queue not closed
接着代码到后面就崩掉了,报错的信息如下:
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"]()]]
大致的意思是,在调用batch_join的时候,队列需要64个元素(一个batch_size大小),但是队列中只有59个元素,导致了OutOffRangeError。设置tf.train.batch_join函数中的allow_smaller_final_batch为True可以避免这样的错误发生,不过这会到导致batch_join函数获得的数据的size是不确定的,会带来一系列其他的影响。
在追踪错误发生的过程中,我注意到上述的警告信息,其整个报错和警告关联的业务代码简化版大致如下:
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相关,是从input_queue中获取元素处理的一个list(涉及每个线程处理的具体业务逻辑,因此省略)。
而警告信息来自于其中某一个队列,可以看出其enqueue的入队操作没有完成,然后在运行中我尝试打印出deueu_op的结果,其结果无误,每次出对的索引数量都是batch_size*batch_num个,因而问题出现在enque_op部分,猜测是enqueue_many过程没有完成,队列就关闭了。
经过反复检查代码,发现可能导致队列关闭的代码如下:
run_config= tf.ConfigProto()
run_config.operation_timeout_in_ms= 10000
这段代码为TensorFlow所有的阻塞操作定义了一个毫秒级别的超时时间,猜测由于是非主线程的其他线程进行enqueue_many操作,然后入队过程中超时,导致了队列被关闭,但是没有抛出异常到主线程,导致主线程继续运行直至报错。
解决办法也很简单,就是不设置超时时间即可。
上述的问题解决过程中可以看到几点:
1.虽然调用的是enqueue_many操作,但是具体实现的时候,enqueue_many也可能是一个一个元素往队列中存放的。
2.TensorFlow有可能忽略掉非主线程的异常的抛出,因而在运行调试中,要注意一些警告信息,或者自己指定处理非主线程的其他线程的异常信息。
最后,如果上述无法解决你的Skipping cancelled enqueue attempt with queue not closed的问题,那么尝试在Session结束的地方,加入
coord.request_stop()
coord.joint(thread)
这个解决办法来自:http://qiita.com/7of9/items/3b9364444418e128c92a
或者是尝试更新TensorFlow的版本,有人提及这个可能涉及到TensorFlow的版本BUG,详情见:https://github.com/TensorBox/TensorBox/issues/25