ConvNetJS — это чисто JavaScript-библиотека для построения и обучения нейронных сетей, особенно сверточных (ConvNet), работающая полностью в браузере. Один из важных аспектов при работе с нейронными сетями — возможность сохранять веса отдельно от структуры сети, чтобы при необходимости загружать их в другую конфигурацию или использовать в различных проектах.
В ConvNetJS веса слоёв хранятся в объектах Vol, которые
представляют собой многомерные массивы данных с числовыми значениями
параметров. Каждое соединение между нейронами и каждый фильтр
сверточного слоя представлен массивом чисел. Внутри сети каждый слой
имеет свои веса (weights) и смещения (biases),
которые и подлежат сохранению.
Ключевые моменты:
layer.params — массив объектов параметров слоя.w (веса) и dw
(градиенты). Для сохранения интересуют только w.Vol объектов, особенно
это касается слоёв типа FullyConnected и Convolutional.Для сохранения весов отдельно используется метод обхода всех слоёв и извлечения их параметров:
function saveWeights(net) {
let weightsData = [];
net.layers.forEach(layer => {
if (layer.hasOwnProperty('filters')) { // сверточный слой
layer.filters.forEach(filter => {
weightsData.push(filter.w);
});
}
if (layer.hasOwnProperty('biases')) { // смещения
weightsData.push(layer.biases.w);
}
if (layer.hasOwnProperty('params')) { // полностью связанные слои
layer.params.forEach(p => {
weightsData.push(p.w);
});
}
});
return JSON.stringify(weightsData);
}
Особенности:
JSON.stringify, так как Vol
представляет собой обычные массивы чисел.dw не сохраняются, так как для инференса они
не нужны.Для загрузки весов необходимо соответствие порядка параметров слоёв, так как ConvNetJS не хранит метаданные типа размеров фильтров внутри сериализованного массива. Пример функции восстановления:
function loadWeights(net, jsonWeights) {
let weightsData = JSON.parse(jsonWeights);
let idx = 0;
net.layers.forEach(layer => {
if (layer.hasOwnProperty('filters')) {
layer.filters.forEach(filter => {
filter.w = weightsData[idx++];
});
}
if (layer.hasOwnProperty('biases')) {
layer.biases.w = weightsData[idx++];
}
if (layer.hasOwnProperty('params')) {
layer.params.forEach(p => {
p.w = weightsData[idx++];
});
}
});
}
Важные моменты:
Сохранение весов отдельно позволяет:
ArrayBuffer.w и biases.Отделение весов от структуры сети в ConvNetJS обеспечивает гибкость в управлении моделями. Это позволяет создавать динамические системы, где одна и та же сеть может использовать разные наборы весов без изменения архитектуры, ускоряя эксперименты и упрощая деплой моделей в браузерных приложениях.