Liquid: сеть с жидкостным состоянием

Сеть с жидкостным состоянием (Liquid State Machine, LSM) представляет собой разновидность рекуррентных нейронных сетей, где активации нейронов формируют динамическое высокоразмерное представление входного сигнала. В библиотеке Synaptic LSM реализована как динамическая сеть, способная обрабатывать временные ряды и потоковые данные.

Ключевая идея LSM заключается в том, что входной сигнал не сразу преобразуется в выход, а проходит через “жидкую” сеть нейронов, где создается временной паттерн активности. Выход формируется только на основе этого состояния.


Структура сети

Компоненты сети с жидкостным состоянием:

  1. Входной слой Входные нейроны принимают потоковые данные. Каждый нейрон может быть подключен к произвольному числу внутренних нейронов, создавая разреженные связи.

  2. Жидкая сеть (reservoir) Основная часть LSM — это рекуррентная сеть с фиксированными весами. Она формирует динамическое представление сигналов. Основные характеристики:

    • Случайные и разреженные соединения: каждая пара нейронов соединена с небольшой вероятностью.
    • Рекуррентные связи: обеспечивают временную память сети.
    • Стабильность состояния: важно настроить веса так, чтобы сеть не выходила из устойчивого режима.
  3. Выходной слой (readout layer) На этом уровне происходит обучение. В отличие от традиционных RNN, только выходные веса подлежат обучению, что ускоряет обучение и повышает устойчивость.


Создание LSM в Synaptic

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

// Входной слой
let inputLayer = new Layer(5);

// Жидкая сеть (reservoir)
let reservoir = new Layer(20);

// Выходной слой
let outputLayer = new Layer(2);

// Соединение входного слоя с резервуаром
inputLayer.project(reservoir, Layer.connectionType.ALL_TO_ALL);

// Рекуррентные соединения внутри резервуара
reservoir.project(reservoir, Layer.connectionType.ALL_TO_ALL);

// Соединение резервуара с выходом
reservoir.project(outputLayer, Layer.connectionType.ALL_TO_ALL);

// Создание сети
let lsm = new Network({
    input: inputLayer,
    hidden: [reservoir],
    output: outputLayer
});

Особенности кода:

  • ALL_TO_ALL — полное соединение, можно использовать ONE_TO_ONE или RANDOM для разреженных сетей.
  • Весовые коэффициенты рекуррентных связей обычно инициализируются малыми случайными значениями, чтобы поддерживать динамику.

Обучение выходного слоя

LSM использует подход trainable readout:

// Пример обучения с использованием метода обратного распространения ошибки
const trainer = new synaptic.Trainer(lsm);

// Данные для обучения
let trainingSet = [
    { input: [0,1,0,1,0], output: [1,0] },
    { input: [1,0,1,0,1], output: [0,1] }
];

trainer.train(trainingSet, {
    rate: 0.1,
    iterations: 2000,
    error: 0.01,
    shuffle: true
});

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


Настройка динамики резервуара

Ключевые параметры, влияющие на работу LSM:

  • Размер резервуара Большой резервуар позволяет сети кодировать более сложные временные зависимости, но увеличивает вычислительные затраты.

  • Плотность соединений Разреженные соединения создают разнообразные паттерны активности. Обычно плотность выбирается 10–30%.

  • Диапазон весов Малые веса предотвращают нестабильность, большие веса могут вызывать хаотическую динамику.

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


Применение LSM

Liquid State Machine особенно эффективна в задачах:

  • Распознавание временных рядов: аудиосигналы, сенсорные данные.
  • Предсказание последовательностей: движения объектов, финансовые индикаторы.
  • Обработка потоковых данных в реальном времени: управление роботами, IoT-системы.

LSM позволяет быстро обучать сеть для задач, где классические RNN требуют долгого обучения.


Визуализация состояния резервуара

Для анализа работы LSM полезно отслеживать активность нейронов резервуара:

function logReservoirState(reservoir) {
    let state = reservoir.neurons().map(n => n.activation);
    console.log(state);
}

// Вызов после подачи входного сигнала
inputLayer.activate([1,0,1,0,1]);
reservoir.activate();
logReservoirState(reservoir);

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