Main Content

Pronóstico de series de tiempo mediante deep learning

Este ejemplo muestra cómo pronosticar datos de series de tiempo mediante una red de memoria de corto-largo plazo (LSTM).

Una red de LSTM es una red neuronal recurrente (RNN) que procesa datos de entrada formando un lazo con las unidades de tiempo y actualizando el estado de la RNN. El estado de la RNN contiene información recordada durante todas las unidades de tiempo anteriores. Puede utilizar una red neuronal de LSTM para pronosticar valores posteriores de una serie de tiempo o secuencia utilizando las unidades de tiempo anteriores como entrada. Para entrenar una red neuronal de LSTM para el pronóstico de series de tiempo, entrene una red neuronal de regresión de LSTM con salida secuencial, donde las respuestas (objetivos) son las secuencias de entrenamiento con valores desplazados una unidad de tiempo. En otras palabras, en cada unidad de tiempo de la secuencia de entrada, la red neuronal de LSTM aprende a predecir el valor de la siguiente unidad de tiempo.

Existen dos métodos para pronosticar: pronóstico de lazo abierto y de lazo cerrado.

  • Pronóstico de lazo abierto: prediga la siguiente unidad de tiempo en una secuencia utilizando solo datos de entrada. Cuando se hacen predicciones para unidades de tiempo posteriores, se recopilan valores reales de la fuente de datos y se utilizan como entrada. Por ejemplo, imagine que desea predecir el valor para la unidad de tiempo t de una secuencia con datos recopilados en las unidades de tiempo desde 1 hasta t-1. Para hacer predicciones para la unidad de tiempo t+1, espere hasta que registre el valor real de la unidad de tiempo t y utilícelo como entrada para hacer la siguiente predicción. Utilice el pronóstico de lazo abierto cuando tenga valores reales que proporcionar a la RNN antes de hacer la siguiente predicción.

  • Pronóstico de lazo cerrado: prediga unidades de tiempo posteriores en una secuencia utilizando las predicciones previas como entrada. En este caso, el modelo no requiere los valores reales para realizar la predicción. Por ejemplo, imagine que desea predecir los valores para las unidades de tiempo desdet hasta t+k de la secuencia con datos recopilados en las unidades de tiempo desde 1 hasta t-1 únicamente. Para hacer predicciones para la unidad de tiempo i, utilice el valor predicho para la unidad de tiempo i-1 como entrada. Utilice el pronóstico de lazo cerrado para pronosticar varias unidades de tiempo posteriores o cuando no tenga valores reales que proporcionar a la RNN antes de hacer la siguiente predicción.

Esta figura muestra un ejemplo de secuencia con valores pronosticados mediante la predicción de lazo cerrado.

closedloop.png

Este ejemplo utiliza el conjunto de datos con forma de onda, que contiene 2000 formas de onda generadas de forma sintética de diferentes longitudes con tres canales. En este ejemplo se entrena una red neuronal de LSTM para pronosticar valores futuros de las formas de onda, dados los valores de unidades de tiempo anteriores, mediante pronósticos tanto de lazo cerrado como de lazo abierto.

Cargar datos

Cargue los datos de ejemplo de WaveformData.mat. Los datos son un arreglo de celdas de numObservations por 1 de secuencias, donde numObservations es el número de secuencias. Cada secuencia es un arreglo numérico de numTimeSteps por -numChannels, donde numTimeSteps es el número de unidades de tiempo y numChannels es el número de canales de la secuencia.

load WaveformData

Visualice los tamaños de las primeras secuencias.

data(1:4)
ans=4×1 cell array
    {103×3 double}
    {136×3 double}
    {140×3 double}
    {124×3 double}

Visualice el número de canales. Para entrenar la red neuronal de LSTM, cada secuencia debe tener el mismo número de canales.

numChannels = size(data{1},2)
numChannels = 3

Visualice las primeras secuencias en una gráfica.

figure
tiledlayout(2,2)
for i = 1:4
    nexttile
    stackedplot(data{i})

    xlabel("Time Step")
end

Figure contains objects of type stackedplot.

Divida los datos en conjuntos de prueba y de entrenamiento. Utilice el 90% de las observaciones para el entrenamiento y el resto para la prueba.

