Keras.js предоставляет возможность запускать нейронные сети в браузере, используя WebGL для ускорения вычислений. Однако прямое выполнение инференса на основном потоке может блокировать интерфейс, особенно при работе с большими моделями. Для решения этой проблемы используется механизм Web Workers, позволяющий запускать вычисления в отдельном потоке.
Web Worker — это отдельный поток выполнения JavaScript, который работает параллельно с основным потоком страницы. Основные особенности:
postMessage и события
onmessage.Transferable Objects, что предотвращает
копирование памяти.Простейший пример создания Worker:
const worker = new Worker('worker.js');
worker.onmess age = (event) => {
console.log('Результат из воркера:', event.data);
};
worker.postMessage({ inputData: [1, 2, 3] });
В файле worker.js:
onmess age = function(event) {
const input = event.data.inputData;
const output = input.map(x => x * 2);
postMessage(output);
};
Для выполнения инференса модели Keras.js необходимо загрузить скрипт
библиотеки в контексте Worker. Обычно это делается с помощью
importScripts:
importScripts('https://cdn.jsdelivr.net/npm/keras-js@0.3.0/dist/keras.min.js');
let model;
async function loadModel() {
model = new KerasJS.Model({
filepaths: {
model: 'model.json',
weights: 'model_weights.buf'
},
gpu: true
});
await model.ready();
postMessage({ status: 'model_loaded' });
}
onmess age = async function(event) {
const { command, inputData } = event.data;
if (command === 'load_model') {
await loadModel();
} else if (command === 'predict') {
const input = { input_1: new Float32Array(inputData) };
const output = await model.predict(input);
postMessage({ result: output });
}
};
Ключевые моменты:
gpu: true позволяет использовать WebGL для ускорения
инференса.await model.ready().Float32Array оптимизирует
производительность.Передача больших массивов напрямую через
postMessage создает копию данных, что увеличивает задержку.
Чтобы этого избежать, используются Transferable
Objects:
const buffer = new Float32Array([1,2,3,4]).buffer;
worker.postMessage({ inputData: buffer }, [buffer]);
После передачи буфера он становится недоступным в основном потоке, что исключает лишнее копирование. Это критично при работе с изображениями, аудио или батчами входных данных.
Для ускорения инференса на больших потоках данных используют пул воркеров:
const NUM_WORKERS = 4;
const workers = [];
for (let i = 0; i < NUM_WORKERS; i++) {
const w = new Worker('worker.js');
w.postMessage({ command: 'load_model' });
workers.push(w);
}
// Распределение задач по воркерам
function predictBatch(batchData) {
return new Promise((resolve) => {
const results = [];
let completed = 0;
workers.forEach((worker, index) => {
worker.onmess age = (event) => {
results[index] = event.data.result;
completed++;
if (completed === workers.length) resolve(results);
};
worker.postMessage({ command: 'predict', inputData: batchData[index] });
});
});
}
Преимущества пулов:
Для стабильной работы важно правильно управлять созданием и завершением воркеров:
workers.forEach(worker => worker.terminate());
Рекомендуется:
terminate() для освобождения ресурсов
после завершения инференса.oner ror = function(error) {
postMessage({ error: error.message });
};
Float32Array для передачи входных
данных.Эта структура позволяет интегрировать Keras.js в веб-приложения с минимальной задержкой интерфейса и высокой производительностью, обеспечивая эффективный неблокирующий инференс на стороне клиента.