Прогнозирование временных рядов с использованием глубокого обучения

В этом примере показано, как предсказать данные временных рядов с помощью сети долгой краткосрочной памяти (LSTM).

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

Чтобы предсказать значения нескольких временных шагов в будущем, используйте predictAndUpdateState функция для предсказания временных шагов по одному и обновления состояния сети при каждом предсказании.

Этот пример использует набор данных chickenpox_dataset. Пример обучает сеть LSTM прогнозировать количество случаев ветряной оспы, учитывая количество случаев в предыдущих месяцах.

Загрузка данных последовательности

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

data = chickenpox_dataset;
data = [data{:}];

figure
plot(data)
xlabel("Month")
ylabel("Cases")
title("Monthly Cases of Chickenpox")

Разделите обучающие и тестовые данные. Обучитесь на первых 90% последовательности и тестируйте на последних 10%.

numTimeStepsTrain = floor(0.9*numel(data));

dataTrain = data(1:numTimeStepsTrain+1);
dataTest = data(numTimeStepsTrain+1:end);

Стандартизация данных

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

mu = mean(dataTrain);
sig = std(dataTrain);

dataTrainStandardized = (dataTrain - mu) / sig;

Подготовка предикторов и ответов

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

XTrain = dataTrainStandardized(1:end-1);
YTrain = dataTrainStandardized(2:end);

Определение сетевой архитектуры LSTM

Создайте регрессионую сеть LSTM. Задает слой LSTM, имеющий 200 скрытые модули.

numFeatures = 1;
numResponses = 1;
numHiddenUnits = 200;

layers = [ ...
    sequenceInputLayer(numFeatures)
    lstmLayer(numHiddenUnits)
    fullyConnectedLayer(numResponses)
    regressionLayer];

Задайте опции обучения. Установите решатель равным 'adam' и обучить 250 эпох. Чтобы предотвратить разнесение градиентов, установите порог градиента равным 1. Задайте начальную скорость обучения 0,005 и опустите скорость обучения после 125 эпох, умножив на множитель 0,2.

options = trainingOptions('adam', ...
    'MaxEpochs',250, ...
    'GradientThreshold',1, ...
    'InitialLearnRate',0.005, ...
    'LearnRateSchedule','piecewise', ...
    'LearnRateDropPeriod',125, ...
    'LearnRateDropFactor',0.2, ...
    'Verbose',0, ...
    'Plots','training-progress');

Обучите сеть LSTM

Обучите сеть LSTM с заданными опциями обучения при помощи trainNetwork.

net = trainNetwork(XTrain,YTrain,layers,options);

Прогнозирование будущих временных шагов

Чтобы предсказать значения нескольких временных шагов в будущем, используйте predictAndUpdateState функция для предсказания временных шагов по одному и обновления состояния сети при каждом предсказании. Для каждого прогноза используйте предыдущее предсказание как вход в функцию.

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

dataTestStandardized = (dataTest - mu) / sig;
XTest = dataTestStandardized(1:end-1);

Чтобы инициализировать состояние сети, сначала предсказайте на обучающих данных XTrain. Затем сделайте первое предсказание, используя последний временной шаг отклика обучения YTrain(end). Закольцуйте оставшиеся предсказания и введите предыдущее предсказание, чтобы predictAndUpdateState.

Для больших наборов данных, длинных последовательностей или больших сетей предсказания на графическом процессоре обычно вычисляются быстрее, чем предсказания на центральном процессоре. В противном случае предсказания на центральном процессоре обычно вычисляются быстрее. Для одного временного шага предсказаний используйте центральный процессор. Чтобы использовать центральный процессор для предсказания, установите 'ExecutionEnvironment' опция predictAndUpdateState на 'cpu'.

net = predictAndUpdateState(net,XTrain);
[net,YPred] = predictAndUpdateState(net,YTrain(end));

numTimeStepsTest = numel(XTest);
for i = 2:numTimeStepsTest
    [net,YPred(:,i)] = predictAndUpdateState(net,YPred(:,i-1),'ExecutionEnvironment','cpu');
end

Удалите предсказания с помощью параметров, рассчитанных ранее.

YPred = sig*YPred + mu;

График процесса обучения сообщает о среднеквадратичной ошибке (RMSE), вычисленной из стандартизированных данных. Вычислите RMSE из нестандартных предсказаний.

YTest = dataTest(2:end);
rmse = sqrt(mean((YPred-YTest).^2))
rmse = single
    248.5531

Постройте график временных рядов обучения с прогнозируемыми значениями.

figure
plot(dataTrain(1:end-1))
hold on
idx = numTimeStepsTrain:(numTimeStepsTrain+numTimeStepsTest);
plot(idx,[data(numTimeStepsTrain) YPred],'.-')
hold off
xlabel("Month")
ylabel("Cases")
title("Forecast")
legend(["Observed" "Forecast"])

Сравните прогнозные значения с тестовыми данными.

figure
subplot(2,1,1)
plot(YTest)
hold on
plot(YPred,'.-')
hold off
legend(["Observed" "Forecast"])
ylabel("Cases")
title("Forecast")

subplot(2,1,2)
stem(YPred - YTest)
xlabel("Month")
ylabel("Error")
title("RMSE = " + rmse)

Обновление состояния сети с наблюдаемыми значениями

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

Во-первых, инициализируйте состояние сети. Чтобы делать предсказания о новой последовательности, сбросьте состояние сети с помощью resetState. Сброс состояния сети препятствует тому, чтобы предыдущие предсказания влияли на предсказания новых данных. Сбросьте состояние сети, а затем инициализируйте состояние сети, предсказав на обучающих данных.

net = resetState(net);
net = predictAndUpdateState(net,XTrain);

Спрогнозируйте каждый временной шаг. Для каждого предсказания прогнозируйте следующий временной шаг, используя наблюдаемое значение предыдущего временного шага. Установите 'ExecutionEnvironment' опция predictAndUpdateState на 'cpu'.

YPred = [];
numTimeStepsTest = numel(XTest);
for i = 1:numTimeStepsTest
    [net,YPred(:,i)] = predictAndUpdateState(net,XTest(:,i),'ExecutionEnvironment','cpu');
end

Удалите предсказания с помощью параметров, рассчитанных ранее.

YPred = sig*YPred + mu;

Вычислите среднеквадратическую ошибку (RMSE).

rmse = sqrt(mean((YPred-YTest).^2))
rmse = 158.0959

Сравните прогнозные значения с тестовыми данными.

figure
subplot(2,1,1)
plot(YTest)
hold on
plot(YPred,'.-')
hold off
legend(["Observed" "Predicted"])
ylabel("Cases")
title("Forecast with Updates")

subplot(2,1,2)
stem(YPred - YTest)
xlabel("Month")
ylabel("Error")
title("RMSE = " + rmse)

Здесь предсказания более точны при обновлении состояния сети наблюдаемыми значениями вместо предсказанных значений.

См. также

| | |

Похожие темы