Bagaimana cara menerapkan prediksi urutan "satu-ke-banyak" dan "banyak-ke-banyak" di Keras?

13

Saya berjuang untuk menafsirkan perbedaan pengkodean Keras untuk pelabelan urutan satu-ke-banyak (misalnya klasifikasi gambar tunggal) dan banyak-ke-banyak (misalnya klasifikasi urutan gambar). Saya sering melihat dua jenis kode:

Tipe 1 adalah di mana TimeDistributed tidak diterapkan seperti ini:

model=Sequential()

model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1], border_mode="valid", input_shape=[1, 56,14]))
model.add(Activation("relu"))
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=pool_size))

model.add(Reshape((56*14,)))
model.add(Dropout(0.25))
model.add(LSTM(5))
model.add(Dense(50))
model.add(Dense(nb_classes))
model.add(Activation("softmax"))

Tipe 2 adalah tempat TimeDistributed diterapkan seperti ini:

model = Sequential()

model.add(InputLayer(input_shape=(5, 224, 224, 3)))
model.add(TimeDistributed(Convolution2D(64, (3, 3))))
model.add(TimeDistributed(MaxPooling2D((2,2), strides=(2,2))))
model.add(LSTM(10))
model.add(Dense(3))

Pertanyaan saya adalah:

  • Apakah asumsi saya benar bahwa Tipe 1 adalah jenis satu-ke-banyak dan Tipe 2 adalah jenis banyak-ke-banyak? Atau TimeDistributedtidak memiliki relevansi dalam aspek ini?

  • Dalam salah satu kasus satu-ke-banyak atau banyak-ke-banyak adalah lapisan padat terakhir seharusnya 1 simpul "panjang" (memancarkan hanya satu nilai pada gilirannya) dan
    lapisan berulang sebelumnya bertanggung jawab untuk menentukan berapa banyak
    1-panjang nilai untuk dipancarkan? Atau lapisan padat terakhir seharusnya terdiri dari N node di mana N=max sequence length? Jika demikian, apa gunanya
    menggunakan RNN di sini ketika kita dapat menghasilkan input yang serupa dengan banyak
    keluaran dengan penduga "vanilla" paralel N?

  • Bagaimana cara menentukan jumlah catatan waktu dalam RNN? Apakah itu entah bagaimana
    berkorelasi dengan panjang urutan output atau hanya
    hiperparameter untuk disetel?

  • Kasus Inn pada contoh 1 saya di atas apa gunanya menerapkan
    LSTM ketika model hanya memancarkan satu prediksi kelas (dari kemungkinan
    nb_classes)? Bagaimana jika seseorang menghilangkan layer LSTM?

Hendrik
sumber
Bisakah Anda memberikan ringkasan dari kedua model?
Fadi Bakoura

Jawaban:

2

Inti dari menggunakan setiap layer berulang adalah memiliki output menjadi hasil tidak hanya satu item independen dari item lain, tetapi juga urutan item, sehingga output dari operasi layer pada satu item dalam urutan adalah hasilnya baik item itu dan item apa pun sebelum itu dalam urutan. Jumlah tanda waktu menentukan berapa lama urutan tersebut. Artinya, berapa banyak item yang harus ditangani secara berurutan, dan memengaruhi hasil yang dihasilkan masing-masing.

Lapisan LSTM beroperasi sedemikian rupa sehingga menerima input pada form number_of_timesteps, dimensi_of_each_item. Jika parameter return_afterences diatur ke False, yang secara default, layer "senyawa" input dari semua catatan waktu menjadi output tunggal. Jika Anda mempertimbangkan urutan, katakan 10 item, layer LSTM dengan return_afterences diatur ke False akan dari urutan seperti itu menghasilkan item output tunggal, dan atribut dari item tunggal ini akan menjadi hasil dari semua item (tanda waktu) di urutan. Inilah yang Anda inginkan dalam hal desain banyak-ke-satu.

Lapisan LSTM dengan return_afterences diatur ke True will untuk setiap item (timestep) dalam urutan input menghasilkan output. Ini dilakukan sedemikian rupa sehingga pada setiap timestep, output tidak hanya bergantung pada item yang sedang dioperasikan, tetapi juga item sebelumnya dalam urutan. Inilah yang Anda inginkan dalam hal desain banyak-ke-banyak.

