Kabul edilen cevabın bir tamamlayıcısı olarak, bu cevap keras davranışlarını ve her bir resmin nasıl elde edileceğini gösterir.
Genel Keras davranışı
Standart keras iç işleme her zaman aşağıdaki resimde olduğu gibi çok sayıdadır (kullandığım yerde features=2
, basınç ve sıcaklık, örnek olarak):
Bu görüntüde, diğer boyutlarla karışıklığı önlemek için adım sayısını 5'e çıkardım.
Bu örnek için:
- N petrol tankımız var
- Saat başı önlemler alarak 5 saat geçirdik (zaman adımları)
- İki özelliği ölçtük:
Girdi dizimiz şu şekilde şekillenmelidir (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]],
]
Sürgülü pencereler için girişler
Çoğu zaman, LSTM katmanlarının tüm sekansları işlemesi beklenir. Pencereleri bölmek en iyi fikir olmayabilir. Katman, bir sekansın ileri doğru adım atarken nasıl geliştiği hakkında dahili durumlara sahiptir. Windows, tüm dizileri pencere boyutuyla sınırlandırarak uzun dizileri öğrenme olasılığını ortadan kaldırır.
Pencerelerde, her pencere uzun bir orijinal dizinin parçasıdır, ancak Keras tarafından her biri bağımsız bir dizi olarak görülecektir:
[ 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]],
....
]
Bu durumda, başlangıçta sadece bir dizinin olduğuna dikkat edin, ancak pencereleri oluşturmak için birçok diziye böldüğünüze dikkat edin.
"Dizi nedir" kavramı soyuttur. Önemli parçalar:
- birçok ayrı diziye sahip partileriniz olabilir
- sekansları sekans haline getiren şey, adımlarla evrimleşmeleridir (genellikle zaman adımları)
Her vakayı "tek katmanlar" ile başarmak
Çoktan çoğa standart elde etmek:
Basit bir LSTM katmanıyla aşağıdakileri kullanarak çoktan çoğa ulaşabilirsiniz return_sequences=True
:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
Bire bir başarmak:
Aynı katmanı kullanarak, keras tam olarak aynı dahili önişlemi yapar, ancak kullandığınızda return_sequences=False
(veya sadece bu argümanı yoksayarsanız), keras otomatik olarak sondan önceki adımları atar:
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
Bire çok ulaşmak
Şimdi, bu sadece keras LSTM katmanları tarafından desteklenmemektedir. Adımları çoğaltmak için kendi stratejinizi oluşturmanız gerekir. İki iyi yaklaşım vardır:
- Bir tensörü tekrarlayarak sabit çok adımlı giriş oluşturun
- Bir kullan
stateful=True
tekrarlı bir adım çıktısını almak ve bir sonraki adımın girdi olarak hizmet vermektedir (ihtiyaçlar output_features == input_features
)
Tekrar vektör ile bire çok
Keras standart davranışına uymak için adım adım girdilere ihtiyacımız var, bu yüzden girişleri istediğimiz uzunluk için tekrarlıyoruz:
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
Durum bilgisi = Doğru
Şimdi olası kullanımlarından biri geliyor stateful=True
(aynı anda bilgisayarınızın belleğine sığamayan verileri yüklemekten kaçının)
Stateful, dizilerin "kısımlarını" aşamalar halinde girmemizi sağlar. Fark şu:
- İçinde
stateful=False
, ikinci parti ilk partiden bağımsız olarak tamamen yeni diziler içerir
- Burada
stateful=True
, ikinci parti, aynı dizileri uzatan ilk seriyi sürdürür.
Bu iki ana farkla dizileri pencerelerde bölmek gibi:
- bu pencereler üst üste gelmiyor !!
stateful=True
bu pencerelerin tek bir uzun dizi olarak bağlı olduğunu görecek
İçinde stateful=True
, her yeni toplu iş bir önceki toplu işi devam ettirmek olarak yorumlanacaktır (siz arayana kadar model.reset_states()
).
- Parti 2'deki sekans 1, parti 1'deki sekans 1'e devam edecektir.
- Toplu iş 2'deki sıra 2, toplu iş 1'deki sıra 2'ye devam edecektir.
- Parti 2'deki n dizisi, parti 1'deki n dizisine devam edecektir.
Girişlere örnek olarak, parti 1, adım 1 ve 2'yi içerir, parti 2, 3-5 arası adımları içerir:
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]],
] ]
Parti 1 ve parti 2'deki tankların hizalamasına dikkat edin! Bu yüzden ihtiyacımız var shuffle=False
(elbette sadece bir sıra kullanmıyorsak).
Süresiz olarak istediğiniz sayıda partiye sahip olabilirsiniz. (Her partide değişken uzunluklara sahip olmak için kullanın input_shape=(None,features)
.
Durum bilgisi olan bire çok = Doğru
Buradaki durumumuz için, parti başına sadece 1 adım kullanacağız, çünkü bir çıkış adımı almak ve bir girdi yapmak istiyoruz.
Resimdeki davranışın "neden olduğu" olmadığını lütfen unutmayın stateful=True
. Bu davranışı aşağıdaki manuel döngüde zorlayacağız. Bu örnekte, stateful=True
diziyi durdurmamıza, istediğimizi değiştirmemize ve durduğumuz yerden devam etmemize "izin veren" şey budur.
Dürüst olmak gerekirse, tekrar yaklaşımı muhtemelen bu dava için daha iyi bir seçimdir. Ama araştırdığımız için stateful=True
bu iyi bir örnek. Bunu kullanmanın en iyi yolu bir sonraki "çoktan çoğa" vakasıdır.
Katman:
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)
Şimdi, tahminler için manuel bir döngüye ihtiyacımız olacak:
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()
Durum bilgisi olan birçok kişiye = Doğru
Şimdi, burada çok güzel bir uygulama elde ediyoruz: bir giriş sırası verildiğinde, gelecekteki bilinmeyen adımlarını tahmin etmeye çalışın.
Yukarıdaki "bire çok" ile aynı yöntemi kullanıyoruz, fark şu:
- dizinin kendisini hedef veri olarak kullanacağız, bir adım önde
- dizinin bir kısmını biliyoruz (sonuçların bu kısmını atarız).
Katman (yukarıdaki ile aynı):
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)
Eğitim:
Dizilerimizin bir sonraki adımını tahmin etmek için modelimizi eğiteceğiz:
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)
tahmin:
Tahminimizin ilk aşaması "devletleri ayarlamayı" içerir. Bu yüzden, bu parçayı zaten biliyor olsak bile, tüm diziyi tekrar tahmin edeceğiz:
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
Şimdi bire çok durumda olduğu gibi döngüye gidiyoruz. Ancak durumları burada sıfırlamayın! . Modelin, dizinin hangi adımı olduğunu bilmesini istiyoruz (ve yukarıda yeni yaptığımız tahmin nedeniyle ilk yeni adımda olduğunu biliyor)
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()
Bu yaklaşım şu cevaplarda ve dosyada kullanılmıştır:
Karmaşık konfigürasyonlar elde etme
Yukarıdaki tüm örneklerde "bir katmanın" davranışını gösterdim.
Tabii ki, aynı katmanı takip etmek zorunda kalmadan, birçok katmanı üst üste istifleyebilir ve kendi modellerinizi oluşturabilirsiniz.
Ortaya çıkan ilginç bir örnek, "çoktan bire enkoderi" ve ardından "birden çoka" kod çözücüsü olan "otomatik kodlayıcı" dır:
Encoder:
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)
dekoder:
"Tekrar" yöntemini kullanarak;
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)
Autoencoder:
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
İle eğitin fit(X,X)
Ek açıklamalar
LSTM'lerde adımların nasıl hesaplandığı veya stateful=True
yukarıdaki durumlarla ilgili ayrıntılar istiyorsanız, bu yanıtta daha fazla bilgi bulabilirsiniz: `Keras LSTM'leri Anlama` ile ilgili şüpheler