Новинка NVIDIA B300 · серверы 288 ГБ HBM3e — от 4 019 $/мес. за GPU

Посмотреть B300

Документация · Multi-GPU

Multi-GPU на одном сервере: топология, NCCL и torchrun

От того, как GPU в сервере соединены между собой, зависит, насколько хорошо масштабируется задача. Перед длительным запуском проверьте топологию, запустите задачу через torchrun и измерьте пропускную способность интерконнекта.

Обновлено 6 мин чтения

Сначала изучите топологию

Связи между GPU определяют, какой вид параллелизма обойдётся дешевле. Проверяйте их, прежде чем выбирать:

nvidia-smi topo -m        # матрица соединений между GPU, NIC и CPU
nvidia-smi topo -p2p r    # какие пары GPU поддерживают P2P-чтение
amd-smi topology          # AMD MI355X
ОбозначениеПуть между двумя GPU
NV#NVLink с # объединёнными линиями; на платах HGX — через NVSwitch
PIXНе более одного переключателя PCIe
PXBНесколько переключателей PCIe без пересечения хост-моста CPU
PHBХост-мост PCIe, что обычно означает связь через CPU
NODEPCIe плюс соединение между хост-мостами внутри одного узла NUMA
SYSPCIe плюс связь между процессорными сокетами: самый медленный путь

Столбцы CPU Affinity и NUMA Affinity показывают, какие ядра ближе всего к каждому GPU. Закрепляйте на этих ядрах задачи загрузки данных, если узким местом становится CPU.

Запуск задач на 2, 4 или 8 GPU с torchrun

torchrun запускает один процесс на каждый GPU и присваивает каждому RANK, LOCAL_RANK и WORLD_SIZE. Перед длительной задачей проверьте настройку коротким скриптом:

# ddp_check.py
import os
import torch
import torch.distributed as dist

local_rank = int(os.environ["LOCAL_RANK"])
torch.cuda.set_device(local_rank)
dist.init_process_group("nccl")

x = torch.ones(1, device="cuda") * dist.get_rank()
dist.all_reduce(x)          # суммирует ранги процессов по всем GPU
print(f"rank {dist.get_rank()} of {dist.get_world_size()}: sum = {x.item():.0f}")
dist.destroy_process_group()
torchrun --standalone --nproc-per-node=gpu ddp_check.py   # один процесс на каждый видимый GPU
torchrun --standalone --nproc-per-node=4 train.py         # четыре процесса
CUDA_VISIBLE_DEVICES=4,5,6,7 torchrun --standalone --nproc-per-node=4 train.py   # только GPU с 4 по 7

Каждый ранг должен вывести одну и ту же сумму, 0 + 1 + … + (n − 1): 28 для восьми GPU. CUDA_VISIBLE_DEVICES позволяет двум независимым задачам делить один сервер, каждой — на своих GPU. torchrun выставляет OMP_NUM_THREADS=1 для каждого процесса, если вы не задали это значение сами; увеличьте его, если CPU-часть внутри процессов обучения работает медленно.

Главное о NCCL

NCCL — это библиотека, стоящая за бэкендом nccl в PyTorch. Она сама определяет топологию и выбирает NVLink, PCIe P2P, общую память или сеть, и её настройки по умолчанию подходят для большинства задач. Эти переменные показывают и помогают отладить то, что она выбрала:

ПеременнаяНазначение
NCCL_DEBUG=INFOВыводит версию NCCL, обнаруженную топологию и транспорт, используемый между GPU (строки вида via P2P или via SHM). Для обычных запусков используйте WARN.
NCCL_DEBUG_SUBSYS=INIT,GRAPHОграничивает вывод INFO инициализацией и решениями по топологии.
NCCL_DEBUG_FILE=/tmp/nccl.%h.%p.logЗаписывает журнал в отдельный файл для каждого процесса (%h — хост, %p — ID процесса).
NCCL_P2P_DISABLE=1Отключает прямую передачу данных между GPU. Диагностический инструмент для зависаний, а не настройка для постоянного использования.
NCCL_P2P_LEVEL=PXBРазрешает P2P только до заданной дистанции: LOC, NVL, PIX, PXB, PHB или SYS.
NCCL_SHM_DISABLE=1Отключает транспорт через общую память (только для отладки).
NCCL_TOPO_DUMP_FILE=/tmp/topo.xmlСохраняет топологию, обнаруженную NCCL.
NCCL_SOCKET_IFNAME, NCCL_IB_DISABLEНастройки сети. Важны только для задач, охватывающих несколько серверов.
NCCL_DEBUG=INFO torchrun --standalone --nproc-per-node=gpu ddp_check.py 2>&1 | grep -E 'via (P2P|SHM|NET)' | head