numObservations = numel(data);
idxTrain = 1:floor(0.9*numObservations);
idxTest = floor(0.9*numObservations)+1:numObservations;
dataTrain = data(idxTrain);
dataTest = data(idxTest);

Preparar datos para el entrenamiento

Para pronosticar los valores de unidades de tiempo futuras de una secuencia, especifique los objetivos como las secuencias de entrenamiento con valores desplazados una unidad de tiempo. No incluya la unidad de tiempo final en las secuencias de entrenamiento. En otras palabras, en cada unidad de tiempo de la secuencia de entrada, la red neuronal de LSTM aprende a predecir el valor de la siguiente unidad de tiempo. Los predictores son las secuencias de entrenamiento sin la unidad de tiempo final.

numObservationsTrain = numel(dataTrain);
XTrain = cell(numObservationsTrain,1);
TTrain = cell(numObservationsTrain,1);
for n = 1:numObservationsTrain
    X = dataTrain{n};
    XTrain{n} = X(1:end-1,:);
    TTrain{n} = X(2:end,:);
end

Para un mejor ajuste y para evitar que el entrenamiento diverja, normalice los predictores y los objetivos para que los canales tengan media cero y varianza unitaria. Cuando haga predicciones, también deberá normalizar los datos de prueba con las mismas estadísticas que los datos de entrenamiento.

Calcule la media por canal y los valores de desviación estándar de las secuencias. Para calcular fácilmente la media y la desviación estándar de los datos de entrenamiento, cree arreglos numéricos que contengan las secuencias concatenadas utilizando la función cell2mat.

muX = mean(cell2mat(XTrain));
sigmaX = std(cell2mat(XTrain),0);

muT = mean(cell2mat(TTrain));
sigmaT = std(cell2mat(TTrain),0);

Normalice las secuencias utilizando la media y los valores de desviación estándar calculados.

for n = 1:numel(XTrain)
    XTrain{n} = (XTrain{n} - muX) ./ sigmaX;
    TTrain{n} = (TTrain{n} - muT) ./ sigmaT;
end

Definir la arquitectura de red neuronal de LSTM

Cree una red neuronal de regresión de LSTM.

  • Utilice una capa de entrada de secuencias con un tamaño de entrada que coincida con el número de canales de los datos de entrada.

  • Utilice una capa de LSTM con 128 unidades ocultas. El número de unidades ocultas determina cuánta información aprende la capa. Utilizar más unidades ocultas puede producir resultados más precisos, pero es más probable que se produzca un sobreajuste de los datos de entrenamiento.

  • Para generar secuencias con el mismo número de canales que los datos de entrada, incluya una capa totalmente conectada con un tamaño de salida que coincida con el número de canales de los datos de entrada.

layers = [
    sequenceInputLayer(numChannels)
    lstmLayer(128)
    fullyConnectedLayer(numChannels)];

Especificar las opciones de entrenamiento

Especifique las opciones de entrenamiento.

  • Entrene utilizando la optimización de Adam.

  • Entrene durante 200 épocas. Para conjuntos de datos más grandes, puede que no sea necesario entrenar durante tantas épocas para conseguir un buen ajuste.

  • En cada minilote, rellene a la izquierda las secuencias para que tengan la misma longitud. Rellenar a la izquierda evita que la RNN prediga valores de relleno al final de las secuencias.

  • Cambie el orden de los datos en cada época.

  • Muestre el progreso del entrenamiento en una gráfica.

  • Deshabilite la salida detallada.

options = trainingOptions("adam", ...
    MaxEpochs=200, ...
    SequencePaddingDirection="left", ...
    Shuffle="every-epoch", ...
    Plots="training-progress", ...
    Verbose=false);

Entrenar una red neuronal recurrente

Entrene la red neuronal de LSTM con la función trainnet. Para la regresión, utilice la pérdida de error cuadrático medio. De forma predeterminada, la función trainnet usa una GPU en caso de que esté disponible. Para utilizar una GPU se requiere una licencia de Parallel Computing Toolbox™ y un dispositivo GPU compatible. Para obtener información sobre los dispositivos compatibles, consulte GPU Computing Requirements (Parallel Computing Toolbox). De lo contrario, la función usa la CPU. Para especificar el entorno de ejecución, utilice la opción de entrenamiento ExecutionEnvironment.

net = trainnet(XTrain,TTrain,layers,"mse",options);