Karena lapisan LSTM mengambil urutan item sebagai input, setiap lapisan sebelum lapisan LSTM dalam model Anda perlu menghasilkan urutan sebagai output. Dalam kasus model Tipe 1 Anda, beberapa layer pertama tidak beroperasi pada urutan, melainkan satu item pada satu waktu. Karenanya, ini tidak menghasilkan urutan item yang akan dioperasikan untuk LSTM.

Menggunakan TimeDistributed memungkinkan lapisan beroperasi pada setiap item secara berurutan tanpa item yang saling mempengaruhi. Lapisan TimeDistributed dengan demikian beroperasi pada urutan item, tetapi tidak ada rekursi.

Dalam kasus model tipe 2 Anda, lapisan pertama akan menghasilkan urutan 5 timestep panjang, dan operasi yang dilakukan pada masing-masing item dalam urutan akan independen satu sama lain, karena lapisan yang dibungkus dalam TimeDistributed tidak berulang. Karena lapisan LSTM menggunakan pengaturan default, return_afterences = Salah, lapisan LSTM akan menghasilkan output tunggal untuk setiap urutan 5 item.

Jumlah akhir node keluaran dalam model Anda sepenuhnya tergantung pada use case. Sebuah simpul tunggal cocok untuk sesuatu seperti klasifikasi biner atau untuk menghasilkan semacam skor.

mevoki
sumber
1

Saya pikir Anda mungkin dapat menggunakan pekerjaan saya sebelumnya. Dalam kode ini saya membuat gelombang sinus (dari panjang gelombang dan fase acak) dan melatih LSTM ke urutan titik dari gelombang sinus ini dan menghasilkan urutan 150 poin yang menyelesaikan setiap gelombang sinus.

Inilah modelnya:

    features_num=5 
    latent_dim=40

    ##
    encoder_inputs = Input(shape=(None, features_num))
    encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoder_inputs)
    encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoded)
    encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoded)
    encoded = LSTM(latent_dim, return_state=True)(encoded)

    encoder = Model (input=encoder_inputs, output=encoded)
    ##

    encoder_outputs, state_h, state_c = encoder(encoder_inputs)
    encoder_states = [state_h, state_c]

    decoder_inputs=Input(shape=(1, features_num))
    decoder_lstm_1 = LSTM(latent_dim, return_sequences=True, return_state=True)
    decoder_lstm_2 = LSTM(latent_dim, return_sequences=True, return_state=True)
    decoder_lstm_3 = LSTM(latent_dim, return_sequences=True, return_state=True)
    decoder_lstm_4 = LSTM(latent_dim, return_sequences=True, return_state=True)

    decoder_dense = Dense(features_num)

    all_outputs = []
    inputs = decoder_inputs


    states_1=encoder_states
   # Place holder values:
    states_2=states_1; states_3=states_1; states_4=states_1

    for _ in range(1):
        # Run the decoder on the first timestep
        outputs_1, state_h_1, state_c_1 = decoder_lstm_1(inputs, initial_state=states_1)
        outputs_2, state_h_2, state_c_2 = decoder_lstm_2(outputs_1)
        outputs_3, state_h_3, state_c_3 = decoder_lstm_3(outputs_2)
        outputs_4, state_h_4, state_c_4 = decoder_lstm_4(outputs_3)

        # Store the current prediction (we will concatenate all predictions later)
        outputs = decoder_dense(outputs_4)
        all_outputs.append(outputs)
        # Reinject the outputs as inputs for the next loop iteration
        # as well as update the states
        inputs = outputs
        states_1 = [state_h_1, state_c_1]
        states_2 = [state_h_2, state_c_2]
        states_3 = [state_h_3, state_c_3]
        states_4 = [state_h_4, state_c_4]


    for _ in range(149):
        # Run the decoder on each timestep
        outputs_1, state_h_1, state_c_1 = decoder_lstm_1(inputs, initial_state=states_1)
        outputs_2, state_h_2, state_c_2 = decoder_lstm_2(outputs_1, initial_state=states_2)
        outputs_3, state_h_3, state_c_3 = decoder_lstm_3(outputs_2, initial_state=states_3)
        outputs_4, state_h_4, state_c_4 = decoder_lstm_4(outputs_3, initial_state=states_4)

        # Store the current prediction (we will concatenate all predictions later)
        outputs = decoder_dense(outputs_4)
        all_outputs.append(outputs)
        # Reinject the outputs as inputs for the next loop iteration
        # as well as update the states
        inputs = outputs
        states_1 = [state_h_1, state_c_1]
        states_2 = [state_h_2, state_c_2]
        states_3 = [state_h_3, state_c_3]
        states_4 = [state_h_4, state_c_4]


    # Concatenate all predictions
    decoder_outputs = Lambda(lambda x: K.concatenate(x, axis=1))(all_outputs)   

    model = Model([encoder_inputs, decoder_inputs], decoder_outputs)

    #model = load_model('pre_model.h5')


    print(model.summary())

