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

问题描述 投票:0回答:6

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

举个例子,在安装 CUDA 时,我选择安装

NVIDIA_CUDA-<#.#>_Samples
,然后运行
nbody
模拟的多个实例,但它们都在一个 GPU 0 上运行; GPU 1 完全空闲(使用
watch -n 1 nvidia-dmi
进行监控)。使用
 检查 
CUDA_VISIBLE_DEVICES

echo $CUDA_VISIBLE_DEVICES

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

设置它
CUDA_VISIBLE_DEVICES=1

然后再次运行

nbody
,但它也转到 GPU 0。

我查看了相关问题,如何选择指定GPU来运行CUDA程序?,但是

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 可执行文件时,如何从命令行管理它?

cuda nvidia
6个回答
221
投票

该问题是由于未正确设置 shell 中的

CUDA_VISIBLE_DEVICES
变量引起的。

例如,要指定 CUDA 设备

1
,您可以使用
 设置 
CUDA_VISIBLE_DEVICES

export CUDA_VISIBLE_DEVICES=1

CUDA_VISIBLE_DEVICES=1 ./cuda_executable

前者为当前 shell 的生命周期设置变量,后者仅为该特定可执行调用的生命周期设置变量。

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

export CUDA_VISIBLE_DEVICES=0,1

CUDA_VISIBLE_DEVICES=0,1 ./cuda_executable

42
投票

如果其他人在 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
...

此处所示。


20
投票

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

CUDA_VISIBLE_DEVICES=5, python test_script.py

19
投票

设置以下两个环境变量:

NVIDIA_VISIBLE_DEVICES=$gpu_id
CUDA_VISIBLE_DEVICES=0

其中

gpu_id
是您所选 GPU 的 ID,如主机系统的
nvidia-smi
(从 0 开始的整数)中所示,它将可供来宾系统(例如 Docker 容器环境)使用。

您可以通过检查在来宾系统终端中运行的

Bus-Id
中的
nvidia-smi
参数来验证是否为每个gpu_id值选择了不同的卡。

更多信息

这种基于

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

请注意,环境变量应在客户系统启动之前设置(因此无法在 Jupyter Notebook 的终端中进行设置),例如在 Kubernetes 或 Openshift 中使用

docker run -e NVIDIA_VISIBLE_DEVICES=0
env

如果您想要 GPU 负载平衡,请在每个来宾系统启动时使

gpu_id
随机。

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

您可以通过检查

gpu_id
的 Bus-Id 参数(在来宾系统中运行的终端中)来验证是否为
nvidia-smi
的每个值选择了不同的卡。

仅基于

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

这也比使用 Kubernetes / Openshift 控制器 (

resources.limits.nvidia.com/gpu
) 的解决方案更可取,后者会对分配的卡施加锁定,将其从可用资源池中删除(因此具有 GPU 访问权限的容器数量不能超过实体卡)。

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


4
投票

更新

下面的评论中有一个由 lukaszzenko 修改的解决方案,它使用相同的想法并产生相同的输出。考虑使用它,因为它更简洁:

export CUDA_VISIBLE_DEVICES=$(nvidia-smi --query-gpu=memory.free,index --format=csv,nounits,noheader | sort -nr | head -1 | awk '{ print $NF }')

选择利用率最低的GPU(原方案)

在路径中提供 xml2json 后,您可以选择利用率最低的 N 个 GPU:

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]]))')

如果您需要单个 GPU 或根据可用 GPU 的最大数量的任何数量,只需将

[:2]
替换为
[:1]


1
投票

对于随机 GPU,你可以这样做:

export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))
© www.soinside.com 2019 - 2024. All rights reserved.