Запуск моделей Deep Learning Framework в Интернете — MegEngine.js

искусственный интеллект JavaScript

Недавно опубликованный «Руководство по участию в проектах платформы глубокого обучения с открытым исходным кодом«В конце статьи мы упомянули, что MegEngine с помощью разработчиков сообщества реализовал MegEngine.js — версию javascript для MegEngine, которая может быстро развертывать модели MegEngine в среде javascript.

Этот проект является проектом деятельности «Программы освещения цепочки поставок программного обеспечения с открытым исходным кодом — лето 2021 г.» Эта статья представляет собой выдержку из заключительного отчета, написанного разработчиком проекта MegEngine.js — Tricster. наслаждайся~

Информация о проекте

Описание схемы

Подключите MegEngine к Интернету с помощью WebAssembly.

Моя реализация сохранит большую часть исходного кода C++, перепишет части Python с использованием Typescript и, наконец, использует WebAssembly для соединения Typescript и C++.

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

Зачем вам Megengine.js?

Прежде чем строить колесо, лучше уточнить значение колеса и не повторять колесо. Ценность Megengine.js в основном отражается в двух аспектах:

Спрос на сквозные вычисления растет

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

Повышенный спрос в сети

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

Какова архитектура Megengine.js?

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

Архитектура большинства фреймворков глубокого обучения

Нетрудно обнаружить, что почти все фреймворки глубокого обучения на самом деле имеют схожие архитектуры, которые в основном делятся на три части, а именно:

  1. Базовый вычислительный модуль: поддержка различных устройств, различных архитектур, предоставление унифицированного интерфейса вверх, эффективное выполнение вычислений, обычно используетсяCилиC++написать.
  2. Основной логический модуль фреймворка: в дополнение к основному операционному модулю завершается основная логика глубокого обучения и рассуждений, включая, помимо прочего: построение графа вычислений, реализацию дифференциального модуля, реализацию сериализации и десериализации, большинство из которых также зависят отC++написать.
  3. Внешний интерфейс: поскольку многие пользователи сред глубокого обучения не знакомы сC++, так и должно бытьC++Кроме того, создавайте привязки для различных других языков, чаще всего используяPybindсоздаватьPythonсвязывать. Таким образом, пользователь можетPythonВ случае простоты использования, он по-прежнему имеет хорошую производительность.

отPytorchНапример, это трехслойная структура:

  1. ATenиC10Обеспечьте базовую вычислительную мощность.
  2. Зависит отC++Реализуйте основную логическую часть.
  3. будетC++часть какExtensionзаPythonзвонить, только когдаPythonпростая упаковка.

Возьмите MegEngine в качестве примера

Файловая структура MegEngine относительно ясна, в основном она выглядит следующим образом:

.
├── dnn
├── imperative
└── src 

Хотя MegEngine имеет схожую структуру, все же есть некоторые отличия.

dnnв папкеMegDnn, является базовым вычислительным модулем, который поддерживает разные архитектуры и разные платформы, такие какx86,CUDA,arm. Хотя эти модули имеют разные реализации, все они предоставляют единый интерфейс для вызова MegEngine.

Как показано на рисунке справа, операторы разных архитектур образуют древовидную структуру в соответствии с отношением включения. Хотя сейчас в основном используются операторы листовых узлов, ноnaiveиfallbackЭто также очень важная часть процесса разработки и очень полезна для реализации новых операторов.

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

MegDnn 算子组织架构图

Организационная схема оператора MegDnn

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

Наконецimperative, дополняет другие части каркаса нейронной сети, такие как обратное распространение, определения различных слоев и некоторые оптимизаторы, и используетPythonОбеспечивает простой в использовании интерфейс для внешнего мира. Стоит упомянуть, что вimperativeв использованииPybindбудетC++иPythonГлубоко связанные,PythonУже не только как открытый интерфейс, но и как часть фреймворка, участвующего в написании логики выполнения. Например, хорошим примером является функция преобразования динамического графика расчета в статический график расчета.Pythonдекоратор вC++Части статического графа вычислений в середине взаимодействуют друг с другом.

Использование такой архитектуры является относительно интуитивно понятным и гибким.Если вы хотите увеличить возможности базового вычислительного модуля, вам нужно только изменитьMegDnnПросто отлично; если вы хотите добавить функции, связанные со статическими изображениями, вам нужно только изменитьsrcчасть; если вы хотите добавить больше интерфейсных функций снаружи, просто изменитеimperativeосуществимо.

Теоретически, если вы хотите портировать MegEngine на другие языки, вам просто нужно заменитьimperativeбудет работать, но так какimperativeсерединаC++иPythonМуфта относительно тугая, надо сначала все зачиститьPythonчасть, а затем дополнить реализацию целевого языка (C++, JS или другие языки) по мере необходимости.

