Методы инициализации весов

Инициализация весов нейронной сети является критически важным этапом при построении и обучении модели. В библиотеке Synaptic она играет особую роль, поскольку от правильного выбора начальных значений весов зависит скорость сходимости сети и её способность к обучению.

Случайная инициализация

По умолчанию Synaptic использует случайную инициализацию весов в диапазоне от -1 до 1. Каждый нейрон создаётся с случайными весами, что предотвращает симметрию между нейронами и позволяет обучению начинаться с разнообразных состояний:

const { Layer } = require('synaptic');

let inputLayer = new Layer(3);
let hiddenLayer = new Layer(4);
let outputLayer = new Layer(2);

inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);

В этом примере веса между слоями будут случайными. Такой подход подходит для большинства простых сетей, однако не всегда обеспечивает оптимальную сходимость, особенно для глубоких моделей.

Инициализация с контролируемым диапазоном

Для более точного контроля над стартовыми весами можно использовать метод set каждого соединения, задавая конкретные значения:

hiddenLayer.list.forEach(neuron => {
  neuron.connections.inputs.forEach(conn => {
    conn.weight = Math.random() * 0.2 - 0.1; // диапазон от -0.1 до 0.1
  });
});

Ключевой момент: меньший диапазон начальных весов снижает вероятность того, что сигналы будут насыщаться функциями активации, такими как сигмоида или tanh, и предотвращает «затухающие градиенты» на старте обучения.

Инициализация по нормальному распределению

Иногда более эффективной оказывается инициализация весов по нормальному распределению с математическим ожиданием 0 и небольшой дисперсией. Это позволяет распределить значения вокруг нуля, создавая симметрично «случайные» веса, что особенно полезно для скрытых слоёв.

function normalRandom(mean = 0, stdDev = 0.1) {
  let u = 0, v = 0;
  while(u === 0) u = Math.random();
  while(v === 0) v = Math.random();
  return mean + stdDev * Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
}

hiddenLayer.list.forEach(neuron => {
  neuron.connections.inputs.forEach(conn => {
    conn.weight = normalRandom();
  });
});

Стратегии инициализации для разных функций активации

  • Сигмоида (sigmoid): рекомендуется использовать веса из диапазона ±0.1–0.5, чтобы избежать насыщения на старте.
  • tanh: диапазон ±0.5 является безопасным выбором, позволяющим нейронам сразу давать ненулевой градиент.
  • ReLU: начальные веса могут быть немного больше, ±1.0, чтобы нейроны могли быстрее активироваться.

Инициализация смещений (bias)

Нейроны Synaptic поддерживают смещения, которые также требуют начальных значений. Обычно их инициализируют нулём или небольшими случайными значениями. Пример установки смещений:

hiddenLayer.list.forEach(neuron => {
  neuron.bias = Math.random() * 0.2 - 0.1;
});

Правильная инициализация смещений помогает ускорить обучение и снижает вероятность того, что нейроны будут полностью «выключены» на старте.

Инициализация сложных сетей

Для многослойных перцептронов или рекуррентных сетей важно контролировать распределение весов на каждом уровне отдельно. Например, скрытые слои могут получать веса с небольшим стандартным отклонением, а выходные слои — чуть более широкий диапазон, чтобы начальные выходы были разнообразными:

function initializeLayer(layer, stdDev) {
  layer.list.forEach(neuron => {
    neuron.connections.inputs.forEach(conn => {
      conn.weight = normalRandom(0, stdDev);
    });
    neuron.bias = normalRandom(0, stdDev);
  });
}

initializeLayer(hiddenLayer, 0.1);
initializeLayer(outputLayer, 0.3);

Такая практика снижает риск того, что сеть будет застревать в локальных минимумах при первом обновлении весов.

Настройка через конфигурацию сети

Synaptic позволяет создавать собственные методы инициализации, расширяя стандартные функции. Можно создать класс, который наследует нейроны и автоматически задаёт веса по выбранной стратегии. Это упрощает повторное использование конфигураций для различных проектов и экспериментов.

Ключевые моменты:

  • Инициализация весов должна учитывать функцию активации.
  • Контроль диапазона начальных значений предотвращает проблемы с градиентами.
  • Смещения играют отдельную роль и требуют аккуратной настройки.
  • Для больших сетей полезно создавать отдельные функции инициализации для каждого слоя.

Инициализация весов — фундаментальная часть настройки нейросети, напрямую влияющая на её способность быстро и эффективно обучаться, а также на стабильность процесса градиентного спуска.