Узнайте, как можно сжать модель глубокого обучения размером 500 МБ до 5 МБ практически без снижения точности.

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

Существует два основных способа развертывания модели ИИ:

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

Теперь, когда мы понимаем необходимость вывода на устройстве, необходимо рассмотреть несколько важных препятствий. Во-первых, средний размер моделей глубокого обучения составляет сотни МБ; например, VGGNet составляет ›500 МБ. Такую большую модель прямо на телефоне не развернешь. Во-вторых, это время вывода. Преимущество облачной модели в том, что вывод можно сделать с помощью графического процессора, и, следовательно, время вывода может быть минимальным. Это не тот случай, когда вам нужно запустить свою модель на телефоне, который имеет гораздо меньшую вычислительную мощность. Наконец, необходимо также учитывать энергоэффективность - работа вашей модели не должна полностью разряжать аккумулятор телефона.

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

  1. Падение / рост точности модели (рост? Да!)
  2. Размер модели
  3. Время вывода
  4. Энергоэффективность

Внутри самого сжатия модели есть две широкие категории методов. Один из классов методов сжатия направлен на уменьшение размера модели после ее обучения. Они называются методами посттренировки. Сокращение и Квантование - это два метода, которые принадлежат к этому классу. Вторая категория, с другой стороны, сначала обучает меньшую модель, чтобы она соответствовала точности более крупной модели для той же задачи. Мобильные сети (v1 и v2) являются примером этой категории методов.

MobileNets

Сначала мы обсудим категорию методов, с помощью которых для начала конструируем меньшую и эффективную модель и обучаем ее с нуля. Наиболее широко известная работа в этом классе методов сжатия называется MobileNets, которая, по сути, представляет собой набор слоев и приемов, которые делают модель глубокого обучения более эффективной с точки зрения времени выполнения, а также сокращают количество параметров. MobileNetv1 обсуждает идею глубокой разделенной свертки (DS-свертка), которая представляет собой эффективный по параметрам способ достижения результата, который дает стандартная двумерная свертка. Он также предлагает два гиперпараметра - множитель ширины и разрешения - которые можно использовать для компромисса между задержкой и точностью. Я попытаюсь объяснить разницу между сверткой DS и обычной сверткой.

Обычная операция свертки выполняется, как показано ниже:

Здесь размер входной карты функций равен I x I x M, размер ядра (также называемого фильтром по всему посту) - K x K, а желаемая выходная карта функций имеет размер O x O x N. На рисунке показано вычисление одной ячейки одного из каналов выходной карты функций. Для вычисления одного канала выходной карты функций требуется K x K x M x I x I умножения и сложения (с этого момента называемые MultAdds). Таким образом, для N-канальной выходной карты функций общее количество MultAdds составляет K x K x M x I x I x N.

Стандартная свертка сочетает в себе этап фильтрации (через ядро) и объединение входных функций (поскольку каждый фильтр имеет форму K x K x M, как показано на рисунке выше). Свертка DS разлагает эти две операции на два отдельных шага - глубинная свертка и точечная свертка - для уменьшения общего количества параметров, а также количества MultAdds.

Шаг глубинной свертки выполняет только операцию фильтрации и не объединяет входные функции. Размер фильтров и глубинная свертка визуально показаны ниже:

Шаг глубинной свертки чрезвычайно эффективен по сравнению с обычной сверткой, поскольку количество задействованных MultAdds составляет всего K x K x M x I x I.

На этапе точечной свертки используется свертка 1x1 для объединения выходных данных глубинной свертки для создания карты характеристик желаемого количества выходных каналов. Количество MultAdds в поточечной свертке M x N x O x O. Таким образом, общее количество MultAdds в свертке с разделением по глубине составляет: K x K x M x I x I + M x N x I x I (Я заменил O x O на I x I при вычислении количества MultAdds для точечной свертки, просто чтобы сравнение с обычной сверткой было простым и асимптотическим, оно выиграло неважно).

Таким образом, количество MultAdds сокращается в 1 / K² (при использовании K x K x M x I x I + M x N x I x I / K x K x M x I x I x N для вычислений и игнорировании 1/N члена, поскольку N обычно велико). Использование размера ядра (K), равного 3, дает уменьшение примерно в 8–9 раз.

