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

TensorFlow Execution on a single (multi-core) CPU Device

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

下面我会尝试总结一下我的理解,同时提出一些问题。

Session->运行() (file direct_session.cc) 调用 ExecutorState::RynAsynch,用根节点初始化 TensorFlow 就绪队列。

然后,指令

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

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

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

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

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

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

反过来,intra_op线程池怎么管理,要看具体的内核吧?内核请求的操作有可能超过 intra_op 线程池大小吗? 如果是,他们以哪种顺序排队? (先进先出?)

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

我在这里问是因为我几乎没有在文档中找到关于这部分执行模型的任何信息,如果我遗漏了一些文档,请指出所有文档。

Re ThreadPool:当Tensorflow使用DirectSession时(就像你的情况一样),它使用Eigen的ThreadPool。 TensorFlow 中使用的Eigen 官方版本我无法得到一个weblink,但是这里有一个link 到线程池code. This thread pool is using this queue implementation RunQueue。每个线程有一个队列。

Re inline_ready: Executor:Process 被安排在一些 Eigen Thread 中。当它 运行s 它执行一些节点。随着这些节点的完成,它们使其他节点(tensorflow 操作)准备就绪。其中一些节点并不昂贵。它们被添加到 inline_ready 并在同一个线程中执行,不会产生。其他节点开销大,不在同一个线程中执行"immediately"。它们的执行是通过 Eigen 线程池调度的。

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

Re Intra Op ThreadPool:内核可以使用内部操作线程池来运行它们的并行计算。大多数 CPU 内核不使用它(GPU 内核只是分派给 GPU)并且 运行 在调用 Compute 方法的线程中同步。根据配置,所有设备 (CPUs) 共享一个内部操作线程池,或者每个设备都有自己的线程池。内核只是在这个线程池上安排它们的工作。这是一个 kernel. If there are more tasks than threads, they are scheduled and executed in unspecified order. Here is the ThreadPool interface 暴露给内核的示例。

我不知道 tensorflow 会以何种方式影响 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 内核并希望在其中进行并行处理(对于非常昂贵的内核通常很少需要),上面的线程池接口 link 是您可以依赖的上。