还有其他很好的并行化例子,包括当我们在微调模型时可以探索更大的超参数空间,并有效地运行大规模神经网络。
但我们必须先学会走路才能跑步。 我们先从一台机器上的几个 GPU 上并行化简单图形开始。
一台机器上多设备
在本节中,我们将介绍如何设置您的环境,以便 TensorFlow 可以在一台机器上使用多个 GPU 卡。 然后,我们将看看如何在可用设备上进行分布操作,并且并行执行它们。
安装
您可以使用nvidia-smi
命令来检查 CUDA 是否已正确安装。 它列出了可用的 GPU 卡以及每张卡上运行的进程:
最后,您必须安装支持 GPU 的 TensorFlow。 如果你使用virtualenv
创建了一个独立的环境,你首先需要激活它:
然后安装合适的支持 GPU 的 TensorFlow 版本:
$ pip3 install --upgrade tensorflow-gpu
现在您可以打开一个 Python shell 并通过导入 TensorFlow 并创建一个会话来检查 TensorFlow 是否正确检测并使用 CUDA 和 cuDNN:
I [...]/dso_loader.cc:108] successfully opened CUDA library libcudnn.so locally
I [...]/dso_loader.cc:108] successfully opened CUDA library libcufft.so locally
I [...]/dso_loader.cc:108] successfully opened CUDA library libcurand.so locally >>> sess = tf.Session() [...] name: GRID K520
major: 3 minor: 0 memoryClockRate (GHz) 0.797 pciBusID 0000:00:03.0 Total memory: 4.00GiB Free memory: 3.95GiB I [...]/gpu_init.cc:126] DMA: 0
看起来不错!TensorFlow 检测到 CUDA 和 cuDNN 库,并使用 CUDA 库来检测 GPU 卡(在这种情况下是 Nvidia Grid K520 卡)。
管理 GPU 内存
E [...]/cuda_driver.cc:965] failed to allocate 3.66G (3928915968 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY
一种解决方案是在不同的 GPU 卡上运行每个进程。 为此,最简单的选择是设置CUDA_VISIBLE_DEVICES
环境变量,以便每个进程只能看到对应的 GPU 卡。 例如,你可以像这样启动两个程序:
# and in another terminal:
程序 #1 只会看到 GPU 卡 0 和 1(分别编号为 0 和 1),程序 #2 只会看到 GPU 卡 2 和 3(分别编号为 1 和 0)。 一切都会正常工作(见图 12-3)。
现在像这样的两个程序可以使用相同的 GPU 卡并行运行(但不是三个,因为3×0.4> 1
)。 见图 12-4。
如果在两个程序都运行时运行nvidia-smi
命令,则应该看到每个进程占用每个卡的总 RAM 大约 40%:
好的,现在你已经有了一个支持 GPU 的 TensorFlow 安装。 让我们看看如何使用它!
设备布置操作
在此之前,TensorFlow都是简单的放置,它(如其名称所示)非常基本。
简单放置
无论何时运行图形,如果 TensorFlow 需要求值尚未放置在设备上的节点,则它会使用简单放置器将其放置在未放置的所有其他节点上。 简单放置尊重以下规则:
如果某个节点已经放置在图形的上一次运行中的某个设备上,则该节点将保留在该设备上。否则,如果用户将一个节点固定到设备上(下面介绍),则放置器将其放置在该设备上。
否则,它默认为 GPU#0,如果没有 GPU,则默认为 CPU。
a = tf.Variable(3.0)
b = tf.constant(4.0)
其中,"/cpu:0"
设备合计多 CPU 系统上的所有 CPU。 目前没有办法在特定 CPU 上固定节点或仅使用所有 CPU 的子集。
记录放置位置
让我们检查一下简单的放置器是否遵守我们刚刚定义的布局约束条件。 为此,您可以将log_device_placement
选项设置为True
;这告诉放置器在放置节点时记录消息。例如:
>>> sess = tf.Session(config=config)
[...] >>> x.initializer.run(session=sess) I [...] a: /job:localhost/replica:0/task:0/cpu:0
I [...] a/read: /job:localhost/replica:0/task:0/cpu:0 I [...] mul: /job:localhost/replica:0/task:0/gpu:0
I [...] b: /job:localhost/replica:0/task:0/cpu:0 I [...] a/initial_value: /job:localhost/replica:0/task:0/cpu:0
动态放置功能
return "/cpu:0" else:
return "/gpu:0" a = tf.Variable(3.0)
您可以轻松实现更复杂的算法,例如以循环方式用GPU锁定变量。
操作和内核
... i = tf.Variable(3)
[...]
[...]
软放置
i = tf.Variable(3)
config = tf.ConfigProto()
到目前为止,我们已经讨论了如何在不同设备上放置节点。 现在让我们看看 TensorFlow 如何并行运行这些节点。