При работе с нейронными сетями на базе библиотеки Brain.js часто возникает необходимость отслеживания промежуточных значений, таких как активации отдельных слоев и выходы нейронов. Это особенно важно для анализа работы сети, выявления ошибок обучения и корректировки структуры модели. Brain.js предоставляет ряд инструментов и подходов для этого.
Brain.js поддерживает несколько типов сетей: Feedforward, Recurrent, LSTM. Каждая из них имеет внутреннюю структуру слоев, каждый слой содержит набор нейронов, у каждого нейрона есть весовые коэффициенты и значение активации. Основной объект сети обычно создаётся через:
const brain = require('brain.js');
const net = new brain.NeuralNetwork({
hiddenLayers: [4, 4] // два скрытых слоя по 4 нейрона
});
Для Feedforward сетей Brain.js не предоставляет прямого API для извлечения значений отдельных нейронов, однако есть обходные пути через JSON-представление сети.
Метод toJSON() возвращает объект с полной структурой
сети:
const json = net.toJSON();
console.log(json);
Ключевые поля JSON:
layers — объект, где ключи соответствуют слоям
(input, hidden0, hidden1,
output), значения — массивы нейронов.weights — веса нейронов относительно предыдущего
слоя.biases — смещения нейронов.outputs — выходные значения нейронов после последнего
запуска run().Используя это представление, можно вручную вычислять промежуточные активации:
function forwardPass(input, networkJSON) {
let activations = { input: input };
let prevLayer = input;
Object.keys(networkJSON.layers).forEach(layerKey => {
if (layerKey === 'input') return;
const layer = networkJSON.layers[layerKey];
const layerActivations = [];
layer.forEach((neuron, i) => {
const sum = neuron.bias + neuron.weights.reduce((acc, w, idx) => acc + w * prevLayer[idx], 0);
const activation = 1 / (1 + Math.exp(-sum)); // сигмоида
layerActivations.push(activation);
});
activations[layerKey] = layerActivations;
prevLayer = layerActivations;
});
return activations;
}
Эта функция позволяет получить значение каждого нейрона на каждом слое, что является основой для глубокой отладки сети.
Метод train() принимает объект конфигурации, где есть
поля log и callback. Параметр
callback можно использовать для мониторинга обучения на
каждом шаге:
net.train(trainingData, {
iterations: 2000,
log: true,
logPeriod: 100,
callback: (stats) => {
console.log(`Эпоха: ${stats.iterations}, Ошибка: ${stats.error}`);
},
callbackPeriod: 50
});
Это позволяет видеть динамику ошибки и промежуточные значения функции потерь, что помогает корректировать гиперпараметры.
Для LSTM и recurrent сетей важно
отслеживать состояние скрытых нейронов между шагами последовательности.
Brain.js не предоставляет прямого API для извлечения внутренних
состояний c и h LSTM, но можно использовать
net.toJSON() для анализа:
Для визуализации временных изменений рекомендуется строить графики активаций скрытых слоёв по шагам последовательности. Это помогает выявить затухание или взрыв градиентов, которые часто встречаются при обучении LSTM.
Для комплексной отладки полезно сохранять промежуточные значения в массивы и визуализировать:
const activationsLog = [];
trainingData.forEach(sample => {
const activations = forwardPass(sample.input, net.toJSON());
activationsLog.push(activations);
});
console.table(activationsLog[0]); // значения нейронов первого примера
Использование таких таблиц или графиков помогает анализировать поведение нейронов, выявлять сильно активные или “мертвые” нейроны, а также проверять, как изменения весов влияют на выходы сети.
Brain.js позволяет глубоко анализировать работу нейронной сети через JSON-представление и кастомные функции forwardPass, что делает возможной детальную отладку промежуточных значений и корректировку обучения. Такой подход особенно полезен при работе с LSTM и рекуррентными сетями, где прозрачность внутренних состояний критична для устойчивого обучения.