Построение обучающего цикла вручную без Trainer

Библиотека Synaptic предоставляет низкоуровневые возможности для работы с нейронными сетями, позволяя создавать обучающие циклы вручную, без использования встроенного класса Trainer. Такой подход необходим для тонкой настройки процесса обучения, реализации нестандартных функций потерь или специфических алгоритмов оптимизации.


Создание сети и структуры

Основой является объект Network или заранее созданные компоненты Layer, Neuron. Для простейшей сети достаточно связать слои через Layer.project():

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 myNetwork = new Network({
    input: inputLayer,
    hidden: [hiddenLayer],
    output: outputLayer
});

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

  • Layer.project() устанавливает полное соединение между слоями.
  • Объект Network можно создать вручную, указав входной, скрытый и выходной слои, что позволяет гибко манипулировать архитектурой.

Прямой проход (Forward Propagation)

Для получения выходных данных сети используется метод activate. Он принимает массив значений входного слоя и возвращает массив выходов:

const input = [0.5, 0.8];
const output = myNetwork.activate(input);
console.log(output); // [0.73] — примерное значение после инициализации

Особенности прямого прохода:

  • Любая модификация весов перед активацией сразу влияет на результат.
  • Можно использовать произвольные функции активации для отдельных слоев (sigmoid, tanh, relu).

Обратное распространение ошибки (Backpropagation)

Метод propagate выполняет шаг обратного распространения ошибки:

const learningRate = 0.1;
const target = [1];

myNetwork.propagate(learningRate, target);

Принципы работы:

  • Ошибка вычисляется на выходном слое как разница между target и фактическим output.
  • Градиенты ошибки распространяются обратно через все соединения, корректируя веса.
  • learningRate регулирует размер шага изменения весов. Мелкие значения дают стабильное обучение, большие ускоряют сходимость, но могут вызвать раскачку сети.

Построение цикла обучения вручную

Основной цикл состоит из нескольких шагов:

  1. Инициализация параметров обучения: количество эпох, коэффициент обучения, набор данных.
  2. Выбор случайного или последовательного примера из обучающего набора.
  3. Прямой проход через сеть (activate).
  4. Вычисление ошибки и обратное распространение (propagate).
  5. Отслеживание метрик качества обучения (среднеквадратичная ошибка, точность).

Пример реализации простого цикла:

const trainingSet = [
    { input: [0, 0], output: [0] },
    { input: [0, 1], output: [1] },
    { input: [1, 0], output: [1] },
    { input: [1, 1], output: [0] }
];

const epochs = 10000;
const learningRate = 0.3;

for (let epoch = 0; epoch < epochs; epoch++) {
    let totalError = 0;
    for (const data of trainingSet) {
        const output = myNetwork.activate(data.input);
        myNetwork.propagate(learningRate, data.output);
        totalError += output.reduce((sum, val, i) => sum + Math.pow(data.output[i] - val, 2), 0);
    }
    if (epoch % 1000 === 0) {
        console.log(`Epoch ${epoch}, Error: ${totalError.toFixed(4)}`);
    }
}

Выделенные моменты цикла:

  • Ошибка накапливается по всем примерам, что позволяет отслеживать динамику обучения.
  • Случайный порядок перебора примеров улучшает обобщающую способность сети.
  • propagate вызывается после каждого примера — это вариант online learning. Для batch learning ошибки можно аккумулировать и применять после полного прохода по набору данных.

Настройка сети вручную

Synaptic позволяет изменять отдельные веса, смещения и функции активации:

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

hiddenLayer.set({
    squash: require('synaptic').Neuron.squash.TANH
});
  • neuron.bias регулирует смещение нейрона.
  • squash задаёт функцию активации: LOGISTIC, TANH, RELU.
  • Изменение функции активации может потребовать корректировки коэффициента обучения.

Мониторинг и отладка

Для оценки прогресса обучения полезно:

  • Выводить суммарную ошибку на каждой эпохе.
  • Визуализировать веса и распределение активаций.
  • Проверять градиенты на выбросы, особенно при нестандартных функциях активации или высоких learningRate.
hiddenLayer.list.forEach(neuron => {
    neuron.connections.projected.forEach(conn => {
        console.log(`Weight: ${conn.weight.toFixed(4)}`);
    });
});
  • Такая детализация позволяет отследить, как именно сеть изменяет свои внутренние параметры, что важно при построении сложных архитектур или нестандартных циклов обучения.

Применение различных стратегий обучения

Вручную можно реализовать:

  • Adaptive learning rate: изменять learningRate динамически в зависимости от ошибки.
  • Early stopping: завершать обучение, если ошибка перестала уменьшаться.
  • Регуляризацию: добавлять к ошибке штраф за слишком большие веса.

Пример простой адаптации коэффициента обучения:

let lr = 0.5;
for (let epoch = 0; epoch < epochs; epoch++) {
    trainingSet.forEach(data => {
        myNetwork.activate(data.input);
        myNetwork.propagate(lr, data.output);
    });
    lr *= 0.999; // постепенное уменьшение
}
  • Это снижает вероятность раскачки весов на поздних этапах обучения.

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