Идеи дизайна MegEngine.js

Основываясь на приведенном выше анализе, Megengine.js использует следующую архитектуру.

Реализация лежащего в основе повторного использования MegEngine, включая модуль вычислений и реализацию графа вычислений; затем имитацияPythonчасть использованияC++написатьRuntime,Заканчиватьimperativeфункции, предоставляемые и сохраняющие все состояния; затем используйтеWebAssemblyОткройте все вышеперечисленные модули дляTypeScriptиспользовать и использоватьTypeScriptРеализуйте остальную логику и предоставьте пользователям простой в использовании интерфейс.

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

Каково текущее состояние Megengine.js?

С точки зрения кадра

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

MegEngine.js опубликован на NPM, где пользователи могут легко его загрузить.

megenginejs

С точки зрения выполнения задачи

Задачи, перечисленные в исходной книге задач, выполнены:

  1. Модели и данные могут быть загружены

Вы можете напрямую загрузить и запустить MegEngine черезdumpПолученная модель статического графа поддерживает оптимизацию графа и оптимизацию хранения в исходной среде.

  1. плотный/матмульный (обязательно) прямой оп одиночный тест пройден

содержитmatmul21 общий оператор, включая все пройденные модульные тесты.

  1. Прогон модели линейной регрессии вперед, прогон назад и обучение модели линейной регрессии

Задача выполнена, смотрите конкретную реализациюdemo3

  1. запустить модель mnist вперед, запустить mnist назад и обучить

Задача выполнена, смотрите конкретную реализациюdemo4

  1. демо mnist

Завершено обучение и проверка mnist, но не реализована соответствующая визуализация (изменение потерь, изменение точности, тестовая выборка), см.demo4

Устранение узких мест производительности

Кроме того, потому чтоWebAssemblyИз-за ограничений Интернета и кросс-платформенных функций Интернета я не мог использовать высокооптимизированные операторы в MegEngine, что приводило к неудовлетворительной производительности на начальном этапе и не могло обеспечить бесперебойную работу, поэтому после среднесрочной перспективы , я имею в видуTensorflow.js, представил XNNPACK , реализовал новый набор операторов и существенно повысил скорость работы Megengine.js.

Бенчмарк оператора на платформе MacOS, время работы оператора свертки снижено на 83%.

WASM.BENCHMARK_CONVOLUTION_MATRIX_MUL (6169 ms)
WASM.BENCHMARK_CONVOLUTION_MATRIX_MUL (36430 ms)

Тренировка Mnist в Safari, сокращение времени одной тренировки на 52%.

Отображение основных достижений

Demo1

Megengine.js Playground, пользователи могут свободно использовать Megengine.js для тестирования связанных функций.

Megengine.js Starter

Demo2

MegEngine.js Model Executor, пользователи могут загружать модель MegEngine для рассуждений. Модель, используемая в демонстрации, экспортируется через образец кода в официальном репозитории MegEngine.

Megengine.js Model Executor

Demo3

MegEngine.js Linear Regression, демонстрация линейной регрессии, показывает, как использовать MegEngine.js для динамического обучения.

Megengine.js Linear Regression

Demo4

Megenging.js Mnist, который реализует полное обучение и проверку распознавания рукописных цифр.

Megengine.js Mnist

Больше демонстраций

Подробности смотрите в папке Example в репозитории.

megenginejs/example · megjs · Summer2021 / 210040016

С какими проблемами вы столкнулись при внедрении Megengine.js?

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

проблема компиляции

описание проблемы

Используется MegEngineC++написано, поэтому первым шагом должна быть компиляция MegEngine какWebAssembly, с помощьюEmscriptenпростоC++программа скомпилирована вWASM, но для проекта размером с MegEngine нет возможности скомпилировать его напрямую, не изменяя его.

Решение

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

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

проблема взаимодействия

описание проблемы

Будь то MegEngine или Megengine.js, вам нужно сделатьC++Базовые слои написаны для взаимодействия с другими языками. использоватьPybind, можно повнимательнееC++иPythonкомбинированный, вPythonСоздание и управлениеC++объект, но вEmscriptenЗдесь либо использовать относительно низкоуровневыйccallиcwrapили используйтеEmbindбудущееC++объект сPythonсвязывать,EmbindХотя подражаяPybind, но не обеспечивает лучшегоC++метод управления объектом, поэтому нет возможности делать такие вещи, какPybindскажи такPythonиC++тесно связаны.

