Intervalo de predicción alrededor del pronóstico de series de tiempo LSTM

13

¿Existe algún método para calcular el intervalo de predicción (distribución de probabilidad) alrededor de un pronóstico de serie temporal de una red neuronal LSTM (u otra red recurrente)?

Digamos, por ejemplo, que pronostico 10 muestras en el futuro (t + 1 a t + 10), con base en las últimas 10 muestras observadas (t-9 a t), esperaría que la predicción en t + 1 sea más precisa que la predicción en t + 10. Por lo general, se pueden dibujar barras de error alrededor de la predicción para mostrar el intervalo. Con un modelo ARIMA (bajo el supuesto de errores distribuidos normalmente), puedo calcular un intervalo de predicción (por ejemplo, 95%) alrededor de cada valor pronosticado. ¿Puedo calcular lo mismo (o algo relacionado con el intervalo de predicción) a partir de un modelo LSTM?

He estado trabajando con LSTM en Keras / Python, siguiendo muchos ejemplos de machinelearningmastery.com , en los que se basa mi código de ejemplo (a continuación). Estoy considerando volver a enmarcar el problema como clasificación en contenedores discretos, ya que eso produce una confianza por clase, pero esa parece una mala solución.

Hay un par de temas similares (como los siguientes), pero nada parece abordar directamente el problema de los intervalos de predicción de las redes neuronales LSTM (o incluso otras):

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

Predicción de series de tiempo 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)
4Oh4
fuente

Respuestas:

9

Directamente, esto no es posible. Sin embargo, si lo modela de una manera diferente, puede obtener intervalos de confianza. En lugar de un enfoque de regresión normal, podría estimar una distribución de probabilidad continua. Al hacer esto para cada paso, puede trazar su distribución. Las formas de hacerlo son Kernel Mixture Networks ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , divulgación, mi blog) o Density Mixture Networks ( http: //www.cedar .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ), el primero usa kernels como base y estima una mezcla sobre estos Kernels y el segundo estima una mezcla de distribuciones, incluidos los parámetros de cada uno de Las distribuciones. Utiliza la probabilidad de registro para entrenar el modelo.

Otra opción para modelar la incertidumbre es usar el abandono durante el entrenamiento y luego también durante la inferencia. Lo haces varias veces y cada vez que obtienes una muestra de tu posterior. No obtienes distribuciones, solo muestras, pero es la más fácil de implementar y funciona muy bien.

En su caso, debe pensar en la forma en que genera t + 2 hasta t + 10. Dependiendo de su configuración actual, es posible que deba tomar una muestra del paso de tiempo anterior y alimentarlo para el siguiente. Eso no funciona muy bien con el primer enfoque, ni con el segundo. Si tiene 10 salidas por paso de tiempo (t + 1 hasta t + 10), todos estos enfoques son más limpios pero un poco menos intuitivos.

Jan van der Vegt
fuente
1
Usar redes mixtas es interesante, intentaré implementar eso. Aquí hay una investigación sólida sobre el uso de la deserción escolar: arxiv.org/abs/1709.01907 y arxiv.org/abs/1506.02142
4Oh4
Una nota para la deserción, en realidad puede calcular la varianza de la predicción de la deserción de monte carlo, y usar eso como cuantificación de la incertidumbre
Charles Chow
Eso es cierto @CharlesChow, pero esa es una mala manera de construir un intervalo de confianza en este contexto. Sería mejor ordenar los valores y usar cuantiles debido a la distribución potencialmente muy sesgada.
Jan van der Vegt
De acuerdo @JanvanderVegt, pero aún puede estimar las estadísticas de abandono de MC sin la suposición de distribución de salida, quiero decir que también puede usar el percentil o bootstrapping para construir el abandono de IC de MC
Charles Chow
2

La predicción conforme como palabra de moda puede ser interesante para usted porque funciona en muchas condiciones, en particular, no necesita un error distribuido normal y funciona para casi cualquier modelo de aprendizaje automático.

Scott Locklin y Henrik Linusson dan dos buenas presentaciones .

Boris W
fuente
1

Voy a divergir un poco y argumentar que el intervalo de confianza de cálculo en la práctica generalmente no es algo valioso. La razón es que siempre hay un montón de suposiciones que debes hacer. Incluso para la regresión lineal más simple, debe tener

  • Relación lineal.
  • Normalidad multivariante.
  • No o poca multicolinealidad.
  • Sin autocorrelación.
  • Homocedasticidad.

Un enfoque mucho más pragmático es hacer una simulación de Monte Carlo. Si ya sabe o está dispuesto a hacer una suposición en torno a la distribución de sus variables de entrada, tome una gran cantidad de muestra y aliméntela a LSTM, ahora puede calcular empíricamente su "intervalo de confianza".

Louis T
fuente
1

Sí tu puedes. Lo único que necesita cambiar es la función de pérdida. Implemente la función de pérdida utilizada en la regresión cuantil e intégrela. Además, desea ver cómo evalúa esos intervalos. Para eso, usaría las métricas ICP, MIL y RMIL.

Iñigo
fuente