Советы по мобильному НЛП от разработчика

Текущие современные алгоритмы обработки естественного языка работают исключительно хорошо во многих задачах, но обычно не разрабатываются с учетом компактности и скорости. Эти два ограничения определяют основную проблему разработки ИИ для мобильных устройств и делают использование современных моделей NLP, таких как BERT (представления двунаправленного кодировщика от преобразователей), в большинстве случаев непрактичным. Цель этой статьи — дать начинающим разработчикам несколько практических советов, взятых из моего опыта разработки Mazidi (ИИ для мобильных устройств на основе НЛП), которые, надеюсь, ускорят ваше время развертывания. Забегая вперед, я предполагаю, что у вас есть некоторые практические знания современного НЛП, Python и Tensorflow.

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

  1. Повторное использование весов в вашей модели
  2. Уменьшите размер своего словарного запаса с помощью токенизаторов слов.
  3. Систематически тестируйте разные размеры моделей, чтобы найти хороший компромисс между размером и качеством (потери тестовой выборки не всегда являются хорошей мерой качества модели).
  4. Квантование
  5. Включить вычисления на графическом процессоре
  6. Возможна поставка вашей модели отдельно

Использование этих методов очень помогло мне уменьшить размер моей модели, в результате чего модель весила менее 20 МБ, но при этом работала исключительно хорошо. Итак, давайте разберем каждый из этих советов более подробно, не так ли?

Повторное использование весов в вашей модели

Взгляните на таблицу лидеров Squad 2.0, и вы заметите, что модели, занимающие первые места (на момент написания статьи), используют некую многослойную (глубокую) реализацию трансформера. Если вы не знаете, как реализовать трансформатор в Tensorflow, ознакомьтесь с этой статьей от разработчиков Tensorflow, в которой вы найдете отличное руководство и рабочий код. Если вы разрабатываете модель с использованием Transformer/RNN, по моему опыту, многослойность неизбежна для более сложных задач. К счастью, это не обязательно должно привести к массивной модели, мы можем уменьшить размер модели, повторно используя веса между слоями. Используя код кодировщика из статьи в качестве примера, внесение простого изменения ниже резко сократит размер модели:

От:

self.enc_layers = [EncoderLayer(d_model, num_heads, dff, rate) 
                       for _ in range(num_layers)]

To:

enc_layer = EncoderLayer(d_model, num_heads, dff, rate)
self.enc_layers = [enc_layer for _ in range(num_layers)]

Теперь мы повторно используем один и тот же слой кодировщика для каждого изnum_layers в модели. Аналогичный процесс можно применить к RNN или другим глубоким нейронным сетям.

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

  1. Для моделей кодировщика/декодера используйте одну и ту же матрицу внедрения для обоих кодировщиков/декодеров, если это возможно.
  2. Вместо окончательной матрицы проекции на ваши классы попробуйте повторно использовать матрицу встраивания для проекции, работает на удивление хорошо!
  3. С нейронными сетями идите глубже с небольшими слоями, а не с мелкими и большими слоями.

Токенизация по частям слова

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

Давайте рассмотрим рабочий пример того, как уменьшить токенизатор BERT из 30 000 токенов, состоящих из слов, до 2000 токенов. Предположим, я хочу преобразовать следующую строку в идентификаторы токенов:

Контекст:"Никола Тесла был инженером и ученым, известным разработкой двигателя переменного тока".

Используя токенизатор BERT по умолчанию, я бы получил следующее:

Tokens:
['nikola', 'tesla', 'was', 'an', 'engineer', 'and', 'scientist', 'known', 'for', 'designing', 'the', 'alternating', '-', 'current', 'motor', '.']
Token Ids:
[24794, 26060, 2001, 2019, 3992, 1998, 3925, 2124, 2005, 12697, 1996, 15122, 1011, 2783, 1006, 9353, 1007, 3751, 5013, 1012]

