Назад
286

Введение в методы ускорения свёрточных нейронных сетей

286

Всё чаще DL-инженерам приходится ускорять нейросети, чтобы уместить их на процессоре смартфона, микрокомпьютере или просто снизить нагрузку на сервер.

Чтобы помочь вам погрузиться в тему ускорения, мы кратко познакомим вас с основными методами для CNN.

Рассмотрим четыре подхода к ускорению и для каждого расскажем:

  • краткое описание подхода
  • мотивацию к использованию
  • пример частного случая

В первом подходе предлагается не ускорять имеющуюся сеть, а изначально подобрать оптимальную архитектуру.

Нейросетевой архитектурный поиск (Neural Architecture Search или NAS) — семейство методов, позволяющих выбрать оптимальную комбинацию слоёв и их параметров под конкретную задачу.

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

Главное, что надо понимать: выбор слоёв при поиске ограничен! Ибо перебрать все возможные варианты слоев и их параметров — невозможно.

В начале поиска в NAS алгоритмах требуется указать:

  • пространство поиска
  • метод оптимизации
  • метод оценки архитектуры

Например, в MNasNet, на котором стоит MobileNetV3, пространство поиска состоит из DWS блоков или обычных сверток, ядра выбирали размером 3 или 5, а для skip connection выбрали сложение, pooling или вообще их исключение. В качестве алгоритма поиска использовали RL, а оптимизировали время работы на смартфоне и точность.

💡 Но не спешите применять эту технологию! Можно потерять много времени, а результаты получить не лучше уже доступных.

Нужно быстро запускать на телефоне — можете выбрать MobileNetV3. На сервере — подойдет EfficientNet. Эти модели уже подобрали архитектурным поиском.

Беритесь за NAS только случаях, когда другие способы уже себя исчерпали.

Описание частного случая NAS: DARTS

https://arxiv.org/pdf/1806.09055.pdf

Метод поиска архитектур DARTS интересен двумя аспектами:

  1. для него достаточно одной GPU и недели времени;
  2. он полностью дифференцируем, в отличии от своих предшественников (эволюционные алгоритмы, обучение с подкреплением).

Дифференцируемость позволяет искать архитектуру в “непрерывном пространстве”. Да, пространство всё ещё состоит из заранее заданных блоков, но вот переключение между блоками пространства во время поиска реализуется плавно, как их взвешенная сумма.

Каждый слой сети представляется более сложной операцией, которая представляет из себя взвешенную сумму базовых операций из пространства поиска. При этом, весовые коэффициенты, с которыми складываются операции (а точнее результаты их работы) становятся обучаемыми.

Это дает возможность увеличивать вклад более полезных операций и минимизировать вклад менее полезных. Домножение происходит по следующей формуле:

где значение выхода \(\overline{o}\) слоя для входа 𝑥 вычисляется, как взвешенная сумма всех возможных в этом слое типов блоков \(𝑜^𝑘(𝑥)\) с нормированными весами \(α^k\).

Такой трюк позволяет обучать сеть методами градиентного спуска. После обучения архитектуру составляют из операций с наибольшим весом. Эффективность такого подхода можно увидеть в таблице (последняя строка):

Сравнение точности различных архитектур на наборе данных ImageNet. Первые три — широко известны и созданы людьми. Все остальные найдены автоматически. Последняя строка — метод DARTS, которому потребовалось всего 4 дня на одной GPU.

⚠️ При использовании DARTS, потребление памяти растёт линейно с увеличением числа блоков в каждом слое!

Это решаемая проблема, но ее рассмотрение выходит за рамки обзорной статьи.

Дистилляция

К дистилляции относятся подходы к обучению нейронных сетей с меньшим числом параметров за счёт «передачи знаний» от сетей с большим числом параметров.

Ключевая идея: сеть с небольшим количеством весов потенциально обучаема до большей точности, но она не способна сделать этого самостоятельно.

При дистилляции такая модель обучается повторять свойства сети с большим числом параметров. Например, приближать распределения весов или выходные векторы признаков. Для этого используют дополнительные слагаемые в функции потерь, которые штрафует модель за расхождение распределений предсказаний или расхождение промежуточных активаций моделей. В качестве функции потерь используют, например, KL-дивергенцию или MSE.

💡 Беседу о дистилляции традиционно начинают с введения понятия “dark knowledge” (тайное знание!) введённого Хинтоном в статье, где он изобрёл дистилляцию.

Хинтон утверждает, что большая сеть способна эффективно обобщать данные и извлекать из них такие признаки, которые малая сеть не в состоянии “разглядеть”. Удачно найденные признаки и закономерности Хинтон и называет “dark knowledge” — что-то, чем обладает большая сеть и, возможно, если передать это сети поменьше, она начнёт работать лучше.

