Предсказание временного ряда

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

Synaptic — это JavaScript-библиотека для построения нейронных сетей, поддерживающая различные типы сетей: перцептроны, многослойные перцептроны (MLP), рекуррентные сети и сети Хопфилда. Для работы с временными рядами ключевое значение имеют рекуррентные нейронные сети (RNN), так как они обладают внутренней памятью, позволяющей учитывать последовательность прошлых данных при прогнозировании будущих значений.


Архитектура сети для временного ряда

  1. Входной слой Входной слой получает последние n значений временного ряда. Размер окна (n) зависит от природы данных: для медленно изменяющихся процессов может быть достаточно небольшого окна, для более сложных процессов требуется больше значений для захвата динамики.

  2. Скрытые слои Рекуррентные слои включают в себя механизмы запоминания предыдущих состояний. В Synaptic рекуррентная сеть строится с помощью класса Layer и соединений типа Layer.project с обратной связью. Количество нейронов в скрытом слое определяет способность сети к обобщению: слишком мало — сеть не уловит сложные зависимости, слишком много — возможна переобучаемость.

  3. Выходной слой Выходной слой обычно состоит из одного нейрона для прогнозирования одного будущего значения или нескольких нейронов для прогнозирования нескольких шагов вперёд. Функция активации часто выбирается линейной, чтобы значения прогноза могли быть произвольными числами.


Подготовка данных

Нормализация данных — обязательный этап. Входные данные временного ряда часто масштабируются в диапазон [0, 1] или [-1, 1]. Это ускоряет обучение и стабилизирует работу сети.

Формирование обучающих примеров производится методом скользящего окна:

Данные: [x1, x2, x3, x4, x5, x6]
Окно = 3

Примеры:
[ x1, x2, x3 ] -> x4
[ x2, x3, x4 ] -> x5
[ x3, x4, x5 ] -> x6

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


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

  1. Создание рекуррентного слоя:
const { Layer, Network } = require('synaptic');

let inputLayer = new Layer(3); // 3 входа — размер окна
let hiddenLayer = new Layer(5); // скрытый слой
let outputLayer = new Layer(1); // один прогнозируемый шаг

inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);
hiddenLayer.project(hiddenLayer); // рекуррентное соединение
  1. Создание сети:
let network = new Network({
    input: inputLayer,
    hidden: [hiddenLayer],
    output: outputLayer
});
  1. Настройка обучения

Используется классический градиентный спуск с обратным распространением ошибки (backpropagation):

const trainer = new Trainer(network);

trainer.train(trainingSet, {
    rate: 0.01,       // скорость обучения
    iterations: 2000, // количество итераций
    error: 0.005,     // целевая ошибка
    shuffle: true,
    log: 100
});

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


Особенности работы с временными рядами

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

Пример прогноза

function predictNext(network, window) {
    return network.activate(window)[0];
}

// Пример использования
let lastWindow = [0.4, 0.5, 0.6]; // последние три значения
let nextValue = predictNext(network, lastWindow);
console.log(nextValue);

Интерпретация результата: Выход сети — нормализованное значение. Чтобы получить прогноз в исходной шкале, необходимо выполнить обратное преобразование (денормализацию).


Практические советы

  • Использование скользящего окна позволяет сети видеть последовательности фиксированной длины, что важно для RNN.
  • Нормализация данных критична для стабильного обучения.
  • Рекуррентные соединения должны быть ограничены по размеру скрытого слоя, иначе сеть становится слишком сложной для обучения на малом объёме данных.
  • Многошаговое прогнозирование лучше реализовать пошагово, чем сразу пытаться обучить сеть выдавать несколько шагов вперёд.