Dan ini adalah keseluruhan skrip:

from keras.models import Model
from keras.layers import Input, LSTM, Dense, TimeDistributed,Lambda, Dropout, Activation ,RepeatVector
from keras.callbacks import ModelCheckpoint 
import numpy as np

from keras.layers import Lambda
from keras import backend as K

from keras.models import load_model

import os


features_num=5 
latent_dim=40

##
encoder_inputs = Input(shape=(None, features_num))
encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoder_inputs)
encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoded)
encoded = LSTM(latent_dim, return_state=False ,return_sequences=True)(encoded)
encoded = LSTM(latent_dim, return_state=True)(encoded)

encoder = Model (input=encoder_inputs, output=encoded)
##

encoder_outputs, state_h, state_c = encoder(encoder_inputs)
encoder_states = [state_h, state_c]

decoder_inputs=Input(shape=(1, features_num))
decoder_lstm_1 = LSTM(latent_dim, return_sequences=True, return_state=True)
decoder_lstm_2 = LSTM(latent_dim, return_sequences=True, return_state=True)
decoder_lstm_3 = LSTM(latent_dim, return_sequences=True, return_state=True)
decoder_lstm_4 = LSTM(latent_dim, return_sequences=True, return_state=True)

decoder_dense = Dense(features_num)

all_outputs = []
inputs = decoder_inputs

# Place holder values:
states_1=encoder_states
states_2=states_1; states_3=states_1; states_4=states_1

for _ in range(1):
    # Run the decoder on one timestep
    outputs_1, state_h_1, state_c_1 = decoder_lstm_1(inputs, initial_state=states_1)
    outputs_2, state_h_2, state_c_2 = decoder_lstm_2(outputs_1)
    outputs_3, state_h_3, state_c_3 = decoder_lstm_3(outputs_2)
    outputs_4, state_h_4, state_c_4 = decoder_lstm_4(outputs_3)

    # Store the current prediction (we will concatenate all predictions later)
    outputs = decoder_dense(outputs_4)
    all_outputs.append(outputs)
    # Reinject the outputs as inputs for the next loop iteration
    # as well as update the states
    inputs = outputs
    states_1 = [state_h_1, state_c_1]
    states_2 = [state_h_2, state_c_2]
    states_3 = [state_h_3, state_c_3]
    states_4 = [state_h_4, state_c_4]


for _ in range(149):
    # Run the decoder on one timestep
    outputs_1, state_h_1, state_c_1 = decoder_lstm_1(inputs, initial_state=states_1)
    outputs_2, state_h_2, state_c_2 = decoder_lstm_2(outputs_1, initial_state=states_2)
    outputs_3, state_h_3, state_c_3 = decoder_lstm_3(outputs_2, initial_state=states_3)
    outputs_4, state_h_4, state_c_4 = decoder_lstm_4(outputs_3, initial_state=states_4)

    # Store the current prediction (we will concatenate all predictions later)
    outputs = decoder_dense(outputs_4)
    all_outputs.append(outputs)
    # Reinject the outputs as inputs for the next loop iteration
    # as well as update the states
    inputs = outputs
    states_1 = [state_h_1, state_c_1]
    states_2 = [state_h_2, state_c_2]
    states_3 = [state_h_3, state_c_3]
    states_4 = [state_h_4, state_c_4]


# Concatenate all predictions
decoder_outputs = Lambda(lambda x: K.concatenate(x, axis=1))(all_outputs)   

model = Model([encoder_inputs, decoder_inputs], decoder_outputs)

#model = load_model('pre_model.h5')


print(model.summary())


model.compile(loss='mean_squared_error', optimizer='adam')


def create_wavelength(min_wavelength, max_wavelength, fluxes_in_wavelength, category )  :         
#category :: 0 - train ; 2 - validate ; 4- test. 1;3;5 - dead space
    c=(category+np.random.random())/6         
    k = fluxes_in_wavelength
#
    base= (np.trunc(k*np.random.random()*(max_wavelength-min_wavelength))       +k*min_wavelength)  /k
    answer=base+c/k
    return (answer)       

def make_line(length,category):
    shift= np.random.random()
    wavelength = create_wavelength(30,10,1,category)
    a=np.arange(length)
    answer=np.sin(a/wavelength+shift)
    return answer

