Model Seq2Seq dan fungsi kerugian (dalam keras)

Saya mengalami beberapa masalah dengan model seq2seq saya dalam beberapa kasus berfungsi dengan baik tetapi dalam beberapa kasus hasilnya hanya token akhir saja yang kembali.

Misalnya :

For given vector :
[2, #start token
3,
123,
1548, #end token
1548,
1548,
1548,
1548,
1548,
1548]

The model predict :
[1548, 
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548]

saya mencoba menggunakan panggilan balik SaveModel dari keras yang memantau "kerugian" tetapi masih memberikan hasil yang sama.

jadi saya berpikir mungkin saya harus menggunakan fungsi kerugian saya sendiri.

fungsi kerugian sederhana yang disediakan keras:

def mean_absolute_error(y_true, y_pred):
    return K.mean(K.abs(y_pred - y_true), axis=-1)

baik y_true dan y_pred adalah objek tensorflow (kita hanya mendapatkan penunjuk ke array sebenarnya) jadi .. untuk membuat beberapa logika kita perlu mendapatkan array dari GPU atau mengunggah array saya sendiri ke GPU..

fungsi kehilangan yang saya inginkan

def mean_absolute_error(y_true, y_pred):
    sum = 0
    for y , _y in zip(y_true , y_pred):
         if (y == _y) and (y == self.startToken or y == self.endToken):
              continue
         else:
              sum += abs(y - _y)
    return sum

saya mencoba menggunakan y_true.eval() yang seharusnya membawa array sebagai objek numpy ke cpu (Tidak dapat mengevaluasi tensor menggunakan eval(): Tidak ada sesi default yang terdaftar)

dan saya tidak berhasil menemukan cara mengunggah array saya sendiri ke tensorflow.

jika Anda memiliki solusi atau saran, saya akan dengan senang hati mendengarnya.

Terima kasih..

(tidak terlalu penting tapi ...)

Model berdasarkan: https://blog.keras.io/a-ten-menit-introduksi-to-sequence-to-sequence-learning-in-keras.html , tetapi dengan one-hot(dua redup [Matrix] ) keluaran.


person Ori Yampolsky    schedule 25.03.2018    source sumber
comment
Di tautan yang Anda berikan, mereka berhenti memprediksi setelah melihat token akhir; khususnya, dalam fungsi decode_sequence: # Exit condition: either hit max length or find stop character. Mereka juga mengisi array keluaran model dengan karakter awal: # Populate the first character of target sequence with the start character. Saya ingin tahu apakah Anda menggunakan fungsi yang mirip dengan fungsi decode_sequence mereka?   -  person vasilyrud    schedule 26.03.2018
comment
tidak, ini bisa dilakukan lebih mudah dengan : model.predict([x,x])   -  person Ori Yampolsky    schedule 26.03.2018
comment
Tapi itu mungkin penyebab masalahnya. Coba ikuti fungsi decode_sequence mereka dengan tepat, dan lihat apakah itu berfungsi terlebih dahulu. Ini mungkin satu-satunya cara untuk memprediksi seq-to-seq di Keras.   -  person vasilyrud    schedule 26.03.2018
comment
aku sudah memeriksanya..sama saja..   -  person Ori Yampolsky    schedule 27.03.2018


Jawaban (1)


Menggunakan K.eval atau if dalam fungsi kerugian bukanlah ide yang baik. Gagasan tentang tensor adalah bahwa mereka memiliki koneksi internal yang dikelola oleh tensorflow/keras, yang memungkinkan untuk menghitung gradien dan hal lainnya.

Menggunakan eval dan mengerjakan nilai numpy akan memutus koneksi ini dan merusak model. Gunakan eval hanya untuk melihat hasilnya, bukan untuk membuat fungsi.

Penggunaan ifs tidak akan berfungsi karena nilai tensor tidak tersedia. Namun ada fungsi keras, seperti K.switch, K.greater, K.less, dll., semuanya tercantum dalam dokumentasi backend .

Anda dapat membuat ulang fungsi Anda menggunakan fungsi tersebut.

Tapi sejujurnya, menurut saya Anda sebaiknya memilih masking atau angkat beban di kelas.

Penyamaran (solusi 1)

Jika Anda menggunakan lapisan penyematan, Anda dapat dengan sengaja mencadangkan nilai nol secara gratis setelah akhir.

Anda kemudian dapat menggunakan mask_zero=True di lapisan penyematan dan mendapatkan input seperti ini:

[2, #start token
3,
123,
1548, #end token
0, #nothing, value to be masked
0,
0,
0,
0,
0]

Pilihan lainnya adalah tidak memiliki token akhir dan menggunakan nol sebagai gantinya.

Pembobotan kelas (solusi 2)

Karena hal ini sangat mungkin terjadi karena Anda memiliki lebih banyak token akhir dibandingkan apa pun dalam keluaran yang Anda inginkan, Anda dapat mengurangi relevansi token akhir.

Hitung setiap kemunculan kelas dalam keluaran Anda dan hitung rasio untuk token akhir. Sebuah contoh:

  • Hitung rata-rata kemunculan semua kelas lainnya
  • Hitung kemunculan token akhir
  • ratio = other_classes_mean / end_token_occurences

Kemudian pada metode fit, gunakan:

class_weight = {0:1, 1:1, 2:1, ...., 1548:ratio, 1549:1,1550:1,...}

Mudah dilakukan dengan:

class_weight = {i:1. for i in range(totalTokens)}
class_weight[1548] = ratio
model.fit(...,...,....., class_weight = class_weight,...)

(Pastikan Anda memiliki 0 sebagai kelas yang memungkinkan dalam kasus ini, atau geser indeks sebanyak 1)

Fungsi kerugian serupa (solusi 3)

Perhatikan bahwa y_pred tidak akan pernah sama dengan y_true.

  • y_pred bersifat variabel, kontinu dan terdiferensiasi
  • y_true tepat dan konstan

Sebagai perbandingan, Anda harus mengambil argmax, yang sangat mirip dengan (jika tidak persis) indeks kelas.

def mean_absolute_error(y_true, y_pred):

    #for comparing, let's take exact values
    y_true_max = K.argmax(y_true)
    y_pred_max = K.argmax(y_pred)

    #compare with a proper tensor function
    equal_mask = K.equal(y_true_max,y_pred_max)
    is_start = K.equal(y_true_max, self.startTokenAsIndex)
    is_end = K.equal(y_true_max, self.endTokenAsIndex)

    #cast to float for multiplying and summing
    equal_mask = K.cast(equal_mask, K.floatx()) 
    is_start = K.cast(is_start, K.floatx())
    is_end = K.cast(is_end, K.floatx())
        #these are tensors with 0 (false) and 1 (true) as float
    
    #entire condition as you wanted
    condition = (is_start + is_end) * equal_mask
        # sum = or ||| multiply = and
        # we don't have to worry about the sum resulting in 2
            # because you will never have startToken == endToken

    #reverse condition:
    condition = 1 - condition

    #result
    return condition * K.mean(K.abs(y_pred - y_true), axis=-1)
person Daniel Möller    schedule 02.04.2018
comment
wow kawan, kamu luar biasa .. saya tidak pernah tahu tentang opsi bobot. dan saya ingin memiliki pijakan di sisi server Keras sehingga Anda banyak membantu.. terima kasih. - person Ori Yampolsky; 03.04.2018