Probar una red neuronal recurrente

Prepare los datos de prueba para la predicción utilizando los mismos pasos que para los datos de entrenamiento.

Normalice los datos de prueba con las estadísticas calculadas a partir de los datos de entrenamiento. Especifique los objetivos como secuencias de prueba con valores desplazados una unidad de tiempo y los predictores como secuencias de prueba sin la unidad de tiempo final.

numObservationsTest = numel(dataTest);
XTest = cell(numObservationsTest,1);
TTest = cell(numObservationsTest,1);
for n = 1:numObservationsTest
    X = dataTest{n};
    XTest{n} = (X(1:end-1,:) - muX) ./ sigmaX;
    TTest{n} = (X(2:end,:) - muT) ./ sigmaT;
end

Realice predicciones con la función minibatchpredict. De forma predeterminada, la función minibatchpredict usa una GPU en caso de que esté disponible. Rellene las secuencias con las mismas opciones de relleno que para el entrenamiento. Para las tareas de secuencia a secuencia con secuencias de diferentes longitudes, devuelva las predicciones como un arreglo de celdas configurando la opción UniformOutput en false.

YTest = minibatchpredict(net,XTest, ...
    SequencePaddingDirection="left", ...
    UniformOutput=false);

En cada secuencia de prueba, calcule el error cuadrático medio raíz (RMSE) entre las predicciones y los objetivos. Ignore cualquier valor de relleno en las secuencias predichas utilizando las longitudes de las secuencias objetivo como referencia.

for n = 1:numObservationsTest
    T = TTest{n};

    sequenceLength = size(T,1);    

    Y = YTest{n}(end-sequenceLength+1:end,:);

    err(n) = rmse(Y,T,"all");
end

Visualice los errores en un histograma. Cuanto más bajos sean los valores, mayor será la precisión.

figure
histogram(err)
xlabel("RMSE")
ylabel("Frequency")

Figure contains an axes object. The axes object with xlabel RMSE, ylabel Frequency contains an object of type histogram.

Calcule el RMSE medio en todas las observaciones de prueba.

mean(err,"all")
ans = single
    0.5099

Pronosticar unidades de tiempo futuras

Dada una serie de tiempo o una secuencia de entrada, para pronosticar los valores de varias unidades de tiempo futuras, utilice la función predict para predecir unidades de tiempo una por una y actualizar el estado de la RNN en cada predicción. Para cada predicción, utilice la predicción anterior como la entrada para la función.

Visualice una de las secuencias de prueba en una gráfica.

idx = 2;
X = XTest{idx};
T = TTest{idx};

figure
stackedplot(X,DisplayLabels="Channel " + (1:numChannels))
xlabel("Time Step")
title("Test Observation " + idx)

Figure contains an object of type stackedplot. The chart of type stackedplot has title Test Observation 2.

Pronóstico de lazo abierto

El pronóstico de lazo abierto predice la siguiente unidad de tiempo en una secuencia utilizando solo datos de entrada. Cuando se hacen predicciones para unidades de tiempo posteriores, se recopilan valores reales de la fuente de datos y se utilizan como entrada. Por ejemplo, imagine que desea predecir el valor para la unidad de tiempo t de una secuencia con datos recopilados en las unidades de tiempo desde 1 hasta t-1. Para hacer predicciones para la unidad de tiempo t+1, espere hasta que registre el valor real de la unidad de tiempo t y utilícelo como entrada para hacer la siguiente predicción. Utilice el pronóstico de lazo abierto cuando tenga valores reales que proporcionar a la RNN antes de hacer la siguiente predicción.

Inicialice el estado de la RNN restableciendo primero el estado mediante la función resetState. A continuación, realice una predicción inicial con las primeras unidades de tiempo de los datos de entrada. Actualice el estado de la RNN con las primeras 75 unidades de tiempo de los datos de entrada.

net = resetState(net);
offset = 75;
[Z,state] = predict(net,X(1:offset,:));
net.State = state;

Para pronosticar más predicciones, forme un bucle con las unidades de tiempo y haga predicciones mediante la función predict. Después de cada predicción, actualice el estado de la RNN. Pronostique los valores para las unidades de tiempo restantes de la observación de prueba formando un lazo con las unidades de tiempo de los datos de entrada y utilícelos como entrada para la RNN. La última unidad de tiempo de la predicción inicial es la primera unidad de tiempo pronosticada.

