Временной ряд представляет собой последовательность значений, расположенных в хронологическом порядке. Цель предсказания временного ряда заключается в прогнозировании будущих значений на основе исторических данных. В контексте нейронных сетей особое внимание уделяется способности сети выявлять скрытые зависимости и тренды, которые могут быть нелинейными и сложными для классических статистических методов.
Synaptic — это JavaScript-библиотека для построения нейронных сетей, поддерживающая различные типы сетей: перцептроны, многослойные перцептроны (MLP), рекуррентные сети и сети Хопфилда. Для работы с временными рядами ключевое значение имеют рекуррентные нейронные сети (RNN), так как они обладают внутренней памятью, позволяющей учитывать последовательность прошлых данных при прогнозировании будущих значений.
Входной слой Входной слой получает последние
n значений временного ряда. Размер окна (n)
зависит от природы данных: для медленно изменяющихся процессов может
быть достаточно небольшого окна, для более сложных процессов требуется
больше значений для захвата динамики.
Скрытые слои Рекуррентные слои включают в себя
механизмы запоминания предыдущих состояний. В Synaptic рекуррентная сеть
строится с помощью класса Layer и соединений типа
Layer.project с обратной связью. Количество нейронов в
скрытом слое определяет способность сети к обобщению: слишком мало —
сеть не уловит сложные зависимости, слишком много — возможна
переобучаемость.
Выходной слой Выходной слой обычно состоит из одного нейрона для прогнозирования одного будущего значения или нескольких нейронов для прогнозирования нескольких шагов вперёд. Функция активации часто выбирается линейной, чтобы значения прогноза могли быть произвольными числами.
Нормализация данных — обязательный этап. Входные
данные временного ряда часто масштабируются в диапазон
[0, 1] или [-1, 1]. Это ускоряет обучение и
стабилизирует работу сети.
Формирование обучающих примеров производится методом скользящего окна:
Данные: [x1, x2, x3, x4, x5, x6]
Окно = 3
Примеры:
[ x1, x2, x3 ] -> x4
[ x2, x3, x4 ] -> x5
[ x3, x4, x5 ] -> x6
Каждое окно подается на вход сети, а следующее значение — это ожидаемый результат.
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); // рекуррентное соединение
let network = new Network({
input: inputLayer,
hidden: [hiddenLayer],
output: outputLayer
});
Используется классический градиентный спуск с обратным распространением ошибки (backpropagation):
const trainer = new Trainer(network);
trainer.train(trainingSet, {
rate: 0.01, // скорость обучения
iterations: 2000, // количество итераций
error: 0.005, // целевая ошибка
shuffle: true,
log: 100
});
Параметры обучения влияют на сходимость сети. Малое
значение rate замедляет обучение, слишком большое может
привести к расходимости. Количество итераций подбирается
экспериментально.
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);
Интерпретация результата: Выход сети — нормализованное значение. Чтобы получить прогноз в исходной шкале, необходимо выполнить обратное преобразование (денормализацию).