Конвертация весов

ConvNetJS — это чисто JavaScript-библиотека для построения и обучения сверточных нейронных сетей (CNN) и полносвязных сетей. Одним из важных аспектов работы с моделями является возможность конвертации весов между различными форматами и сохранение/загрузка параметров сети для последующего использования.

Форматы хранения весов

В ConvNetJS веса и смещения каждой слоя хранятся в объектах типа Vol (volume), представляющих многомерные массивы. Основные свойства:

  • w — массив весов в виде одномерного Float32Array.
  • dw — массив градиентов соответствующих весов.
  • sx, sy, depth — размеры объемного тензора.
  • get(x, y, d) и set(x, y, d, v) — методы доступа к элементам.

Для конвертации и сохранения модели используется метод toJSON() у объекта сети (Net). Он возвращает объект, содержащий:

  • layers — массив описаний всех слоев сети.
  • Для каждого слоя: тип, размеры, веса, смещения и параметры активации.

Пример структуры JSON для слоя:

{
  "layer_type": "fc",
  "num_inputs": 100,
  "num_neurons": 10,
  "biases": {
    "sx": 1,
    "sy": 1,
    "depth": 10,
    "w": [0.1, -0.2, 0.05, ...]
  },
  "filters": [
    {
      "sx": 10,
      "sy": 10,
      "depth": 1,
      "w": [...]
    }
  ]
}

Сохранение весов

Сохранение весов в JSON позволяет:

  • Передавать модели между разными приложениями.
  • Восстанавливать сеть после перезапуска.
  • Конвертировать веса для использования в других фреймворках при необходимости.

Пример сохранения модели в JSON:

var json = net.toJSON();
var jsonString = JSON.stringify(json);

JSON-строку можно сохранить на сервере или в локальном хранилище браузера (localStorage).

Загрузка весов

Для восстановления сети используется метод fromJSON(json):

var json = JSON.parse(jsonString);
net.fromJSON(json);

При этом структура сети должна полностью совпадать с той, из которой был сохранён JSON, иначе веса не будут корректно назначены.

Конвертация между форматами

Иногда требуется конвертировать веса из других библиотек (например, TensorFlow или PyTorch) в формат ConvNetJS. Для этого необходимо:

  1. Преобразовать многомерные массивы весов в одномерный массив, соответствующий структуре Vol.w.
  2. Обратить внимание на порядок индексов. В ConvNetJS используется формат width × height × depth, а многие библиотеки используют depth × height × width.
  3. Создать новый объект Vol с размерностями слоя:
var vol = new convnetjs.Vol(sx, sy, depth, 0.0);
for (var i = 0; i < weightsArray.length; i++) {
  vol.w[i] = weightsArray[i];
}
layer.filters[j] = vol;
  1. Для полносвязных слоев (fc) и слоя смещений (biases) используется аналогичный подход.

Автоматическая конвертация слоев

Можно написать функцию, которая принимает массивы весов и смещений из другой библиотеки и автоматически распределяет их по слоям ConvNetJS:

function convertWeights(convnetLayers, externalWeights) {
  for (var i = 0; i < convnetLayers.length; i++) {
    var layer = convnetLayers[i];
    if (layer.layer_type === 'fc') {
      for (var j = 0; j < layer.filters.length; j++) {
        var vol = new convnetjs.Vol(layer.filters[j].sx, layer.filters[j].sy, layer.filters[j].depth);
        vol.w = externalWeights[i][j];
        layer.filters[j] = vol;
      }
      var biasVol = new convnetjs.Vol(1, 1, layer.biases.depth);
      biasVol.w = externalWeights[i].biases;
      layer.biases = biasVol;
    } else if (layer.layer_type === 'conv') {
      for (var j = 0; j < layer.filters.length; j++) {
        var vol = new convnetjs.Vol(layer.filters[j].sx, layer.filters[j].sy, layer.filters[j].depth);
        vol.w = externalWeights[i][j];
        layer.filters[j] = vol;
      }
      var biasVol = new convnetjs.Vol(1, 1, layer.biases.depth);
      biasVol.w = externalWeights[i].biases;
      layer.biases = biasVol;
    }
  }
}

Эта функция гарантирует, что все веса и смещения будут корректно размещены в слоях ConvNetJS, сохраняя совместимость сети.

Особенности при конвертации

  • Совпадение размеров слоев: количество фильтров, глубина входных каналов и размерность свёртки должны совпадать.
  • Тип активации: ConvNetJS поддерживает только ограниченный набор функций активации (relu, sigmoid, tanh, softmax). Если исходная модель использует другую функцию, её необходимо заменить.
  • Порядок индексов: критично при переносе весов из фреймворков, использующих разные схемы хранения каналов (например, NCHW в PyTorch и NHWC в TensorFlow).

Применение конвертированных весов

После конвертации веса можно использовать для:

  • Инициализации новой сети без дополнительного обучения.
  • Fine-tuning на новой задаче.
  • Сравнительного анализа работы сети с оригинальной моделью.

Использование методов toJSON и fromJSON в сочетании с ручной конвертацией обеспечивает гибкую интеграцию ConvNetJS с внешними моделями, позволяя строить обучаемые веб-приложения с заранее подготовленными сетями.