我正在使用tensorflow 0.10,我正在对official HowTo on reading data中的示例进行基准测试。本文介绍了使用相同的MNIST示例将数据移动到tensorflow的不同方法。
我对结果感到惊讶,我想知道是否有人有足够的低层次理解来解释正在发生的事情。
在HowTo中,基本上有3种方法可以读取数据:
Feeding
:在python中构建小批量并使用sess.run(..., feed_dict={x: mini_batch})
Reading from files
:使用tf
操作打开文件并创建小批量。 (在python中绕过处理数据。)Preloaded data
:将所有数据加载到单个tf
变量或常量中,并使用tf
函数将其分解为迷你批次。变量或常量固定到cpu,而不是gpu。我用来运行基准测试的脚本可以在tensorflow中找到:
Feeding
:examples/tutorials/mnist/fully_connected_feed.py Reading from files
:examples/how_tos/reading_data/convert_to_records.py和examples/how_tos/reading_data/fully_connected_reader.py Preloaded data (constant)
:examples/how_tos/reading_data/fully_connected_preloaded.py Preloaded data (variable)
:examples/how_tos/reading_data/fully_connected_preloaded_var.py 我运行这些脚本未经修改,除了最后两个因为它们崩溃 - 至少版本0.10--除非我添加额外的sess.run(tf.initialize_local_variables())
。
在GTX1060上执行100个小批量100个示例的时间:
Feeding
:~0.001 s
Reading from files
:~0.010 s
Preloaded data (constant)
:~0.010 s
Preloaded data (variable)
:~0.010 s
这些结果对我来说非常令人惊讶。我希望Feeding
是最慢的,因为它几乎在python中做了所有事情,而其他方法使用低级tensorflow / C ++来执行类似的操作。这与我的预期完全相反。有谁知道发生了什么?
我可以访问另一台拥有Titan X和旧版NVidia驱动程序的机器。相对结果大致与上述结果一致,除了Preloaded data (constant)
这是一个灾难性的缓慢,单个小批量需要几秒钟。
这是一个已知的问题,即硬件/驱动程序的性能会有很大差异吗?
答案 0 :(得分:5)
更新10月9日缓慢之处是因为计算运行速度太快,Python无法抢占计算线程并安排预取线程。主线程中的计算需要2ms,并且显然对于预取线程来说抓取GIL太少了。预取线程具有较大的延迟,因此总是可以被计算线程抢占。因此计算线程遍历所有示例,然后大部分时间在GIL上被阻塞,因为一些预取线程被调度并且将一个示例排队。解决方案是增加Python线程的数量,增加队列大小以适应整个数据集,启动队列运行器,然后暂停主线程几秒钟,让队列运行器预先填充队列。
旧东西
这太慢了。
这看起来有些特殊情况使得最后3个示例不必要地变慢(大部分工作都用于优化像ImageNet这样的大型模型,因此MNIST没有得到足够多的关注)。
您可以按照here
所述的时间表来诊断问题此处are启用了时间轴收集的示例中的3个。
这是feed_dict
实施的时间表
需要注意的重要一点是,matmul占用了大量的时间,因此读取开销并不显着
您可以看到QueueDequeueMany上的操作存在瓶颈,需要高达45毫秒。
如果你放大,你会看到一堆微小的MEMCPY和Cast操作,这表明某些操作只是CPU(parse_single_example
),并且出列必须安排多个独立的CPU - > GPU传输
对于下面禁用GPU的var
示例,我看不到微小的操作,但QueueDequeueMany仍然需要10毫秒。时间似乎与批量大小呈线性关系,因此存在一些根本性的缓慢。提起#4740
答案 1 :(得分:2)
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)
这也在SO question中解决了。
答案 2 :(得分:1)
主要问题是为什么带有预加载数据的示例(常量) 使用GPU 时,examples/how_tos/reading_data/fully_connected_preloaded.py明显慢于其他数据加载示例代码。
我遇到了同样的问题,我的Titan X上fully_connected_preloaded.py
出乎意料地慢了。问题是整个数据集都预装在CPU上,而不是GPU上。
首先,让我分享我最初的尝试。我应用了雅罗斯拉夫的以下表现提示。
capacity=55000
设置tf.train.slice_input_producer
。(在我的情况下,55000是MNIST训练集的大小)num_threads=5
设置tf.train.batch
。capacity=500
设置tf.train.batch
。time.sleep(10)
放在tf.train.start_queue_runners
之后。但是,每批的平均速度保持不变。我尝试了timeline
可视化进行性能分析,但仍然有QueueDequeueManyV2
支配。
问题是fully_connected_preloaded.py
the line 65。以下代码将整个数据集加载到CPU,仍然为CPU-GPU数据传输提供瓶颈。
with tf.device('/cpu:0'):
input_images = tf.constant(data_sets.train.images)
input_labels = tf.constant(data_sets.train.labels)
因此,我切换了设备分配。
with tf.device('/gpu:0')
然后我每批都获得x100加速。
注意:
fully_connected_preloaded.py
)中,the line 64中的注释表示"管道的其余部分仅限CPU"。我不确定这条评论的意图。