Русские новости
Последний
ИИ и технологии

Внутри cuda-convnet: слои AlexNet на двух GPU и эпоха ImageNet

Иллюстративное изображение: деталь кристалла процессора, не GPU NVIDIA, о котором идёт речь в статье.
Иллюстративное изображение: деталь кристалла процессора, не GPU NVIDIA, о котором идёт речь в статье.

Веховая работа AlexNet 2012 года опиралась на низкоуровневую GPU-инженерию (cuda-convnet) и разделённую архитектуру на двух GPU и напрямую запустила быструю гонку за более глубокими и эффективными моделями компьютерного зрения.

1. Как cuda-convnet работал под капотом

До того как NVIDIA создала cuDNN, Алекс Крижевский написал cuda-convnet на чистом CUDA C++, чтобы выжать максимум скорости из ранних GPU архитектуры Fermi (GTX 580). Современные библиотеки обычно разворачивают свёртки в гигантские матричные умножения (im2col), что требует огромного объёма памяти. Поскольку у каждой GTX 580 было всего 3 ГБ VRAM, Крижевский разработал прямые, экономящие память GPU-процедуры.

  • Раскладка памяти с батчем впереди (CHWN). Современные фреймворки по умолчанию используют NCHW (батч, каналы, высота, ширина), при этом все пиксели одного изображения лежат в памяти рядом. Крижевский хранил тензоры в порядке CHWN, помещая измерение батча (N) последним. Когда 32 потока GPU в варпе обрабатывали 32 разных изображения в одной и той же пиксельной позиции, их чтения из памяти были полностью последовательными (coalesced), что максимизировало пропускную способность VRAM.
  • Тайлинг в разделяемой памяти. Чтение из глобальной VRAM занимает сотни тактов, тогда как встроенная разделяемая память (всего 48 КБ на потоковый мультипроцессор в GTX 580) требует лишь нескольких тактов. Блоки потоков загружали в разделяемую память небольшие двумерные фрагменты пикселей изображения и весов фильтров, вычисляя десятки скалярных произведений, прежде чем записать итоговые результаты обратно в VRAM.
  • Повторное использование регистров на уровне варпа. Крижевский поручал каждому блоку потоков вычислять тайл выходных пикселей сразу для нескольких фильтров. Благодаря хранению весов фильтров в быстрых регистрах GPU один фрагмент изображения, загруженный из разделяемой памяти, использовался сразу многими фильтрами, что резко сокращало трафик памяти.

2. Конкретные слои AlexNet и разделение на два GPU

AlexNet содержала 8 обучаемых слоёв (5 свёрточных и 3 полносвязных) с общим числом параметров примерно 60 миллионов. Поскольку одной GTX 580 не хватало 3 ГБ+ VRAM, необходимых для активаций, весов и градиентов, Крижевский вертикально разделил сеть на два параллельных потока.

СлойТипВсего фильтров / нейроновРазделение по GPUОбмен между GPU
ВходRGB-изображение224 × 224 × 3Копируется на оба GPUНет
Conv 1Свёртка 11×11 (шаг 4) + MaxPool96 фильтров48 фильтров на GPUИзолирован (без синхронизации)
Conv 2Свёртка 5×5 + MaxPool256 фильтров128 фильтров на GPUИзолирован (читает только Conv 1 своего GPU)
Conv 3Свёртка 3×3384 фильтра192 фильтра на GPUПолная синхронизация (читает все 256 карт с обоих GPU)
Conv 4Свёртка 3×3384 фильтра192 фильтра на GPUИзолирован (читает только Conv 3 своего GPU)
Conv 5Свёртка 3×3 + MaxPool256 фильтров128 фильтров на GPUИзолирован (читает только Conv 4 своего GPU)
FC 6Полносвязный + Dropout4 096 нейронов2 048 нейронов на GPUПолная синхронизация (связан со всеми выходами Conv 5)
FC 7Полносвязный + Dropout4 096 нейронов2 048 нейронов на GPUПолная синхронизация (связан со всеми нейронами FC 6)
FC 8Полносвязный (Softmax)1 000 классов1 000 классов (объединённо)Полная синхронизация (выдаёт итоговые предсказания ImageNet)
  • Естественная специализация признаков. Что интересно, поскольку слои 1 и 2 никогда не обменивались данными между GPU, две карты стабильно развивали специализированные роли. Один GPU обучался детекторам границ и текстур, не зависящим от цвета (полутоновые фильтры, похожие на фильтры Габора), а другой специализировался на цветовых пятнах и оттенках.
  • Минимизация узких мест PCIe. Передача данных по шине PCIe материнской платы была медленной. Ограничив обмен между GPU строго слоем Conv 3 и полносвязными слоями, Крижевский позволил GPU вычислять на полной скорости, не простаивая в ожидании передачи данных.

3. Что произошло дальше в эпоху ImageNet

Победа AlexNet разожгла ежегодную гонку на конкурсе ImageNet и всего за три года довела сети от 8 слоёв до более чем 150.

  • 2013 – ZFNet (визуализация & настройка). Мэтью Зайлер и Роб Фергус предложили методы деконволюции, чтобы визуализировать, что AlexNet на самом деле видела внутри скрытых слоёв. Уменьшив размер фильтра первого слоя AlexNet с 11×11 до 7×7 и снизив шаг, ZFNet снизила ошибку top-5 на ImageNet с 15,3% до 14,8%.
  • 2014 – VGGNet (глубина за счёт единообразных фильтров 3×3). Исследователи из Оксфорда доказали, что стек из множества крошечных свёрток 3×3 (до 16 или 19 слоёв) работает лучше, чем одиночные крупные фильтры (например, 11×11 или 5×5). Два подряд идущих слоя 3×3 покрывают ту же область обзора 5×5 при меньшем числе параметров и с дополнительными нелинейными активациями ReLU, снизив ошибку до 7,3%.
  • 2014 – GoogLeNet / Inception (многомасштабная эффективность). Google представила модуль Inception, который параллельно выполнял в одном слое свёртки 1×1, 3×3 и 5×5 и объединял выходы. Используя дешёвые свёртки 1×1 для сжатия глубины каналов перед дорогими вычислениями, GoogLeNet достигла 22 слоёв и ошибки 6,7%, применяя в 12 раз меньше параметров, чем AlexNet.
  • 2015 – ResNet (пропускные соединения & 152 слоя). Простое наращивание числа слоёв в итоге приводило к ухудшению точности обучения из-за затухания градиентов при обратном распространении. Microsoft Research решила это с помощью остаточных соединений (skip connections), позволяющих данным обходить слои по прямым тождественным обходным путям. Это открыло путь к сетям из 152 слоёв с ошибкой top-5 в 3,57%, впервые превзойдя уровень человека по эталонному показателю (~5%).

Больше новостей: ИИ и технологии