Previsione delle serie temporali tramite il Deep Learning
Questo esempio mostra come prevedere i dati delle serie temporali utilizzando una rete con memoria a breve e lungo termine (LSTM).
Una rete LSTM è una rete neurale ricorrente (RNN) che elabora i dati di input eseguendo un loop sulle fasi temporali e aggiornando lo stato RNN. Lo stato RNN contiene le informazioni ricordate in tutte le fasi temporali precedenti. È possibile utilizzare una rete neurale LSTM per prevedere i valori successivi di una serie o di una sequenza temporale utilizzando come input le fase temporali precedenti. Per addestrare una rete neurale LSTM per la previsione di serie temporali, è necessario addestrare una rete neurale LSTM di regressione con una sequenza di output, dove le risposte (target) sono le sequenze di addestramento con valori spostati di una fase temporale. In altre parole, in ciascuna fase temporale della sequenza di input, la rete neurale LSTM impara a prevedere il valore della fase temporale successiva.
Esistono due metodi di previsione: la previsione a loop aperto e la previsione a loop chiuso.
Previsione a loop aperto: prevedere la fase temporale successiva di una sequenza utilizzando solo i dati di input. Quando si effettuano le previsioni per le fasi temporali successive, si raccolgono i valori reali dalla sorgente dei dati e li si utilizzano come input. Ad esempio, si supponga di voler prevedere il valore per la fase temporale di una sequenza utilizzando i dati raccolti nelle fasi temporali da 1 a . Per fare previsioni per la fase temporale , è necessario attendere che il valore reale per la fase temporale sia registrato e quindi utilizzarlo come input per eseguire la previsione successiva. Utilizzare la previsione a loop aperto quando si dispone di valori reali da fornire alla RNN prima di effettuare la previsione successiva.
Previsione a loop chiuso: prevedere le fasi temporali successive di una sequenza utilizzando le previsioni precedenti come input. In questo caso, il modello non necessita dei valori reali per effettuare la previsione. Ad esempio, si supponga di voler prevedere i valori per le fasi temporali da a della sequenza utilizzando solo i dati raccolti nelle fasi temporali da 1 a . Per fare previsioni per la fase temporale , utilizzare il valore previsto per la fase temporale come input. Utilizzare la previsione a loop chiuso per prevedere più fasi temporali successive o quando non si dispone dei valori reali da fornire alla RNN prima di effettuare la previsione successiva.
Questa figura mostra un esempio di sequenza con valori previsti utilizzando la previsione a loop chiuso.
Questo esempio utilizza l’insieme di dati waveform, che contiene 2000 forme d'onda generate sinteticamente di varia lunghezza con tre canali. L'esempio addestra una rete neurale LSTM a prevedere i valori futuri delle forme d'onda in base ai valori dati dalle fasi temporali precedenti, utilizzando sia la previsione a loop chiuso sia la previsione a loop aperto.
Caricamento dei dati
Caricare i dati di esempio da WaveformData.mat
. I dati sono un array di sequenze di celle numObservations
per 1, dove numObservations
è il numero delle sequenze. Ciascuna sequenza è un array numerico numTimeSteps
per -numChannels
, dove numTimeSteps
è il numero di fasi temporali della sequenza e numChannels
è il numero di canali della sequenza.
load WaveformData
Visualizzare le dimensioni delle prime sequenze.
data(1:4)
ans=4×1 cell array
{103×3 double}
{136×3 double}
{140×3 double}
{124×3 double}
Visualizzare il numero di canali. Per addestrare la rete neurale LSTM, ciascuna sequenza deve avere lo stesso numero di canali.
numChannels = size(data{1},2)
numChannels = 3
Visualizzare le prime sequenze in un grafico.
figure tiledlayout(2,2) for i = 1:4 nexttile stackedplot(data{i}) xlabel("Time Step") end
Suddividere i dati in insiemi di addestramento e di test. Utilizzare il 90% delle osservazioni per l'addestramento e il resto per il test.
numObservations = numel(data); idxTrain = 1:floor(0.9*numObservations); idxTest = floor(0.9*numObservations)+1:numObservations; dataTrain = data(idxTrain); dataTest = data(idxTest);
Preparazione dei dati per l’addestramento
Per prevedere i valori delle fasi temporali future di una sequenza, specificare i target come sequenze di addestramento e con valori spostati di una fase temporale. Non includere la fase temporale finale nelle sequenze di addestramento. In altre parole, in ciascuna fase temporale della sequenza di input, la rete neurale LSTM impara a prevedere il valore della fase temporale successiva. I predittori sono le sequenze di addestramento senza la fase temporale finale.
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
Per un migliore adattamento e per evitare che l'addestramento diverga, normalizzare i predittori e i target in modo che i canali abbiano una media pari a zero e una varianza unitaria. Quando si effettuano le previsioni, è necessario normalizzare anche i dati di test utilizzando le stesse statistiche dei dati di addestramento.
Calcolare i valori della media e della deviazione standard per canale delle sequenze. Per calcolare facilmente la media e la deviazione standard dei dati di addestramento, creare array numerici che contengano le sequenze concatenate utilizzando la funzione cell2mat
.
muX = mean(cell2mat(XTrain)); sigmaX = std(cell2mat(XTrain),0); muT = mean(cell2mat(TTrain)); sigmaT = std(cell2mat(TTrain),0);
Normalizzare le sequenze utilizzando i valori della media e della deviazione standard calcolati.
for n = 1:numel(XTrain) XTrain{n} = (XTrain{n} - muX) ./ sigmaX; TTrain{n} = (TTrain{n} - muT) ./ sigmaT; end
Definizione dell'architettura della rete neurale LSTM
Creare una rete neurale LSTM di regressione.
Utilizzare un livello di input in sequenza con una dimensione di input che corrisponda al numero di canali dei dati di input.
Utilizzare un livello LSTM con 128 unità nascoste. Il numero di unità nascoste determina quante informazioni sono apprese dal livello. L’utilizzo di un numero maggiore di unità nascoste può dare risultati più accurati, ma è più probabile che porti a un sovraadattamento dei dati di addestramento.
Per ottenere sequenze di output con lo stesso numero di canali dei dati di input, includere un livello completamente connesso con una dimensione di output che corrisponda al numero di canali dei dati di input.
layers = [ sequenceInputLayer(numChannels) lstmLayer(128) fullyConnectedLayer(numChannels)];
Specificazione delle opzioni di addestramento
Specificare le opzioni di addestramento.
Addestrare utilizzando l'ottimizzazione Adam.
Addestrare per 200 epoche. Per insiemi di dati più grandi, potrebbe non essere necessario l’addestramento per un numero così elevato di epoche per ottenere un buon adattamento.
In ciascun mini-batch, eseguire il riempimento a sinistra delle sequenze in modo che abbiano la stessa lunghezza. Il riempimento a sinistra impedisce alla RNN di prevedere i valori di riempimento alle estremità delle sequenze.
Mescolare i dati a ciascuna epoca.
Visualizzare l'andamento dell'addestramento in un grafico.
Disattivare l’output verboso.
options = trainingOptions("adam", ... MaxEpochs=200, ... SequencePaddingDirection="left", ... Shuffle="every-epoch", ... Plots="training-progress", ... Verbose=false);
Addestramento di una rete neurale ricorrente
Addestrare la rete neurale LSTM utilizzando la funzione trainnet
. Per la regressione, utilizzare la perdita dell'errore quadratico medio. Per impostazione predefinita, la funzione trainnet
utilizza una GPU, se disponibile. L'utilizzo di una GPU richiede una licenza Parallel Computing Toolbox™ e un dispositivo GPU supportato. Per informazioni sui dispositivi supportati, vedere GPU Computing Requirements (Parallel Computing Toolbox). In caso contrario, la funzione utilizza la CPU. Per specificare l'ambiente di esecuzione, utilizzare l'opzione di addestramento ExecutionEnvironment
.
net = trainnet(XTrain,TTrain,layers,"mse",options);
Test della rete neurale ricorrente
Preparare i dati di test per la previsione utilizzando gli stessi passaggi utilizzati per i dati di addestramento.
Normalizzare i dati di test utilizzando le statistiche calcolate dai dati di addestramento. Specificare i target come sequenze di test con valori spostati di una fase temporale e i predittori come sequenze di test senza la fase temporale finale.
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
Eseguire le previsioni utilizzando la funzione minibatchpredict
. Per impostazione predefinita, la funzione minibatchpredict
utilizza una GPU, se disponibile. Riempire le sequenze utilizzando le stesse opzioni di riempimento utilizzate per l'addestramento. Per le attività sequenza-sequenza con sequenze di lunghezza variabile, restituire le previsioni come array di celle impostando l'opzione UniformOutput
su false
.
YTest = minibatchpredict(net,XTest, ... SequencePaddingDirection="left", ... UniformOutput=false);
Per ciascuna sequenza di test, calcolare l'errore quadratico medio (RMSE) tra le previsioni e i target. Ignorare eventuali valori di riempimento nelle sequenze previste utilizzando come riferimento le lunghezze delle sequenze target.
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
Visualizzare gli errori in un istogramma. Valori più bassi indicano una maggiore precisione.
figure histogram(err) xlabel("RMSE") ylabel("Frequency")
Calcolare l'RMSE medio su tutte le osservazioni del test.
mean(err,"all")
ans = single
0.5099
Previsione delle fasi temporali future
Data una serie o una sequenza temporale di input, per prevedere i valori di più fasi temporali future, utilizzare la funzione predict
per prevedere le fasi temporali una alla volta e aggiornare lo stato della RNN a ogni previsione. Per ogni previsione, utilizzare la previsione precedente come input della funzione.
Visualizzare una delle sequenze di test in un grafico.
idx = 2; X = XTest{idx}; T = TTest{idx}; figure stackedplot(X,DisplayLabels="Channel " + (1:numChannels)) xlabel("Time Step") title("Test Observation " + idx)
Previsione a loop aperto
La previsione a loop aperto prevede la fase temporale successiva di una sequenza utilizzando solo i dati di input. Quando si effettuano le previsioni per le fasi temporali successive, si raccolgono i valori reali dalla sorgente dei dati e li si utilizzano come input. Ad esempio, si supponga di voler prevedere il valore per la fase temporale di una sequenza utilizzando i dati raccolti nelle fasi temporali da 1 a . Per fare previsioni per la fase temporale , è necessario attendere che il valore reale per la fase temporale sia registrato e quindi utilizzarlo come input per eseguire la previsione successiva. Utilizzare la previsione a loop aperto quando si dispone di valori reali da fornire alla RNN prima di effettuare la previsione successiva.
Inizializzare lo stato della RNN resettando prima lo stato utilizzando la funzione resetState
, quindi fare una previsione iniziale utilizzando le prime poche fasi temporali dei dati di input. Aggiornare lo stato della RNN utilizzando le prime 75 fasi temporali dei dati di input.
net = resetState(net); offset = 75; [Z,state] = predict(net,X(1:offset,:)); net.State = state;
Per prevedere ulteriori previsioni, eseguire un loop sulle fasi temporali e fare le previsioni utilizzando la funzione predict
. Dopo ciascuna previsione, aggiornare lo stato della RNN. Prevedere i valori per le restanti fasi temporali dell'osservazione di test eseguendo un loop sulle fasi temporali dei dati di input e utilizzandoli come input della RNN. L'ultima fase temporale della previsione iniziale è la prima fase temporale prevista.
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
Confrontare le previsioni con i valori di input.
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"])
Previsione a loop chiuso
La previsione a loop chiuso prevede le fasi temporali successive di una sequenza utilizzando le previsioni precedenti come input. In questo caso, il modello non necessita dei valori reali per effettuare la previsione. Ad esempio, si supponga di voler prevedere il valore per le fasi temporali da a della sequenza utilizzando solo i dati raccolti nelle fasi temporali da 1 a . Per fare previsioni per la fase temporale , utilizzare il valore previsto per la fase temporale come input. Utilizzare la previsione a loop chiuso per prevedere più fasi temporali successive o quando non si dispone di valori reali da fornire alla RNN prima di effettuare la previsione successiva.
Inizializzare lo stato della RNN resettando prima lo stato utilizzando la funzione resetState
, quindi fare una previsione iniziale Z
utilizzando le prime poche fasi temporali dei dati di input. Aggiornare lo stato della RNN utilizzando tutte le fasi temporali dei dati di input.
net = resetState(net); offset = size(X,1); [Z,state] = predict(net,X(1:offset,:)); net.State = state;
Per prevedere ulteriori previsioni, eseguire un loop sulle fasi temporali e fare le previsioni utilizzando la funzione predict
. Dopo ciascuna previsione, aggiornare lo stato della RNN. Prevedere le successive 200 fasi temporali passando iterativamente il precedente valore previsto alla RNN. Poiché la RNN non ha bisogno dei dati di input per fare ulteriori previsioni, è possibile specificare un numero qualsiasi di fasi temporali da prevedere. L'ultima fase temporale della previsione iniziale è la prima fase temporale prevista.
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
Visualizzare i valori previsti in un grafico.
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"])
La previsione a loop chiuso consente di prevedere un numero arbitrario di fasi temporali, ma può essere meno accurata rispetto a quella a loop aperto in quanto la RNN non ha accesso ai valori reali durante il processo di previsione.
Vedi anche
trainnet
| trainingOptions
| dlnetwork
| lstmLayer
| sequenceInputLayer
Argomenti complementari
- Generate Text Using Deep Learning
- Classificazione di sequenze utilizzando il Deep Learning
- Classificazione sequenza-sequenza utilizzando il Deep Learning
- Sequence-to-Sequence Regression Using Deep Learning
- Sequence-to-One Regression Using Deep Learning
- Long Short-Term Memory Neural Networks
- Deep Learning in MATLAB