ฝึกอบรม RNN ด้วยตัวอย่างความยาวต่างกันใน Keras


60

ฉันพยายามเริ่มเรียนรู้เกี่ยวกับ RNNs และฉันใช้ Keras ฉันเข้าใจหลักฐานพื้นฐานของเลเยอร์วานิลลา RNN และ LSTM แต่ฉันมีปัญหาในการเข้าใจประเด็นทางเทคนิคบางประการสำหรับการฝึกอบรม

ในเอกสาร kerasมันบอกว่าการป้อนข้อมูลไปยังชั้น RNN (batch_size, timesteps, input_dim)ต้องมีรูปร่าง นี่แสดงให้เห็นว่าตัวอย่างการฝึกอบรมทั้งหมดมีความยาวตามลำดับที่timestepsแน่นอน

แต่นี่ไม่ใช่เรื่องปกติโดยเฉพาะใช่ไหม? ฉันอาจต้องการให้ RNN ทำงานกับประโยคที่มีความยาวต่างกัน เมื่อฉันฝึกมันในคลังข้อมูลบางอย่างฉันจะให้อาหารมันเป็นชุดของประโยคความยาวที่แตกต่างกันทั้งหมด

ฉันคิดว่าสิ่งที่ชัดเจนที่ต้องทำคือค้นหาความยาวสูงสุดของลำดับใด ๆ ในชุดฝึกอบรมและ zero pad มัน แต่นั่นหมายความว่าฉันไม่สามารถคาดการณ์เวลาทดสอบที่มีความยาวอินพุทมากกว่านั้นได้หรือไม่?

นี่เป็นคำถามเกี่ยวกับการใช้งานของ Keras โดยเฉพาะฉันคิดว่า แต่ฉันก็ถามว่าคนทั่วไปจะทำอย่างไรเมื่อต้องเผชิญกับปัญหาแบบนี้


@kbrose ถูกต้อง อย่างไรก็ตามฉันมีหนึ่งความกังวล ในตัวอย่างคุณมีเครื่องกำเนิดพิเศษที่ให้ผลลัพธ์แบบไม่ จำกัด ที่สำคัญกว่านั้นคือมันถูกออกแบบมาเพื่อให้ได้แบทช์ 1000 ขนาดในทางปฏิบัติมันยากเกินกว่าที่จะตอบสนองถ้ามันเป็นไปไม่ได้ คุณต้องจัดระเบียบรายการของคุณอีกครั้งเพื่อให้รายการที่มีความยาวเท่ากันถูกจัดเรียงไว้ด้วยกันและคุณต้องกำหนดตำแหน่งการแบ่งแบทช์อย่างระมัดระวัง ยิ่งกว่านั้นคุณไม่มีโอกาสที่จะสับเปลี่ยนชุด ดังนั้นความคิดเห็นของฉันคือ: อย่าใช้อินพุตที่มีความยาวต่างกันใน Keras เว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่ ใช้ padding และตั้งMaskingเลเยอร์เป็น ignor
Bs เขา

คำตอบ:


56

นี่แสดงให้เห็นว่าตัวอย่างการฝึกอบรมทั้งหมดมีความยาวตามลำดับที่timestepsแน่นอน

นั่นไม่ถูกต้องนักเนื่องจากขนาดนั้นสามารถเป็นได้Noneนั่นคือความยาวผันแปร ภายในชุดเดียวคุณต้องมีจำนวนการประทับเวลาเท่ากัน (ซึ่งโดยทั่วไปจะเป็นที่ที่คุณเห็น 0-padding และ masking) แต่ระหว่างแบตช์ไม่มีข้อ จำกัด ดังกล่าว ในระหว่างการอนุมานคุณสามารถมีความยาวได้

โค้ดตัวอย่างที่สร้างกลุ่มข้อมูลการฝึกอบรมแบบสุ่ม

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-tuple (inputs, targets, sample_weights)และคุณสามารถตั้งค่าsample_weights0-pads ของคุณเป็น 0 อย่างไรก็ตามฉันไม่แน่ใจว่ามันจะทำงานได้อย่างสมบูรณ์แบบสำหรับแบบสองทิศทาง RNN
kbrose