В документе также представлены два гиперпараметра для настройки сетевой архитектуры с целью достижения компромисса между задержкой и точностью:
i) Множитель ширины (α): в документе количество каналов в каждой карте функций обозначается как ширина этой карты функций. α можно использовать для создания каждой карты признаков и, следовательно, сети, тоньше или толще. Для свертки DS с количеством входных каналов M и выходных каналов N использование множителя ширины α делает их «αM» и «αN» соответственно. Таким образом, количество MultAdds становится равным: K x K x αM x I x I + αM x αN x I x I. Используйте α ‹1, чтобы уменьшить ширину сети.
ii) Множитель разрешения (ρ): используется для уменьшения разрешения каждой из карт объектов в сети. Вместе с α количество MultAdds становится K x K x αM x ρI x ρI + αM x αN x ρI x ρI. Это эффективно реализуется за счет уменьшения размера ввода.

Обрезка

Теперь мы переходим к классу техник после тренировки. Первое среди них - обрезка. Общая идея показана ниже. Вы начинаете с обученной модели и, по сути, «разрезаете» или удаляете некоторые соединения, чтобы они не оказывали большого влияния на конечную точность. Результирующая модель - это сокращенная модель с меньшим количеством параметров.

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

На рисунке показаны два уровня отсечения - один на уровне отдельных соединений между нейронами, а другой на уровне узлов, где отдельные узлы удаляются (и, таким образом, любое соединение с / от этого узла).

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

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

Как показано выше, можно добиться почти никакого падения точности, удалив почти 95% параметров. Более подробную информацию можно найти в оригинальной статье здесь.

Квантование

Все гири не нужно хранить с полной точностью, и, возможно, даже не следует хранить с полной точностью. В качестве грубого примера, 1.98, 2.11, 2.03 могут быть представлены просто цифрой 2. Причина, по которой эта могла быть даже лучше исходной модели, заключается в том, что она могла обеспечивать некоторые уровень регуляризации. Однако наивное приближение может быть не лучшей идеей. Эта статья представила идею обученного квантования, при котором вы можете не только лучше выполнять квантование, но даже дополнительно обучать квантованную модель. Кроме того, как показано на изображении выше, энергоэффективность увеличивается почти в три раза при использовании 16-разрядного числа с плавающей запятой по сравнению с 32-разрядным числом с плавающей запятой.

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

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

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

Теперь нужно хранить только индексы кластера и значения центроидов. Предположим, что выбрано 16 кластеров, матрица весов может быть представлена ​​с использованием только 4 битов, что является 8-кратным уменьшением размера модели (асимптотически). Комбинируя это с кодированием Хаффмана для эффективного представления битов, окончательный размер модели может быть значительно уменьшен с небольшим падением точности. Комбинация Pruning + Quantization + Huffman coding была предложена в статье о глубоком сжатии, на которую ссылались в этом посте.

Ресурсы:

  • CS 231N Гостевая лекция: Эффективные методы и оборудование для глубокого обучения (слайды) (видео)
  • Великолепное сжатие модели (Github)
  • Официальная реализация PyTorch для MobileNetv2
  • PyTorch реализация MobileNetv1, совместимого с обнаружением объектов
  • Реализация обрезки в PyTorch (Github)
  • Реализация Deep Compression в PyTorch (Github)

Этот пост был очень мягким введением в мир сжатия моделей. Есть тонна работы, которая не была охвачена, и это активная область исследований в сообществе ИИ - с серьезным толчком со стороны промышленности. Я намерен написать еще одну запись в блоге, в которой будут описаны еще несколько методов, особенно «Внутреннее измерение» (от Uber Research) и MobileNetv2 с их кровавыми подробностями. Я надеюсь, что это было забавное чтение для вас и послужило отправной точкой для вас, чтобы теперь понять концепции, обсуждаемые выше, более подробно, а также освоить терминологию, обычно используемую в этой области.

Когда я учился в колледже, я хотел участвовать в вещах, которые изменят мир. Теперь я.
- Илон Маск

Если есть что-нибудь, чем вы, возможно, захотите поделиться со мной или высказать свое мнение по поводу моих писем / мыслей, я хотел бы услышать это от вас. Не стесняйтесь связываться со мной в LinkedIn или подписывайтесь на меня на Github. Чтобы быть в курсе моих сообщений, подписывайтесь на меня на Medium. Вы можете следить за нашей публикацией на Medium здесь.

Не забудьте дать нам 👏 и подписывайтесь на нас!