Main Content

Crear una red para el pronóstico de series de tiempo con Deep Network Designer

Este ejemplo muestra cómo crear una red de memoria de corto-largo plazo (LSTM) para pronosticar datos de series de tiempo con la app Deep Network Designer.

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 crear una red de LSTM para pronosticar series de tiempo, utilice la app Deep Network Designer.

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

Cargar datos secuenciales

Cargue los datos de ejemplo de WaveformData. Para acceder a los datos, abra el ejemplo como un script en vivo. El conjunto de datos con forma de onda contiene 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.

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 algunas de las secuencias.

idx = 1;
numChannels = size(data{idx},2);

figure
stackedplot(data{idx},DisplayLabels="Channel " + (1:numChannels))

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.

numObservations = numel(data);
XData = cell(numObservations,1);
TData = cell(numObservations,1);
for n = 1:numObservations
    X = data{n};
    XData{n} = X(1:end-1,:);
    TData{n} = X(2:end,:);
end

Divida los datos en conjuntos de entrenamiento, validación y prueba. Utilice el 80% de los datos para el entrenamiento, el 10% para la validación y el 10% para la prueba. Para dividir los datos, use la función trainingPartitions, incluida en este ejemplo como un archivo de soporte. Para acceder al archivo, abra el ejemplo como un script en vivo.

[idxTrain,idxValidation,idxTest] = trainingPartitions(numObservations,[0.8 0.1 0.1]);

XTrain = XData(idxTrain);
TTrain = TData(idxTrain);

XValidation = XData(idxValidation);
TValidation = TData(idxValidation);

XTest = XData(idxTest);
TTest = TData(idxTest);

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 validación y 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 los datos de entrenamiento 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

Normalice los datos de validación y prueba con las estadísticas calculadas a partir de los datos de entrenamiento.

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

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

Definir la arquitectura de red

Para crear la red, abra la app Deep Network Designer.

deepNetworkDesigner

Para crear una red de secuencia, en la sección Sequence Networks, deténgase en Sequence-to-Sequence y haga clic en Open.

Se abrirá una red preconstruida adecuada para problemas de clasificación de secuencias. La red contiene estas capas:

  • sequenceInputLayer

  • lstmLayer

  • dropoutLayer

  • fullyConnectedLayer

  • softmaxLayer

Puede convertir la red de clasificación en una red adecuada para el pronóstico de series de tiempo editando las capas finales. Primero, elimine la capa softmax.

A continuación, ajuste las propiedades de las capas para que sean adecuadas para el conjunto de datos con forma de onda. Dado que el objetivo es pronosticar puntos de datos futuros en una serie de tiempo, el tamaño de salida debe ser igual que el tamaño de entrada. En este ejemplo, los datos de entrada tienen tres canales de entrada, por lo que la salida de la red también debe tener tres canales de salida.

Seleccione la capa de entrada de secuencias input y establezca InputSize en 3.

Seleccione la capa totalmente conectada fc y establezca OutputSize en 3.

La capa de LSTM tiene 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. La capa de abandono ayuda a evitar el sobreajuste estableciendo aleatoriamente las entradas de la capa en cero y cambiando de forma efectiva la arquitectura de red entre iteraciones de entrenamiento. Una mayor probabilidad de abandono puede mejorar la generalización del modelo a costa de perder información y ralentizar el proceso de aprendizaje.

Para comprobar que la red está preparada para el entrenamiento, haga clic en Analyze. Dado que el analizador Deep Learning Network Analyzer no detecta ningún error o advertencia, la red está preparada para el entrenamiento. Para exportar la red, haga clic en Export. La app guarda la red en la variable net_1.

Especificar las opciones de entrenamiento

Especifique las opciones de entrenamiento. Para escoger entre las opciones se requiere un análisis empírico. Para explorar diferentes configuraciones de opciones de entrenamiento mediante la ejecución de experimentos, puede utilizar la app Experiment Manager.

  • 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.

  • Monitorice el sobreajuste con los datos de validación.

  • Monitorice el error cuadrático medio raíz.

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

  • Deshabilite la salida detallada.

options = trainingOptions("adam", ...
    MaxEpochs=200, ...
    SequencePaddingDirection="left", ...
    Shuffle="every-epoch", ...
    ValidationData={XValidation,TValidation}, ...
    Metrics="rmse", ...
    Plots="training-progress", ...
    Verbose=false);

Entrenar una red neuronal

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,net_1,"mse",options);

Probar una red neuronal recurrente

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 eliminándolo antes de calcular el RMSE.

numObservationsTest = numel(XTest);

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")

Calcule el RMSE medio en todas las observaciones de prueba.

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

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 = 3;
X = XTest{idx};
T = TTest{idx};

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

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.

Pronóstico de lazo abierto

Realice un pronóstico de lazo abierto.

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,:);

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"])

Pronóstico de lazo cerrado

Realice un pronóstico de lazo cerrado.

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"])

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