สิ่งนี้มีประโยชน์ แต่ฉันหวังว่ามันจะมีตัวอย่างของการใช้model.predict_generatorกับชุดทดสอบ เมื่อฉันพยายามที่จะทำนายกับเครื่องกำเนิดไฟฟ้าฉันได้รับข้อผิดพลาดเกี่ยวกับการต่อข้อมูล (ชุดทดสอบยังมีลำดับความยาวแปรผัน) ทางออกของฉันคือการใช้มาตรฐานmodel.predictในวิธีแฮ็ค บางทีนี่อาจจะเหมาะกับคำถามใหม่ดีกว่า
มิกกี้

@ มิกกี้ที่ฟังดูเหมือนคำถามที่แตกต่าง คำถามนี้เกี่ยวกับการฝึกอบรมไม่ใช่การคาดเดา
kbrose

หากคำถามในความคิดเห็นนั้นถูกถามเป็นคำถามใหม่คุณสามารถเชื่อมโยงไปได้หรือไม่?
Itamar Mushkin

7

@kbrose ดูเหมือนจะมีทางออกที่ดีกว่า

ฉันคิดว่าสิ่งที่ชัดเจนที่ต้องทำคือค้นหาความยาวสูงสุดของลำดับใด ๆ ในชุดฝึกอบรมและ zero pad มัน

นี่เป็นวิธีแก้ปัญหาที่ดี อาจลองลำดับความยาวสูงสุด + 100 ใช้สิ่งที่ดีที่สุดสำหรับแอปพลิเคชันของคุณ

แต่นั่นหมายความว่าฉันไม่สามารถคาดการณ์เวลาทดสอบที่มีความยาวอินพุทมากกว่านั้นได้หรือไม่?

ไม่จำเป็น. เหตุผลที่ใช้ความยาวคงที่ใน keras เป็นเพราะช่วยปรับปรุงประสิทธิภาพอย่างมากโดยการสร้างเทนเซอร์ของรูปร่างคงที่ แต่นั่นเป็นเพียงการฝึกอบรม หลังจากการฝึกอบรมคุณจะได้เรียนรู้น้ำหนักที่เหมาะสมสำหรับงานของคุณ

สมมติว่าหลังจากฝึกอบรมเป็นเวลาหลายชั่วโมงคุณจะรู้ว่าความยาวสูงสุดของโมเดลไม่ใหญ่ / เล็กพอและตอนนี้คุณต้องเปลี่ยนขั้นตอนเวลาเพียงดึงน้ำหนักที่ได้เรียนรู้จากโมเดลเก่าสร้างโมเดลใหม่ด้วยขั้นตอนเวลาใหม่ และฉีดน้ำหนักที่เรียนรู้เข้าไป

คุณสามารถทำได้โดยใช้สิ่งต่อไปนี้:

new_model.set_weights(old_model.get_weights())

ฉันไม่ได้ลองเอง โปรดลองและโพสต์ผลลัพธ์ของคุณที่นี่เพื่อประโยชน์ของทุกคน นี่คือลิงค์บางส่วน: หนึ่ง สอง


1
แน่นอนคุณสามารถมีปัจจัยตัวแปรความยาวไม่ต้องแนะนำ hacks max length + 100เช่น ดูคำตอบของฉันสำหรับรหัสตัวอย่าง
kbrose

1
การถ่ายโอนตุ้มน้ำหนักไปยังโมเดลที่มีการประทับเวลามากขึ้นจะทำงานได้ดีอย่างสมบูรณ์แบบ! ฉันกระแทกเวลาที่กำหนดBidirectional(LSTM)()และRepeatVector()เลเยอร์และการคาดคะเนก็เป็นไปได้อย่างสมบูรณ์แบบ
komodovaran_

@kbrose นี่ไม่ใช่แฮ็คมันเป็นวิธีที่คุณทำตามปกติ การใช้ batch_size ของหนึ่งช้าเกินไปและ keras เปิดใช้งานเลเยอร์การปิดบังเพื่อให้การปิดบังไม่ส่งผลต่อการสูญเสีย
Ferus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.