What exactly is a device in TensorFlow?

tensorflow

Solution

Too long for a comment (perhaps @mrry or @keveman could give an official definition), but here are some observations:

- A logical device in TensorFlow is a computation unit with its own memory.

- TensorFlow scheduler adds Send/Recv ops to copy data to proper device when data crosses cross device boundaries

- It's a logical device so you can have more logical devices than physical devices (cores) and some of the ops on available "devices" may be scheduled but sit idly waiting until a physical device frees up. For CPU devices, you may have more threads than you have cores, so a OS thread scheduler selects subset of threads to run at any given moment

- An op scheduled on logical `tf.device("gpu:0")` device can keep its data on in main memory (ie, physical CPU device), so logical device boundary is sometimes violated in practice. This is the `HostMemory` annotation you see in ops like integer `Add` here. This allows one to do ops like shape manipulation on logical device GPU and avoid crossing logical device boundary (Send/Recv ops) even though the data is not stored on physical device GPU.

- Using `device_count={"CPU": m}...intra_op_parallelism_threads=n` creates multiple Eigen thread-pools with `n` threads each, so you can manually partition your graph to run `m` ops in parallel where each op will request `n` threads. However you can't run more threads concurrently than you have physical cores so this may be slow.

- Logical devices like `cpu:0` are not pinned specific cores, so they can use whichever cores are available

- You can see what was the actual parallelism by looking at timelines

Here's an example of creating 8 CPU devices and running 2 matmul's in parallel: https://gist.github.com/yaroslavvb/9a5f4a0b613c79152152b35c0bc840b8

The core graph construction looks like this

with tf.device("cpu:0"):
    a1 = tf.ones((n, n))
    a2 = tf.ones((n, n))
with tf.device("cpu:1"):
    a3 = tf.matmul(a1, a2)
with tf.device("cpu:2"):
    a4 = tf.matmul(a1, a2)
with tf.device("cpu:3"):
    a5 = tf.matmul(a3, a4)

If you run the gist you look at the `run_metadata` partition graphs section that's printed, you see `Send/Recv` ops added that transfer data between CPU devices, ie something like this

partition_graphs {
  node {
    name: "MatMul_1/_11"
    op: "_Recv"
    device: "/job:localhost/replica:0/task:0/cpu:3"
    attr {
      key: "client_terminated"
      value {
        b: false
      }
    }
    attr {
      key: "recv_device"
      value {
        s: "/job:localhost/replica:0/task:0/cpu:3"
      }
    }
    attr {
      key: "send_device"
      value {
        s: "/job:localhost/replica:0/task:0/cpu:2"
      }
    }

So you see that there's a `Send` op scheduled to transfer data from `cpu:2` to `cpu:3`. Since all CPU devices share memory, this op doesn't do anything, but it may do something in the future if TensorFlow becomes NUMA aware.

Also, you can open `timeline.json` in browser under `chrome://tracing` and see the timing

You can see it runs two 1024x1024 matrix multiplications in parallel, each one taking about 85ms, which comes down to 25 M ops/second, decent for single core performance of 2 year-old macbook.

On other hand, you can run 6 of such matrix multiplications on 6 different CPU devices, and you'll see something like this.

I only have 4 physical cores, and you see that 2 of the operations take 2x longer. Even though they were active on a logical `cpu` device, there were any available physical cores for first 100ms so they weren't making any progress.

Problem

I would be extremely helpful to have a clear definition what a device in TensorFlow is exactly. Is a device a single processing unit (no "real" concurrency possible)? You can define as many devices as you want by doing the following: ``` config = tf.ConfigProto(device_count={"CPU": 2}, inter_op_parallelism_threads=2, intra_op_parallelism_threads=1) sess = tf.Session(config=config) ``` How is it possible that you can define as many devices as you want despite having only one processor with 4 cores?

Original source