单个(多核)CPU设备上的TensorFlow执行

时间:2017-11-21 15:14:34

标签: tensorflow threadpool

我对TensorFlow的执行模型有一些疑问,在这种情况下,只有一个CPU设备并且网络仅用于推理,例如使用图像识别(https://www.tensorflow.org/tutorials/image_recognition)C ++示例一个多核平台。

在下文中,我将尝试总结我理解的内容,同时提出一些问题。

Session-> Run()(文件direct_session.cc)调用ExecutorState :: RynAsynch,它使用根节点初始化TensorFlow就绪队列。

然后,说明

runner_([=]() { Process(tagged_node, scheduled_usec); }); (executor.cc, function ScheduleReady, line 2088)

将节点(以及相关操作)分配给inter_op池的线程。 但是,我不完全了解它是如何工作的。 例如,在ScheduleReady尝试分配的操作多于inter_op池大小的情况下,操作如何排队?(FIFO顺序?) 池中的每个线程都有一个操作队列,或者只有一个共享队列? 我在哪里可以在代码中找到这个? 我在哪里可以找到泳池中每个螺纹的主体?

另一个问题是由inline_ready管理的节点。这些(廉价或死的)节点的执行与其他节点的执行有何不同?

然后,(仍然,据我所知),执行流程继续执行ExecutorState :: Process,它执行操作,区分同步和异步操作。 同步和异步操作在执行方面有何不同?

当执行操作时,PropagateOutputs(调用ActivateNodes)将准备好的队列中的每个后继节点的节点添加到就绪队列中,这要归功于当前节点(前任)的执行。

最后,NodeDone()调用ScheduleReady()来处理当前在TensorFlow就绪队列中的节点。

相反,如何管理intra_op线程池取决于特定的内核,对吧?内核可能会请求比intra_op线程池大小更多的操作? 如果是,他们排队的是哪种排序? (FIFO?)

一旦将操作分配给池的线程,那么它们的调度是留给底层操作系统还是TensorFlow强制执行某种调度策略?

我在这里问,因为我在文档中没有找到关于执行模型的这一部分的任何内容,如果我错过了一些文档,请指向我所有文档。

1 个答案:

答案 0 :(得分:3)

Re ThreadPool :当Tensorflow使用DirectSession时(就像你的情况一样),它使用Eigen的ThreadPool。我无法获得TensorFlow中使用的Eigen官方版本的Web链接,但这里是一个指向线程池code的链接。此线程池正在使用此队列实现RunQueue。每个线程有一个队列。

Re inline_ready Executor:Process计划在某些特征线程中。当它运行时,它执行一些节点。当这些节点完成后,它们会使其他节点(tensorflow操作)准备就绪。其中一些节点并不昂贵。它们被添加到inline_ready并在同一个线程中执行,而不会屈服。其他节点很昂贵,并且不会立即执行#34;在同一个线程中。它们的执行是通过Eigen线程池安排的。

重新同步/异步内核: Tensorflow操作可以由同步(大多数CPU内核)或异步内核(大多数GPU内核)支持。同步内核在运行Process的线程中执行。异步内核被分派到他们的设备(通常是GPU)来执行。完成异步内核后,它们会调用NodeDone方法。

重新内部操作ThreadPool:内部操作线程池可供内核使用以并行运行计算。大多数CPU内核不使用它(GPU内核只调度到GPU)并在调用Compute方法的线程中同步运行。根据配置,所有设备(CPU)共享一个内部操作线程池,或者每个设备都有自己的。内核只是在这个线程池上安排他们的工作。这是一个这样的kernel的例子。如果有多个任务而不是线程,则会以未指定的顺序调度和执行它们。这是暴露给内核的ThreadPool interface

我不知道张量流如何影响OS线程的调度。您可以要求它进行一些旋转(即不立即将线程传递给OS)以最小化延迟(来自OS调度),但这就是它。

这些内部细节没有故意记录,因为它们可能会发生变化。如果您通过Python API使用tensorflow,那么您应该知道您的操作将在其输入准备就绪时执行。如果你想强制执行一些超出此订单的订单,你应该使用:

with tf.control_dependencies(<tensors_that_you_want_computed_before_the_ops_inside_this_block>):
  tf.foo_bar(...) 

如果您正在编写自定义CPU内核并希望在其中进行并行操作(通常很少需要非常昂贵的内核),上面链接的线程池接口就是您可以信赖的。