Saya punya data X. Ukurannya (32, 10, 16), seperti contoh pada dokumentasi Keras.
x = np.random.random(size=(32, 10, 16)
Artinya, saya punya 32 data (sample). Setiap sample berisi data (10, 16): 10 baris dan 16 kolom. Ketika saya mengaplikasikan suatu layer (katakanlah, dan paling umum: Dense), agar bobot dari satu layer tersebut merata pada setiap elemen maka perlu kita gunakan timedistributed layer ini.
Perhatikan contoh berikut,
model0 = Sequential() model0.add(Dense(8, input_shape=(10, 16))) model0.summary()Hasilnya adalah sebagai berikut,
---
Model: "sequential_6" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= time_distributed_1 (TimeDist (None, 10, 8) 136 ================================================================= Total params: 136 Trainable params: 136 Non-trainable params: 0Bedakan dengan ini,
model1 = Sequential() model1.add(Dense(8, input_shape=(10, 16))) model1.summary()Hasilnya,
---
Model: "sequential_5" _________________________________________________________________ Layer (type) Shape Param # ================================================================= dense_3 (Dense) (None, 10, 8) 136 ================================================================= Total params: 136 Trainable params: 136Apa perbedaannya? Tidak ada. Saya juga bingung. Mari kita cari contoh lain, dari machinelearningmastery.
Sebenarnya, jika kita teliti, ada perbedaan bentuk output shape dari kedua contoh diatas, yang pertama memberikan bentuk ouput (TimeDist(None, 8, 10)), sedangkan yang kedua hanya (None, 8, 10).
Perhatikan contoh panjang berikut. Input dan output adalah sama, yakni [0 0.2 0.4 0.6 0.8], bayangkan sistem echo yang memberikan output yang sama dengan inputnya namun dengan time delay. Bedakan blok fungsi build_model() dengan build_tdmodel().
# keras demo timeditributed import numpy as np from keras.models import Sequential from keras.layers import Dense from keras.layers import TimeDistributed from keras.layers import LSTM # prepare sequence length = 5 seq = np. array([i/float(length) for i in range(length)]) X = seq.reshape(1, length, 1) y = seq.reshape(1, length, 1) # define LSTM configuration n_neurons = length n_batch = 1 n_epoch = 1000 # create LSTM without timedistributed: many-to-one def build_model(): model = Sequential() model.add(LSTM(n_neurons, input_shape=(length, 1))) model.add(Dense(length)) model.compile(loss='mean_squared_error', optimizer='adam') return model without_td = build_model() print(without_td.summary()) # train LSTM without_td.fit(X, y.reshape(1,5), epochs=n_epoch, batch_size=n_batch, verbose=2) # evaluate result_wtd = without_td.predict(X, batch_size=n_batch, verbose=0) for value in result_wtd[0,:]: print('%.1f' % value) # create LSTM with timedistibuted: many-to-many def build_tdmodel(): model = Sequential() model.add(LSTM(n_neurons, input_shape=(length, 1), return_sequences=True)) model.add(TimeDistributed(Dense(1))) model.compile(loss='mean_squared_error', optimizer='adam') return model model = build_tdmodel() print(model.summary()) # train LSTM model.fit(X, y, epochs=n_epoch, batch_size=n_batch, verbose=2) # evaluate result = model.predict(X, batch_size=n_batch, verbose=0) print('Output: ') for value in result[0,:,0]: print('%.1f' % value)
Jika kita cetak summary-nya adalah sbb:
Tanpa timedistributed:
Model: "sequential_5" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= lstm_5 (LSTM) (None, 5) 140 _________________________________________________________________ dense_5 (Dense) (None, 5) 30 ================================================================= Total params: 170 Trainable params: 170 Non-trainable params: 0 _________________________________________________________________ None
Dengan timedistributed:
Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= lstm_2 (LSTM) (None, 5, 5) 140 _________________________________________________________________ time_distributed_1 (TimeDist (None, 5, 1) 6 ================================================================= Total params: 146 Trainable params: 146 Non-trainable params: 0 _________________________________________________________________ None
Sekarang perbedaanya terlihat lebih jelas. Selain jumlah trainable parameter yang lebih sedikit, timedtributed juga lebih compact. Menghemat ruang dan waktu komputasi. Jadi dengan timedistributed,
- Operasi dilakukan per frame
- Hemat ruang dan waktu (memory efficient)
Input - output timedistibuted:
- input: 3D (seperti halnya LSTM) --> perhatikan input X yang direshape menjadi 3D
- output: juga 3D --> sama, Y juga direshape menjadi 3D
Perbedaan format dan pengolahan data input-output di atas adalah perbedaan mendasar dari timedistributed. Untuk mengefisienkan komputasi, maka digunakan timedistributed, "which allows to apply a layer to every temporal slice of an input.". Artinya, CMIIW, setiap temporal slice akan diaplikasikan dense layer (dengan unit 1 pada contoh kasus diatas). Jadi kita tidak perlu mendefinisikan dense layer pada tiap temporal slice, cukup dengan timedistributed ini saja. Karena itu diperlukan matriks 3D sebagi input, begitu pula outputnya.
Jadi, dua fungsi build_model() dan build_tdmodel() di atas menghasilkan dua arsitektur yang sama secara konsep namun berbeda pendekatan. Yang pertama adalah many-to-one (tanpa timedistributed), yang kedua adalah many-to-many (dengan timedistributed). Gambar terakhir di bawah ini menjelaskan timedistributed pada berbagai architecture (blok hijau).
Terakhir, ada penjelasan sederhana yang saya ambil dari diskusi di channel Slack keras seperti di bawah ini, semoga bisa menambah pemahaman kita.
The timedistributed dense layer is used on RNNs and LSTMSs to keep one-to-one relations on the input and output. Assume you have 100 time steps with 200 samples of data (100 x 200 in another word) and you want to use RNN with output of 300. If you don't have a timedistributed dense layer, you will get a 200 x 100 x 300 tensor with the output flattened with each timestep; however, if you apply timedistributed, you get a fully connected dense on each time step and get output separately by timesteps.Referensi:
- https://machinelearningmastery.com/timedistributed-layer-for-long-short-term-memory-networks-in-python/
- https://github.com/keras-team/keras/issues/1029
Akan lebih jelas bila ditambahkan gambar visualisasi apa itu timedistributed...
ReplyDelete