Keras에서 다른 길이의 예제를 사용하여 RNN 교육


60

RNN에 대해 배우려고 노력 중이며 Keras를 사용하고 있습니다. 바닐라 RNN 및 LSTM 레이어의 기본 전제를 ​​이해하고 있지만 교육을위한 특정 기술 요점을 이해하는 데 어려움을 겪고 있습니다.

에서 keras 문서 , 그것은 RNN 층에 입력이 모양이 있어야합니다 말한다 (batch_size, timesteps, input_dim). 이것은 모든 훈련 예제가 고정 된 시퀀스 길이, 즉timesteps .

그러나 이것은 특별한 것이 아닙니다. 그렇지 않습니까? RNN이 다양한 길이의 문장에서 작동하도록 할 수 있습니다. 내가 어떤 말뭉치에 대해 훈련시킬 때, 나는 길이가 다른 모든 문장들을 배치 할 것입니다.

분명히해야 할 일은 훈련 세트에서 시퀀스의 최대 길이를 찾아서 제로 패딩하는 것입니다. 그렇다면 테스트 시간에 입력 길이가 그보다 큰 예측을 할 수 없다는 것을 의미합니까?

이것은 Keras의 특정 구현에 대한 질문이지만, 일반적으로 이런 종류의 문제에 직면했을 때 사람들이 일반적으로하는 일을 묻습니다.


@kbrose가 정확합니다. 그러나 한 가지 우려가 있습니다. 이 예에서는 무한한 수율을 가진 매우 특별한 생성기가 있습니다. 더 중요한 것은 1000 크기의 배치를 생성하도록 설계되었습니다. 실제로 불가능하지는 않지만 만족 시키기에는 너무 어렵습니다. 동일한 길이의 항목이 함께 정렬되도록 항목을 다시 구성해야하며 배치 분할 위치를 신중하게 설정해야합니다. 또한 배치 전체에서 셔플을 만들 기회가 없습니다. 내 의견은 : 당신이 무엇을하는지 정확히 알지 않는 한 Keras에서 가변 길이 입력을 사용하지 마십시오. 패딩을 사용하고 Masking레이어를 무시하도록 설정
Bs He

답변:


56

이 모든 훈련 예, 즉, 고정 된 시퀀스 길이를 가지고 있음을 시사한다 timesteps.

치수가 None가변 길이 일 수 있기 때문에 정확하지 않습니다 . 단일 배치 내 에서 동일한 수의 시간 간격을 가져야합니다 (일반적으로 0 패딩 및 마스킹이 표시되는 위치). 그러나 배치 간에는 그러한 제한이 없습니다. 추론하는 동안 길이를 늘릴 수 있습니다.

임의의 시간 길이의 훈련 데이터를 생성하는 예제 코드.

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를 0으로 계속 전달하기 때문에 숨겨진 상태와 메모리 셀에 영향을 미칩니다. 사실이면 아무것도 전달되지 않아야합니다. normal에서는 매개 변수를 fit()전달하여 sequence_lenth제외 할 시퀀스의 길이를 지정할 수 있습니다. 생성기 접근 방식으로 0 시퀀스를 무시할 수없는 것 같습니다.
GRS

1
@GRS 생성기는의 3 튜플을 반환 (inputs, targets, sample_weights)할 수 있으며 sample_weights0 패드를 0으로 설정할 수 있습니다. 그러나 양방향 RNN에 완벽하게 작동하는지는 확실하지 않습니다.
kbrose

이것은 도움이되었지만 model.predict_generator테스트 세트와 함께 사용하는 예제도 포함되기를 바랍니다 . 발전기로 예측하려고하면 연결에 관한 오류가 발생합니다 (테스트 세트에는 가변 길이 시퀀스가 ​​있음). 내 솔루션은 표준 model.predict을 해키 방식으로 사용하는 것이 었 습니다. 아마도 이것은 새로운 질문에 더 적합할까요?
미키

다른 질문처럼 들리는 @mickey. 이 질문은 예측이 아니라 훈련에 관한 것입니다.
kbrose

의견의 질문이 실제로 새로운 질문으로 질문 된 경우 링크 할 수 있습니까?
Itamar Mushkin

7

@kbrose는 더 나은 솔루션을 가지고있는 것 같습니다

분명히해야 할 일은 훈련 세트에서 시퀀스의 최대 길이를 찾아서 제로 패딩하는 것입니다.

이것은 일반적으로 좋은 해결책입니다. 어쩌면 최대 길이 + 100을 사용해보십시오. 응용 프로그램에 가장 적합한 것을 사용하십시오.

그렇다면 테스트 시간에 입력 길이가 그보다 큰 예측을 할 수 없다는 것을 의미합니까?

반드시 그런 것은 아닙니다. 케 라스에서 고정 길이가 사용되는 이유는 고정 모양의 텐서를 생성하여 성능을 크게 향상시키기 때문입니다. 그러나 그것은 훈련만을위한 것입니다. 훈련 후, 당신은 당신의 작업에 적합한 무게를 배웁니다.

몇 시간 동안 훈련 한 후 모델의 최대 길이가 충분히 크지 않았으며 시간 단계를 변경하고 이전 모델에서 학습 된 가중치를 추출하고 새로운 시간 단계로 새 모델을 작성해야한다고 가정 해 봅시다. 학습 된 분동을 주입합니다.

아마도 다음과 같이 사용하면됩니다 :

new_model.set_weights(old_model.get_weights())

나는 그것을 직접 시도하지 않았다. 사용해 보시고 결과를 여기에 게시하십시오. 다음은 몇 가지 링크입니다. 하나


1
실제로 다양한 길이의 입력을 가질 수 있으므로 같은 핵을 도입 할 필요가 없습니다 max length + 100. 예제 코드는 내 답변을 참조하십시오.
kbrose

1
더 많은 시간 간격으로 모델에 가중치를 전송하면 실제로 완벽하게 작동합니다! 나는 시간 단계 Bidirectional(LSTM)()RepeatVector()계층을 올렸으며 예측은 완벽하게 실행 가능합니다.
komodovaran_

@kbrose 이것은 해킹이 아니며 일반적으로 수행하는 방식입니다. batch_size를 사용하는 것은 너무 느리고 keras는 마스킹 레이어를 활성화하여 마스킹이 손실에 영향을 미치지 않도록합니다.
Ferus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.