Метод, предложенный Хинтоном для передачи dark knowledge: «Давайте при обучении классификации будем обращать внимание не только на правильный класс, но и на распределение вероятностей в ответе в целом». Скажем, мы хотим проклассифицировать собаку:

Гав!

Большая сеть способна не только правильно угадать её породу, но и дать вразумительные догадки на какие ещё породы она похожа. Однако зачастую по выходу softmax сложно делать какие-то суждения о других классах из-за явного пика в top-1. Поэтому его требуется модифицировать. Так Хинтон добавляет температуру T, которая регулирует насколько мы хотим видеть какие-то классы кроме основного предсказанного:

Теперь мы получаем некоторый dark knowledge — информацию изнутри сети. Так она думает распределены вероятности для какой-то картинки.

При этом эта модификация T простая, как топор: просто делим все входные значения в softmax на некоторую константу T:

Формула для солидности

А уже затем, используя KL-дивергенцию (или реже MSE), стягиваем вероятности меньшей сети к вероятностям большей сети.

Описание частного случая дистилляции: BAN

http://proceedings.mlr.press/v80/furlanello18a/furlanello18a.pdf

Обратите внимание: дистилляция может быть очень эффективным методом. В некотрых случаях она позволяет получить лучшую точность в сравнении с большой сетью, из которой производится.

Сравнение ошибки на CIFAR100. Использование техники дистилляции позволило получить ошибку даже меньше, чем у сети учителя!

Применяя технику дистилляции, авторы работы смогли получить наибольшую точность для наборов данных CIFAR-10 и CIFAR-100.

Это достигается за счёт использования техники дистилляции не для сокращения числа параметров в сети, а для повышения её обобщающей способности.

Для этого авторы обучают последовательно несколько нейронных сетей с одинаковой архитектурой и случайной инициализацией параметров. При этом в качестве обучающих данных используют предсказания предыдущих обученных сетей.

Получается последовательная дистилляция из модели в модель. Приятный бонус: итоговую последовательность сетей можно объединить в ансамбль для ещё большего увеличения точности модели.

Прунинг

Прунинг — семейство методов, основанных на удалении «лишних» весов из нейронной сети. Лишние — те, что наименьшим образом влияют на результат работы модели.

Алгоритмы выглядит примерно так:

  1. определяем критерий оценки «важности» веса;
  2. удаляем заданный процент самых «не важных» весов;
  3. дообучаем сеть;
  4. повторяем пункты 2 и 3 пока не достигнем желаемого ускорения.

Существующие на сегодняшний день алгоритмы прунинга можно разделить по следующим признакам:

Неструктурированный
— не учитывает связи между различными параметрами при их удалении. При неструктурированном прунинге мы просто зануляем некоторые значения в матрице весов.

Такой метод даёт большую гибкость при удалении и, как правило, позволяет удалить большее количество весов.

Однако на практике это часто приводит к разрежённости матриц параметров и снижению эффективности вычислений на реальном устройстве (GPU в холостую перемножает нули).

Структурированный
— удаляем группы параметров, а не отдельные значения. То есть удаляем всю матрицу: часть свёрточных фильтров или даже слой целиком.

В основном на практике используют именно этот метод, так как он позволяет действительно сократить количество операций. Ведь выброшенные фильтры из свертки не просто зануляются, а вовсе удаляются из сети.

Но если в группе окажется небольшая доля важных весов, их тоже отбросят. Поэтому метод менее гибок.

Оценка важности по значению веса параметра
— считаем, что чем больше абсолютное значение параметра, тем он важнее.
Но такие методы не всегда оптимальны.
В целом, странно предполагать, что в сети должны быть только маленькие значения.

Оценка по величине протекающего градиента
— считаем, что чем больше значение градиента в среднем протекало через этот параметр во время обучения, тем он важнее.
Этот способ пользуется большей популярностью, так как показывает хорошие результаты и не зависит от регуляризаций на величину веса.

Последовательное удаление с дообучением
— удаляем веса малыми порциями с дообучением на каждом шаге.
Такой метод более устойчив к снижению точности, так как мы даем сети адаптироваться к отсутствию весов.

1 раз удалить веса, 1 раз дообучить модель
— название говорит само за себя.
На практике показывает результаты хуже, поэтому не популярно.

Современные DL-фреймворки поддерживают различные алгоритмы прунинга в своём API:

Описание частного случая прунинга: Лотерейные билеты

https://arxiv.org/pdf/1803.03635.pdf

Интересный с точки зрения идеи и её описания подход. Гипотеза о лотерейных билетах заключается в следующем: если случайным образом инициализировать веса нейронной сети, то найдётся такая её подсеть, которая за меньшее или такое же число шагов обучения будет сходиться к той же точности, что и исходная сеть.

