Давайте сосредоточимся на вышеуказанных двух вопросах со ссылкой на следующий код:
Примечание: create_dataset принимает последовательность длины N и возвращает массив N-look_back
каждый из которых является последовательностью длины look_back
.
Как видно, TrainX представляет собой трехмерный массив с Time_steps, а Feature - последние два измерения соответственно (3 и 1 в этом конкретном коде). Что касается изображения ниже, значит ли это, что мы рассматриваем many to one
случай, когда число розовых коробок составляет 3? Или буквально означает, что длина цепи равна 3 (т.е. Рассматривается только 3 зеленых квадрата). ![enter image description here]()
Является ли аргумент признаков актуальным, когда мы рассматриваем многомерные ряды? например, моделирование двух финансовых запасов одновременно?
Поддерживает ли LSTM с точки зрения состояния, что мы сохраняем значения памяти ячейки между сериями партий? Если это так, batch_size
- это один, и память сбрасывается между batch_size
обучения, так что смысл говорить, что он был сдержанным. Я предполагаю, что это связано с тем, что данные обучения не перетасовываются, но я не уверен, как это сделать.
Немного смущенно о комментарии @van о том, что красные и зеленые коробки равны. Итак, просто чтобы подтвердить, соответствуют ли следующие вызовы API развернутым диаграммам? Особенно отметив вторую диаграмму (batch_size
был произвольно выбран.):
![enter image description here]()
Ответ 2
В качестве дополнения к принятому ответу, этот ответ показывает поведение keras и способы достижения каждой картины.
Поведение генерала Кераса
Стандартная внутренняя обработка keras всегда много-много, как показано на следующем рисунке (в качестве примера я использовал features=2
, давление и температура):
![ManyToMany]()
На этом изображении я увеличил количество шагов до 5, чтобы избежать путаницы с другими измерениями.
Для этого примера:
- У нас есть N нефтяных резервуаров
- Мы потратили 5 часов, принимая меры каждый час (временные шаги)
- Мы измерили две особенности:
Наш входной массив должен иметь вид (N,5,2)
:
[ Step1 Step2 Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]
Входы для раздвижных окон
Часто слои LSTM должны обрабатывать все последовательности. Разделительные окна могут быть не лучшей идеей. Слой имеет внутренние состояния о том, как последовательность развивается по мере продвижения вперед. Windows исключает возможность изучения длинных последовательностей, ограничивая все последовательности размером окна.
В окнах каждое окно является частью длинной оригинальной последовательности, но для Keras они будут рассматриваться как независимая последовательность:
[ Step1 Step2 Step3 Step4 Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]
Обратите внимание, что в этом случае у вас изначально есть только одна последовательность, но вы делите ее на несколько последовательностей для создания окон.
Понятие "что такое последовательность" абстрактно. Важными частями являются:
- Вы можете иметь партии со многими отдельными последовательностями
- что делает последовательности последовательностями, так это то, что они развиваются поэтапно (обычно временные шаги)
Достижение каждого случая с "отдельными слоями"
Достижение стандарта много ко многим:
![StandardManyToMany]()
Вы можете достичь многого с помощью простого слоя LSTM, используя return_sequences=True
:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
Достижение многих к одному:
Используя точно такой же слой, keras будет выполнять ту же самую внутреннюю предварительную обработку, но когда вы используете return_sequences=False
(или просто игнорируете этот аргумент), keras автоматически отбрасывает шаги, предшествующие последнему:
![ManyToOne]()
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
Достижение один ко многим
Теперь это не поддерживается только слоями keras LSTM. Вам нужно будет создать свою собственную стратегию, чтобы умножить шаги. Есть два хороших подхода:
- Создайте постоянный многошаговый ввод, повторяя тензор
- Используйте
stateful=True
чтобы периодически принимать выходные данные одного шага и использовать их в качестве входных данных следующего шага (требуется output_features == input_features
)
Один ко многим с повторным вектором
Чтобы соответствовать стандартному поведению keras, нам нужно вводить шаги поэтапно, поэтому мы просто повторяем вводы для желаемой длины:
![OneToManyRepeat]()
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
Понимание состояния = True
Теперь приходит одно из возможных применений stateful=True
(кроме того, что нужно избегать загрузки данных, которые не могут сразу вместить память вашего компьютера)
Stateful позволяет вводить "части" последовательностей поэтапно. Разница в том, что:
- В
stateful=False
вторая партия содержит совершенно новые последовательности, независимые от первой партии - В
stateful=True
, второй пакет продолжает первый пакет, расширяя те же последовательности.
Это как разделение последовательностей в окнах, с этими двумя основными отличиями:
- эти окна не накладываются !!
-
stateful=True
увидит, что эти окна связаны как одна длинная последовательность
В stateful=True
каждый новый пакет будет интерпретироваться как продолжение предыдущего пакета (до тех пор, пока вы не model.reset_states()
).
- Последовательность 1 в партии 2 продолжит последовательность 1 в партии 1.
- Последовательность 2 в партии 2 продолжит последовательность 2 в партии 1.
- Последовательность n в партии 2 продолжит последовательность n в партии 1.
Пример входов, партия 1 содержит шаги 1 и 2, партия 2 содержит шаги с 3 по 5:
BATCH 1 BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]
Обратите внимание на выравнивание резервуаров в партии 1 и партии 2! Вот почему нам нужно shuffle=False
(если, конечно, мы не используем только одну последовательность).
Вы можете иметь любое количество партий, на неопределенный срок. (Для того чтобы иметь переменную длину в каждом пакете, используйте input_shape=(None,features)
.
Один ко многим с сохранением состояния = True
Для нашего случая здесь мы будем использовать только 1 шаг на пакет, потому что мы хотим получить один выходной шаг и сделать его входным.
Обратите внимание, что поведение на картинке не "вызвано" stateful=True
. Мы приведем это в действие в ручной цикл ниже. В этом примере stateful=True
- это то, что "позволяет" нам остановить последовательность, манипулировать тем, что мы хотим, и продолжить с того места, где мы остановились.
![OneToManyStateful]()
Честно говоря, повторный подход, вероятно, является лучшим выбором для этого случая. Но так как мы рассматриваем stateful=True
, это хороший пример. Лучший способ использовать это - следующий случай "многие ко многим".
Слой:
outputs = LSTM(units=features,
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Теперь нам понадобится ручной цикл для предсказаний:
input_data = someDataWithShape((batch, 1, features))
#important, we're starting new sequences, not continuing old ones:
model.reset_states()
output_sequence = []
last_step = input_data
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
Многие ко многим с Stateful = True
Теперь, здесь, мы получаем очень хорошее приложение: учитывая входную последовательность, попытайтесь предсказать ее будущие неизвестные шаги.
Мы используем тот же метод, что и в примере "один ко многим", с той разницей, что:
- мы будем использовать саму последовательность, чтобы быть целевыми данными, на шаг впереди
- мы знаем часть последовательности (поэтому мы отбрасываем эту часть результатов).
![ManyToManyStateful]()
Слой (такой же, как выше):
outputs = LSTM(units=features,
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Повышение квалификации:
Мы собираемся обучить нашу модель прогнозированию следующего шага последовательностей:
totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)
X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X
#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)
Предсказание:
Первый этап нашего прогнозирования включает в себя "регулирование состояний". Вот почему мы собираемся снова предсказать всю последовательность, даже если мы уже знаем эту часть:
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step
Теперь перейдем к циклу, как в случае один ко многим. Но не сбрасывайте состояния здесь! , Мы хотим, чтобы модель знала, в каком шаге последовательности она находится (и она знает это на первом новом шаге из-за предсказания, которое мы только что сделали)
output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
Этот подход был использован в этих ответах и файле:
Достижение сложных конфигураций
Во всех приведенных выше примерах я показал поведение "одного слоя".
Конечно, вы можете размещать много слоев друг над другом, не обязательно все по одной схеме, и создавать свои собственные модели.
Один интересный пример, который появился, - это "автоматический кодер", который имеет кодер "многие к одному", за которым следует декодер "один ко многим":
Кодер:
inputs = Input((steps,features))
#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)
#many to one layer:
outputs = LSTM(hidden3)(outputs)
encoder = Model(inputs,outputs)
декодер:
Использование метода "повторить";
inputs = Input((hidden3,))
#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)
#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)
#last layer
outputs = LSTM(features,return_sequences=True)(outputs)
decoder = Model(inputs,outputs)
автоассоциатор:
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
Тренируйся с fit(X,X)
Дополнительные объяснения
Если вам нужны подробности о том, как рассчитываются шаги в LSTM, или подробности о приведенных выше stateful=True
, вы можете прочитать больше в этом ответе: Сомнения относительно "Понимания LSTM Keras"