В этом примере показано, как предсказать данные временных рядов с помощью сети долгой краткосрочной памяти (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, имеющий 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 с заданными опциями обучения при помощи 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)
Здесь предсказания более точны при обновлении состояния сети наблюдаемыми значениями вместо предсказанных значений.
lstmLayer
| sequenceInputLayer
| trainingOptions
| trainNetwork