NCCL описывает NCCL_ALGO, NCCL_PROTO и похожие переменные тонкой настройки как инструменты отладки. Не оставляйте их в продакшен-скриптах: они могут привести к снижению производительности или зависаниям.

Измерьте пропускную способность шины с nccl-tests

nccl-tests измеряет реальную пропускную способность интерконнекта. Для него нужны CUDA toolkit и файлы разработки NCCL из репозитория NVIDIA (см. Драйверы NVIDIA и CUDA); в контейнере NGC PyTorch обе эти вещи уже есть.

sudo apt install -y libnccl2 libnccl-dev
git clone https://github.com/NVIDIA/nccl-tests.git
cd nccl-tests
make -j                                          # CUDA_HOME по умолчанию указывает на /usr/local/cuda
./build/all_reduce_perf -b 8 -e 2G -f 2 -g 8     # -g: количество GPU в сервере

-b и -e задают наименьший и наибольший размер сообщения, -f — множитель между размерами, а -g — количество GPU. Каждая строка вывода соответствует одному размеру сообщения:

  • algbw: объём данных, делённый на время.
  • busbw: algbw с поправкой на количество GPU (для all-reduce — × 2(n − 1)/n). Отражает скорость самого медленного участка пути (NVLink, PCIe или связь между процессорными сокетами), и именно эту величину нужно сравнивать между серверами.
  • #wrong должен оставаться равным 0. Запуск завершается строкой Avg bus bandwidth.

Смотрите строки с крупными сообщениями. Записывайте результат, когда сервер работает исправно, чтобы иметь ориентир на случай, если позже производительность изменится.

Модели крупнее: FSDP и DeepSpeed

  • DDP (DistributedDataParallel): каждый GPU хранит полную копию модели и состояния оптимизатора. Проще и быстрее всего, когда всё помещается в память одного GPU.
  • FSDP2 (torch.distributed.fsdp.fully_shard): шардирует параметры, градиенты и состояние оптимизатора между GPU, поэтому модель должна помещаться только в их суммарную память. Запускается через torchrun, как и DDP; см. руководство по FSDP2 от PyTorch.
  • DeepSpeed ZeRO: стадии с 1 по 3 шардируют сначала состояние оптимизатора, затем градиенты, затем параметры, с возможной разгрузкой в память CPU или на NVMe. pip install deepspeed; см. Начало работы.
  • Тензорный и конвейерный параллелизм (например, в стиле Megatron): разбивает слои или группы слоёв между GPU. Используется для самых больших моделей; тензорный параллелизм требует быстрого интерконнекта.

Hugging Face Accelerate и Transformers Trainer оборачивают DDP, FSDP и DeepSpeed конфигурационным файлом. Если вам нужен инференс, а не обучение, см. Инференс-сервер.

RCCL на AMD MI355X

На MI355X тот же код работает без изменений. Бэкенд nccl в PyTorch использует RCCL — реализацию API NCCL от AMD; torchrun работает точно так же, а RCCL читает те же переменные NCCL_*, например NCCL_DEBUG=INFO. Выбирайте GPU через HIP_VISIBLE_DEVICES; CUDA_VISIBLE_DEVICES также поддерживается.

amd-smi topology                           # связи между GPU
git clone https://github.com/ROCm/rccl-tests.git
cd rccl-tests
make GPU_TARGETS=gfx950                    # добавьте HIP_HOME=..., если ROCm не в /opt/rocm
./build/all_reduce_perf -b 8 -e 2G -f 2 -g 8

Проще всего собрать rccl-tests в контейнере rocm/pytorch, где ROCm и RCCL уже установлены. Установка и выбор GPU описаны в ROCm на MI355X.

Нужна помощь с этим руководством?

Расскажите нам о своём GPU, командах, которые вы выполнили, и результате, который получили, через форму обратной связи.

Личный кабинет

Войти в CryptGPU

Ваши заказы, счета и серверы в одном месте.

Новичок в CryptGPU?

Аккаунты создаются при оформлении заказа: выберите сервер и программное обеспечение, затем создайте аккаунт на шаге Аккаунт первого заказа.

Запустить сервер