Intervallo di previsione attorno alla previsione delle serie temporali LSTM


13

Esiste un metodo per calcolare l'intervallo di previsione (distribuzione di probabilità) attorno a una previsione di serie temporali da una rete neurale LSTM (o altra rete ricorrente)?

Supponiamo, ad esempio, che prevedo 10 campioni nel futuro (da t + 1 a t + 10), in base agli ultimi 10 campioni osservati (da t-9 a t), mi aspetto che la previsione in t + 1 sia maggiore accurato rispetto alla previsione at + 10. In genere, è possibile disegnare barre di errore attorno alla previsione per mostrare l'intervallo. Con un modello ARIMA (presupponendo errori normalmente distribuiti), posso calcolare un intervallo di previsione (ad es. Il 95%) attorno a ciascun valore previsto. Posso calcolare lo stesso (o qualcosa correlato all'intervallo di previsione) da un modello LSTM?

Sto lavorando con LSTM in Keras / Python, seguendo molti esempi di machinelearningmastery.com , da cui si basa il mio codice di esempio (sotto). Sto prendendo in considerazione la ridefinizione del problema come classificazione in bin discreti, in quanto ciò produce una confidenza per classe, ma sembra una soluzione scadente.

Esistono un paio di argomenti simili (come quelli di seguito), ma nulla sembra affrontare direttamente il problema degli intervalli di predizione dalle reti neurali LSTM (o addirittura da altre):

/stats/25055/how-to-calculate-the-confidence-interval-for-time-series-prediction

Previsione di serie storiche usando ARIMA vs LSTM

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from math import sin
from matplotlib import pyplot
import numpy as np

# Build an LSTM network and train
def fit_lstm(X, y, batch_size, nb_epoch, neurons):
    X = X.reshape(X.shape[0], 1, X.shape[1]) # add in another dimension to the X data
    y = y.reshape(y.shape[0], y.shape[1])      # but don't add it to the y, as Dense has to be 1d?
    model = Sequential()
    model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
    model.add(Dense(y.shape[1]))
    model.compile(loss='mean_squared_error', optimizer='adam')
    for i in range(nb_epoch):
        model.fit(X, y, epochs=1, batch_size=batch_size, verbose=1, shuffle=False)
        model.reset_states()
    return model

# Configuration
n = 5000    # total size of dataset
SLIDING_WINDOW_LENGTH = 30
SLIDING_WINDOW_STEP_SIZE = 1
batch_size = 10
test_size = 0.1 # fraction of dataset to hold back for testing
nb_epochs = 100 # for training
neurons = 8 # LSTM layer complexity

# create dataset
#raw_values = [sin(i/2) for i in range(n)]  # simple sine wave
raw_values = [sin(i/2)+sin(i/6)+sin(i/36)+np.random.uniform(-1,1) for i in range(n)]  # double sine with noise
#raw_values = [(i%4) for i in range(n)] # saw tooth

all_data = np.array(raw_values).reshape(-1,1) # make into array, add anothe dimension for sci-kit compatibility

# data is segmented using a sliding window mechanism
all_data_windowed = [np.transpose(all_data[idx:idx+SLIDING_WINDOW_LENGTH]) for idx in np.arange(0,len(all_data)-SLIDING_WINDOW_LENGTH, SLIDING_WINDOW_STEP_SIZE)]
all_data_windowed = np.concatenate(all_data_windowed, axis=0).astype(np.float32)

# split data into train and test-sets
# round datasets down to a multiple of the batch size
test_length = int(round((len(all_data_windowed) * test_size) / batch_size) * batch_size)
train, test = all_data_windowed[:-test_length,:], all_data_windowed[-test_length:,:]
train_length = int(np.floor(train.shape[0] / batch_size)*batch_size) 
train = train[:train_length,...]

half_size = int(SLIDING_WINDOW_LENGTH/2) # split the examples half-half, to forecast the second half
X_train, y_train = train[:,:half_size], train[:,half_size:]
X_test, y_test = test[:,:half_size], test[:,half_size:]

# fit the model
lstm_model = fit_lstm(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epochs, neurons=neurons)

# forecast the entire training dataset to build up state for forecasting
X_train_reshaped = X_train.reshape(X_train.shape[0], 1, X_train.shape[1])
lstm_model.predict(X_train_reshaped, batch_size=batch_size)

# predict from test dataset
X_test_reshaped = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])
yhat = lstm_model.predict(X_test_reshaped, batch_size=batch_size)

#%% Plot prediction vs actual

x_axis_input = range(half_size)
x_axis_output = [x_axis_input[-1]] + list(half_size+np.array(range(half_size)))

