Как выбрать графический процессор для выполнения задания?
Как на компьютере с несколькими графическими процессорами определить, на каком графическом процессоре должно выполняться задание CUDA?
Например, при установке 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.
Я посмотрел на связанный вопрос, как выбрать назначенный графический процессор для запуска программы CUDA?, но deviceQuery
Команда не находится в каталоге bin CUDA 8.0. В дополнение к $CUDA_VISIBLE_DEVICES$
Я видел другие посты ссылающиеся на переменную окружения $CUDA_DEVICES
но они не были установлены, и я не нашел информации о том, как его использовать.
Хотя не имеет прямого отношения к моему вопросу, используя nbody -device=1
Я смог заставить приложение работать на GPU 1, но с помощью nbody -numdevices=2
не работал на обоих GPU 0 и 1.
Я тестирую это в системе, работающей с использованием оболочки bash, на CentOS 6.8, с CUDA 8.0, 2 графическими процессорами GTX 1080 и драйвером NVIDIA 367.44.
Я знаю, что при написании с использованием CUDA вы можете управлять и контролировать, какие ресурсы CUDA использовать, но как бы я управлял этим из командной строки при запуске скомпилированного исполняемого файла CUDA?
8 ответов
Проблема была вызвана не установкой CUDA_VISIBLE_DEVICES
переменная внутри оболочки правильно.
Чтобы указать устройство CUDA 1
например, вы бы установить CUDA_VISIBLE_DEVICES
с помощью
export CUDA_VISIBLE_DEVICES=1
или же
CUDA_VISIBLE_DEVICES=1 ./cuda_executable
Первый устанавливает переменную для срока службы текущей оболочки, второй - только для срока службы конкретного исполняемого вызова.
Если вы хотите указать более одного устройства, используйте
export CUDA_VISIBLE_DEVICES=0,1
или же
CUDA_VISIBLE_DEVICES=0,1 ./cuda_executable
В случае, если кто-то другой делает это на 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 №5, вы можете ввести в командной строке следующее, и он запустит ваш скрипт только один раз на GPU №5:
CUDA_VISIBLE_DEVICES=5, python test_script.py
Установите следующие две переменные среды:
NVIDIA_VISIBLE_DEVICES=$gpu_id
CUDA_VISIBLE_DEVICES=0
где gpu_id
это идентификатор выбранного вами графического процессора, как показано в хост-системе nvidia-smi
(целое число, отсчитываемое от 0), которое будет доступно для гостевой системы (например, для среды контейнера D ocker).
Вы можете убедиться, что для каждого значения gpu_id выбрана другая карта, проверив Bus-Id
параметр в nvidia-smi
запустить в терминале в гостевой системе).
Больше информации
Этот метод основан на NVIDIA_VISIBLE_DEVICES
предоставляет системе только одну карту (с нулевым локальным идентификатором), поэтому мы также жестко кодируем другую переменную, CUDA_VISIBLE_DEVICES
до 0 (в основном, чтобы не допустить, чтобы по умолчанию была пустая строка, указывающая на отсутствие графического процессора).
Обратите внимание, что переменная среды должна быть установлена до запуска гостевой системы (поэтому нет шансов сделать это в терминале Jupyter Notebook), например, используя docker run -e NVIDIA_VISIBLE_DEVICES=0
или env
в Kubernetes или Openshift.
Если вам нужна балансировка нагрузки на GPU, сделайте gpu_id
случайным образом при каждом запуске гостевой системы.
Если вы устанавливаете это с помощью python, убедитесь, что вы используете строки для всех переменных среды, включая числовые.
Вы можете убедиться, что для каждого значения gpu_id
путем проверки nvidia-smi
Параметр Bus-Id (в терминале, запущенном в гостевой системе).
Принятое решение на основе CUDA_VISIBLE_DEVICES
сам по себе не скрывает другие карты (отличные от закрепленной) и, таким образом, вызывает ошибки доступа, если вы пытаетесь использовать их в пакетах python с поддержкой GPU. С помощью этого решения другие карты не видны гостевой системе, но другие пользователи по-прежнему могут получить к ним доступ и поделиться своей вычислительной мощностью на равной основе, как и с CPU (проверено).
Это также предпочтительнее решений с использованием контроллеров Kubernetes / Openshift (resources.limits.nvidia.com/gpu
), что наложило бы блокировку на выделенную карту, удалив ее из пула доступных ресурсов (чтобы количество контейнеров с доступом к GPU не могло превышать количество физических карт).
Это было протестировано под CUDA 8.0, 9.0 и 10.1 в контейнерах докеров под управлением Ubuntu 18.04 под управлением Openshift 3.11.
Выберите GPU с наименьшей загрузкой
После того, как вы сделаете xml2json доступным на вашем пути, вы можете выбрать N графических процессоров с наименьшей загрузкой:
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]
если вам нужен один графический процессор или любое количество в соответствии с максимальным количеством доступных графических процессоров.
Для случайного графического процессора вы можете сделать это:
export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))
Могу ли я установить несколько графических процессоров в коде Python следующим образом:
os.environ["CUDA_VISIBLE_DEVICES"] = "1,2"