Bir RNN'nin Keras'ta farklı uzunluktaki örneklerle eğitimi


60

RNN'ler hakkında bilgi almaya başladım ve Keras kullanıyorum. Vanilya RNN ve LSTM katmanlarının temel öncülünü anlıyorum, ancak eğitim için belirli bir teknik noktayı anlamakta güçlük çekiyorum.

Gelen keras belgeler , bir RYSA katmanına girdi şekline sahip olmalıdır diyor (batch_size, timesteps, input_dim). Bu, tüm eğitim örneklerinin sabit bir sekans uzunluğuna sahip olduğunu, yani timesteps.

Ama bu özellikle tipik değil, değil mi? RNN'nin farklı uzunluklardaki cezalar üzerinde işlemesini isteyebilirim. Bir korpus üzerinde eğittiğimde, farklı uzunluklardaki tüm cümle gruplarını besleyeceğim.

Sanırım yapılacak açık bir şey, antrenman setindeki herhangi bir dizinin maksimum uzunluğunu bulmak ve onu sıfırlamak olacaktır. Ancak bu, test süresi boyunca giriş uzunluğu bundan daha büyük olan tahminler yapamayacağım anlamına mı geliyor?

Bu Keras'ın özel uygulamasıyla ilgili bir soru, sanırım, ama genel olarak bu tür bir sorunla karşılaştığında insanların tipik olarak ne yaptığını da soruyorum.


@kbrose doğru. Ancak bir endişem var. Örnekte çok özel bir sonsuz verim üreteciniz var. Daha da önemlisi, 1000 büyüklüğünde partilerin üretilmesi için tasarlanmıştır. Uygulamada, imkansız değilse bile bu durumu karşılamak çok zordur. Girdilerinizi, aynı uzunluktakiler bir arada olacak şekilde yeniden düzenlemelisiniz ve toplu bölme konumlarını dikkatlice ayarlamanız gerekir. Dahası, gruplar arasında karıştırılma şansınız yoktur. Yani bence: Ne yaptığınızı tam olarak bilmiyorsanız, Keras'ta asla değişken uzunluktaki bir girdi kullanmayın. MaskingYok saymak için dolguyu kullanın ve katmanı ayarlayın
Bs He

Yanıtlar:


56

Bu, tüm eğitim örneklerinin sabit bir sekans uzunluğuna sahip olduğunu, yani timesteps.

Bu tam olarak doğru değil, çünkü o boyut olabilir None, yani değişken uzunluk. Tek bir toplu iş içinde , aynı sayıda zaman aşımına sahip olmanız gerekir (bu genellikle 0 doldurma ve maskeleme gördüğünüz yerdir). Ancak partiler arasında böyle bir kısıtlama yoktur. Çıkarım sırasında herhangi bir uzunlukta olabilir.

Zaman aralıklarında eğitim verisi için rastgele gruplar oluşturan örnek kod.

from keras.models import Sequential
from keras.layers import LSTM, Dense, TimeDistributed
from keras.utils import to_categorical
import numpy as np

model = Sequential()

model.add(LSTM(32, return_sequences=True, input_shape=(None, 5)))
model.add(LSTM(8, return_sequences=True))
model.add(TimeDistributed(Dense(2, activation='sigmoid')))

print(model.summary(90))

model.compile(loss='categorical_crossentropy',
              optimizer='adam')

def train_generator():
    while True:
        sequence_length = np.random.randint(10, 100)
        x_train = np.random.random((1000, sequence_length, 5))
        # y_train will depend on past 5 timesteps of x
        y_train = x_train[:, :, 0]
        for i in range(1, 5):
            y_train[:, i:] += x_train[:, :-i, i]
        y_train = to_categorical(y_train > 2.5)
        yield x_train, y_train

model.fit_generator(train_generator(), steps_per_epoch=30, epochs=10, verbose=1)

Ve bu yazdırdığı şey. Çıkış şekillerinin (None, None, x)değişken parti boyutunu ve değişken timestep boyutunu gösterdiğini unutmayın.

