Vorhersageintervall um die LSTM-Zeitreihenprognose


12

Gibt es eine Methode zur Berechnung des Vorhersageintervalls (Wahrscheinlichkeitsverteilung) um eine Zeitreihenprognose aus einem LSTM-Netzwerk (oder einem anderen wiederkehrenden neuronalen Netzwerk)?

Angenommen, ich prognostiziere 10 Stichproben für die Zukunft (t + 1 bis t + 10), basierend auf den letzten 10 beobachteten Stichproben (t-9 bis t), würde ich erwarten, dass die Vorhersage bei t + 1 höher ist genauer als die Vorhersage bei t + 10. Normalerweise kann man Fehlerbalken um die Vorhersage ziehen, um das Intervall anzuzeigen. Mit einem ARIMA-Modell (unter der Annahme normalverteilter Fehler) kann ich ein Vorhersageintervall (z. B. 95%) um jeden vorhergesagten Wert berechnen. Kann ich dasselbe (oder etwas, das sich auf das Vorhersageintervall bezieht) aus einem LSTM-Modell berechnen?

Ich habe mit LSTMs in Keras / Python gearbeitet und dabei viele Beispiele von machinelearningmastery.com befolgt , auf denen mein Beispielcode (unten) basiert. Ich denke darüber nach, das Problem als Klassifizierung in diskrete Klassen umzuformulieren, da dies ein Vertrauen pro Klasse erzeugt, aber das scheint eine schlechte Lösung zu sein.

Es gibt einige ähnliche Themen (wie das folgende), aber nichts scheint das Problem der Vorhersageintervalle von LSTM (oder anderen) neuronalen Netzen direkt anzusprechen:

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

Zeitreihenvorhersage mit 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)

Antworten:


8

Dies ist direkt nicht möglich. Wenn Sie es jedoch anders modellieren, können Sie Konfidenzintervalle ermitteln. Sie könnten anstelle eines normalen Regressionsansatzes eine kontinuierliche Wahrscheinlichkeitsverteilung schätzen. Auf diese Weise können Sie für jeden Schritt Ihre Verteilung zeichnen. Möglichkeiten hierfür sind Kernel Mixture Networks ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , Offenlegung, mein Blog) oder Density Mixture Networks ( http: //www.cedar) .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ) verwendet der erste Kernel als Basis und schätzt eine Mischung über diese Kernel und der zweite schätzt eine Mischung von Verteilungen, einschließlich der Parameter von jedem von die Verteilungen. Sie verwenden die Protokollwahrscheinlichkeit zum Trainieren des Modells.

Eine weitere Möglichkeit zur Modellierung der Unsicherheit besteht darin, Dropout während des Trainings und dann auch während der Inferenz zu verwenden. Sie tun dies mehrmals und jedes Mal, wenn Sie eine Probe von Ihrem Seitenzahn erhalten. Sie erhalten keine Distributionen, nur Beispiele, aber es ist am einfachsten zu implementieren und funktioniert sehr gut.

In Ihrem Fall müssen Sie darüber nachdenken, wie Sie t + 2 bis t + 10 erzeugen. Abhängig von Ihrem aktuellen Setup müssen Sie möglicherweise den vorherigen Zeitschritt probieren und diesen für den nächsten füttern. Das funktioniert weder beim ersten noch beim zweiten Ansatz sehr gut. Wenn Sie 10 Ausgänge pro Zeitschritt haben (t + 1 bis t + 10), sind alle diese Ansätze sauberer, aber etwas weniger intuitiv.


1
Die Verwendung von Mischungsnetzwerken ist interessant, ich werde versuchen, dies umzusetzen. Hier gibt es einige solide Untersuchungen zur Verwendung von Dropout: arxiv.org/abs/1709.01907 und arxiv.org/abs/1506.02142
4Oh4

Ein Hinweis für den Dropout: Sie können die Varianz der Vorhersage des Monte-Carlo-Dropouts tatsächlich berechnen und als Quantifizierung der Unsicherheit verwenden
Charles Chow

Das ist wahr @CharlesChow, aber das ist eine schlechte Möglichkeit, in diesem Zusammenhang ein Konfidenzintervall zu erstellen. Aufgrund der möglicherweise sehr verzerrten Verteilung ist es besser, die Werte zu sortieren und Quantile zu verwenden.
Jan van der Vegt

Stimmen Sie @JanvanderVegt zu, aber Sie können die Statistik des MC-Ausfalls immer noch ohne die Annahme einer Ausgabeverteilung schätzen. Ich meine, Sie können auch Perzentil oder Bootstrapping verwenden, um den CI des MC-Ausfalls zu erstellen
Charles Chow

2

Konforme Vorhersage als Modewort könnte für Sie interessant sein, da sie unter vielen Bedingungen funktioniert - insbesondere benötigt sie keinen normalverteilten Fehler und funktioniert für fast jedes Modell des maschinellen Lernens.

Zwei nette Einführungen geben Scott Locklin und Henrik Linusson .


1

Ich werde ein wenig auseinander gehen und argumentieren, dass das Berechnungskonfidenzintervall in der Praxis normalerweise keine wertvolle Sache ist. Der Grund ist, dass Sie immer eine ganze Reihe von Annahmen treffen müssen. Selbst für die einfachste lineare Regression müssen Sie haben

  • Lineare Beziehung.
  • Multivariate Normalität.
  • Keine oder wenig Multikollinearität.
  • Keine Autokorrelation.
  • Homoskedastizität.

Ein viel pragmatischerer Ansatz ist die Durchführung einer Monte-Carlo-Simulation. Wenn Sie bereits wissen oder bereit sind, Annahmen über die Verteilung Ihrer Eingabevariablen zu treffen, nehmen Sie eine ganze Reihe von Stichproben und geben Sie sie an LSTM weiter. Jetzt können Sie Ihr "Konfidenzintervall" empirisch berechnen.


1

Ja, du kannst. Das einzige, was Sie ändern müssen, ist die Verlustfunktion. Implementieren Sie die in der Quantilregression verwendete Verlustfunktion und integrieren Sie sie. Außerdem möchten Sie einen Blick darauf werfen, wie Sie diese Intervalle bewerten. Dafür würde ich ICP-, MIL- und RMIL-Metriken verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.