fig = pyplot.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x_axis_input,np.zeros_like(x_axis_input), 'r-')
line2, = ax.plot(x_axis_output,np.zeros_like(x_axis_output), 'o-')
line3, = ax.plot(x_axis_output,np.zeros_like(x_axis_output), 'g-')
ax.set_xlim(np.min(x_axis_input),np.max(x_axis_output))
ax.set_ylim(-4,4)
pyplot.legend(('Input','Actual','Predicted'),loc='upper left')
pyplot.show()

# update plot in a loop
for idx in range(y_test.shape[0]):

    sample_input = X_test[idx]
    sample_truth = [sample_input[-1]] + list(y_test[idx]) # join lists
    sample_predicted = [sample_input[-1]] + list(yhat[idx])

    line1.set_ydata(sample_input)
    line2.set_ydata(sample_truth)
    line3.set_ydata(sample_predicted)
    fig.canvas.draw()
    fig.canvas.flush_events()

    pyplot.pause(.25)

Risposte:


9

Direttamente, questo non è possibile. Tuttavia, se lo modelli in un modo diverso, puoi ottenere intervalli di confidenza. Al posto di una normale regressione, invece, potresti avvicinarti a una stima della distribuzione della probabilità continua. In questo modo per ogni passaggio puoi tracciare la tua distribuzione. I modi per farlo sono Kernel Mixture Networks ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , divulgazione, il mio blog) o Density Mixture Networks ( http: //www.cedar .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ), il primo utilizza i kernel come base e stima una miscela su questi kernel e il secondo stima una miscela di distribuzioni, inclusi i parametri di ciascuno di le distribuzioni. Si utilizza la probabilità del registro per addestrare il modello.

Un'altra opzione per modellare l'incertezza è usare il dropout durante l'allenamento e poi anche durante l'inferenza. Lo fai più volte e ogni volta che ottieni un campione dal tuo posteriore. Non ottieni distribuzioni, solo esempi, ma è la più facile da implementare e funziona molto bene.

Nel tuo caso devi pensare al modo in cui generi t + 2 fino a t + 10. A seconda della configurazione corrente, potrebbe essere necessario campionare dal passaggio temporale precedente e alimentare quello per il successivo. Ciò non funziona molto bene con il primo approccio, né con il secondo. Se hai 10 uscite per passo temporale (da t + 1 a t + 10), tutti questi approcci sono più chiari ma un po 'meno intuitivi.


1
L'uso di reti miste è interessante, cercherò di implementarlo. C'è qualche solida ricerca sull'uso del dropout qui: arxiv.org/abs/1709.01907 e arxiv.org/abs/1506.02142
4Oh4

Una nota per il dropout, puoi effettivamente calcolare la varianza della previsione del dropout di Monte Carlo e usarla come quantificazione dell'incertezza
Charles Chow,

Questo è vero @CharlesChow ma è un modo scadente per costruire un intervallo di confidenza in questo contesto. Sarebbe meglio ordinare i valori e usare i quantili a causa della distribuzione potenzialmente molto distorta.
Jan van der Vegt,

Accetto @JanvanderVegt, ma puoi ancora stimare le statistiche del dropout MC senza il presupposto della distribuzione dell'output, intendo che puoi anche usare percentile o bootstrap per costruire il CI di dropout MC
Charles Chow

2

La previsione conforme come parola d'ordine potrebbe essere interessante per te perché funziona in molte condizioni - in particolare non ha bisogno di un normale errore distribuito e funziona per quasi tutti i modelli di apprendimento automatico.

Due simpatiche presentazioni sono date da Scott Locklin e Henrik Linusson .


1

Divergerò un po 'e sosterrò che l'intervallo di confidenza del calcolo è in pratica di solito non è una cosa preziosa da fare. Il motivo è che c'è sempre un sacco di ipotesi che devi fare. Anche per la regressione lineare più semplice, devi avere

  • Relazione lineare.
  • Normalità multivariata.
  • Nessuna o poca multicollinearità.
  • Nessuna auto-correlazione.
  • Omoschedasticità.

Un approccio molto più pragmatico è quello di fare una simulazione Monte Carlo. Se già conosci o sei disposto a fare ipotesi sulla distribuzione delle variabili di input, prendi un sacco di campioni e forniscili a LSTM, ora puoi calcolare empiricamente il tuo "intervallo di confidenza".


1

Si, puoi. L'unica cosa che devi cambiare è la funzione di perdita. Implementare la funzione di perdita utilizzata nella regressione quantile e integrarla. Inoltre, vuoi dare un'occhiata a come valuti questi intervalli. Per questo, vorrei usare le metriche ICP, MIL e RMIL.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.