__________________________________________________________________________________________
Layer (type)                            Output Shape                        Param #
==========================================================================================
lstm_1 (LSTM)                           (None, None, 32)                    4864
__________________________________________________________________________________________
lstm_2 (LSTM)                           (None, None, 8)                     1312
__________________________________________________________________________________________
time_distributed_1 (TimeDistributed)    (None, None, 2)                     18
==========================================================================================
Total params: 6,194
Trainable params: 6,194
Non-trainable params: 0
__________________________________________________________________________________________
Epoch 1/10
30/30 [==============================] - 6s 201ms/step - loss: 0.6913
Epoch 2/10
30/30 [==============================] - 4s 137ms/step - loss: 0.6738
...
Epoch 9/10
30/30 [==============================] - 4s 136ms/step - loss: 0.1643
Epoch 10/10
30/30 [==============================] - 4s 142ms/step - loss: 0.1441

Bunun için teşekkür ederim. Bununla birlikte, dizileri 0 olarak değiştirirsek, gizli durumları ve bellek hücresini etkileyecektir, çünkü x_t'yi 0s olarak geçmeye devam ediyoruz, eğer gerçekte, hiçbir şey geçilmemelidir. Normalde fit(), sequence_lenthhariç tutulacak dizinin uzunluğunu belirlemek için parametreyi geçebiliriz . Jeneratör yaklaşımının 0 sekansı görmezden gelmesine izin vermiyor gibi görünüyor
GRS

1
@GRS Jeneratörünüz 3 tuple dönebilir (inputs, targets, sample_weights)ve sample_weights0-pad'lerinizi 0 olarak ayarlayabilirsiniz . Ancak bunun Çift Yönlü RNN'ler için mükemmel çalışacağından emin değilim.
kbrose

Bu yardımcı oldu, ancak keşke model.predict_generatorbir test setiyle kullanmanın da bir örneğini içermesini diliyorum . Bir jeneratör ile tahmin etmeye çalıştığımda bitiştirmeyle ilgili bir hata alıyorum (test setinde değişken uzunluk dizileri de var). Benim çözümüm, standardı model.predictengebeli bir şekilde kullanmaktı. Belki de bu sadece yeni bir soru için daha uygun olur mu?
Mickey

@mickey, farklı bir soru gibi geliyor. Bu soru, eğitim değil, öngörmeyle ilgilidir.
Ocak'ta kbrose

Yorumlardaki soru gerçekten yeni bir soru olarak istendiyse, ona bağlayabilir misiniz?
Itamar Mushkin

7

@kbrose daha iyi bir çözüme sahip görünüyor

Sanırım yapılacak açık bir şey, antrenman setindeki herhangi bir dizinin maksimum uzunluğunu bulmak ve onu sıfırlamak olacaktır.

Bu genellikle iyi bir çözümdür. Belki maksimum dizi uzunluğu + 100'ü deneyin. Uygulamanız için en iyi olanı kullanın.

Ancak bu, test süresi boyunca giriş uzunluğu bundan daha büyük olan tahminler yapamayacağım anlamına mı geliyor?

Şart değil. Sabit bir uzunluğun keraslarda kullanılmasının nedeni, sabit şekillerin tensörlerini oluşturarak performansı büyük ölçüde geliştirmesidir. Ama bu sadece eğitim için. Eğitimden sonra, göreviniz için doğru ağırlıkları öğrenmiş olacaksınız.

Saatlerce egzersiz yaptıktan sonra modelinizin maksimum uzunluğunun yeterince büyük / küçük olmadığını fark edersiniz ve şimdi zaman adımlarını değiştirmeniz gerekir, sadece eski modelden öğrenilen ağırlıkları çıkarın, yeni zaman adımlarıyla yeni bir model oluşturun ve öğrenilen ağırlıkları buna enjekte edin.

Muhtemelen böyle bir şey kullanarak bunu yapabilirsiniz:

new_model.set_weights(old_model.get_weights())

Kendim denemedim. Lütfen deneyin ve sonuçlarınızı herkesin yararı için buraya gönderin İşte bazı bağlantılar: bir iki


1
Gerçekten de değişken uzunluktaki girişlere sahip olabilirsiniz max length + 100; Örnek kod için cevabımı gör.
kbrose

1
Ağırlıkları daha fazla timestepsli bir modele aktarmak gerçekten de işe yarar! Timesteps Bidirectional(LSTM)()ve RepeatVector()katmanlar için çarptım ve tahminler tamamen uygun.
komodovaran_

@kbrose Bu bir kesmek değil, normalde nasıl yaptığınızdır. Bir toplu iş boyutu kullanmak çok yavaştır ve keranlar maskeleme katmanlarını etkinleştirir, böylece maskeleme kaybı etkilemez.
Ferus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.