При работе с нейронными сетями в браузере часто возникает необходимость использовать Web Workers для выполнения вычислительно интенсивных операций в отдельном потоке, чтобы не блокировать пользовательский интерфейс. Библиотека Synaptic предоставляет гибкие средства для создания и обучения нейронных сетей, однако объекты сети нельзя напрямую передавать между потоками из-за ограничений сериализации JavaScript. Необходим подход, который позволяет сериализовать модель, передать её в Worker и восстановить там для дальнейшего использования.
Synaptic предоставляет методы toJSON()
и fromJSON(), которые позволяют
преобразовать объект сети в сериализуемый формат и восстановить его.
// Создание сети
const { Layer, Network } = require('synaptic');
const inputLayer = new Layer(2);
const hiddenLayer = new Layer(3);
const outputLayer = new Layer(1);
inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);
const network = new Network({
input: inputLayer,
hidden: [hiddenLayer],
output: outputLayer
});
// Сериализация сети в JSON
const networkJSON = network.toJSON();
Сериализация превращает структуру сети, веса и смещения в объект,
который можно безопасно передавать через
postMessage в Worker:
worker.postMessage({ type: 'loadNetwork', networkData: networkJSON });
Внутри Worker сеть восстанавливается с помощью
fromJSON:
importScripts('synaptic.js');
let workerNetwork = null;
self.onmess age = function(event) {
if (event.data.type === 'loadNetwork') {
const { Network } = synaptic;
workerNetwork = Network.fromJSON(event.data.networkData);
}
};
Существует два основных подхода к обмену данными между главным потоком и Worker:
Обмен объектами через postMessage
Работает для сериализуемых объектов: массивов, объектов, JSON. Для
моделей Synaptic это основной метод.
Использование Transferable Objects
Для больших массивов данных, например входных сигналов или батчей
обучающих примеров, эффективнее передавать ArrayBuffer.
Это предотвращает копирование и ускоряет обмен данными:
const inputArray = new Float32Array([0.1, 0.9]);
worker.postMessage(inputArray.buffer, [inputArray.buffer]);
В Worker можно получить данные обратно, обернув буфер в TypedArray:
self.onmess age = function(event) {
const inputs = new Float32Array(event.data);
const output = workerNetwork.activate(inputs);
self.postMessage(output);
};
После обучения модели в Worker может возникнуть необходимость передать обновлённые веса обратно в главный поток. Для этого используется та же сериализация:
// В Worker после обучения
const updatedNetworkJSON = workerNetwork.toJSON();
self.postMessage({ type: 'updateNetwork', networkData: updatedNetworkJSON });
В главном потоке:
worker.onmess age = function(event) {
if (event.data.type === 'updateNetwork') {
network = Network.fromJSON(event.data.networkData);
}
};
Такой подход позволяет полностью сохранять состояние сети между потоками, включая структуру, веса и смещения, что особенно важно для долгих обучающих сессий.
postMessage без сериализации. Любая
попытка передачи сложных объектов приведёт к ошибкам или потере
данных.fromJSON необходимо
использовать объект Synaptic, чтобы методы сети были доступны.Главный поток:
const worker = new Worker('worker.js');
// Отправка модели в Worker
worker.postMessage({ type: 'loadNetwork', networkData: network.toJSON() });
// Отправка входных данных
worker.postMessage({ type: 'activate', inputs: [0.5, 0.7] });
worker.onmess age = function(event) {
if (event.data.type === 'result') {
console.log('Результат из Worker:', event.data.output);
}
};
Worker:
importScripts('synaptic.js');
let network = null;
self.onmess age = function(event) {
const data = event.data;
const { Network } = synaptic;
if (data.type === 'loadNetwork') {
network = Network.fromJSON(data.networkData);
}
if (data.type === 'activate' && network) {
const output = network.activate(data.inputs);
self.postMessage({ type: 'result', output });
}
};
Эта схема обеспечивает полноценное взаимодействие между потоками, безопасное хранение модели и её обновление, а также эффективное использование вычислительных ресурсов браузера при работе с Synaptic.