Навчання на кількох GPU
Навчання на кількох GPU в LibreYOLO використовує PyTorch DistributedDataParallel: по одному процесу на GPU, кожен із повною реплікою моделі та частиною кожного батча, а градієнти усереднюються між рангами на кожному кроці.
Запуск на двох GPU
Передайте список пристроїв. Більше нічого не змінюється.
from libreyolo import LibreYOLO # Ця захисна умова підтримується; звичайні скрипти працюють і без неї.# Збережіть її для колбеків і логерів, яким потрібен стандартний pickle.if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") model.train( data="my-dataset.yaml", epochs=100, batch=32, # глобальний батч: 16 зображень на GPU для двох GPU device="0,1", )libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \ epochs=100 batch=32 device=0,1Якщо задано більше одного пристрою без середовища torchrun, train() моделі зберігає ваги в тимчасовий файл, визначає автоматичний розмір батча за потреби й запускає робочі процеси під керуванням координатора, по одному на GPU. Кожен процес повторно імпортує клас моделі, відтворює її зі збережених ваг і запускає звичайний шлях для одного пристрою, оскільки всередині створеного процесу задано змінні середовища torchrun. Після завершення запуску найкраща контрольна точка рангу 0 завантажується назад в екземпляр моделі викликача.
device приймає "0,1", [0, 1], 0, "cuda:0", "cpu", "mps" і
"auto". Автоматичний запуск активує лише список із кількох індексів CUDA.
libreyolo train device=0,1 або device=[0,1] будує модель на першому GPU зі
списку й передає список у train(), який запускає робочі процеси так само.
Автоматичний запуск і захисна умова main
model.train(device=[0, 1]) і device="0,1" використовують ранги під керуванням координатора без повторного виконання коду верхнього рівня звичайного скрипту без захисної умови. Скрипти із захисною умовою й явний torchrun і далі підтримуються. Завдання координатора використовують cloudpickle; об'єкти колбеків або логерів, яким потрібен резервний стандартний pickle, і далі потребують умови if __name__ == "__main__":.
batch є глобальним батчем
batch є кількістю зображень на крок оптимізатора для всіх GPU. Завантажувач даних
кожного рангу створюється зі значенням batch // world_size і DistributedSampler,
тому batch=32 на двох GPU означає 16 зображень на GPU, а не 32.
Якщо батч не ділиться без остачі на world size, породжується помилка замість непомітного навчання з іншим розміром:
batch=6 is the global batch and must be divisible by world_size=4: each ranktrains at batch // world_size, so this value would silently train at adifferent global batch than requested. Use batch=4 or batch=8.DDP сам усереднює градієнти, тому функція втрат передається без масштабування. Додаткове множення на world size збільшило б ефективну швидкість навчання приблизно в кількість разів, що дорівнює кількості GPU.
Autobatch у DDP
batch=-1 працює й повертає глобальний батч, кратний world size.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") # Перевіряється один раз на GPU 0 і масштабується до числа, кратного world size. model.train(data="my-dataset.yaml", batch=-1, device="0,1")На шляху автоматичного породження перевірка виконується в батьківському процесі на першому пристрої до появи робочих процесів, тому кожен із них отримує конкретне ціле число й не потребує міжпроцесної координації. У torchrun ранг 0 виконує перевірку та транслює результат як один тензор long.
Перевірка вимірює місткість одного GPU й множить її на world size. Якщо задано nbs,
глобальний батч обмежується значенням nbs та округлюється вниз до числа, кратного
world size. Отже, додавання GPU зменшує кількість кроків накопичення, а не розмір
батча на GPU. Механіку самої перевірки описано в розділі
Гіперпараметри.
SyncBatchNorm
У DDP шари BatchNorm кожного рангу бачать лише його частину даних. За значення
batch // world_size ця частина може бути настільки малою, що поточна статистика
погіршить збіжну модель порівняно із запуском на одному GPU.
sync_bn=True перетворює кожен BatchNorm на SyncBatchNorm, щоб статистика обчислювалася
за глобальним батчем. Перетворення виконується лише за активного розподіленого режиму,
тому прапорець не впливає на запуск з одним GPU.
Воно вже типово ввімкнене для згорткових сімейств із великою кількістю BatchNorm:
YOLOX, YOLOv7, YOLOv9 та його варіантів, YOLO-NAS, PicoDet, RTMDet і FOMO.
Для всіх інших сімейств воно типово вимкнене. Якщо модель містить BatchNorm,
sync_bn вимкнено, а батч на ранг менший за 16, засіб навчання виводить попередження.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreRTDETRr18.pt") model.train( data="my-dataset.yaml", batch=32, device="0,1", sync_bn=True, )Прапорця CLI для sync_bn немає. Це аргумент Python.
Запуск за допомогою torchrun
Torchrun також підтримується й є правильним вибором, коли планувальник кластера вже керує запуском процесів. Напишіть скрипт для одного пристрою, а torchrun налаштує середовище рангів.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") model.train(data="my-dataset.yaml", epochs=100, batch=32)torchrun --nproc_per_node=2 train.pyНе поєднуйте два способи. За наявності середовища torchrun значення device="0,1"
не породжує процеси; засіб навчання вибирає cuda:LOCAL_RANK, а кількістю процесів
керує torchrun.
Поведінка рангів
Ранг 0 виконує всі побічні дії. Він визначає каталог запуску й транслює визначену назву, щоб усі ранги її узгодили, записує контрольні точки та артефакти й викликає зворотні виклики та логери користувача. Інші ранги навчаються й додають градієнти.
Кожен ранг ініціалізує генератори випадкових чисел свого завантажувача даних
і аугментації різними значеннями, виведеними з налаштованого seed, тому ранги
не отримують однакових аугментацій.
Платформа й backend
Backend вибирається автоматично: NCCL, коли доступні CUDA й NCCL, інакше Gloo. NCCL не збирається на Windows, тому без додаткового налаштування запуски Windows використовують Gloo. Група процесів ініціалізується з тайм-аутом три години.
Що не працює в DDP
- Захоплення графа CUDA.
cuda_graph=Trueзаписує один рядок у лог і навчається в eager-режимі. Див. розділ Продуктивність навчання. - Профайлер навчання.
profile=Trueігнорується з попередженням.
Не кожне сімейство підтримує автоматичне породження процесів. Його підтримують двадцять чотири сімейства, що охоплюють навчувані сімейства виявлення, класифікації, семантичної сегментації та відновлення. Якщо передати кілька GPU сімейству без такої підтримки, воно породжує помилку з назвою API моделі й командою torchrun, а не непомітно навчається на одному GPU.
Пов'язані матеріали
- Гіперпараметри описують
batch,nbsі відновлення. - Логери експериментів описують вимогу підтримки pickle для зворотних викликів.
- Хмарні GPU описують оренду машини з кількома GPU.