如何选择在哪个 GPU 上运行作业?

在多 GPU 计算机中,如何指定 CUDA 作业应该在哪个 GPU 上运行?

例如,在安装 CUDA 时,我选择安装 NVIDIA_CUDA-<#.#>_Samples,然后运行 nbody模拟的几个实例,但它们都在一个 GPU 0上运行; GPU 1完全空闲(使用 watch -n 1 nvidia-dmi监控)。使用

echo $CUDA_VISIBLE_DEVICES

我发现这个没有设置。我试图设置它使用

CUDA_VISIBLE_DEVICES=1

then running nbody again but it also went to GPU 0.

我查看了相关的问题 how to choose designated GPU to run CUDA program?,但是 deviceQuery命令不在 CUDA 8.0 bin 目录中。除了 $CUDA_VISIBLE_DEVICES$之外,我还看到其他帖子提到了环境变量 $CUDA_DEVICES,但这些都没有设置,我也没有找到关于如何使用它的信息。

虽然与我的问题没有直接关系,但是使用 nbody -device=1我能够让应用程序在 GPU 1上运行,但是使用 nbody -numdevices=2并不能同时在 GPU 0和1上运行。

我正在使用 bash shell 在 CentOS 6.8、 CUDA 8.0、2 GTX 1080 GPU 和 NVIDIA 驱动程序367.44上运行的系统上进行测试。

我知道当使用 CUDA 编写时,你可以管理和控制使用哪些 CUDA 资源,但是当运行一个已编译的 CUDA 可执行文件时,我如何从命令行管理这些资源?

326731 次浏览

问题是由于没有在 shell 中正确设置 CUDA_VISIBLE_DEVICES变量造成的。

To specify CUDA device 1 for example, you would set the CUDA_VISIBLE_DEVICES using

export CUDA_VISIBLE_DEVICES=1

或者

CUDA_VISIBLE_DEVICES=1 ./cuda_executable

The former sets the variable for the life of the current shell, the latter only for the lifespan of that particular executable invocation.

如果要指定多个设备,请使用

export CUDA_VISIBLE_DEVICES=0,1

或者

CUDA_VISIBLE_DEVICES=0,1 ./cuda_executable

设置以下两个环境变量:

NVIDIA_VISIBLE_DEVICES=$gpu_id
CUDA_VISIBLE_DEVICES=0

其中 gpu_id是所选 GPU 的 ID,如主机系统的 nvidia-smi(一个从0开始的整数)所示,它将提供给客户系统(例如 Docker 容器环境)。

通过检查在来宾系统的终端中运行的 nvidia-smi中的 Bus-Id参数,可以验证为 gpu _ id 的每个值选择了不同的卡)。

更多信息

这个基于 NVIDIA_VISIBLE_DEVICES的方法只向系统公开一个卡(本地 ID 为0) ,因此我们还硬编码了另一个变量 CUDA_VISIBLE_DEVICES到0(主要是为了防止它默认为一个空字符串,表示没有 GPU)。

请注意,环境变量应该在客户系统启动之前设置(因此不可能在你的 Jupiter 笔记本终端上设置) ,例如在 Kubernetes 使用 docker run -e NVIDIA_VISIBLE_DEVICES=0env或 Openshift。

如果你想 GPU 负载平衡,使 gpu_id随机在每个客户系统启动。

如果使用 python 设置此值,请确保对于所有环境变量(包括数值变量)都是 使用字符串

通过检查 nvidia-smi的 Bus-Id 参数(在来宾系统的终端运行中) ,可以验证为 gpu_id的每个值选择了不同的卡。

仅基于 CUDA_VISIBLE_DEVICES的公认解决方案不会隐藏其他卡(与固定的不同) ,因此如果您试图在启用 GPU 的 python 包中使用它们,就会导致访问错误。有了这个解决方案,其他卡对于客户系统是不可见的,但是其他用户仍然可以访问它们并在平等的基础上共享他们的计算能力,就像 CPU (已验证)一样。

这也比使用 Kubernetes/Openshift 控制器(resources.limits.nvidia.com/gpu)的解决方案更可取,后者会对分配的卡强加一个锁,将其从可用资源池中移除(因此具有 gpU 访问权限的容器数量不能超过物理卡的数量)。

这已经在 CUDA 8.0,9.0.10.1和11.2下在运行 Ubuntu 18.04或20.04的 Docker 容器中进行了测试,并由 Openshift 3.11编排。

如果有人在 Python 中做这件事,但是它不工作,尝试将它设置为 之前,然后导入 pycuda 和 tensorflow。

例如:

import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
...
import pycuda.autoinit
import tensorflow as tf
...

正如看到的 给你

还可以在命令行中设置 GPU,这样就不需要将设备硬编码到脚本中(在没有多个 GPU 的系统上,脚本可能会失败)。假设你想在 GPU # 5上运行你的脚本,你可以在命令行输入以下命令,它就会在 GPU # 5上运行你的脚本一次:

CUDA_VISIBLE_DEVICES=5, python test_script.py

对于一个随机的 gpu,你可以这样做:

export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))

选择使用率最低的 GPU

After making Xml2json available in your path you can select the N GPU(s) that have the lowest utilization:

export CUDA_VISIBLE_DEVICES=$(nvidia-smi -x -q | xml2json | jq '.' | python -c 'import json;import sys;print(",".join([str(gpu[0]) for gpu in sorted([(int(gpu["minor_number"]), float(gpu["utilization"]["gpu_util"].split(" ")[0])) for gpu in json.load(sys.stdin)["nvidia_smi_log"]["gpu"]], key=lambda x: x[1])[:2]]))')

只是取代 [:2][:1],如果你需要一个单一的图形处理器或任何数字根据您的最大数量的可用图形处理器。