TLDR;在with tf.device("/gpu:0")
中創建的操作將始終在GPU上運行。如果您指定輸入放置在cpu
上,則它們將被放置在CPU上。如果您省略了輸入的設備規格,則它們將放置在GPU上以更接近您的操作。您可以使用run_metadata
來獲取包含所有設備分配的Python對象,並在那裏查找您的操作。
安置是通過誤導性地命名爲simple_placer.cc完成的,雖然註釋指定了機制,但仍有一些錯誤被散列(即,here),所以最好的方法是在實踐中檢查它。
當你說在GPU上創建變量時,實際上有兩種放置方式 - 明確的,當你在with tf.device
塊內創建相關操作時,以及隱含的,在這種塊之外。在with tf.device
之外創建操作等同於在with tf.device(None)
塊中創建操作。
所以這裏有一個簡單的實驗
n = 10**6
def inputs_cpu():
tf.reset_default_graph()
with tf.device("/cpu:0"):
a = tf.ones((n,), name="A")
b = tf.ones((n,), name="B")
with tf.device("/gpu:0"):
c = tf.add(a, b, name="C")
return c
def inputs_none():
tf.reset_default_graph()
a = tf.ones((n,), name="A")
b = tf.ones((n,), name="B")
with tf.device("/gpu:0"):
c = tf.add(a, b, name="C")
return c
def run_and_summarize(target):
# turn off graph-rewriting optimizations
sess = tf.Session(config=tf.ConfigProto(graph_options=tf.GraphOptions(optimizer_options=tf.OptimizerOptions(opt_level=tf.OptimizerOptions.L0))))
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
sess.run(target, options=run_options, run_metadata=run_metadata)
for device in run_metadata.step_stats.dev_stats:
device_name = device.device
if not (device_name.endswith("/cpu:0") or device_name.endswith("/gpu:0")):
continue
print(device.device)
for node in device.node_stats:
print(" ", node.node_name)
現在你可以做到這一點
run_and_summarize(inputs_cpu())
與固定於CPU的投入運行,你會看到這個位置得到尊重
/job:localhost/replica:0/task:0/gpu:0
_SOURCE
C
/job:localhost/replica:0/task:0/cpu:0
_SOURCE
A
B
另一方面,當輸入未指定時
run_and_summarize(inputs_none())
你可以看到,現在所有的OPS放在GPU
/job:localhost/replica:0/task:0/cpu:0
_SOURCE
/job:localhost/replica:0/task:0/gpu:0
_SOURCE
A
B
C
棒極了!我現在明白了。非常感謝! –
BTW,最近[提交](https://github.com/tensorflow/tensorflow/commit/3f5f9585)澄清了評論中的行爲。基本上,如果你明確地設置設備,它將永遠在該設備 –
我以前的印象是TF會隱式地分配ops給GPU,只要GPU和適合這些操作系統的內核可用。從這個描述我現在明白,如果其他與這些操作符具有輸入關係的操作符已經明確地(例如'with tf.device(「/ gpu:0」):'),則TF只會隱含地將操作分配給GPU。所以如果我沒有明確指定GPU的任何操作,TF也不會隱含地分配任何操作。那是對的嗎? – Drux