Навчання RNN з прикладами різної тривалості в Керасі


61

Я намагаюся почати вивчати RNN, і я використовую Keras. Я розумію основні передумови шарів ванільного RNN та LSTM, але у мене виникають проблеми з розумінням певного технічного моменту для тренувань.

У документації про керас сказано, що вхід до шару RNN повинен мати форму (batch_size, timesteps, input_dim). Це говорить про те, що всі приклади тренувань мають фіксовану довжину послідовності, а саме timesteps.

Але це не особливо типово, чи не так? Я, можливо, захочу, щоб RNN оперував пропозиціями різної тривалості. Коли я буду тренувати його на якомусь корпусі, я буду його подавати партіями пропозицій, різної довжини.

Думаю, очевидною справою було б знайти максимальну довжину будь-якої послідовності в тренувальному наборі та нульову накладку. Але чи означає це, що я не можу робити прогнози у тестовий час із довжиною введення, що перевищує це?

Я думаю, це питання щодо конкретного впровадження Кераса, але я також запитую, що зазвичай роблять люди, стикаючись із подібними проблемами.


@kbrose правильна. Однак у мене є одна турбота. У прикладі у вас є дуже особливий генератор нескінченних врожаїв. Що ще важливіше, він розроблений для отримання партій розміром 1000. На практиці це занадто важко задовольнити, якщо не неможливо. Вам потрібно переорганізувати свої записи, щоб ті, що мають однакову довжину, були розташовані разом, і вам потрібно ретельно встановити пакетні розділові позиції. Більше того, у вас немає шансів зробити перемішування по партіях. Тому моя думка така: ніколи не використовуйте різну довжину введення в Керасі, якщо ви точно не знаєте, що робите. Використовуйте набивання та встановіть Maskingшар, щоб ігнорувати
Bs He

Відповіді:


57

Це говорить про те, що всі приклади тренувань мають фіксовану довжину послідовності, а саме timesteps.

Це не зовсім правильно, оскільки цей розмір може бути None, тобто змінна довжина. У межах однієї партії ви повинні мати однакову кількість часових кроків (це зазвичай там, де ви бачите 0-padding та маскування). Але між партіями такого обмеження немає. Під час умовиводу ви можете мати будь-яку довжину.

Приклад коду, який створює випадкові партії навчальних даних.

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)

І саме це друкує. Зверніть увагу, форми виводу (None, None, x)вказують змінний розмір партії та розмір змінного часового кроку.

__________________________________________________________________________________________
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

Дякую за це. Однак, якщо ми покладемо 0 послідовностей, це вплине на приховані стани та комірку пам'яті, оскільки ми продовжуємо передавати x_t як 0s, якщо, якщо факт, нічого не повинно пройти. У звичайному випадку fit()ми можемо передавати sequence_lenthпараметр, щоб вказати довжину послідовності, щоб виключити його. Здається, що генераторний підхід не дозволяє ігнорувати 0 послідовностей?
GRS

1
@GRS Ваш генератор може повернути 3-х пакет (inputs, targets, sample_weights), а ви можете встановити sample_weights0-колодки до 0. Однак я не впевнений, що це буде ідеально працювати для двонаправлених RNN.
kbrose

Це було корисно, але я хочу, щоб він також включав приклад використання model.predict_generatorз тестовим набором. Коли я намагаюся передбачити генератор, я отримую помилку щодо конкатенації (тестовий набір також має послідовності змінної довжини). Моє рішення полягало в тому, щоб використовувати стандарт model.predictхакітним способом. Можливо, це було б краще підходити до нового питання?
Міккі

@mickey, це звучить як інше питання. Це питання стосується тренувань, а не прогнозування.
кбросе

Якщо питання в коментарях справді було задано як нове запитання, чи можете ви посилання на нього?
Ітамар Мушкін

7

@kbrose, здається, має краще рішення

Я припускаю, що очевидною справою було б знайти максимальну довжину будь-якої послідовності у навчальному наборі та нульову накладку.

Зазвичай це хороше рішення. Можливо, спробуйте максимальну довжину послідовності + 100. Використовуйте все, що найкраще підходить для вашої програми.

Але чи це означає, що я не можу робити прогнози у тестовий час із довжиною введення, що перевищує це?

Не обов'язково. Причина, що в керах використовується фіксована довжина, полягає в тому, що вона значно покращує продуктивність, створюючи тензори нерухомих форм. Але це лише для тренувань. Після тренування ви навчилися правильних ваг для свого завдання.

Припустимо, після тренувань протягом декількох годин ви розумієте, що максимальна довжина вашої моделі не була достатньо великою / малою, і тепер вам потрібно змінити часові кроки, просто витягніть вивчені ваги зі старої моделі, побудуйте нову модель з новими кроками часу і ввести в нього вивчені ваги.

Ви, ймовірно, можете це зробити, використовуючи щось на кшталт:

new_model.set_weights(old_model.get_weights())

Я сам цього не пробував. Спробуйте, опублікуйте свої результати тут на користь кожному. Ось декілька посилань: один два


1
Ви дійсно можете мати введення різної довжини, не потрібно вводити хакі, як max length + 100. Дивіться мою відповідь, наприклад, код.
кбросе

1
Перенесення ваг на модель з більшою кількістю кроків дійсно працює чудово! Я наткнувся на часові кроки Bidirectional(LSTM)()і RepeatVector()шари, і прогнози цілком реальні.
комодован_

@kbrose Це не хак, це як ви це робите. Використання batch_size одного занадто повільне, і кери дозволяють маскувати шари, щоб маскування не впливало на втрати.
Ферус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.