def make_data(seq_num,seq_len,dim,category):
    data=np.array([]).reshape(0,seq_len,dim)
    for i in range (seq_num):
        mini_data=np.array([]).reshape(0,seq_len)
        for j in range (dim):
            line = make_line(seq_len,category)
            line=line.reshape(1,seq_len)            
            mini_data=np.append(mini_data,line,axis=0)
        mini_data=np.swapaxes(mini_data,1,0)
        mini_data=mini_data.reshape(1,seq_len,dim)      
        data=np.append(data,mini_data,axis=0)
    return (data)


def train_generator():
    while True:
        sequence_length = np.random.randint(150, 300)+150       
        data=make_data(1000,sequence_length,features_num,0) # category=0 in train


    #   decoder_target_data is the same as decoder_input_data but offset by one timestep

        encoder_input_data = data[:,:-150,:] # all but last 150 

        decoder_input_data = data[:,-151,:] # the one before the last 150.
        decoder_input_data=decoder_input_data.reshape((decoder_input_data.shape[0],1,decoder_input_data.shape[1]))


        decoder_target_data = (data[:, -150:, :]) # last 150        
        yield [encoder_input_data, decoder_input_data], decoder_target_data
def val_generator():
    while True:

        sequence_length = np.random.randint(150, 300)+150       
        data=make_data(1000,sequence_length,features_num,2) # category=2 in val

        encoder_input_data = data[:,:-150,:] # all but last 150 

        decoder_input_data = data[:,-151,:] # the one before the last 150.
        decoder_input_data=decoder_input_data.reshape((decoder_input_data.shape[0],1,decoder_input_data.shape[1]))

        decoder_target_data = (data[:, -150:, :]) # last 150        
        yield [encoder_input_data, decoder_input_data], decoder_target_data

filepath_for_w= 'flux_p2p_s2s_model.h5' 
checkpointer=ModelCheckpoint(filepath_for_w, monitor='val_loss', verbose=0, save_best_only=True, mode='auto', period=1)     
model.fit_generator(train_generator(),callbacks=[checkpointer], steps_per_epoch=30, epochs=2000, verbose=1,validation_data=val_generator(),validation_steps=30)
model.save(filepath_for_w)




def predict_wave(input_wave,input_for_decoder):  # input wave= x[n,:,:], ie points except the last 150; each wave has feature_num features. run this function for all such instances (=n)   
    #print (input_wave.shape)
    #print (input_for_decoder.shape)
    pred= model.predict([input_wave,input_for_decoder])

    return pred

def predict_many_waves_from_input(x):   
    x, x2=x # x == encoder_input_data ; x==2 decoder_input_data

    instance_num= x.shape[0]


    multi_predict_collection=np.zeros((x.shape[0],150,x.shape[2]))

    for n in range(instance_num):
        input_wave=x[n,:,:].reshape(1,x.shape[1],x.shape[2])
        input_for_decoder=x2[n,:,:].reshape(1,x2.shape[1],x2.shape[2])
        wave_prediction=predict_wave(input_wave,input_for_decoder)
        multi_predict_collection[n,:,:]=wave_prediction
    return (multi_predict_collection)

def test_maker():
    if True:        
        sequence_length = np.random.randint(150, 300)+150       
        data=make_data(470,sequence_length,features_num,4) # category=4 in test

        encoder_input_data = data[:,:-150,:] # all but last 150 

        decoder_input_data = data[:,-151,:] # the one before the last 150.
        decoder_input_data=decoder_input_data.reshape((decoder_input_data.shape[0],1,decoder_input_data.shape[1]))

        decoder_target_data = (data[:, -150:, :]) # last 150        
        return [encoder_input_data, decoder_input_data],    decoder_target_data

x,y= test_maker()   



a=predict_many_waves_from_input (x) # is that right..?
x=x[0] # keep the wave (generated data except last 150 time points) 
print (x.shape)
print (y.shape)
print (a.shape)

np.save ('a.npy',a)
np.save ('y.npy',y)
np.save ('x.npy',x)



print (np.mean(np.absolute(y[:,:,0]-a[:,:,0])))
print (np.mean(np.absolute(y[:,:,1]-a[:,:,1])))
print (np.mean(np.absolute(y[:,:,2]-a[:,:,2])))
print (np.mean(np.absolute(y[:,:,3]-a[:,:,3])))
print (np.mean(np.absolute(y[:,:,4]-a[:,:,4])))
Lafayette
sumber