numTimeSteps = size(X,1);
numPredictionTimeSteps = numTimeSteps - offset;
Y = zeros(numPredictionTimeSteps,numChannels);
Y(1,:) = Z(end,1);

for t = 1:numPredictionTimeSteps-1
    Xt = X(offset+t,:);
    [Y(t+1,:),state] = predict(net,Xt);
    net.State = state;
end

Compare las predicciones con los valores de entrada.

figure
t = tiledlayout(numChannels,1);
title(t,"Open Loop Forecasting")

for i = 1:numChannels
    nexttile
    plot(X(:,i))
    hold on
    plot(offset:numTimeSteps,[X(offset,i) Y(:,i)'],"--")
    ylabel("Channel " + i)
end

xlabel("Time Step")
nexttile(1)
legend(["Input" "Forecasted"])

Figure contains 3 axes objects. Axes object 1 with ylabel Channel 1 contains 2 objects of type line. These objects represent Input, Forecasted. Axes object 2 with ylabel Channel 2 contains 2 objects of type line. Axes object 3 with xlabel Time Step, ylabel Channel 3 contains 2 objects of type line.

Pronóstico de lazo cerrado

El pronóstico de lazo cerrado predice unidades de tiempo posteriores en una secuencia utilizando las predicciones previas como entrada. En este caso, el modelo no requiere los valores reales para realizar la predicción. Por ejemplo, imagine que desea predecir el valor para las unidades de tiempo desde t hasta t+k de la secuencia con datos recopilados en las unidades de tiempo desde 1 hasta t-1 únicamente. Para hacer predicciones para la unidad de tiempo i, utilice el valor predicho para la unidad de tiempo i-1 como entrada. Utilice el pronóstico de lazo cerrado para pronosticar varias unidades de tiempo posteriores o cuando no tenga valores reales que proporcionar a la RNN antes de hacer la siguiente predicción.

Inicialice el estado de la RNN restableciendo primero el estado mediante la función resetState. A continuación, realice una predicción inicial Z con las primeras unidades de tiempo de los datos de entrada. Actualice el estado de la RNN con todas las unidades de tiempo de los datos de entrada.

net = resetState(net);
offset = size(X,1);
[Z,state] = predict(net,X(1:offset,:));
net.State = state;

Para pronosticar más predicciones, forme un bucle con las unidades de tiempo y haga predicciones mediante la función predict. Después de cada predicción, actualice el estado de la RNN. Pronostique las próximas 200 unidades de tiempo pasando iterativamente el valor predicho anteriormente a la RNN. Dado que la RNN no requiere los datos de entrada para realizar más predicciones, puede especificar cualquier número de unidades de tiempo que desee pronosticar. La última unidad de tiempo de la predicción inicial es la primera unidad de tiempo pronosticada.

numPredictionTimeSteps = 200;
Y = zeros(numPredictionTimeSteps,numChannels);
Y(1,:) = Z(end,:);

for t = 2:numPredictionTimeSteps
    [Y(t,:),state] = predict(net,Y(t-1,:));
    net.State = state;
end

Visualice los valores pronosticados en una gráfica.

numTimeSteps = offset + numPredictionTimeSteps;

figure
t = tiledlayout(numChannels,1);
title(t,"Closed Loop Forecasting")

for i = 1:numChannels
    nexttile
    plot(X(1:offset,i))
    hold on
    plot(offset:numTimeSteps,[X(offset,i) Y(:,i)'],"--")
    ylabel("Channel " + i)
end

xlabel("Time Step")
nexttile(1)
legend(["Input" "Forecasted"])

Figure contains 3 axes objects. Axes object 1 with ylabel Channel 1 contains 2 objects of type line. These objects represent Input, Forecasted. Axes object 2 with ylabel Channel 2 contains 2 objects of type line. Axes object 3 with xlabel Time Step, ylabel Channel 3 contains 2 objects of type line.

El pronóstico de lazo cerrado permite pronosticar un número arbitrario de unidades de tiempo, pero puede resultar menos preciso en comparación con el pronóstico de lazo abierto, ya que la RNN no tiene acceso a los valores reales durante el proceso de pronóstico.

Consulte también

| | | |

Temas relacionados