Устройство ячейки LSTM

LSTM (Long Short-Term Memory) — разновидность рекуррентной нейронной сети (RNN), предназначенная для работы с последовательными данными, где важен контекст из предыдущих шагов. В Brain.js LSTM реализован через специализированный класс recurrent.LSTM, который скрывает сложную внутреннюю логику, но понимание устройства отдельной ячейки LSTM позволяет эффективно настраивать сеть и интерпретировать результаты.


Структура LSTM-ячейки

Основная единица LSTM — ячейка, которая хранит и управляет информацией во времени. Ячейка состоит из нескольких ключевых компонентов:

  1. Входной слой (Input Gate) Контролирует, какая информация из текущего входа и предыдущего состояния должна быть добавлена в память ячейки. Формула для входного гейта:

    i_t = σ(W_i * x_t + U_i * h_{t-1} + b_i)
    • σ — сигмоида (ограничивает значения между 0 и 1)
    • x_t — входные данные на текущем шаге
    • h_{t-1} — скрытое состояние предыдущего шага
    • W_i, U_i, b_i — веса и смещение входного гейта

    Значение i_t определяет степень обновления памяти: 0 — не добавлять информацию, 1 — полностью принять.

  2. Забвение (Forget Gate) Определяет, какая информация из предыдущей памяти будет забыта. Рассчитывается по формуле:

    f_t = σ(W_f * x_t + U_f * h_{t-1} + b_f)

    Забвение критично для предотвращения накопления устаревших данных, что решает проблему затухающих градиентов в RNN.

  3. Обновление состояния ячейки (Cell State Update) Новое состояние ячейки C_t формируется как комбинация старого состояния и новой информации:

    C_t = f_t * C_{t-1} + i_t * ĝ_t
    ĝ_t = tanh(W_c * x_t + U_c * h_{t-1} + b_c)
    • ĝ_t — кандидат на обновление состояния, который проходит через гиперболический тангенс для нормализации значений между -1 и 1.
    • Операция умножения на f_t и i_t обеспечивает селективное сохранение и обновление данных.
  4. Выходной слой (Output Gate) Определяет, какая часть состояния ячейки будет отправлена на выход и скрытое состояние для следующего шага:

    o_t = σ(W_o * x_t + U_o * h_{t-1} + b_o)
    h_t = o_t * tanh(C_t)

    Здесь h_t — скрытое состояние, которое используется как выход LSTM на текущем шаге и как вход на следующий шаг временной последовательности.


Взаимодействие компонентов

  • Память ячейки (Cell State C_t) служит каналом передачи информации сквозь множество временных шагов.
  • Гейты обеспечивают гибкий контроль над потоком данных: что сохранять, что забывать и что выдавать на выход.
  • Комбинация сигмоидного и тангенциального активационных функций позволяет модели сохранять как краткосрочную, так и долгосрочную зависимость.

В Brain.js внутренняя реализация скрыта, но при создании сети через new brain.recurrent.LSTM() или new brain.recurrent.LSTMTimeStep() автоматически формируются эти гейты и память ячейки. Тренировка происходит через алгоритм обратного распространения ошибки по времени (BPTT), оптимизируя веса всех гейтов.


Практические особенности LSTM в Brain.js

  • Инициализация весов: веса задаются случайными значениями, что влияет на скорость сходимости. Для стабильного обучения рекомендуется нормализовать входные данные.
  • Скрытое состояние (hidden layers) можно регулировать через параметр hiddenLayers. Например, [10, 20] создаст двухслойную LSTM с 10 и 20 нейронами соответственно.
  • Выходные данные: в классе LSTMTimeStep выход — предсказание следующего шага временной последовательности, что особенно удобно для временных рядов и генерации числовых последовательностей.

Ограничения и рекомендации

  • LSTM в Brain.js подходит для средних по объему данных. Для очень длинных последовательностей может потребоваться оптимизация или использование специализированных библиотек с поддержкой GPU.
  • Тщательная нормализация входов и правильная конфигурация слоев критичны для избежания переобучения и затухания градиентов.
  • Выбор функции активации по умолчанию (tanh и sigmoid) хорошо сбалансирован, но можно экспериментировать с другими функциями для нестандартных задач.

Пример структуры LSTM в Brain.js

const brain = require('brain.js');
const net = new brain.recurrent.LSTM({
  inputSize: 3,
  hiddenLayers: [10, 10],
  outputSize: 3
});

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

net.train(trainingData, {
  iterations: 2000,
  learningRate: 0.01,
  log: true
});

const output = net.run([0, 1, 0]);
console.log(output);

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