Интуитивно гипотеза объясняется так: мы можем выбрать подсеть достаточно большим количеством способов, чтобы утверждать, что вероятность её существования не нулевая.

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

  1. параметры нейронной сети инициализируют случайными значениями из некоторого распределения, значения сохраняются в буфер;
  2. сеть обучается до сходимости;
  3. удаляют желаемый процент параметров на основе их абсолютного значения;
  4. сеть обучают без этих параметров, зануляя их маской, остальные параметры инициализируют сохраненными в буфере значениями;
  5. можно вернуться к пункту 3 и повторять до тех пор, пока не достигнем желаемого размера сети или не получим критическое снижение точности.

💡 Полученная таким образом сеть будет подсетью исходной модели. Но интересно, что если не восстанавливать оставшиеся веса из буфера на каждом шаге, а инициализировать их заново, метод работать не будет.

Квантование

Последний по порядку, но не по значимости, метод использует понижение дискретности весов нейронной сети для эффективного использования вычислителя.

Так, нейронная сеть, обученная с использованием 32-битных чисел с плавающей запятой (float32) может быть заквантована и выполняться на мобильном процессоре в 8-битных беззнаковых целых числах (uint8) или в серверном решении с уполовиниванием ёмкости весов (float16).

Подходы к квантованию основываются на вычислении коэффициентов сдвига и масштабирования значений весов, чтобы перевести веса в более узкий диапазон (32 → 8) (объясним в формуле ниже).

Математически квантование весов нейронной сети можно представить следующим образом:

«Скукожить и сдвинуть распределение»

где для квантования веса r мы сжимаем его до требуемого диапазона, конвертируем в необходимый тип данных и сдвигаем точку нуля. При этом коэффициент S, отвечающий за «масштаб» веса, вычисляется следующим образом:

Коэффициент сжатия

Где b — число бит, в которое производится квантование, а вот alpha и beta — левая и правая границы возможных значений веса. В зависимости от способа выбора этих alpha и beta различают следующие способы квантования:

  • Симметричное или асимметричное квантование — левая и правая границы квантуемых значений веса симметричны или не симметричны относительно нуля;
  • Статическое или динамическое квантование — левая и правая границы квантуемых значений фиксируется при обучении или выбираются динамически на этапе инференса сети;
  • Поканальное или послойное квантование — выбор левой и правой границ квантуемых значений определяется для каждого свёрточного фильтра отдельно или для всего слоя целиком;
  • Квантование при обучении или квантование после обучения — квантование можно выполнять во время обучения сети или над уже обученной сетью с последующим дообучением.

Квантование как инструмент широко применяется при разработке нейронных сетей для мобильных приложений. Так как с помощью него даже при отсутствии специального вычислителя удаётся поднять скорость в несколько раз (регистр, который до этого обрабатывал один float32, теперь может обработать четыре uint8 за раз).

Описание частного случая квантования: “как в Tensorflow”

https://openaccess.thecvf.com/content_cvpr_2018/papers/Jacob_Quantization_and_Training_CVPR_2018_paper.pdf

Для квантования моделей Tensorflow использует подход асимметричного статичного послойного квантования, требующий дообучения модели.

Предложенный ими метод осуществляет квантование в 8 бит и получил широкую популярность из-за того, что их фреймворк имеет эффективную реализацию для инференса на мобильных устройствах.

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

Проще говоря, все квантуют сети, где много весов, а тут квантуют сети с любым числом весов. В частности, была продемонстрирована эффективность квантования для архитектуры MobileNet SSD для задачи детекции объектов на датасете COCO. Даже для архитектуры, изначально оптимизированной для мобильного телефона, данный подход позволил получить минимальное снижение mAP (метрика для детекции), показав существенный выигрыш по скорости выполнения:

Big и LITTLE — различные версии ядер Snapdragon процессора. mAP показывает насколько хорошо работает детекция.

Итог

Не обязательно применять все описанные в статье подходы сразу. Их можно комбинировать в зависимости от ваших ресурсов и времени, отведённого на решение задачи.

💡 Практический совет для дочитавших: если вам нужно что-то ускорить, начните с дистилляции и квантования. И только если это не поможет — принимайтесь за остальное.

⚠️ Но, помимо изменений самой архитектуры, можно ускорять модели за счет конвертации моделей или использования подходящего бэкенда!

Старт — 30 сентября
Ускорение нейросетей

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

0/0

Телеграм-канал

DeepSchool

Короткие посты по теории ML/DL, полезные
библиотеки и фреймворки, вопросы с собеседований
и советы, которые помогут в работе

Открыть Телеграм

Увидели ошибку?

Напишите нам в Telegram!