Huấn luyện một RNN với các ví dụ về độ dài khác nhau trong Keras


61

Tôi đang cố gắng bắt đầu tìm hiểu về RNN và tôi đang sử dụng Keras. Tôi hiểu tiền đề cơ bản của các lớp RNN và LSTM của vani, nhưng tôi gặp khó khăn trong việc hiểu một điểm kỹ thuật nhất định để đào tạo.

Trong tài liệu về máy ảnh , nó cho biết đầu vào của lớp RNN phải có hình dạng (batch_size, timesteps, input_dim). Điều này cho thấy rằng tất cả các ví dụ đào tạo có độ dài trình tự cố định, cụ thể là timesteps.

Nhưng điều này không phải là đặc biệt điển hình, phải không? Tôi có thể muốn RNN hoạt động trên các câu có độ dài khác nhau. Khi tôi huấn luyện nó trên một số kho văn bản, tôi sẽ cho nó ăn hàng loạt câu, tất cả các độ dài khác nhau.

Tôi cho rằng điều rõ ràng cần làm là tìm độ dài tối đa của bất kỳ chuỗi nào trong tập huấn luyện và không đệm nó. Nhưng điều đó có nghĩa là tôi không thể đưa ra dự đoán tại thời điểm thử nghiệm với độ dài đầu vào lớn hơn thế?

Đây là một câu hỏi về việc triển khai cụ thể của Keras, tôi cho rằng, nhưng tôi cũng đang hỏi mọi người thường làm gì khi phải đối mặt với loại vấn đề này nói chung.


@kbrose là đúng. Tuy nhiên, tôi có một mối quan tâm. Trong ví dụ này, bạn có một trình tạo rất đặc biệt của năng suất vô hạn. Quan trọng hơn, nó được thiết kế để mang lại các lô có kích thước 1000. Trong thực tế, điều này là quá khó để đáp ứng, nếu không muốn nói là không thể. Bạn cần sắp xếp lại các mục nhập của mình để các mục có cùng độ dài được sắp xếp cùng nhau và bạn cần đặt cẩn thận các vị trí phân chia hàng loạt. Hơn nữa, bạn không có cơ hội để thực hiện xáo trộn trên các lô. Vì vậy, ý kiến ​​của tôi là: không bao giờ sử dụng đầu vào độ dài khác nhau trong Keras trừ khi bạn biết chính xác những gì bạn đang làm. Sử dụng phần đệm và đặt Maskinglớp để bỏ qua
Bs He

Câu trả lời:


57

Điều này cho thấy rằng tất cả các ví dụ đào tạo có độ dài trình tự cố định, cụ thể là timesteps.

Điều đó không hoàn toàn chính xác, vì kích thước đó có thể None, tức là chiều dài thay đổi. Trong một duy nhất , bạn phải có cùng số dấu thời gian (đây thường là nơi bạn thấy 0-padding và masking). Nhưng giữa các đợt không có hạn chế như vậy. Trong quá trình suy luận, bạn có thể có bất kỳ chiều dài.

Mã ví dụ tạo ra các lô dữ liệu đào tạo thời gian ngẫu nhiên.

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)

Và đây là những gì nó in. Lưu ý các hình dạng đầu ra đang (None, None, x)chỉ ra kích thước lô thay đổi và kích thước dấu thời gian thay đổi.

__________________________________________________________________________________________
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

Cảm ơn vì điều này. Tuy nhiên, nếu chúng ta 0 đệm các chuỗi, nó sẽ ảnh hưởng đến các trạng thái ẩn và ô nhớ vì chúng ta tiếp tục truyền x_t là 0, khi thực tế, sẽ không có gì được thông qua. Trong bình thường fit(), chúng ta có thể truyền sequence_lenththam số để chỉ định độ dài của chuỗi để loại trừ nó. Có vẻ như cách tiếp cận máy phát điện không cho phép bỏ qua 0 chuỗi?
GRS

1
@GRS Trình tạo của bạn có thể trả về 3 tuple (inputs, targets, sample_weights)và bạn có thể đặt sample_weights0 miếng đệm của mình thành 0. Tuy nhiên, tôi không chắc chắn điều này sẽ hoạt động hoàn hảo cho RNN hai chiều.
kbrose

Điều này rất hữu ích, nhưng tôi ước nó cũng bao gồm một ví dụ về việc sử dụng model.predict_generatorvới một bộ kiểm tra. Khi tôi cố gắng dự đoán với một trình tạo, tôi gặp lỗi liên quan đến ghép (bộ kiểm tra cũng có các chuỗi có độ dài thay đổi). Giải pháp của tôi là sử dụng tiêu chuẩn model.predictmột cách hacky. Có lẽ điều này sẽ phù hợp hơn cho một câu hỏi mới?
mickey

@mickey mà nghe như một câu hỏi khác. Câu hỏi này là về đào tạo, không phải dự đoán.
kbrose

Nếu câu hỏi trong các ý kiến ​​thực sự được hỏi như một câu hỏi mới, bạn có thể liên kết với nó không?
Nấm Itamar

7

@kbrose dường như có một giải pháp tốt hơn

Tôi cho rằng điều rõ ràng cần làm là tìm độ dài tối đa của bất kỳ chuỗi nào trong tập huấn luyện và không đệm nó.

Đây thường là một giải pháp tốt. Có thể thử độ dài tối đa của chuỗi + 100. Sử dụng bất cứ thứ gì hoạt động tốt nhất cho ứng dụng của bạn.

Nhưng điều đó có nghĩa là tôi không thể đưa ra dự đoán tại thời điểm thử nghiệm với độ dài đầu vào lớn hơn thế?

Không cần thiết. Lý do độ dài cố định được sử dụng trong máy ảnh, là vì nó cải thiện đáng kể hiệu suất bằng cách tạo ra các tenxơ có hình dạng cố định. Nhưng đó chỉ là để đào tạo. Sau khi đào tạo, bạn sẽ học được các trọng số phù hợp cho nhiệm vụ của mình.

Giả sử, sau khi đào tạo hàng giờ, bạn nhận ra chiều dài tối đa của mô hình của bạn không đủ lớn / nhỏ và bây giờ bạn cần thay đổi các bước thời gian, chỉ cần trích xuất các trọng số đã học từ mô hình cũ, xây dựng mô hình mới với các bước thời gian mới và tiêm trọng lượng đã học vào nó.

Bạn có thể có thể làm điều này bằng cách sử dụng một cái gì đó như:

new_model.set_weights(old_model.get_weights())

Tôi đã không thử bản thân mình. Hãy thử nó và gửi kết quả của bạn ở đây vì lợi ích của mọi người. Đây là một số liên kết: một hai


1
Bạn thực sự có thể có đầu vào chiều dài thay đổi, không cần phải giới thiệu hack như thế nào max length + 100. Xem câu trả lời của tôi cho ví dụ mã.
kbrose

1
Chuyển trọng lượng sang một mô hình có nhiều dấu thời gian hơn thực sự hoạt động hoàn toàn tốt! Tôi tình cờ gặp lên timesteps cho Bidirectional(LSTM)()RepeatVector()lớp, và những dự đoán là hoàn toàn khả thi.
komodovaran_

@kbrose Đây không phải là hack, nó là cách bạn thường làm. Sử dụng batch_size của một cái là quá chậm và máy ảnh cho phép các lớp mặt nạ để mặt nạ không ảnh hưởng đến mất mát.
Ferus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.