2017-01-14 14 views
7

我的訓練過程使用tfrecord格式的火車& eval數據集。TFRecordReader看起來非常慢,並且多線程閱讀不起作用

我測試閱讀器的基準,只有8000記錄/秒。和io速度(見iotop命令)只有400KB-500KB/s。

我使用的protobuf的CPP版本在這裏

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/g3doc/get_started/os_setup.md#protobuf-library-related-issues

如果可能的話,提供一個最小的可重複的例子(我們通常沒有時間來閱讀數百你的代碼的行)

def read_and_decode(filename_queue): 
    reader = tf.TFRecordReader() 
    _, serialized_example = reader.read(filename_queue) 
    return serialized_example 
    serialized_example = read_and_decode(filename_queue) 
    batch_serialized_example = tf.train.shuffle_batch(
     [serialized_example], 
     batch_size=batch_size, 
     num_threads=thread_number, 
     capacity=capacity, 
     min_after_dequeue=min_after_dequeue) 
    features = tf.parse_example(
     batch_serialized_example, 
     features={ 
      "label": tf.FixedLenFeature([], tf.float32), 
      "ids": tf.VarLenFeature(tf.int64), 
      "values": tf.VarLenFeature(tf.float32), 
     }) 

您嘗試過其他嘗試的解決方案嗎?

我嘗試在tf.train.shuffle_batch中設置num_threads,但無法正常工作。

似乎當設置爲2個線程時,它工作在8000個記錄/秒,當放大線程數時,它變慢。 (我刪除了所有花費cpus的ops,只是讀取數據。)

我的服務器是24核心cpus。

+0

您受CPU或磁盤限制嗎?做時間線可視化可以幫助看到瓶頸在哪裏 –

+0

很高興再次見到你。 1)不,我不限制CPU的使用。 2)我的tfrecords文件存儲在本地磁盤驅動器中。這是表現的原因嗎? 3)我現在要做時間線。感謝您的建議。我稍後再更新。 – ericyue

+0

這裏是我的基準腳本和時間軸結果(timeline.json原始文件inlcude)https://gist.github.com/ericyue/7705407a88e643f7ab380c6658f641e8 – ericyue

回答

7

這裏的問題是,每個session.run都有一個固定的開銷,並且在隊列中填充很多小例子會很慢。

特別是,每個session.run大約100-200 usec,所以你只能做約5k-10k session.run每秒的呼叫。

如果執行Python性能分析(python -m cProfile),這個問題很明顯,但很難從時間軸配置文件或CPU配置文件中查看。

解決方法是使用enqueue_many分批向隊列中添加內容。我從https://gist.github.com/ericyue/7705407a88e643f7ab380c6658f641e8中抽取了基準,並將其修改爲按照.run的調用排列許多項目,並使速度提高了10倍。

的修改是修改電話如下:

if enqueue_many: 
    reader = tf.TFRecordReader(options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB)) 
    queue_batch = [] 
    for i in range(enqueue_many_size): 
     _, serialized_example = reader.read(filename_queue) 
     queue_batch.append(serialized_example) 
    batch_serialized_example = tf.train.shuffle_batch(
     [queue_batch], 
     batch_size=batch_size, 
     num_threads=thread_number, 
     capacity=capacity, 
     min_after_dequeue=min_after_dequeue, 
     enqueue_many=True) 

對於完整的源代碼,請點擊這裏: https://github.com/yaroslavvb/stuff/blob/master/ericyue-slowreader/benchmark.py

很難優化它去得更快,因爲現在大部分的時間是花在隊列操作上。查看stripped down版本,它只是將整數添加到隊列中,您也可以獲得類似的速度,並且在查看時間軸時,時間花在出隊操作上。

enter image description here

每個出隊運算大約需要60微秒,但有平均5並行捉迷藏,讓您得到12微秒每出隊。所以這意味着你會在最好的情況下每秒鐘得到200k個例子。

5

這裏有雅羅斯拉夫的回答一個簡單的加速建設:

Tensorflow有一個內置的功能,tf.TFRecordReader.read_up_to,在每個session.run()調用讀取多個記錄,從而消除造成多次調用多餘開銷。

enqueue_many_size = SOME_ENQUEUE_MANY_SIZE 
reader = tf.TFRecordReader(options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB)) 
_, queue_batch = reader.read_up_to(filename_queue, enqueue_many_size) 
batch_serialized_example = tf.train.shuffle_batch(
    [queue_batch], 
    batch_size=batch_size, 
    num_threads=thread_number, 
    capacity=capacity, 
    min_after_dequeue=min_after_dequeue, 
    enqueue_many=True) 

與雅羅斯拉夫的答案,你需要設置enqueue_many=True使批處理功能知道它正在接受多個記錄。

這在我的用例中非常快。

+0

謝謝!這對我來說也非常快。用io解決了我所有的速度問題。 – Pekka

1

增編雅羅斯拉夫的回答是: 您可以使用tf.python_io.tf_record_iterator通過以實例來遍歷它們添加到列表中,你可以傳遞給tf.train.shuffle_batchenqueue_many=true

queue_batch = [] 
for serialized_example in tf.python_io.tf_record_iterator(filename,options = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.ZLIB)): 
    queue_batch.append(serialized_example) 
batch_serialized_example = tf.train.shuffle_batch(
    [queue_batch], 
    batch_size=batch_size, 
    num_threads=thread_number, 
    capacity=capacity, 
    min_after_dequeue=min_after_dequeue, 
    enqueue_many=True) 

似乎試圖遍歷使用reader.read()的示例將導致每批讀取一次。即第n批將是batch_num副本的第n記錄而不是batch_num許多獨特的記錄。