Отображение весов и активаций в DOM

Библиотека Synaptic предоставляет гибкие средства для создания и обучения нейронных сетей в JavaScript. Одной из часто востребованных возможностей является визуализация состояния сети: весов связей и активаций нейронов в реальном времени. Это особенно полезно при образовательных проектах, отладке моделей или демонстрации работы сети.


Структура нейронной сети в Synaptic

Нейронная сеть в Synaptic строится из объектов Neuron, объединённых в Layer и Network. Основные элементы:

  • Neuron — содержит свойства bias, activation, trace и массив connections.projected.
  • Layer — набор нейронов, предоставляет методы project для соединения с другими слоями и activate для вычисления активаций.
  • Network — объединяет слои в единую сеть, управляет обучением и распространением сигналов.

Для визуализации интерес представляют:

  1. Вес соединений (connection.weight)
  2. Активация нейрона (neuron.activation)

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


Создание визуальной структуры в DOM

В качестве основы создаётся контейнер для сети и отдельных блоков слоев и нейронов:

const container = document.getElementById('network');

function createLayerDOM(layer) {
    const layerDiv = document.createElement('div');
    layerDiv.classList.add('layer');
    layer.neurons.forEach(neuron => {
        const neuronDiv = document.createElement('div');
        neuronDiv.classList.add('neuron');
        layerDiv.appendChild(neuronDiv);
        neuron.dom = neuronDiv; // Привязка DOM-элемента к нейрону
    });
    container.appendChild(layerDiv);
}

В этом примере каждому нейрону присваивается DOM-элемент, что позволяет обновлять визуальное состояние напрямую.


Отображение активаций нейронов

Активация нейрона обычно нормируется значением от 0 до 1. Для наглядного представления можно использовать цвет или прозрачность элемента:

function updateNeuronActivations(layer) {
    layer.neurons.forEach(neuron => {
        const intensity = Math.floor(neuron.activation * 255);
        neuron.dom.style.backgroundColor = `rgb(${intensity}, ${intensity}, 255)`;
    });
}

Каждое обновление сети через layer.activate(input) сопровождается вызовом функции визуализации, что позволяет увидеть, как сигнал проходит через слои.


Визуализация весов связей

Соединения между нейронами хранятся в массиве connections. Вес соединения влияет на силу передачи сигнала. Для отображения используется толщина линии или цветовая интенсивность:

function createConnectionsDOM(layer) {
    layer.neurons.forEach(neuron => {
        neuron.connections.projected.forEach(conn => {
            const line = document.createElement('div');
            line.classList.add('connection');
            line.style.height = `${Math.abs(conn.weight) * 5}px`;
            line.style.backgroundColor = conn.weight > 0 ? 'green' : 'red';
            container.appendChild(line);
            conn.dom = line;
        });
    });
}

Обновление веса после обучения или корректировки также может динамически менять визуальный стиль:

function updateConnectionWeights(layer) {
    layer.neurons.forEach(neuron => {
        neuron.connections.projected.forEach(conn => {
            const intensity = Math.min(Math.abs(conn.weight) * 255, 255);
            conn.dom.style.backgroundColor = conn.weight > 0 
                ? `rgb(0, ${intensity}, 0)` 
                : `rgb(${intensity}, 0, 0)`;
        });
    });
}

Динамическое обновление в реальном времени

Для отображения работы сети в реальном времени используется комбинация методов активации и визуализации. Например, при обучении через network.activate(input) и network.propagate(learningRate, target):

function stepNetwork(input, target) {
    network.activate(input);
    updateNeuronActivations(inputLayer);
    updateNeuronActivations(hiddenLayer);
    updateNeuronActivations(outputLayer);
    network.propagate(0.1, target);
    updateConnectionWeights(inputLayer);
    updateConnectionWeights(hiddenLayer);
}

Циклический вызов функции с задержкой создаёт эффект анимации прохождения сигналов и изменения весов.


Стиль и оформление визуализации

Для наглядности применяются CSS-классы с переходами и градиентами:

.layer {
    display: flex;
    justify-content: center;
    margin-bottom: 20px;
}
.neuron {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    margin: 5px;
    transition: background-color 0.2s;
}
.connection {
    width: 4px;
    margin: 2px;
    transition: background-color 0.2s, height 0.2s;
}

Плавные переходы позволяют визуально отслеживать изменения активаций и весов при каждом шаге.


Расширенные возможности

  • Интерактивное редактирование весов: привязка событий mousedown и drag к DOM-элементам соединений для изменения connection.weight на лету.
  • Отображение суммарного сигнала: можно вычислять neuron.bias + Σ(weights * inputs) и отображать как числовое значение или градиент.
  • Исторические графики: хранение предыдущих значений активации и веса для построения временных графиков в реальном времени.

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