Якщо ви запускаєте навантаження на GPU в продакшені, ви вже зустрічали одного й того самого лиходія в десятьох різних костюмах: «GPU повільний».
Іноді це правда. Частіше GPU просто чекає — на ваш CPU, на сховище, на мережу, на драйвери, на контейнерний рантайм,
або на один пропущений прапорець, який перетворює прискорювач за $20k на обігрівач.
Нижче — десять GPU-міфів, які продовжують точити бюджети та сон. Кожен міф супроводжується практичною поправкою,
командами, які ви можете виконати сьогодні, та типовими режимами відмов, що з’являються о 2:00, коли завдання з навчання «таємничо» регресує.
Швидкий план діагностики: знайдіть вузьке місце за 10 хвилин
Найшвидший спосіб відлагодити «продуктивність» GPU — перестати говорити про GPU і почати вимірювати весь конвеєр.
Ви шукаєте перший дефіцитний ресурс. Не найдорогоцінніший.
1) Перша перевірка: чи справді GPU виконує роботу?
- Подивіться на завантаження SM, завантаження пам’яті та споживання потужності. Якщо потужність низька — швидше за все ви не обчислювально-зв’язані.
- Перевірте тактові частоти і тротлінг. GPU на 300 МГц не «повільний», він обмежений.
2) Друга перевірка: чи голодує GPU через CPU/дані?
- Високе завантаження CPU, великий iowait або повільні читання зазвичай означають, що GPU чекає на вхідні дані.
- Шукайте затримки в даталоадері, маленькі батчі, надмірну аугментацію на CPU або незафіксовану (non-pinned) хост-пам’ять.
3) Третя перевірка: чи зв’язує вас пропускна здатність (PCIe / мережа / сховище)?
- Знижена ширина PCIe (x16 → x4) або перехід Gen4 → Gen3 тихо підрізають пропускну здатність.
- Мережа або спільне сховище можуть обмежити розподілене тренування задовго до того, як «закінчаться GPU».
4) Четверта перевірка: чи боретеся ви з програмним тертям?
- Невідповідності драйверів/рантайму, неправильний контейнерний рантайм, відключений persistence mode або неправильно задані змінні оточення можуть змусити використовувати повільні шляхи.
- Версії ядра, налаштування IOMMU та cgroups також можуть додати несподіваний оверхед.
5) Остання перевірка: профілюйте одну ітерацію повністю
- Не здогадуйтеся. Виміряйте час кроку, розбивши його на: введення, CPU-трансформації, H2D-передачу, GPU-обчислення, D2H і синхронізацію.
Одна перефразована ідея (операційна легенда, приписують): перефразована ідея
— John Allspaw (операції та реагування на інциденти): поведінка системи має сенс, коли ви бачите обмеження.
У світі GPU обмеження майже ніколи не там, де ви їх очікуєте.
10 міфів (і що робити натомість)
Міф 1: «GPU має бути ~100% завантаженим, інакше ви марнуєте гроші.»
«Завантаження» — одна з тих метрик, що звучать об’єктивно, але поводяться як плітки. GPU може показувати 20–40% завантаження
і при цьому бути цілком здоровим, якщо у моделі часті точки синхронізації, короткі ядра або вона обмежена затримкою.
Навпаки, 99% завантаження може означати, що виконується неправильна робота — наприклад постійне переформатування тензорів або витрачання циклів на непотрібні касти.
Що робити натомість:
- Відстежуйте час на крок і пропродуктивність (зразків/сек) як основні KPI.
- Слідкуйте за споживанням потужності та частотами. Обчислювальні навантаження тягнуть потужність.
- Перед тим як ганятися за «більшим завантаженням», перевірте очікування CPU та затримки даталоадера.
Практичне рішення: якщо час кроку стабільний і відповідає SLO — не «чиніть» завантаження. Якщо час кроку регресував — знайдіть затримку.
Міф 2: «Більше VRAM робить навчання швидшим.»
VRAM — це ємність, а не потужність. Більше VRAM дозволяє вмістити більші батчі, більш великі моделі, довші послідовності або більше кешованих активацій.
Воно не підвищує автоматично FLOPS або пропускну здатність пам’яті. Іноді більше VRAM спокушає команди збільшити батч, що погіршує узагальнення або дестабілізує навчання — це регресія продуктивності з додатковими кроками.
Що робити натомість:
- Купуйте VRAM для вміщення (чи зможе модель запуститись?) та для зменшення повторних обчислень (вибір checkpointing), а не заради швидкості сам по собі.
- Спочатку бенчмаркуйте з фіксованим розміром батчу. Потім вивчайте масштабування батчу й коректне налаштування learning rate.
Історичний факт: ранні GPU ери CUDA мали значно менше пам’яті, ніж CPU, що змусило індустрію винаходити розумніші батчі, злиті ядра та змішану точність.
Міф 3: «Якщо вміщується в VRAM — ви в безпеці від OOM.»
Фраза «вміщується в VRAM» приховує дві пастки: фрагментацію та пікове використання.
Багато фреймворків виділяють і звільняють тимчасові буфери під час forward/backward проходів. Піки можуть перевищувати стабільний слід.
Фрагментація може завадити виділити великий суміжний блок навіть коли «вільної пам’яті» здається достатньо.
Що робити натомість:
- Вимірюйте пікову пам’ять за ітерацію. Слідкуйте за зростанням з часом (витоки, кешування, накопичення графа).
- Використовуйте контролі аллокатора (де доступні) і уникайте патологічних схем виділення (багато тензорів різних розмірів).
- Віддавайте перевагу консистентним формам і розмірам батчів; динамічні форми чудові, поки не стають стрес-тестом для аллокатора.
Цікаво: аллокатори GPU часто використовують кешування, щоб уникнути дорогих викликів виділення на пристрої; «reserved» не означає «leaked».
Міф 4: «PCIe не має значення — вузьке місце в обчисленнях.»
PCIe важливий, коли ви рухаєте дані хост↔пристрій або пристрій↔пристрій без швидшої шини. Маленькі батчі, часті передачі або важка попередня обробка на CPU можуть зробити PCIe метрономом вашої задачі.
Гірше — PCIe часто «провалює» без видимих симптомів: слот, що працює на x4, або лінк, який навчився Gen3 замість Gen4, може виглядати «нормально», але працювати як машина з затиснутим ручним гальмом.
Що робити натомість:
- Тримайте дані на GPU довше. Зливайте операції. Уникайте перетягування тензорів на CPU для зручності.
- Перевіряйте ширину та швидкість лінку. Не припускайте за замовчуванням.
- Використовуйте pinned memory і асинхронні копії, коли потрібно передати дані.
Історичний факт: NVLink був частково введений тому, що пропускна здатність PCIe не встигала за багатогPUтним тренуванням і модельним паралелізмом.
Міф 5: «Tensor Cores / змішана точність завжди швидші.»
Змішана точність може бути подарунком. А може бути й рахунком до оплати. Ви отримуєте прискорення, коли модель і набір ядер
налаштовані для використання швидких шляхів обчислень і коли накладні витрати (касти, loss scaling, синхронізація) не домінують.
Деякі моделі стають зв’язаними по пам’яті або страждають від оверхеду запуску ядер, де зменшена точність мало допомагає.
Що робити натомість:
- Бенчмаркуйте FP32 проти AMP з фіксованими сидми та ідентичним даталоадингом.
- Слідкуйте за числовою нестабільністю: NaN’и, стрибки loss, дивергентні градієнти.
- Переконайтесь, що швидкий математичний шлях дійсно використовується (профілювання), а не просто запитується.
Цікаво: ера Tensor Core почалася з NVIDIA Volta (V100) і змінила підходи фреймворків до планування GEMM та згорток.
Міф 6: «Якщо nvidia-smi показує використану пам’ять — GPU працює.»
Використання VRAM не означає активності. Це може лише означати, що процес ініціалізував контекст і закешував алокації.
Ви можете зайняти 30 ГБ тензорами на GPU і водночас не виконувати жодних корисних обчислень, якщо робота застрягла на попередній обробці на CPU,
заблокована на локі або зависла в розподіленому з’єднанні.
Що робити натомість:
- Перевірте завантаження SM, споживання потужності та по-процесне використання.
- Корелюйте з логами застосунку: чи збільшується лічильник ітерацій? Чи ви застрягли до першого кроку?
Жарт #1: GPU з повним VRAM і без обчислень — це як конференц-зала, «зарезервована» весь день, бо хтось залишив там пляшку води.
Міф 7: «Масштабування на кількох GPU майже лінійне.»
Лінійне масштабування — це маркетингове демо, де мережа ніколи не втрачає пакет, батчі масштабуются ідеально, і ніхто не логує INFO.
У реальних системах витрати на all-reduce, «відстаючі» воркери, конкуренція за конвеєр вводу і топологічні обмеження NCCL їдять ваші прирости.
Що робити натомість:
- Вимірюйте ефективність масштабування (продуктивність / кількість GPU) і слідкуйте, де вона падає.
- Перевіряйте топологію: PCIe, NVLink, розміщення по NUMA та афінність NIC.
- Спочатку виправляйте відсталих: один повільний воркер може тягнути всю роботу вниз.
Цікавинка: ring all-reduce зробив розподілене тренування практичним, бо уникає єдиного параметрового сервера, але чутливий до найповільнішого ланцюга.
Міф 8: «Проблеми з GPU вирішуються „оновленням драйвера“.»
Драйвери важливі. Але «оновіть драйвер» — це операційний еквівалент «вимкніть і увімкніть». Іноді це правильно; часто — відволікання від реального вузького місця — конвеєра даних, неправильних частот, обмежень потужності
або контейнерного рантайму, який і взагалі не дає доступу до GPU.
Що робити натомість:
- Зафіксуйте відомо-робочі комбінації драйвер/тулкіт для вашого кластера. Оновлюйте свідомо, а не емоційно.
- Коли оновлюєте, валідируйте набором тестів продуктивності та коректності на невеликій кількості вузлів.
Історичний факт: розділення driver/runtime у CUDA потужне, але невблаганне; «працює на моєму ноутбуці» часто приховано в сумісності версій.
Міф 9: «Терміка важлива лише для геймерів.»
У продакшені терміка — це фінанси. GPU, який знижує частоти через обмеження потужності або температуру, перетворює вашу налаштовану задачу на повільну краплю.
У дата-центрах причин багато: забиті фільтри, зламані вентилятори, дивна аеродинаміка шасі або сусідній сервер з високим TDP.
Що робити натомість:
- Моніторте температури, споживання потужності та причини тротлінгу.
- Переконайтеся, що ліміт потужності встановлено правильно і охолодження працює як ви думаєте.
Цікаво: багато GPU вважають за краще тротлінг по ліміту потужності перед термальним відключенням; ви можете втратити продуктивність без драматичного «перегріву».
Міф 10: «GPU — це найважча частина; зі сховищем все вирішено.»
Сховище — місце, куди «швидке навчання» тихо вмирає. Якщо ваш датасет лежить на навантаженій спільній файловій системі,
або ви робите випадкові читання багатьох маленьких файлів, GPU проведе життя, чекаючи наступного батчу.
Ви будете звинувачувати CUDA, потім драйвери, потім фази Місяця, а весь час це буде буря метаданих на NAS.
Що робити натомість:
- Виміряйте пропускну здатність конвеєра вводу і затримку сховища під час тренування.
- Використовуйте шардинг, великі формати записів, локальні NVMe-кеші та менше дрібних файлів.
- Віддавайте перевагу послідовним читанням і prefetch замість «хаотичного випадкового доступу».
Жарт #2: GPU — це гоночний автомобіль; підгодовувати його спільним NFS з дрібними JPEG — це як тягнути човен на велосипеді.
Історичний факт: підйом форматів на кшталт TFRecord/WebDataset був зумовлений не лише зручністю ML, а й масштабованістю метаданих і сховища.
Короткі історичні й контекстні факти (бо міфи мають походження)
- CUDA з’явилась у 2007 році, перетворивши GPU з графічних пристроїв на загального призначення паралельні обчислювачі.
- Tensor Cores з’явилися з Volta (2017), змістивши налаштування продуктивності в бік матричних операцій і вибору точності.
- «Persistence mode» існує тому, що повторна ініціалізація контекстів GPU додає секунди затримки — болісно для батчових планувальників.
- Multi-Instance GPU (MIG) від NVIDIA зробив GPU шліфованими для ізоляції, але також породив питання «чому мій GPU став маленьким?» щотижня.
- NCCL став дефолтною бібліотекою для колективних операцій, бо розподілене тренування потребує ефективних по пропускній здатності алгоритмів.
- Проблеми тренування PCIe старші за сучасний ML; просто тепер вони дорожчі, коли пристрій — GPU.
- На Linux законтринена (page-locked) хост-пам’ять — різниця між асинхронними копіями і «чому memcpy блокує мій крок?»
- Тактові частоти GPU можуть керуватися лімітами потужності, термальними умовами і application clocks — три різні ручки, які люди постійно плутають.
Практичні завдання: команди, виводи та рішення
Це реальні речі, які ви можете виконати на Linux-хості з GPU. Кожне завдання містить, що означає вивід і яке рішення з нього випливає.
Не розглядайте їх як чек-лист, який запускають один раз; розглядайте як інструменти, які треба тримати каліброваними.
Завдання 1: Підтвердіть, що GPU видимий і драйвер справний
cr0x@server:~$ nvidia-smi
Tue Jan 21 11:02:13 2026
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|-----------------------------------------+----------------------+----------------------|
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA A100-SXM4-40GB On | 00000000:81:00.0 Off | 0 |
| 34% 52C P0 180W / 400W| 12000MiB / 40536MiB | 62% Default |
+-----------------------------------------+----------------------+----------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 23141 C python 11850MiB |
+---------------------------------------------------------------------------------------+
Значення: драйвер завантажений, GPU присутній, і процес дійсно його використовує.
Рішення: якщо це не так або показує «No devices were found», зупиніться і виправте драйвери/контейнерний рантайм/PCIe перед тим, як гонитися за продуктивністю.
Завдання 2: Слідкуйте за завантаженням, частотами та потужністю в часі (визначте голодування або тротлінг)
cr0x@server:~$ nvidia-smi dmon -s pucmt
# gpu pwr gtemp mtemp sm mem enc dec mclk pclk
# Idx W C C % % % % MHz MHz
0 185 53 - 61 48 0 0 1215 1410
0 85 50 - 8 6 0 0 1215 510
0 190 54 - 63 49 0 0 1215 1410
Значення: коли SM% і потужність падають разом — GPU просто простоює або чекає. Якщо SM% високий, але такти низькі — можливо тротлінг.
Рішення: простої → дослідіть конвеєр вводу/CPU/IO; тротлінг → перевірте терміку, ліміти потужності та частоти.
Завдання 3: Перевірте причини тротлінгу (ліміти потужності/термальні)
cr0x@server:~$ nvidia-smi -q -d PERFORMANCE | sed -n '1,160p'
==============NVSMI LOG==============
Performance
Clocks Throttle Reasons
Idle : Not Active
Applications Clocks Setting : Not Active
SW Power Cap : Active
HW Slowdown : Not Active
HW Thermal Slowdown : Not Active
Sync Boost : Not Active
Значення: «SW Power Cap: Active» вказує, що GPU обмежений лімітом потужності.
Рішення: підтвердьте, що ліміти потужності встановлені умисно; якщо ні — відрегулюйте ліміт потужності або виправте політику живлення/охолодження в стійці.
Завдання 4: Підтвердіть швидкість і ширину PCIe (мовчазний вбивця продуктивності)
cr0x@server:~$ nvidia-smi -q | grep -A3 "PCI"
PCI
Bus : 0x81
Device : 0x00
Domain : 0x0000
--
Link Width : 16x
Link Generation : 4
Значення: x16 Gen4 — бажаний варіант на сучасних серверах; x8 або Gen3 можуть бути очікуваними на деяких платформах, але про це потрібно знати.
Рішення: якщо бачите x4 або Gen1/2/3 несподівано — пересадіть плату, перевірте BIOS, підключення riser’ів і проводку слоту.
Завдання 5: Перевірте топологію NUMA і афінність пристрою (уникайте міжсокетного болю)
cr0x@server:~$ nvidia-smi topo -m
GPU0 NIC0 CPU Affinity NUMA Affinity
GPU0 X PHB 0-31 0
NIC0 PHB X 0-31 0
Значення: GPU і NIC ділять PCIe host bridge (PHB) і прив’язані до того самого NUMA-вузла.
Рішення: якщо GPU приєднано до NUMA-вузла 1, а потоки даталоадера працюють на вузлі 0 — прив’язуйте процеси/IRQ, щоб зменшити затримку.
Завдання 6: Перевірте доступ контейнера до GPU (класика «виконується на CPU»)
cr0x@server:~$ docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
Tue Jan 21 11:03:48 2026
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
+---------------------------------------------------------------------------------------+
Значення: контейнер бачить GPU через рантайм.
Рішення: якщо це не так — виправте конфігурацію NVIDIA Container Toolkit/рантайму перед тим, як звинувачувати ML-код.
Завдання 7: Підтвердіть, що завантажені правильні модулі ядра
cr0x@server:~$ lsmod | grep -E '^nvidia|^nvidia_uvm'
nvidia_uvm 1679360 0
nvidia_drm 126976 2
nvidia_modeset 1327104 1 nvidia_drm
nvidia 62287872 72 nvidia_uvm,nvidia_modeset
Значення: відсутність nvidia_uvm може ламати деякі CUDA-навантаження; відсутність основних модулів означає, що драйвер не завантажений.
Рішення: якщо модулі відсутні — перевірте secure boot, збірку DKMS, оновлення ядра та стан інсталяції драйвера.
Завдання 8: Виявіть вузькі місця на стороні CPU (iowait і переключення контекстів)
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0-21-generic (train-node-07) 01/21/2026 _x86_64_ (64 CPU)
11:04:10 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
11:04:11 AM all 420.0 0.0 35.0 98.0 0.0 2.0 0.0 3445.0
11:04:12 AM all 415.0 0.0 33.0 105.0 0.0 2.0 0.0 3445.0
Значення: значний iowait вказує, що латентність сховища гальмує ваш конвеєр; високий %sys може натякати на мережу або файлову систему.
Рішення: якщо iowait високий, а GPU простає, пріоритезуйте виправлення сховища та формату даних, а не налаштування GPU.
Завдання 9: Перевірте затримку файлової системи й пропускну здатність на шляху датасету
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0-21-generic (train-node-07) 01/21/2026 _x86_64_ (64 CPU)
Device r/s rkB/s rrqm/s %rrqm r_await aqu-sz %util
nvme0n1 820.0 52480.0 12.0 1.4 1.2 0.9 58.0
nfs0 1200.0 19200.0 0.0 0.0 18.5 22.0 99.0
Значення: NFS-подібний пристрій показує високу очікувану затримку і 99% завантаження: ви зв’язані сховищем для читань.
Рішення: перенесіть дані на локальний NVMe, шардуйте/упаковуйте файли, додайте кешування або перейдіть на формат з меншою кількістю метаданих.
Завдання 10: Доведіть, що на хості не використовується swap і немає тиску пам’яті
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 503Gi 212Gi 21Gi 2.1Gi 270Gi 286Gi
Swap: 16Gi 7.5Gi 8.5Gi
Значення: використання swap під час тренування — червоний прапор; воно може гальмувати даталоадери, токенізатори і кеші.
Рішення: зменшіть споживання пам’яті на хості, додайте більше ОЗП або обмежте паралелізм; уникайте swap для вузлів з критичною продуктивністю.
Завдання 11: Підтвердіть, що процес дійсно використовує GPU (і не застряг)
cr0x@server:~$ ps -o pid,ppid,stat,etime,cmd -p 23141
PID PPID STAT ELAPSED CMD
23141 22980 Sl+ 00:17:42 python train.py --config prod.yaml
Значення: процес живий; «Sl+» вказує на сон з потоками — може бути нормально, може чекати.
Рішення: якщо GPU простає, а процес спить — перевірте даталоадер, локи або розподілені бар’єри.
Завдання 12: Подивіться по-процесне використання GPU і режим обчислень
cr0x@server:~$ nvidia-smi pmon -c 1
# gpu pid type sm mem enc dec jpg ofa command
0 23141 C 62 48 0 0 0 0 python
0 1822 G 0 1 0 0 0 0 Xorg
Значення: python споживає SM і пам’ять. Якщо SM = 0 при великому використанні пам’яті — ймовірно ви застрягли або між кроками.
Рішення: корелюйте з логами; якщо застрягли — підключіть профайлер або увімкніть дебаг-логи навколо вибірки даних і forward pass.
Завдання 13: Перевірте ECC і лічильники помилок GPU (мовчазна корупція і повтори)
cr0x@server:~$ nvidia-smi -q -d ECC | sed -n '1,120p'
ECC Mode
Current ECC : Enabled
Pending ECC : Enabled
ECC Errors
Volatile
Single Bit
Device Memory : 0
Double Bit
Device Memory : 0
Значення: ECC увімкнено, лічильники чисті.
Рішення: якщо бачите зростання коригованих помилок — плануйте техобслуговування; якщо з’являються некориговані помилки — виведіть вузол з експлуатації.
Завдання 14: Підтвердіть persistence mode (зменшує затрати на ініціалізацію і нестабільність)
cr0x@server:~$ nvidia-smi -pm 1
Enabled persistence mode for GPU 00000000:81:00.0.
Значення: persistence mode тримає драйверний контекст «теплим».
Рішення: вмикайте його на виділених обчислювальних вузлах, якщо ваш оперативний режим не вимагає інакше (наприклад, суворої економії енергії).
Завдання 15: Підтвердіть політику частот / застосункові частоти (щоб уникнути випадкового зниження)
cr0x@server:~$ nvidia-smi -q -d CLOCK | sed -n '1,140p'
Clocks
Graphics : 1410 MHz
SM : 1410 MHz
Memory : 1215 MHz
Applications Clocks
Graphics : 1410 MHz
Memory : 1215 MHz
Значення: частоти там, де ви очікуєте. Якщо application clocks встановлені низько — ви будете недовантажені «таємничо».
Рішення: стандартизувати налаштування частот через провізіювання і аудитувати зсуви після оновлень драйвера.
Три міні-історії з корпоративного світу
Міні-історія 1: Інцидент через неправильне припущення (GPU «вийшов з ладу», насправді сховище)
Середня компанія запускала нічне перенавчання на спільному кластері. Одного тижня час навчання подвоївся. Оператор побачив низьке завантаження GPU,
відніс це до «погіршення GPU» і ескалував до апаратного відділу. Було відкрито тікет постачальнику. Обговорювались терміни заміни.
CFO тимчасово зацікавився ML, що означає — було погано.
Першою підказкою було те, що GPU не були гарячими. Потужність була низькою і сплескоподібною, ніби завдання бігає і потім дрімає.
Тим часом iowait CPU зріс, і спільна файлова система виглядала хворою: велика латентність, велике навантаження метаданих.
Модель була нормальною; GPU були в порядку. Тихо «вмер» конвеєр датасету.
Оптимізація, що її спричинила, була невинною: оновлення датасету, яке збільшило кількість маленьких файлів шляхом розділення шардів «для паралелізму».
На локальному SSD розробника це покращило один бенчмарк, але в продакшені на спільному сховищі вибухнуло.
Робота почала робити десятки тисяч дрібних відкриттів і stat-операцій на хвилину по багатьох воркерах.
Виправлення було нудним: упакувати зразки в більші шарди, застейджити на локальний NVMe і префетчити. Завантаження GPU підскочило як побічний ефект,
але справжній виграш — передбачуваний час кроку. Тікет на апаратне забезпечення було закрито з тихим соромом.
Міні-історія 2: Оптимізація, що відкотилася (змішана точність усюди, коректності немає)
Інша організація гналася за швидкістю. Вони включили автоматичну змішану точність глобально і відсвяткували великий приріст пропускної здатності на одному вузлі.
Потім у розподіленому тренуванні почали з’являтися періодичні NaN’и. Не завжди. Досить, щоб підірвати довіру і спричинити повторні запуски.
Шаблон інциденту був класичним: «Працює в staging, ламається в продакшені, тільки коли Місяць… зайнятий».
Справжня проблема була не в AMP сама по собі. Це був шар у моделі, який був чисельно чутливий при зменшеній точності,
плюс конфігурація loss scaling, яка працювала для однієї розподілу датасету і була крихкою для іншого.
Додайте різний порядок вибірки в мульти-воркерному даталоадингу — і нестабільність вилізла.
Команда відповіла відключенням AMP повністю. Навчання стабілізувалось, але пропускна здатність впала нижче бізнес-цілей.
Потім вони спробували компенсувати збільшенням батчу. Це змінило збіжність, вимагало переналаштування learning rate і спричинило другу хвилю регресій:
моделі навчались швидше, але працювали гірше.
Остаточне вирішення було дисциплінованим: вибірково зберегти чутливі операції у FP32, перевірити loss scaling, додати захисти від NaN,
і впроваджувати зміни з невеликим набором тестів на коректність. AMP повернувся — цього разу як інженерне рішення, а не як масовий тумблер.
Урок не в тому, що «AMP ризикований». Урок у тому, щоб ставитися до змін продуктивності як до продакшн-змін: спостерігати, тестувати, впроваджувати обережно.
Міні-історія 3: Нудна, але правильна практика, що врятувала день (топологія і pinning)
Компанія запускала мульти-GPU інференс з жорсткими SLO по хвостовій затримці. Одного дня p95 піднявся без очевидних змін у коді.
Сервіс виглядав здоровим: немає помилок, GPU видно, немає термальних тривог. Але латентність піднімалася повільно, ніби тече дірка.
Вони мали одну нудну практику, яка окупилась: при кожному завантаженні вузла запускався невеликий «hardware sanity» скрипт.
Він фіксував ширину лінку PCIe, NUMA-афінність, частоти GPU, версії драйверів і базові метрики сховища, а потім порівнював їх з відомо-робочою базою.
Коли p95 змінився, вони не гадали; вони зробили diff.
Diff показав, що на одному вузлі GPU опинився на іншому NUMA-вузлі, ніж NIC, після заміни материнської плати.
Завантаження виконувало часті host↔device передачі для попередньої та пост-обробки.
Міжсокетний трафік підвищив латентність і джиттер. GPU не сповільнився; шлях пам’яті став довшим.
Виправлення було простим: зафіксувати процес і алокації пам’яті на правильному NUMA-вузлі, відрегулювати афінність IRQ,
і оновити документацію стійки, щоб майбутні заміни відповідали топології слотів. Ніякої героїки, ніяких переписувань.
Просто відмова від «припустити, що шина в порядку».
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: пам’ять GPU висока, завантаження GPU майже нульове
- Корінна причина: затримка конвеєра даних (латентність сховища, deadlock даталоадера, повільні CPU-трансформації) або робота застрягла перед першою ітерацією.
- Виправлення: виміряйте розбивку часу кроку; перевірте iowait; зменшіть читання дрібних файлів; увімкніть prefetch; обережно збільшуйте num_workers; використовуйте pinned memory.
2) Симптом: новіший GPU повільніший за старий
- Корінна причина: ліміт потужності, неправильні частоти, downtraining PCIe або модель, що зв’язана пам’яттю, а не обчисленнями.
- Виправлення: перевірте причини тротлінгу і лінк PCIe; порівняйте споживання потужності; профілюйте ядра; настройте батч і ф’южн замість звинувачення кремнію.
3) Симптом: випадкові CUDA OOM, хоча «вільної пам’яті» достатньо
- Корінна причина: фрагментація або пікові сплески пам’яті (різні розміри, змінні послідовності, динамічні графи), або витік пам’яті в кешуючих шарах.
- Виправлення: використовуйте фіксовані форми де можливо; обмежте макс. довжину послідовності; зменшіть батч; очищайте кеші у безпечних точках; перезапускайте воркери для ресету фрагментації.
4) Симптом: масштабування multi-GPU погане, один GPU завжди відстає
- Корінна причина: відсталий воркер (CPU-конкуренція, інший NUMA-вузол, шумний сусід по IO), або NCCL використовує неоптимальний інтерфейс/топологію.
- Виправлення: перевірте топологію; зафіксуйте CPU-потоки; забезпечте консистентну локальність сховища; налаштуйте NCCL на правильний NIC; усуньте дисбаланс в даталоадингу по рангах.
5) Симптом: навчання швидке деякий час, а потім поступово гальмує
- Корінна причина: фонові конфлікти за сховище, термальне тротлінг CPU, тиск пам’яті, що викликає swap, або зростання логування/метрик з часом.
- Виправлення: моніторте в часі; обмежте логування; ізолюйте IO тренування; перевірте терміку хоста; упевніться, що немає зростання пам’яті чи витоків.
6) Симптом: «GPU доступний», але код виконується на CPU
- Корінна причина: контейнер не використовує GPU-рантайм, збірка для CPU, відсутні змінні видимості пристрою, або фреймворк не переміщує тензори на пристрій.
- Виправлення: перевірте
docker run --gpus all nvidia-smi; перевірте розміщення пристрою у фреймворку; додайте асерти щодо пристрою в коді і CI.
7) Симптом: високе завантаження GPU, але низька пропускна здатність
- Корінна причина: ви виконуєте дорогі операції неефективно: крихітні ядра, надмірна синхронізація, поганий розмір батчу або не злиті операції.
- Виправлення: профілюйте; збільшіть батч; зливайте операції; зменшіть точки синхронізації; уникайте частих кругових звернень до CPU.
Чек-листи / покроковий план
Покроково: від звіту «GPU повільний» до кореневої причини
- Зафіксуйте базову лінію. Запишіть час на крок, пропускну здатність і апаратні ідентифікатори для одного запуску. Якщо ви не можете порівняти — ви не зможете відлагодити.
- Перевірте здоров’я GPU. Запустіть
nvidia-smi, перевірте помилки/ECC, частоти та потужність. - Перевірте завантаження з контекстом. Використовуйте
nvidia-smi dmonпід час активної роботи; корелюйте провали з логами даталоадера. - Підтвердіть топологію. Переконайтесь у ширині/Gen PCIe і NUMA-афінності. Виправте очевидні неправильні розміщення першими.
- Перевірте навантаження хоста. CPU iowait, використання swap, тиск пам’яті та латентність файлової системи під час роботи.
- Доведіть пропускну здатність конвеєра даних. Виміряйте швидкість читання і затримки на шляху датасету; підтвердіть кількість файлів і шаблон доступу.
- Профілюйте одну ітерацію. Визначте час у вводі vs H2D transfer vs GPU compute vs синхронізація.
- Змінюйте по одному параметру. Батч, num_workers, глибина prefetch, режим точності. Вимірюйте після кожної зміни.
- Розгортайте обережно. Впроваджуйте зміни з набором тестів продуктивності + коректності; уникайте флотських перемикань без канарок.
Чек-лист: «Ми збираємось купувати GPU»
- Визначте, чи ви обчислювально-зв’язані або зв’язані пам’яттю/пропускною здатністю за допомогою профілювання, а не відчуттів.
- Включіть у бюджет сховище і мережу. Ваші GPU такі швидкі, наскільки швидкий ваш ввід та all-reduce.
- Перевірте живлення та охолодження для сталих навантажень, а не для спринтових демо.
- Стандартизуйте відомо-робочу матрицю драйвер/тулкіт і включіть її в провізіювання.
Чек-лист: «Ми збираємось запускати multi-GPU / розподілене»
- Підтвердіть топологію NCCL і афінність NIC.
- Усуньте відсталих: консистентний даталоадинг, фіксація CPU, консистентне IO.
- Вимірюйте ефективність масштабування при 1, 2, 4, 8… GPU. Зупиніться, коли вигоди згладжуються і виправте обмеження.
Питання й відповіді
1) Чому моє завантаження GPU низьке, хоча навчання повільне?
Низьке завантаження плюс повільне навчання зазвичай означає, що GPU чекає: даталоадинг, латентність сховища, CPU-трансформації або синхронізація.
Перевірте споживання потужності і частоти; потім перевірте iowait і латентність читання датасету.
2) Чи 100% завантаження GPU — хороша мета для сервісів inference?
Ні, якщо вам важлива затримка. Для онлайн-інференсу «гарячий» режим часто підвищує хвостову затримку і робить систему вразливою до пік-трафіку.
Плануйте ємність по SLO (p95/p99), а не заради трофею завантаження.
3) Як зрозуміти, чи я обчислювально- чи пам’яттєво-зв’язаний?
Швидка підказка: високе завантаження SM і велике споживання потужності вказують на обчислювальний тиск; низьке SM при високій пропускній здатності пам’яті — на зв’язування по пам’яті.
Реальна відповідь — профілювання: потрібно бачити, де витрачається час і чи ядра обмежені пропускною здатністю.
4) Чому я отримую CUDA OOM після годин тренування?
Типові причини: фрагментація через змінні форми, зростання кешованих алокацій або витік (збереження тензорів у списку, накопичення графа).
Слідкуйте за піковою пам’яттю з часом, встановлюйте ліміти форм і не зберігайте граф випадково.
5) Чи завжди допомагає pinned memory?
Вона допомагає для хост→пристрій передач і асинхронних копій, але забагато pinned memory може шкодити хосту, зменшуючи гнучність pageable пам’яті.
Використовуйте її свідомо: для буферів даталоадера, а не для всього підряд.
6) Чому multi-GPU навчання повільніше за одиночний GPU?
Бо ви додали комунікацію і синхронізацію. Якщо батч замалий — all-reduce домінує.
Якщо один воркер повільніший (IO, CPU, NUMA) — всі чекають. Усуньте відсталих і перевірте топологію NCCL.
7) Чи завжди вмикати змішану точність?
Вмикайте, коли виміряно, що це прискорює, і доведено, що не шкодить коректності. Деякі моделі потребують вибіркових FP32 операцій, стабільного loss scaling або інших гіперпараметрів.
Ставтеся до цього як до продакшн-зміни з тестами.
8) Чому навчання прискорюється, коли я копіюю датасет на локальний NVMe?
Бо спільні файлові системи часто не справляються з метаданично-важкими шаблонами доступу, багатьма дрібними файлами або високою конкуренцією.
Локальний NVMe зменшує латентність, уникає шумних сусідів і перетворює «випадкові читання пекла» на щось, що ядро може кешувати та префетчити.
9) Чи покращують оновлення драйверів продуктивність?
Іноді. Вони також можуть погіршити продуктивність або зламати сумісність. Фіксуйте версії, тестуйте оновлення на канарці
і розгортайте лише тоді, коли можете виміряти вигоду.
10) Як запобігти «GPU працює на низьких частотах»?
Моніторьте частоти, ліміти потужності і причини тротлінгу. Примусово встановлюйте базові налаштування через провізіювання і сповіщайте про зсуви.
Більшість «таємничих уповільнень» — це політичні зміни, а не фізика.
Висновок: наступні кроки, які ви справді можете виконати
Міфи про GPU переживають, бо вони заспокоюють. «GPU недовантажений» здається дієвим.
«Наша структура сховища викликає конфлікт метаданих при конкуренції» — це вже робота. Робіть цю роботу.
Наступні кроки:
- Оберіть одне репрезентативне завдання і зафіксуйте енд-ту-енд базову лінію: час кроку, пропускну здатність, потужність/частоти GPU та затримку IO.
- Запускайте швидкий план діагностики коли продуктивність змінилась. Починайте не з оновлення драйверів, а з обмежень конвеєра.
- Стандартизуйте перевірки «здоров’я» вузла (ширина/Gen PCIe, NUMA-афінність, частоти, версії драйверів) і робіть diff при змінах.
- Виправляйте нудні вузькі місця спочатку: формат датасету, локальне кешування, pinned memory і розміщення CPU. GPU винагороджують дисципліну.