【问题标题】:TensorFlow Execution on a single (multi-core) CPU Device在单个(多核)CPU 设备上执行 TensorFlow
【发布时间】:2017-11-28 03:06:59
【问题描述】:

在只有一个 CPU 设备且网络仅用于推理的特定情况下,我对 TensorFlow 的执行模型有一些疑问,例如使用 Image Recognition(https://www.tensorflow.org/tutorials/image_recognition) C++ Example with a multi - 核心平台。

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

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 线程池大小更多? 如果是,它们以哪种顺序排列? (先进先出?)

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

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

【问题讨论】:

    标签: tensorflow threadpool


    【解决方案1】:

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

    Re inline_readyExecutor:Process 被安排在某个 Eigen 线程中。当它运行时,它会执行一些节点。当这些节点完成后,它们使其他节点(张量流操作)准备就绪。其中一些节点并不昂贵。它们被添加到 inline_ready 并在同一个线程中执行,没有产生。其他节点很昂贵,并且不会在同一线程中“立即”执行。它们的执行是通过 Eigen 线程池安排的。

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

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

    我不知道 tensorflow 会以何种方式影响 OS 线程的调度。您可以要求它进行一些旋转(即不立即将线程让给操作系统)以最小化延迟(来自操作系统调度),但仅此而已。

    这些内部细节并非故意记录在案,因为它们可能会发生变化。如果您通过 Python API 使用 tensorflow,您只需要知道您的操作将在输入准备就绪时执行。如果您想执行超出此范围的某些命令,您应该使用:

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

    如果您正在编写自定义 CPU 内核并希望在其中进行并行处理(对于非常昂贵的内核通常很少需要),那么您可以依赖上面链接的线程池接口。

    【讨论】:

    • @Dan 很高兴我能帮上忙
    • 如何限制 TensorFlow 只使用一个线程?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-04
    • 1970-01-01
    相关资源
    最近更新 更多