Intervalle de prédiction autour des prévisions de séries chronologiques LSTM

13

Existe-t-il une méthode pour calculer l'intervalle de prédiction (distribution de probabilité) autour d'une série chronologique prévue à partir d'un réseau de neurones LSTM (ou autre récurrent)?

Disons, par exemple, que je prédis 10 échantillons dans le futur (t + 1 à t + 10), sur la base des 10 derniers échantillons observés (t-9 à t), je m'attendrais à ce que la prédiction à t + 1 soit plus précis que la prédiction à t + 10. En règle générale, on peut tracer des barres d'erreur autour de la prédiction pour afficher l'intervalle. Avec un modèle ARIMA (sous l'hypothèse d'erreurs normalement distribuées), je peux calculer un intervalle de prédiction (par exemple 95%) autour de chaque valeur prédite. Puis-je calculer la même chose (ou quelque chose qui se rapporte à l'intervalle de prédiction) à partir d'un modèle LSTM?

Je travaille avec des LSTM dans Keras / Python, en suivant de nombreux exemples de machinelearningmastery.com , à partir desquels mon exemple de code (ci-dessous) est basé. J'envisage de recadrer le problème en tant que classification en compartiments discrets, car cela produit une confiance par classe, mais cela semble une mauvaise solution.

Il existe quelques sujets similaires (tels que ceux ci-dessous), mais rien ne semble résoudre directement le problème des intervalles de prédiction à partir des réseaux de neurones LSTM (ou bien d'autres):

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

Prédiction de séries chronologiques utilisant 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)
4Oh4
la source

Réponses:

9

Ce n'est pas possible directement. Cependant, si vous le modélisez d'une manière différente, vous pouvez obtenir des intervalles de confiance. Vous pourriez, au lieu d'une régression normale, l'approcher comme une estimation d'une distribution de probabilité continue. En faisant cela pour chaque étape, vous pouvez tracer votre distribution. Les moyens de le faire sont les réseaux de mélanges de noyaux ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , divulgation, mon blog) ou les réseaux de mélanges de densité ( http: //www.cedar .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ), le premier utilise des noyaux comme base et estime un mélange sur ces noyaux et le second estime un mélange de distributions, y compris les paramètres de chacun des les distributions. Vous utilisez la probabilité logarithmique pour l'apprentissage du modèle.

Une autre option pour modéliser l'incertitude consiste à utiliser le décrochage pendant la formation, puis également pendant l'inférence. Vous faites cela plusieurs fois et chaque fois que vous obtenez un échantillon de votre postérieur. Vous n'obtenez pas de distributions, seulement des échantillons, mais c'est la plus facile à implémenter et cela fonctionne très bien.

Dans votre cas, vous devez penser à la façon dont vous générez t + 2 jusqu'à t + 10. Selon votre configuration actuelle, vous devrez peut-être échantillonner à partir du pas de temps précédent et le nourrir pour le suivant. Cela ne fonctionne pas très bien avec la première approche, ni avec la seconde. Si vous avez 10 sorties par pas de temps (t + 1 jusqu'à t + 10), alors toutes ces approches sont plus propres mais un peu moins intuitives.

Jan van der Vegt
la source
1
L'utilisation de réseaux mixtes est intéressante, je vais essayer de l'implémenter. Il y a des recherches solides sur l'utilisation du décrochage ici: arxiv.org/abs/1709.01907 et arxiv.org/abs/1506.02142
4Oh4
Une note pour le décrochage, vous pouvez réellement calculer la variance de la prédiction du décrochage de monte carlo, et l'utiliser comme quantification de l'incertitude
Charles Chow
C'est vrai @CharlesChow mais c'est une mauvaise façon de construire un intervalle de confiance dans ce contexte. Il serait préférable de trier les valeurs et d'utiliser des quantiles en raison de la distribution potentiellement très asymétrique.
Jan van der Vegt
D'accord @JanvanderVegt, mais vous pouvez toujours estimer les statistiques du décrochage MC sans l'hypothèse de distribution de sortie, je veux dire que vous pouvez également utiliser le centile ou le bootstrap pour construire le CI du décrochage MC
Charles Chow
2

La prédiction conforme en tant que mot à la mode peut être intéressante pour vous car elle fonctionne dans de nombreuses conditions - en particulier, elle n'a pas besoin d'erreur distribuée normale et elle fonctionne pour presque tous les modèles d'apprentissage automatique.

Scott Locklin et Henrik Linusson présentent deux belles présentations .

Boris W
la source
1

Je vais diverger un peu et affirmer que le calcul de l'intervalle de confiance dans la pratique n'est généralement pas une chose valable à faire. La raison en est qu'il y a toujours tout un tas d'hypothèses à faire. Même pour la régression linéaire la plus simple, vous devez avoir

  • Relation linéaire.
  • Normalité multivariée.
  • Pas ou peu de multicolinéarité.
  • Pas d'auto-corrélation.
  • Homoscédasticité.

Une approche beaucoup plus pragmatique consiste à faire une simulation de Monte Carlo. Si vous connaissez déjà ou êtes prêt à faire des hypothèses sur la distribution de vos variables d'entrée, prenez tout un échantillon et alimentez-le LSTM, vous pouvez maintenant calculer empiriquement votre "intervalle de confiance".

Louis T
la source
1

Oui, vous pouvez. La seule chose que vous devez changer est la fonction de perte. Implémentez la fonction de perte utilisée dans la régression quantile et intégrez-la. De plus, vous voulez voir comment vous évaluez ces intervalles. Pour cela, j'utiliserais des métriques ICP, MIL et RMIL.

Inigo
la source