TensorFlow.js работает в браузере и Node.js, и на обеих платформах доступно множество различных конфигураций. Каждая платформа имеет уникальный набор соображений, которые влияют на способ разработки приложений.
В браузере TensorFlow.js поддерживает как мобильные, так и настольные устройства. Каждое устройство имеет определенный набор ограничений, таких как доступные API-интерфейсы WebGL, которые автоматически определяются и настраиваются для вас.
В Node.js TensorFlow.js поддерживает прямую привязку к TensorFlow API или работу с более медленными ванильными реализациями ЦП.
Окружающая среда
Когда программа TensorFlow.js выполняется, конкретная конфигурация называется средой. Среда состоит из единого глобального бэкенда, а также набора флагов, управляющих детализированными функциями TensorFlow.js.
Бэкенды
TensorFlow.js поддерживает несколько различных бэкендов, реализующих тензорное хранилище и математические операции. В любой момент времени активен только один бэкэнд. В большинстве случаев TensorFlow.js автоматически выбирает для вас лучший бэкенд с учетом текущей среды. Однако иногда важно знать, какой сервер используется и как его переключать.
Чтобы узнать, какой бэкенд вы используете:
console.log(tf.getBackend());
Если вы хотите вручную изменить бэкэнд:
tf.setBackend('cpu');
console.log(tf.getBackend());
Серверная часть WebGL
Серверная часть WebGL, 'webgl', в настоящее время является самой мощной серверной частью для браузера. Этот бэкэнд до 100 раз быстрее, чем бэкэнд ванильного процессора. Тензоры хранятся в виде текстур WebGL, а математические операции реализуются в шейдерах WebGL. Вот несколько полезных вещей, которые нужно знать при использовании этого бэкенда: \
Избегайте блокировки потока пользовательского интерфейса
Когда вызывается операция, например tf.matMul(a, b), результирующий tf.Tensor возвращается синхронно, однако вычисление матричного умножения может быть еще не готово. Это означает, что возвращаемый tf.Tensor является просто дескриптором вычисления. Когда вы вызываете x.data()
или x.array()
, значения разрешатся, когда вычисление действительно завершится. Это делает важным использование асинхронных x.data()
и x.array()
их синхронных аналогов x.dataSync()
и x.arraySync()
, чтобы избежать блокировки потока пользовательского интерфейса во время завершения вычислений.
Управление памятью
Одним из предостережений при использовании бэкенда WebGL является необходимость явного управления памятью. WebGLTextures, где в конечном счете хранятся данные Tensor, браузер не собирает мусор автоматически.
Чтобы уничтожить память tf.Tensor
, вы можете использовать метод dispose dispose()
:
const a = tf.tensor([[1, 2], [3, 4]]);
a.dispose();
Очень часто в приложении несколько операций объединяются в цепочку. Сохранение ссылок на все промежуточные переменные для их удаления может снизить читаемость кода. Чтобы решить эту проблему, TensorFlow.js предоставляет метод tf.tidy()
, который очищает все tf.Tensor
, которые не возвращаются функцией после ее выполнения, аналогично тому, как очищаются локальные переменные при выполнении функции:
const a = tf.tensor([[1, 2], [3, 4]]);
const y = tf.tidy(() => {
const result = a.square().log().neg();
return result;
});
Точность
На мобильных устройствах WebGL может поддерживать только 16-битные текстуры с плавающей запятой. Однако большинство моделей машинного обучения обучаются с использованием 32-битных весов с плавающей запятой и активаций. Это может вызвать проблемы с точностью при переносе модели на мобильное устройство, поскольку 16-битные числа с плавающей запятой могут представлять только числа в диапазоне [0.000000059605, 65504]
. Это означает, что вы должны быть осторожны, чтобы веса и активации в вашей модели не превышали этот диапазон. Чтобы проверить, поддерживает ли устройство 32-битные текстуры, проверьте значение tf.ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE')
, если оно ложно, то устройство поддерживает только 16-битные текстуры с плавающей запятой. Вы можете использовать tf.ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED')
, чтобы проверить, использует ли TensorFlow.js 32-битные текстуры.
Компиляция шейдеров и загрузка текстур
TensorFlow.js выполняет операции на графическом процессоре, запуская шейдерные программы WebGL. Эти шейдеры собираются и компилируются лениво, когда пользователь просит выполнить операцию. Компиляция шейдера происходит на ЦП в основном потоке и может выполняться медленно. TensorFlow.js будет автоматически кэшировать скомпилированные шейдеры, что значительно ускорит второй вызов той же операции с входными и выходными тензорами одинаковой формы. Как правило, приложения TensorFlow.js будут использовать одни и те же операции несколько раз за время существования приложения, поэтому второй проход через модель машинного обучения выполняется намного быстрее.
TensorFlow.js также хранит данные tf.Tensor в виде WebGLTextures. Когда создается tf.Tensor
, мы не сразу загружаем данные в GPU, а храним данные в CPU до тех пор, пока tf.Tensor
не будет использован в операции. Если tf.Tensor
используется во второй раз, данные уже находятся на графическом процессоре, поэтому затраты на загрузку отсутствуют. В типичной модели машинного обучения это означает, что веса загружаются во время первого прогноза через модель, и второй проход через модель будет намного быстрее.
Если вас волнует производительность первого прогноза с помощью вашей модели или кода TensorFlow.js, мы рекомендуем разогреть модель, передав входной тензор той же формы, прежде чем использовать реальные данные.
Например:
const model = await tf.loadLayersModel(modelUrl);
// Warmup the model before using real data.
const warmupResult = model.predict(tf.zeros(inputShape));
warmupResult.dataSync();
warmupResult.dispose();
// The second predict() will be much faster
const result = model.predict(userData);
Серверная часть Node.js TensorFlow
В бэкэнде TensorFlow Node.js, «узле», API-интерфейс TensorFlow C используется для ускорения операций. При этом будет использоваться доступное аппаратное ускорение машины, например CUDA, если оно доступно.
В этом бэкенде, как и в бэкенде WebGL, операции возвращают tf.Tensor
синхронно. Однако, в отличие от серверной части WebGL, операция завершается до того, как вы вернете тензор. Это означает, что вызов tf.matMul(a, b)
заблокирует поток пользовательского интерфейса.
По этой причине, если вы собираетесь использовать это в рабочем приложении, вам следует запускать TensorFlow.js в рабочих потоках, чтобы не блокировать основной поток.
Дополнительные сведения о Node.js см. в этом руководстве.
Серверная часть WASM
TensorFlow.js предоставляет серверную часть WebAssembly ( wasm
), которая предлагает ускорение ЦП и может использоваться в качестве альтернативы базовым процессорам JavaScript ( cpu
) и ускоренным WebGL ( webgl
). Чтобы использовать его:
// Set the backend to WASM and wait for the module to be ready.
tf.setBackend('wasm');
tf.ready().then(() => {...});
Если ваш сервер обслуживает файл .wasm
по другому пути или с другим именем, используйте setWasmPath
перед инициализацией серверной части. Дополнительные сведения см. в разделе «Использование сборщиков» в файле README:
import {setWasmPath} from '@tensorflow/tfjs-backend-wasm';
setWasmPath(yourCustomPath);
tf.setBackend('wasm');
tf.ready().then(() => {...});
Почему ВАСМ?
WASM был представлен в 2015 году как новый двоичный веб-формат, предоставляющий программам, написанным на JavaScript, C, C++ и т. д., цель компиляции для запуска в Интернете. WASM поддерживается Chrome, Safari, Firefox и Edge с 2017 года и поддерживается 90 % устройств по всему миру.
Производительность
Серверная часть WASM использует библиотеку XNNPACK для оптимизированной реализации операторов нейронных сетей.
По сравнению с JavaScript : двоичные файлы WASM, как правило, намного быстрее, чем пакеты JavaScript для загрузки, анализа и выполнения браузерами. JavaScript динамически типизируется и обрабатывается сборщиком мусора, что может привести к замедлению работы во время выполнения.
По сравнению с WebGL : WebGL быстрее, чем WASM для большинства моделей, но для крошечных моделей WASM может превзойти WebGL из-за фиксированных накладных расходов на выполнение шейдеров WebGL. В разделе «Когда следует использовать WASM» ниже обсуждаются эвристики для принятия этого решения.
Портативность и стабильность
WASM имеет портативную 32-битную арифметику с плавающей запятой, обеспечивающую точность четности на всех устройствах. WebGL, с другой стороны, зависит от аппаратного обеспечения, и разные устройства могут иметь разную точность (например, возврат к 16-битным числам с плавающей запятой на устройствах iOS).
Как и WebGL, WASM официально поддерживается всеми основными браузерами. В отличие от WebGL, WASM может работать в Node.js и использоваться на стороне сервера без необходимости компилировать собственные библиотеки.
Когда мне следует использовать WASM?
Размер модели и требования к вычислительным ресурсам
В общем, WASM — хороший выбор, когда модели меньше или вам нужны более дешевые устройства, которые не поддерживают WebGL (расширение OES_texture_float
) или имеют менее мощные графические процессоры. На приведенной ниже диаграмме показано время вывода (начиная с TensorFlow.js 1.5.2) в Chrome на MacBook Pro 2018 года для 5 наших официально поддерживаемых моделей в серверных частях WebGL, WASM и ЦП:
Меньшие модели
Модель | WebGL | ВАСМ | Процессор | Память |
---|---|---|---|---|
BlazeFace | 22,5 мс | 15,6 мс | 315,2 мс | 0,4 МБ |
FaceMesh | 19,3 мс | 19,2 мс | 335 мс | 2,8 МБ |
Большие модели
Модель | WebGL | ВАСМ | Процессор | Память |
---|---|---|---|---|
Поснет | 42,5 мс | 173,9 мс | 1514,7 мс | 4,5 МБ |
БодиПикс | 77 мс | 188,4 мс | 2683 мс | 4,6 МБ |
Мобильная сеть v2 | 37 мс | 94 мс | 923,6 мс | 13 МБ |
В приведенной выше таблице показано, что WASM в 10-30 раз быстрее, чем простой серверный процессор JS для разных моделей, и конкурирует с WebGL для небольших моделей, таких как BlazeFace , который легкий (400 КБ), но имеет приличное количество операций (~ 140). Учитывая, что программы WebGL имеют фиксированные накладные расходы на выполнение операции, это объясняет, почему такие модели, как BlazeFace, работают быстрее на WASM.
Эти результаты будут различаться в зависимости от вашего устройства. Лучший способ определить, подходит ли WASM для вашего приложения, — это протестировать его на разных серверах.
Вывод против обучения
Для решения основного варианта использования для развертывания предварительно обученных моделей при разработке серверной части WASM приоритет будет отдаваться логическим выводам , а не поддержке обучения . Ознакомьтесь с актуальным списком поддерживаемых операций в WASM и сообщите нам, если в вашей модели есть неподдерживаемая операция. Для моделей обучения мы рекомендуем использовать серверную часть Node (TensorFlow C++) или серверную часть WebGL.
Серверная часть процессора
Серверная часть ЦП, «cpu», является наименее производительной, однако самой простой. Все операции реализованы на ванильном JavaScript, что делает их менее распараллеливаемыми. Они также блокируют поток пользовательского интерфейса.
Этот бэкенд может быть очень полезен для тестирования или на устройствах, где WebGL недоступен.
Флаги
TensorFlow.js имеет набор флагов среды, которые автоматически оцениваются и определяют наилучшую конфигурацию для текущей платформы. Эти флаги в основном внутренние, но несколькими глобальными флагами можно управлять с помощью общедоступного API.
-
tf.enableProdMode():
включает производственный режим, который удаляет проверку модели, проверки NaN и другие проверки правильности в пользу производительности. -
tf.enableDebugMode()
: включает режим отладки, в котором на консоль будет записываться каждая выполняемая операция, а также информация о производительности во время выполнения, такая как объем памяти и общее время выполнения ядра. Обратите внимание, что это сильно замедлит ваше приложение, не используйте это в продакшене.