Интервал прогнозирования вокруг прогноза временных рядов LSTM

13

Существует ли метод для расчета интервала прогнозирования (распределения вероятностей) вокруг прогноза временного ряда из нейронной сети LSTM (или другой рекуррентной)?

Скажем, например, я прогнозирую 10 выборок в будущем (от t + 1 до t + 10), основываясь на последних 10 наблюдаемых выборках (от t-9 до t), я ожидаю, что прогноз при t + 1 будет больше точнее, чем прогноз при t + 10. Как правило, вокруг прогноза можно нарисовать полосы ошибок, чтобы показать интервал. С моделью ARIMA (в предположении нормально распределенных ошибок) я могу рассчитать интервал прогнозирования (например, 95%) вокруг каждого прогнозируемого значения. Могу ли я рассчитать то же самое (или что-то, что относится к интервалу прогнозирования) из модели LSTM?

Я работаю с LSTM в Keras / Python, следуя множеству примеров из machinelearningmastery.com , на которых основан мой пример кода (ниже). Я рассматриваю возможность переформулировать проблему как классификацию в дискретные ячейки, поскольку это дает уверенность для каждого класса, но это кажется плохим решением.

Есть пара похожих тем (например, ниже), но, кажется, ничто не решает проблему интервалов прогнозирования от нейронных сетей LSTM (или даже других):

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

Прогнозирование временных рядов с использованием ARIMA против 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
источник

Ответы:

9

Непосредственно, это невозможно. Однако, если вы смоделируете это по-другому, вы можете получить доверительные интервалы. Вместо обычной регрессии вы можете использовать ее как оценку непрерывного распределения вероятностей. Делая это для каждого шага, вы можете построить свой дистрибутив. Способы сделать это - сети смешанного ядра ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , раскрытие информации, мой блог) или сети смешивания плотности ( http: //www.cedar). .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ), первый использует ядра в качестве базы и оценивает смесь по этим ядрам, а второй оценивает смесь распределений, включая параметры каждого из распределения. Вы используете логарифмическую вероятность для обучения модели.

Еще один вариант для моделирования неопределенности является использование отсев в процессе обучения, а затем и во время вывода. Вы делаете это несколько раз, и каждый раз, когда вы получаете образец из задней части. Вы не получаете дистрибутивы, только образцы, но это проще всего реализовать и работает очень хорошо.

В вашем случае вы должны думать о том, как вы генерировать т + 2 до Т + 10. В зависимости от вашей текущей настройки вам, возможно, придется сэмплировать с предыдущего временного шага и передать его для следующего. Это не очень хорошо работает с первым подходом, ни со вторым. Если у вас есть 10 выходов за шаг по времени (от t + 1 до t + 10), то все эти подходы более понятны, но немного менее интуитивны.

Ян ван дер Вегт
источник
1
Использование сетей смеси интересно, я буду стараться осуществить это. Существуют некоторые твердые исследования с использованием отсева здесь: arxiv.org/abs/1709.01907 и arxiv.org/abs/1506.02142
4Oh4
Примечание для отсева: вы можете фактически рассчитать дисперсию прогноза отсева из Монте-Карло и использовать его как количественную оценку неопределенности
Чарльз Чоу,
Это верно @CharlesChow, но это плохой способ построить доверительный интервал в этом контексте. Было бы лучше , чтобы отсортировать значения и использовать квантили из - за потенциально очень неравномерное распределение.
Ян ван дер VegT
Согласитесь @JanvanderVegt, но вы все равно можете оценить статистику MC отсева без предположения о распределении выходного, я имею в виду вы можете также использовать процентиль или самонастройки для построения CI ЦА отсева
Чарльз Чоу
2

Конформное прогнозирование как модное слово может быть вам интересно, потому что оно работает во многих условиях - в частности, оно не требует нормальной распределенной ошибки и работает практически для любой модели машинного обучения.

Два хороших введения даны Скоттом Локлином и Хенриком Линуссоном .

Борис З
источник
1

Я собираюсь немного расходиться и утверждать, что расчетный доверительный интервал на практике обычно не является полезной вещью. Причина в том, что всегда нужно делать целый ряд предположений. Даже для самой простой линейной регрессии вам необходимо иметь

  • Линейные отношения.
  • Многомерная нормальность.
  • Нет или мало мультиколлинеарности.
  • Нет автокорреляции.
  • Гомоскедастичность.

Гораздо более прагматичный подход - это симуляция Монте-Карло. Если вы уже знаете или хотите сделать предположение относительно распределения ваших входных переменных, возьмите целую кучу выборок и передайте их вам LSTM, теперь вы можете эмпирически рассчитать свой «доверительный интервал».

Луи Т
источник
1

Да, ты можешь. Единственное, что вам нужно изменить - это функция потерь. Реализуйте функцию потерь, используемую в квантильной регрессии, и интегрируйте ее. Кроме того, вы хотите посмотреть, как вы оцениваете эти интервалы. Для этого я бы использовал метрики ICP, MIL и RMIL.

Иниго
источник