Идеально,JSиC++должен управлять одной и той же переменной, напримерPythonсозданныйTensor,наследоватьC++изTensor, когдаTensorсуществуетPythonвыходит за рамки вGCПри переработке он также будет непосредственно уничтожен вC++ресурсы, созданные в . Преимущества этого вполне очевидны.Tensorможет быть непосредственно использован в качестве параметра вC++иPythonПереходя туда и обратно между ними, связь очень тесная и очень интуитивная.

Но когдаJS, этого делать нельзя, во-первыхcwrapиccallПоддерживаются только основные типы,EmbindНесмотря на то, что он поддерживает привязку пользовательских классов, он громоздок в использовании: переменные, объявленные таким образом, необходимо удалять вручную, что сильно увеличивает нагрузку.

Решение

В этом случае я выбираюC++встроенныйRuntime,использовать этоRuntimeсправлятьсяTensorЖизненный цикл используется для отслеживания переменных состояния, генерируемых при выполнении программы.

например, вJSсоздан вTensorПосле этого актуальные данные будут скопированы вC++в, вC++Создание фактических данных управленияTensor(также используется в MegEngineTensor), затем передатьC++ Runtimeуправлять этимTensor, после его создания поместите этоTensorизIDВернуться кJS. Это,JSсерединаTenosrбольше похоже на указатель, указывающий наC++тот, что вTensor.

После этого разделения, хотя им нужно управлятьC++иJSсерединаTensor, но это значительно упрощаетJSиC++между вызовами, независимо от того, используется ли базовыйccall,cwrapвсе ещеEmbindможет быть доставленTensor.

Конечно, в этом есть и недостатки, потому чтоC++иJSЭто отдельный дизайн, требующий написания множества повторяющихся функций.

Проблемы с сборщиком мусора

описание проблемы

JSиPythonу всех естьGCиз,PythonОн сыграл большую роль в MegEngine и может вовремя утилизировать неиспользуемые.Tensor, эффективность относительно высока, но вJSСитуация сложнее. Несмотря на то чтоJSТам естьGC, но сPythonПо сравнению с агрессивными стратегиями переработки,JS\ Более буддийский, может быть из-за \ сценариев использования браузера илиJSфилософия дизайна. Невозможно определить, восстанавливается ли переменная и когда, и даже когда переменная восстанавливается, нет возможности выполнить функцию обратного вызова.

Решение

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

О финализаторе

существуетJSВ новом стандарте добавлен механизм, позволяющийGCВызвать функцию обратного вызова при переработке (Finalizer) для обработки некоторых ресурсов. Идеал прекрасен.В реальном тестировании время, когда эта переменная перерабатывается, очень неопределенно (JSСтратегия утилизации более буддистская), мало того, нашаTensorДанные фактически хранятся вWebAssemblyсреди,JSизGCне могу контролироватьWASMиспользование памяти вWASMпамять заполнена из-заJSИспользование памяти здесь относительно невелико.GCи не будет перерабатываться.

По этим двум причинамFinalizerНе очень хороший выбор.

P.S. Многие браузеры еще не поддерживают Finalizer.

проблемы с производительностью

описание проблемы

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

Решение

Существует не так много BLAS, оптимизированных для Интернета. XNNPACK, запущенный Google, основан на предыдущемPytorchТе, которые оптимизированы для запущенного QNNPACK, также используются в Tensorflow.js, поэтому я решил добавить сюда XNNPACK. Однако, из-за множества ограничений в XNNPACK, не все операторы были добавлены, но скорость после доработки увеличилась.

Что дальше для Megengine.js?

После 3 месяцев разработки у меня появилось более глубокое понимание MegEngine, и я хочу все больше и больше участвовать в построении сообщества. Хотя Megengine.js имеет базовые функции, он все еще далек от полного фреймворка, и предстоит еще много работы.

Дальнейшее улучшение различных модулей

Квалифицированная среда глубокого обучения должна иметь всестороннюю поддержку операторов и модулей.В настоящее время MegEngine.js поддерживает относительно небольшое количество операторов и модулей, и в будущем необходимо добавить более практичные операторы.Дальнейшее продвижение платформы.

Еще больше повысить производительность

Улучшения производительности никогда не бывает достаточно, в такую ​​стремительную эпоху скорость бега является показателем, который нельзя игнорировать. Хотя добавление XNNPACK повышает скорость, этого недостаточно не только потому, что поддержки оператора недостаточно, но и должно быть больше возможностей для улучшения.

Дальнейшая оптимизация фреймворка

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

Расширенное чтение

[Блог автора] Глубокое обучение в Интернете | Avalon

[Учебник] Учебник по использованию MegEngine.js в мини-программах

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

Руководство по участию в проектах платформы глубокого обучения с открытым исходным кодом — включает простой в использовании список задач

Группа технического обмена MegEngine, номер группы QQ: 1029741705