Если я правильно понял, у вас есть серии m
последовательностей, каждая длиной 7, элементы которых являются трехмерными векторами (поэтому пакет имеет форму (m*7*3)
).
В любом Keras RNN вы можете установить
return_sequences
указывает на True
, чтобы стать промежуточными состояниями, т. Е. Для каждого пакета вместо окончательного прогноза вы получите соответствующие 7 выходных данных, где выход i
представляет прогноз на этапе i
для всех входных данных. от 0 до i
.
Но вы получите все сразу в конце. Насколько я знаю, Keras не предоставляет прямой интерфейс для получения пропускной способности во время обработки пакета . Это может быть еще более ограничено, если вы используете любой из CUDNN
-оптимизированных вариантов. Что вы можете сделать, так это, в основном, считать вашу партию 7 последовательными партиями формы (m*1*3)
и постепенно передавать их в LSTM , записывая скрытое состояние и прогноз на каждом шаге. Для этого вы можете либо установить return_state
на True
и сделать это вручную, либо вы можете просто установить stateful
на True
и позволить объекту отслеживать его.
Следующий пример Python2 + Keras должен точно представлять, что вы хотите. В частности:
- , позволяющий сохранить все промежуточное состояние LSTM на постоянной основе
- во время ожидания следующего образца
- и прогнозирование для модели, обученной для определенного размера партии, который может быть произвольным и неизвестным.
Для этого он включает в себя пример stateful=True
для простоты обучения и return_state=True
для наиболее точного вывода, так что вы получите представление об обоих подходах. Это также предполагает, что вы получаете модель, которая была сериализована и о которой вы мало что знаете. Структура тесно связана с тем, что есть в курсе Эндрю Нг, который определенно более авторитетен, чем я в этой теме. Поскольку вы не указываете, как обучалась модель, я предполагал настройку обучения «многие к одному», но ее можно легко адаптировать.
from __future__ import print_function
from keras.layers import Input, LSTM, Dense
from keras.models import Model, load_model
from keras.optimizers import Adam
import numpy as np
# globals
SEQ_LEN = 7
HID_DIMS = 32
OUTPUT_DIMS = 3 # outputs are assumed to be scalars
##############################################################################
# define the model to be trained on a fixed batch size:
# assume many-to-one training setup (otherwise set return_sequences=True)
TRAIN_BATCH_SIZE = 20
x_in = Input(batch_shape=[TRAIN_BATCH_SIZE, SEQ_LEN, 3])
lstm = LSTM(HID_DIMS, activation="tanh", return_sequences=False, stateful=True)
dense = Dense(OUTPUT_DIMS, activation='linear')
m_train = Model(inputs=x_in, outputs=dense(lstm(x_in)))
m_train.summary()
# a dummy batch of training data of shape (TRAIN_BATCH_SIZE, SEQ_LEN, 3), with targets of shape (TRAIN_BATCH_SIZE, 3):
batch123 = np.repeat([[1, 2, 3]], SEQ_LEN, axis=0).reshape(1, SEQ_LEN, 3).repeat(TRAIN_BATCH_SIZE, axis=0)
targets = np.repeat([[123,234,345]], TRAIN_BATCH_SIZE, axis=0) # dummy [[1,2,3],,,]-> [123,234,345] mapping to be learned
# train the model on a fixed batch size and save it
print(">> INFERECE BEFORE TRAINING MODEL:", m_train.predict(batch123, batch_size=TRAIN_BATCH_SIZE, verbose=0))
m_train.compile(optimizer=Adam(lr=0.5), loss='mean_squared_error', metrics=['mae'])
m_train.fit(batch123, targets, epochs=100, batch_size=TRAIN_BATCH_SIZE)
m_train.save("trained_lstm.h5")
print(">> INFERECE AFTER TRAINING MODEL:", m_train.predict(batch123, batch_size=TRAIN_BATCH_SIZE, verbose=0))
##############################################################################
# Now, although we aren't training anymore, we want to do step-wise predictions
# that do alter the inner state of the model, and keep track of that.
m_trained = load_model("trained_lstm.h5")
print(">> INFERECE AFTER RELOADING TRAINED MODEL:", m_trained.predict(batch123, batch_size=TRAIN_BATCH_SIZE, verbose=0))
# now define an analogous model that allows a flexible batch size for inference:
x_in = Input(shape=[SEQ_LEN, 3])
h_in = Input(shape=[HID_DIMS])
c_in = Input(shape=[HID_DIMS])
pred_lstm = LSTM(HID_DIMS, activation="tanh", return_sequences=False, return_state=True, name="lstm_infer")
h, cc, c = pred_lstm(x_in, initial_state=[h_in, c_in])
prediction = Dense(OUTPUT_DIMS, activation='linear', name="dense_infer")(h)
m_inference = Model(inputs=[x_in, h_in, c_in], outputs=[prediction, h,cc,c])
# Let's confirm that this model is able to load the trained parameters:
# first, check that the performance from scratch is not good:
print(">> INFERENCE BEFORE SWAPPING MODEL:")
predictions, hs, zs, cs = m_inference.predict([batch123,
np.zeros((TRAIN_BATCH_SIZE, HID_DIMS)),
np.zeros((TRAIN_BATCH_SIZE, HID_DIMS))],
batch_size=1)
print(predictions)
# import state from the trained model state and check that it works:
print(">> INFERENCE AFTER SWAPPING MODEL:")
for layer in m_trained.layers:
if "lstm" in layer.name:
m_inference.get_layer("lstm_infer").set_weights(layer.get_weights())
elif "dense" in layer.name:
m_inference.get_layer("dense_infer").set_weights(layer.get_weights())
predictions, _, _, _ = m_inference.predict([batch123,
np.zeros((TRAIN_BATCH_SIZE, HID_DIMS)),
np.zeros((TRAIN_BATCH_SIZE, HID_DIMS))],
batch_size=1)
print(predictions)
# finally perform granular predictions while keeping the recurrent activations. Starting the sequence with zeros is a common practice, but depending on how you trained, you might have an <END_OF_SEQUENCE> character that you might want to propagate instead:
h, c = np.zeros((TRAIN_BATCH_SIZE, HID_DIMS)), np.zeros((TRAIN_BATCH_SIZE, HID_DIMS))
for i in range(len(batch123)):
# about output shape: https://keras.io/layers/recurrent/#rnn
# h,z,c hold the network's throughput: h is the proper LSTM output, c is the accumulator and cc is (probably) the candidate
current_input = batch123[i:i+1] # the length of this feed is arbitrary, doesn't have to be 1
pred, h, cc, c = m_inference.predict([current_input, h, c])
print("input:", current_input)
print("output:", pred)
print(h.shape, cc.shape, c.shape)
raw_input("do something with your prediction and hidden state and press any key to continue")
Дополнительная информация:
Поскольку у нас есть две формы сохранения состояния:
1. Сохраненные / обученные параметры модели, которые одинаковы для каждой последовательности
2. a
, c
состояния, которые развиваются по всей последовательности и могут быть «перезапущены»
Интересно взглянуть на внутренности объекта LSTM. В приведенном мною примере Python веса a
и c
обрабатываются явно, а обученные параметры - нет, и может быть не очевидно, как они реализованы внутри или что они означают. Их можно проверить следующим образом:
for w in lstm.weights:
print(w.name, w.shape)
В нашем случае (32 скрытых состояния) возвращает следующее:
lstm_1/kernel:0 (3, 128)
lstm_1/recurrent_kernel:0 (32, 128)
lstm_1/bias:0 (128,)
Мы наблюдаем размерность 128. Почему это? эта ссылка описывает реализацию Keras LSTM следующим образом:
g - рекуррентная активация, p - активация, Ws - ядра, Us - рекуррентные ядра, h - скрытая переменная, которая также является выходной, а запись * - это поэлементное умножение.
Что объясняет, что 128=32*4
является параметрами для аффинного преобразования, происходящего внутри каждого из 4 шлюзов, сцепленных:
- Матрица формы
(3, 128)
(с именем kernel
) обрабатывает ввод для данного элемента последовательности
- Матрица формы
(32, 128)
(с именем recurrent_kernel
) обрабатывает ввод для последнего текущего состояния h
.
- Вектор формы
(128,)
(названный bias
), как обычно в любой другой настройке NN.