Kлючевой особенностью современных веб-приложений для машинного обучения является возможность использовать многопоточность для повышения производительности. В среде JavaScript это достигается через Web Workers и объект SharedArrayBuffer, позволяющий нескольким потокам совместно использовать область памяти.
SharedArrayBuffer — это тип объекта, который создаёт
область памяти, доступную одновременно нескольким Web Workers без
копирования данных. В отличие от обычного ArrayBuffer,
который передаётся между потоками по принципу клонирования,
SharedArrayBuffer обеспечивает прямой доступ к одной и той
же памяти, что критично для производительных вычислений, таких как
нейросетевые операции.
Пример создания:
const buffer = new SharedArrayBuffer(1024); // 1024 байта общей памяти
const sharedArray = new Float32Array(buffer); // представление как массив float
Ключевое преимущество — отсутствие затрат на копирование больших массивов данных между потоками.
Keras.js реализует нейронные сети в браузере с поддержкой WebGL и CPU. Для CPU-вычислений интенсивные операции, например матричные умножения и свёртки, могут быть распараллелены. SharedArrayBuffer позволяет хранить веса сети и промежуточные тензоры в общей памяти, доступной для всех воркеров.
Пример параллельного вычисления матричного умножения:
// В основном потоке создаём общий буфер
const size = 1024;
const sharedBuffer = new SharedArrayBuffer(size * Float32Array.BYTES_PER_ELEMENT);
const matrixA = new Float32Array(sharedBuffer);
const matrixB = new Float32Array(size); // отдельная матрица для примера
// Запуск Web Worker для вычислений
const worker = new Worker('matrixWorker.js');
worker.postMessage({ buffer: sharedBuffer, size: size });
В воркере:
onmess age = function(e) {
const { buffer, size } = e.data;
const matrixA = new Float32Array(buffer);
// Выполнение параллельных вычислений с использованием Atomics
for (let i = 0; i < size; i++) {
Atomics.add(matrixA, i, 1); // пример атомарной операции
}
postMessage('done');
}
Использование Atomics необходимо для корректного обновления данных несколькими потоками без гонок данных.
Keras.js не управляет потоками автоматически, но разработчик может создать пул воркеров для распараллеливания операций. Общие рекомендации:
Keras.js поддерживает вычисления на GPU через WebGL. В этом случае SharedArrayBuffer используется преимущественно для CPU-части, например:
import KerasJS from 'keras-js';
const model = new KerasJS.Model({
filepaths: {
model: 'model.json',
weights: 'weights.buf',
metadata: 'metadata.json'
},
gpu: false
});
// Создание общего буфера для входного тензора
const sharedInputBuffer = new SharedArrayBuffer(224*224*3*Float32Array.BYTES_PER_ELEMENT);
const inputTensor = new Float32Array(sharedInputBuffer);
// Распараллеливание заполнения входного тензора
const numWorkers = 4;
const chunkSize = inputTensor.length / numWorkers;
for (let i = 0; i < numWorkers; i++) {
const worker = new Worker('inputWorker.js');
worker.postMessage({ buffer: sharedInputBuffer, start: i*chunkSize, end: (i+1)*chunkSize });
}
// После заполнения данных можно выполнить инференс
model.ready().then(() => {
model.predict({ input: inputTensor }).then(output => {
console.log(output);
});
});
Вывод: использование SharedArrayBuffer в сочетании с Web Workers и Keras.js позволяет добиться значительного ускорения CPU-вычислений нейросетей в браузере, особенно для больших тензоров и многослойных моделей. Атомарные операции и корректное разделение данных между потоками критически важны для предотвращения гонок данных и обеспечения стабильности вычислений.