Токен «Никола» имеет идентификатор 24 794 или, другими словами, это 24 794-я строка матрицы вложения с 30 000 строк (довольно большая). Изменив файл «vocab.txt», сохранив только первые 5000 слов, токенизатор выдает следующее:

Tokens:
['n', '##ik', '##ol', '##a', 't', '##es', '##la', 'was', 'an', 'engineer', 'and', 'scientist', 'known', 'for', 'design', '##ing', 'the', 'al', '##ter', '##na', '##ting', '-', 'current', 'motor', '.']
Token Ids:
[56, 3567, 2834, 137, 62, 316, 808, 88, 106, 2079, 85, 3924, 211, 92, 727, 162, 83, 719, 1421, 619, 1523, 17, 870, 3100, 18]

Здесь «Никола» разбит на несколько частей, поскольку его больше нет в словаре, но все части по-прежнему имеют связанные с ними идентификаторы. Такое сжатие нашего словаря может значительно помочь уменьшить общий размер модели.

Систематически тестируйте разные размеры моделей

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

Исследователям может быть вполне комфортно увеличить размер модели на 20%, если это приведет к улучшению показателя F1 модели на 1%. Однако при рассмотрении возможности развертывания модели на мобильных устройствах необходимо более строго учитывать компромисс между размером модели и ее качеством. Кроме того, такие показатели, как F1, BLEU, потери журналов и т. д., могут оказаться не такими уж полезными при выборе модели, которую вы хотите развернуть. Ниже приведен пример вопроса, созданного Мазиди при условии, что он зависит от Контекста и Ответа:

Контекст «Поэтому Вестингауз отправил своего партнера Панталеони в Турин, чтобы купить американские права на идеи Феррари. Точно так же, как он сделал годом ранее, обеспечив патентный контроль над трансформаторами переменного тока, Вестингауз приобрел права на работу Феррариса, чтобы получить широкое освещение в области двигателей переменного тока».

Ответ"Панталеони"

Из таблицы видно, что «большая» модель (31 МБ) дает наименьшие средние потери журнала в тестовой выборке, и у меня может возникнуть соблазн сказать, что это моя «лучшая» модель, и развернуть ее. Тем не менее, пример вопроса, сгенерированный моделью «Средний», здесь так же актуален, и действительно, это имело место для многих других Context/Answer пары. Вместо использования F1, BLEU или log-loss я решил выбрать следующую модель:

  1. Примеры 20 пар контекст/ответ
  2. Составьте вопрос для каждой пары и для каждой модели (60 вопросов)
  3. Не зная, какая модель выдала какой вопрос, дайте балл модели(ям) с лучшими вопросами.
  4. Разверните модель с наибольшим количеством очков

Выяснилось, что «большая» модель работала лучше всего, но только на один балл по сравнению со «средней» моделью. Учитывая разницу в размерах между ними, для моих целей «лучшей» моделью была «Средняя» и та, которая была развернута. При выборе модели может быть лучше использовать ваши собственные субъективные показатели в систематической основе.

Квантуйте свою модель

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

Квантование вашей модели Tensorflow

Введение в квантование

Более подробное чтение

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

Вычисления на графическом процессоре

В зависимости от того, насколько параллелен ваш поток вычислений для вашей модели, перенос вычислений на графический процессор устройства может стать огромным преимуществом для снижения задержки. Mazidi делает это, когда это возможно, и это довольно легко сделать с помощью Java API Tensorflow Lite. Ниже приведен фрагмент кода, который создает экземпляр интерпретатора модели с помощью GpuDelegate.

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

Доставка вашей модели отдельно

В крайнем случае, если ваша модель все еще слишком велика, и вы беспокоитесь о шоке от стикера из-за размера загрузки вашего приложения, доставьте свою модель отдельно. Firebase — это сервис Google, который позволяет вам инициировать загрузку вашей модели, когда это необходимо вашему приложению, избегая необходимости связывать ее в вашем APK. Причина, по которой Mazidi избегает этого метода, заключается в том, что на момент написания Firebase API не поддерживал перенос вычислений на GPU, так что имейте это в виду.

Вывод

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