Недавно опубликованный «Руководство по участию в проектах платформы глубокого обучения с открытым исходным кодом«В конце статьи мы упомянули, что 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?
Если вы хотите быстро понять проект, лучше сначала изучить архитектуру проекта и технологии, используемые в проекте, с точки зрения высокого уровня, а затем углубиться в детали кода.
Архитектура большинства фреймворков глубокого обучения
Нетрудно обнаружить, что почти все фреймворки глубокого обучения на самом деле имеют схожие архитектуры, которые в основном делятся на три части, а именно:
- Базовый вычислительный модуль: поддержка различных устройств, различных архитектур, предоставление унифицированного интерфейса вверх, эффективное выполнение вычислений, обычно используется
C
илиC++
написать. - Основной логический модуль фреймворка: в дополнение к основному операционному модулю завершается основная логика глубокого обучения и рассуждений, включая, помимо прочего: построение графа вычислений, реализацию дифференциального модуля, реализацию сериализации и десериализации, большинство из которых также зависят от
C++
написать. - Внешний интерфейс: поскольку многие пользователи сред глубокого обучения не знакомы с
C++
, так и должно бытьC++
Кроме того, создавайте привязки для различных других языков, чаще всего используяPybind
создаватьPython
связывать. Таким образом, пользователь можетPython
В случае простоты использования, он по-прежнему имеет хорошую производительность.
отPytorch
Например, это трехслойная структура:
-
ATen
иC10
Обеспечьте базовую вычислительную мощность. - Зависит от
C++
Реализуйте основную логическую часть. - будет
C++
часть какExtension
заPython
звонить, только когдаPython
простая упаковка.
Возьмите MegEngine в качестве примера
Файловая структура MegEngine относительно ясна, в основном она выглядит следующим образом:
.
├── dnn
├── imperative
└── src
Хотя MegEngine имеет схожую структуру, все же есть некоторые отличия.
dnn
в папкеMegDnn
, является базовым вычислительным модулем, который поддерживает разные архитектуры и разные платформы, такие какx86
,CUDA
,arm
. Хотя эти модули имеют разные реализации, все они предоставляют единый интерфейс для вызова MegEngine.
Как показано на рисунке справа, операторы разных архитектур образуют древовидную структуру в соответствии с отношением включения. Хотя сейчас в основном используются операторы листовых узлов, ноnaive
иfallback
Это также очень важная часть процесса разработки и очень полезна для реализации новых операторов.
Кроме того, сэмплирование такой древовидной структуры позволяет хорошо повторно использовать код, например, мы можем реализовать только некоторые операторы, а другие операторы могут искать существующие реализации, что может сэкономить много работы.
Организационная схема оператора 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, где пользователи могут легко его загрузить.
С точки зрения выполнения задачи
Задачи, перечисленные в исходной книге задач, выполнены:
- Модели и данные могут быть загружены
Вы можете напрямую загрузить и запустить MegEngine черезdump
Полученная модель статического графа поддерживает оптимизацию графа и оптимизацию хранения в исходной среде.
- плотный/матмульный (обязательно) прямой оп одиночный тест пройден
содержитmatmul
21 общий оператор, включая все пройденные модульные тесты.
- Прогон модели линейной регрессии вперед, прогон назад и обучение модели линейной регрессии
Задача выполнена, смотрите конкретную реализациюdemo3
- запустить модель mnist вперед, запустить mnist назад и обучить
Задача выполнена, смотрите конкретную реализациюdemo4
- демо 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 для тестирования связанных функций.
Demo2
MegEngine.js Model Executor, пользователи могут загружать модель MegEngine для рассуждений. Модель, используемая в демонстрации, экспортируется через образец кода в официальном репозитории MegEngine.
Demo3
MegEngine.js Linear Regression, демонстрация линейной регрессии, показывает, как использовать MegEngine.js для динамического обучения.
Megengine.js Linear Regression
Demo4
Megenging.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