Як доповнення до прийнятої відповіді, ця відповідь показує поведінку кераса та способи досягнення кожної картини.
Загальна поведінка Кераса
Стандартна внутрішня обробка керас - це завжди багато-багато, як на наступному малюнку (де я використовувався features=2
, тиск і температура, як приклад):
У цьому зображенні я збільшив кількість кроків до 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 виключає можливість вивчення довгих послідовностей, обмежуючи всі послідовності розміром вікна.
У вікнах кожне вікно є частиною тривалої оригінальної послідовності, але Керас їх бачить як незалежну послідовність:
[ 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]],
....
]
Зауважте, що в цьому випадку ви спочатку маєте лише одну послідовність, але ви ділите її на багато послідовностей, щоб створити вікна.
Поняття "що таке послідовність" є абстрактним. Важливі частини:
- Ви можете мати партії з безліччю окремих послідовностей
- що робить послідовності послідовностями, це те, що вони розвиваються поетапно (як правило, часові кроки)
Досягнення кожного випадку за допомогою "окремих шарів"
Досягнення стандартів багато-багато:
Ви можете досягти багатьох до багатьох за допомогою простого шару LSTM, використовуючи return_sequences=True
:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
Досягнення багатьох до одного:
Використовуючи той самий шар, керас виконає таку ж внутрішню попередню обробку, але коли ви будете використовувати return_sequences=False
(або просто ігнорувати цей аргумент), керас автоматично відкидає етапи, попередні до останнього:
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
Досягнення одного до багатьох
Тепер це не підтримується лише шарами LSTM keras. Вам потрібно буде створити власну стратегію для множення кроків. Є два хороших підходи:
- Створіть постійний багатоступінчастий вхід, повторивши тензор
- Використовуйте a,
stateful=True
щоб періодично брати результат одного кроку і слугувати ним як вхід наступного кроку (потреби output_features == input_features
)
Один до багатьох з повторним вектором
Для того, щоб підходити до стандартної поведінки кераса, нам потрібні введення поетапно, тому ми просто повторюємо входи на потрібну нам довжину:
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
Розуміння наголошений = Правда
Зараз з'являється одне з можливих застосувань 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
є те, що "дозволяє" нам зупинити послідовність, маніпулювати тим, що ми хочемо, і продовжувати туди, де ми зупинилися.
Чесно кажучи, повторний підхід, мабуть, кращий вибір для цієї справи. Але оскільки ми розглядаємо 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()
Багато до багатьох із заявою = Істинно
Тепер ми отримуємо дуже приємне додаток: задавши послідовність введення, спробуйте передбачити її майбутні невідомі кроки.
Ми використовуємо той самий метод, що і в "один до багатьох" вище, з тією різницею, що:
- ми будемо використовувати саму послідовність, щоб бути цільовими даними, на крок попереду
- ми знаємо частину послідовності (тому ми відкидаємо цю частину результатів).
Шар (такий же, як і вище):
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
випадки, описані вище, ви можете прочитати більше у цій відповіді: Сумніви щодо "Розуміння Керса LSTMs"