Next.js: серверные компоненты, dynamic import, заголовки

ONNX Runtime Web (ORT Web) предоставляет высокопроизводительную среду для выполнения моделей машинного обучения, подготовленных в формате ONNX, непосредственно в браузере с использованием WebAssembly (WASM) или WebGPU. Для начала работы необходимо установить пакет:

npm install onnxruntime-web

Импорт модуля в проекте осуществляется через стандартный синтаксис ES6:

import * as ort from 'onnxruntime-web';

Библиотека поддерживает несколько бэкендов выполнения: wasm, webgl и webgpu. По умолчанию используется wasm, который работает на всех современных браузерах без дополнительных настроек.


Создание и загрузка сессии модели

Основной объект для работы с моделью — InferenceSession. Он инкапсулирует всю информацию о вычислительной сессии и предоставляет метод run для инференса.

const session = await ort.InferenceSession.create('model.onnx', {
  executionProviders: ['wasm'], // можно указать 'webgl' или 'webgpu'
});

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


Подготовка входных данных

Для инференса модель принимает входы в формате Tensor. Типы данных должны соответствовать определению модели. Пример подготовки тензора для модели, принимающей изображение:

const inputTensor = new ort.Tensor('float32', imageData, [1, 3, 224, 224]);
  • Первый аргумент — тип данных (float32, int32 и др.).
  • Второй аргумент — одномерный массив с данными.
  • Третий аргумент — форма (shape) тензора.

Важно следить за порядком осей. Для изображений часто используется формат [batch, channels, height, width].


Выполнение инференса

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

const feeds = { input: inputTensor };
const results = await session.run(feeds);
console.log(results.output.data);

Если модель имеет несколько выходов, каждый можно получить по ключу, указанному в ONNX модели.


Оптимизация производительности

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

Выбор подходящего бэкенда. webgl и webgpu используют GPU, что ускоряет работу моделей с большими тензорами, особенно для свёрточных нейросетей.

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


Обработка ошибок

ORT Web предоставляет понятные сообщения об ошибках. Чаще всего встречаются:

  • Несовпадение формы тензора: проверка формы входных данных и типов.
  • Ошибки загрузки модели: отсутствие файла или неправильный путь.
  • Недоступность выбранного execution provider: проверка поддержки браузером.

Пример обработки:

try {
  const session = await ort.InferenceSession.create('model.onnx');
  const results = await session.run(feeds);
} catch (e) {
  console.error('Ошибка инференса:', e);
}

Использование WebGPU для ускорения

Для использования WebGPU необходимо убедиться, что браузер поддерживает экспериментальный API:

if (ort.env.webgpu.isSupported) {
  const session = await ort.InferenceSession.create('model.onnx', {
    executionProviders: ['webgpu'],
  });
}

Преимущество WebGPU заключается в снижении времени обработки больших свёрточных и полносвязных моделей, где CPU и WASM оказываются медленными.


Интеграция с Next.js

В Next.js выполнение ONNX Runtime Web может быть выполнено на клиентской стороне, так как ORT Web требует браузерные API:

"use client";

import * as ort from 'onnxruntime-web';
import { useEffect, useState } from 'react';

export default function ModelComponent() {
  const [result, setResult] = useState(null);

  useEffect(() => {
    async function runModel() {
      const session = await ort.InferenceSession.create('/model.onnx');
      const input = new ort.Tensor('float32', [0, 0, 0, 0], [1, 4]);
      const output = await session.run({ input });
      setResult(output.output.data);
    }
    runModel();
  }, []);

  return <div>Результат: {JSON.stringify(result)}</div>;
}

Важно использовать "use client" для компонентов, где выполняется инференс, так как серверные компоненты Next.js не имеют доступа к Web API, необходимым для работы ORT Web.


Загрузка модели динамически

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

const ModelLoader = dynamic(() => import('./ModelComponent'), { ssr: false });

Здесь ssr: false гарантирует выполнение только на клиенте.


Работа с большими моделями и потоками данных

Для моделей, размер которых превышает десятки мегабайт, рекомендуется:

  • Использовать fetch с потоковой загрузкой.
  • Преобразовывать данные в подходящий формат до передачи в тензор.
  • Оптимизировать порядок вычислений, чтобы минимизировать промежуточные копии.
const response = await fetch('/large-model.onnx');
const arrayBuffer = await response.arrayBuffer();
const session = await ort.InferenceSession.create(arrayBuffer);

Управление памятью

ORT Web использует WebAssembly память, которая может увеличиваться по мере создания новых тензоров. Для долгоживущих приложений важно очищать ненужные тензоры, используя Tensor.dispose() или просто удаляя ссылки на них.


Особенности совместимости

  • Некоторые модели ONNX используют операторы, которые не поддерживаются на WebGPU. В таких случаях рекомендуется fallback на WASM.
  • Не все типы данных (например, double) поддерживаются в веб-бэкендах. Часто требуется конвертация в float32.
  • Для анимации и потоковой обработки изображений лучше использовать асинхронные функции и requestAnimationFrame для снижения блокировки UI.