Melatih RNN dengan contoh dengan panjang berbeda di Keras

63

Saya mencoba untuk mulai belajar tentang RNNs dan saya menggunakan Keras. Saya memahami premis dasar lapisan vanilla RNN dan LSTM, tetapi saya mengalami kesulitan memahami poin teknis tertentu untuk pelatihan.

Dalam dokumentasi keras , dikatakan input ke layer RNN harus berbentuk (batch_size, timesteps, input_dim). Ini menunjukkan bahwa semua contoh pelatihan memiliki panjang urutan tetap, yaitu timesteps.

Tapi ini tidak terlalu khas, bukan? Saya mungkin ingin agar RNN beroperasi pada kalimat dengan panjang yang berbeda-beda. Ketika saya melatihnya pada beberapa corpus, saya akan memberinya banyak kalimat, semua panjangnya berbeda.

Saya kira hal yang jelas harus dilakukan adalah menemukan panjang maksimal urutan apa pun dalam set pelatihan dan nol pad. Tetapi apakah itu berarti saya tidak dapat membuat prediksi pada waktu pengujian dengan panjang input lebih besar dari itu?

Ini adalah pertanyaan tentang implementasi khusus Keras, saya kira, tapi saya juga menanyakan apa yang biasanya dilakukan orang ketika menghadapi masalah seperti ini secara umum.

Taktik
sumber
@ KBrose benar. Namun, saya punya satu keprihatinan. Dalam contoh ini, Anda memiliki generator yang sangat istimewa untuk hasil tanpa batas. Lebih penting lagi, ini dirancang untuk menghasilkan batch ukuran 1000. Dalam praktiknya, ini terlalu sulit untuk dipenuhi, jika bukan tidak mungkin. Anda perlu mengatur kembali entri Anda sehingga entri dengan panjang yang sama disusun bersama, dan Anda perlu mengatur posisi split batch dengan hati-hati. Selain itu, Anda tidak memiliki kesempatan untuk membuat shuffle di seluruh batch. Jadi pendapat saya adalah: jangan pernah menggunakan input panjang yang bervariasi di Keras kecuali Anda tahu persis apa yang Anda lakukan. Gunakan padding dan atur Maskinglayer ke ignor
Bs He

Jawaban:

59

Ini menunjukkan bahwa semua contoh pelatihan memiliki panjang urutan tetap, yaitu timesteps.

Itu tidak sepenuhnya benar, karena dimensi itu bisa None, yaitu panjang variabel. Dalam satu batch , Anda harus memiliki jumlah timesteps yang sama (ini biasanya Anda melihat 0-padding dan masking). Tapi di antara batch tidak ada batasan seperti itu. Selama inferensi, Anda dapat memiliki panjang apa pun.

Kode contoh yang membuat batch acak dari data pelatihan.

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)

Dan inilah yang dicetaknya. Perhatikan bentuk output (None, None, x)menunjukkan ukuran batch variabel dan ukuran cap waktu variabel.

__________________________________________________________________________________________
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
kbrose
sumber
Terima kasih untuk ini. Namun, jika kita menambahkan urutannya, itu akan mempengaruhi status tersembunyi dan sel memori karena kita terus meneruskan x_t sebagai 0s, ketika jika faktanya, seharusnya tidak ada yang berlalu. Dalam keadaan normal fit(), kita dapat melewatkan sequence_lenthparameter untuk menentukan panjang urutan untuk mengecualikannya. Tampaknya pendekatan generator tidak memungkinkan mengabaikan 0 urutan?
GRS
1
@ GRS Generator Anda dapat mengembalikan 3-tupel (inputs, targets, sample_weights), dan Anda dapat mengatur sample_weights0-bantalan Anda ke 0. Namun, saya tidak yakin ini akan bekerja dengan baik untuk Bidirectional RNNs.
kbrose
Ini sangat membantu, tetapi saya berharap ini juga akan termasuk contoh penggunaan model.predict_generatordengan set tes. Ketika saya mencoba untuk memprediksi dengan generator saya mendapatkan kesalahan tentang penggabungan (set tes juga memiliki urutan panjang variabel). Solusi saya adalah menggunakan standar model.predictdengan cara hacky. Mungkin ini hanya akan lebih cocok untuk pertanyaan baru?
mickey
@ickey itu terdengar seperti pertanyaan yang berbeda. Pertanyaan ini tentang pelatihan, bukan prediksi.
kbrose
Jika pertanyaan dalam komentar memang ditanyakan sebagai pertanyaan baru, dapatkah Anda menautkannya?
Itamar Mushkin
7

@ KBrose tampaknya memiliki solusi yang lebih baik

Saya kira hal yang jelas harus dilakukan adalah menemukan panjang maksimal urutan apa pun dalam set pelatihan dan nol pad.

Ini biasanya merupakan solusi yang baik. Mungkin coba maks panjang urutan + 100. Gunakan apa pun yang paling cocok untuk aplikasi Anda.

Tetapi apakah itu berarti saya tidak dapat membuat prediksi pada waktu pengujian dengan panjang input lebih besar dari itu?

Belum tentu. Alasan panjang tetap digunakan dalam keras, adalah karena itu sangat meningkatkan kinerja dengan menciptakan tensor bentuk tetap. Tapi itu hanya untuk pelatihan. Setelah pelatihan, Anda akan mempelajari bobot yang tepat untuk tugas Anda.

Mari kita asumsikan, setelah pelatihan selama berjam-jam, Anda menyadari bahwa panjang maks model Anda tidak cukup besar / kecil dan Anda sekarang perlu mengubah langkah-langkah waktu, cukup ekstrak bobot yang dipelajari dari model lama, buat model baru dengan langkah-langkah waktu baru dan menyuntikkan bobot yang dipelajari ke dalamnya.

Anda mungkin dapat melakukan ini menggunakan sesuatu seperti:

new_model.set_weights(old_model.get_weights())

Saya belum mencobanya sendiri. Silakan coba dan kirim hasil Anda di sini untuk keuntungan semua orang. Berikut ini beberapa tautan: satu dua

aneesh joshi
sumber
1
Anda memang dapat memiliki input panjang variabel, tidak perlu memperkenalkan peretasan seperti max length + 100. Lihat jawaban saya sebagai contoh kode.
kbrose
1
Mentransfer bobot ke model dengan timesteps lebih banyak memang bekerja dengan sangat baik! Saya menaiki timesteps untuk Bidirectional(LSTM)()dan RepeatVector()berlapis - lapis, dan prediksi yang sempurna.
komodovaran_
@ KBrose Ini bukan hack, itu adalah bagaimana Anda biasanya melakukannya. Menggunakan batch_size satu terlalu lambat dan keras mengaktifkan lapisan masking sehingga penutupan tidak mempengaruhi kerugian.
Ferus