Mengapa binary_crossentropy danategical_crossentropy memberikan kinerja yang berbeda untuk masalah yang sama?

160

Saya mencoba melatih CNN untuk mengkategorikan teks berdasarkan topik. Ketika saya menggunakan cross-entropy biner saya mendapatkan akurasi ~ 80%, dengan cross-entropy kategoris saya mendapatkan akurasi ~ 50%.

Saya tidak mengerti mengapa ini terjadi. Ini masalah multikelas, bukankah itu berarti saya harus menggunakan cross-entropy kategoris dan bahwa hasil dengan binary cross-entropy tidak ada artinya?

model.add(embedding_layer)
model.add(Dropout(0.25))
# convolution layers
model.add(Conv1D(nb_filter=32,
                    filter_length=4,
                    border_mode='valid',
                    activation='relu'))
model.add(MaxPooling1D(pool_length=2))
# dense layers
model.add(Flatten())
model.add(Dense(256))
model.add(Dropout(0.25))
model.add(Activation('relu'))
# output layer
model.add(Dense(len(class_id_index)))
model.add(Activation('softmax'))

Lalu saya mengkompilasinya seperti ini menggunakan categorical_crossentropyfungsi loss:

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

atau

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

Secara intuitif masuk akal mengapa saya ingin menggunakan lintas-entropi kategoris, saya tidak mengerti mengapa saya mendapatkan hasil yang baik dengan biner, dan hasil yang buruk dengan kategorikal.

Daniel Messias
sumber
10
Jika ini masalah multikelas, Anda harus menggunakannya categorical_crossentropy. Label juga perlu dikonversi ke dalam format kategorikal. Lihat to_categoricaluntuk melakukan ini. Juga lihat definisi crossentropies kategorikal dan biner di sini .
Otonomi
Label saya kategorikal, dibuat menggunakan to_categorical (satu vektor panas untuk setiap kelas). Apakah itu berarti ~ 80% akurasi dari biner crossentropy hanyalah angka palsu?
Daniel Messias
Aku pikir begitu. Jika Anda menggunakan label kategorikal yaitu satu vektor panas, maka Anda inginkan categorical_crossentropy. Jika Anda memiliki dua kelas, mereka akan direpresentasikan sebagai 0, 1dalam label biner dan 10, 01dalam format label kategorikal.
Otonomi
1
Saya pikir dia hanya membandingkan dengan angka pertama dalam vektor dan mengabaikan sisanya.
Thomas Pinetz
2
@NilavBaranGhosh Representasi akan [[1, 0], [0, 1]] untuk klasifikasi kategorikal yang melibatkan dua kelas (bukan [[0, 0], [0, 1]] seperti yang Anda sebutkan). Dense(1, activation='softmax')untuk klasifikasi biner adalah salah. Ingat output softmax adalah distribusi probabilitas yang berjumlah satu. Jika Anda hanya ingin memiliki satu neuron output dengan klasifikasi biner, gunakan sigmoid dengan entropi silang biner.
Otonomi

Jawaban:

204

Alasan untuk perbedaan kinerja yang jelas antara entropi kategorikal & biner ini adalah apa yang telah dilaporkan pengguna xtof54 dalam jawabannya di bawah ini , yaitu:

akurasi yang dihitung dengan metode Keras evaluatehanya salah ketika menggunakan binary_crossentropy dengan lebih dari 2 label

Saya ingin menguraikan lebih lanjut tentang ini, menunjukkan masalah mendasar yang sebenarnya, menjelaskannya, dan menawarkan obat.

Perilaku ini bukan bug; alasan yang mendasari adalah masalah yang agak halus & tidak berdokumen tentang bagaimana Keras benar-benar menebak keakuratan mana yang akan digunakan, tergantung pada fungsi kerugian yang telah Anda pilih, ketika Anda memasukkannya metrics=['accuracy']dalam kompilasi model Anda. Dengan kata lain, saat opsi kompilasi pertama Anda

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

valid, yang kedua:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

tidak akan menghasilkan apa yang Anda harapkan, tetapi alasannya bukan penggunaan entropi silang biner (yang, pada prinsipnya, merupakan fungsi kerugian yang benar-benar valid).

Mengapa demikian? Jika Anda memeriksa kode sumber metrik , Keras tidak mendefinisikan satu metrik akurasi, tetapi beberapa yang berbeda, di antaranya binary_accuracydan categorical_accuracy. Apa yang terjadi di bawah tenda adalah bahwa, karena Anda telah memilih entropi silang biner sebagai fungsi kerugian Anda dan belum menentukan metrik akurasi tertentu, Keras (salah ...) menyimpulkan bahwa Anda tertarik pada binary_accuracy, dan inilah yang dikembalikan - padahal sebenarnya Anda tertarik dengan categorical_accuracy.

Mari kita verifikasi bahwa inilah masalahnya, menggunakan contoh MNIST CNN di Keras, dengan modifikasi berikut:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  # WRONG way

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=2,  # only 2 epochs, for demonstration purposes
          verbose=1,
          validation_data=(x_test, y_test))

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.9975801164627075

# Actual accuracy calculated manually:
import numpy as np
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98780000000000001

score[1]==acc
# False    

Untuk memperbaiki hal ini, yaitu menggunakan entropi memang biner lintas sebagai fungsi kerugian Anda (seperti yang saya katakan, tidak ada yang salah dengan ini, setidaknya pada prinsipnya) sementara masih mendapatkan kategoris akurasi yang diperlukan oleh masalah di tangan, Anda harus meminta secara eksplisit untuk categorical_accuracydi kompilasi model sebagai berikut:

from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])

Dalam contoh MNIST, setelah pelatihan, penilaian, dan prediksi set tes seperti yang saya tunjukkan di atas, kedua metrik sekarang sama, seperti seharusnya:

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.98580000000000001

# Actual accuracy calculated manually:
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98580000000000001

score[1]==acc
# True    

Pengaturan sistem:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

UPDATE : Setelah posting saya, saya menemukan bahwa masalah ini sudah diidentifikasi dalam jawaban ini .

desertnaut
sumber
1
Apakah ada yang salah dengan menggunakan loss='categorical_crossentropy', metrics=['categorical_accuracy']klasifikasi multi-kelas? Ini akan menjadi intuisi saya
NeStack
2
@NeStack Tidak hanya tidak ada yang salah, tetapi ini adalah kombinasi nominal.
desertnaut
1
Menurut apa yang Anda katakan, selama saya menggunakan loss = 'binary_crossentropy', saya akan mendapatkan pengembalian yang sama tanpa masalah saya menggunakan metrik = 'binary_accuracy' atau metrik = 'akurasi'?
BioCoder
2
@BioCoder persis
desertnaut
54

Itu semua tergantung pada jenis masalah klasifikasi yang Anda hadapi. Ada tiga kategori utama

  • klasifikasi biner (dua kelas target),
  • klasifikasi multi-kelas (lebih dari dua target eksklusif ),
  • klasifikasi multi-label (lebih dari dua target non-eksklusif ), di mana beberapa kelas target dapat diaktifkan secara bersamaan.

Dalam kasus pertama, cross-entropy biner harus digunakan dan target harus dikodekan sebagai vektor satu-panas.

Dalam kasus kedua, lintas-entropi kategoris harus digunakan dan target harus dikodekan sebagai vektor satu-panas.

Dalam kasus terakhir, cross-entropy biner harus digunakan dan target harus dikodekan sebagai vektor satu-panas. Setiap neuron output (atau unit) dianggap sebagai variabel biner acak yang terpisah, dan kehilangan untuk seluruh vektor output adalah produk dari hilangnya variabel biner tunggal. Oleh karena itu itu adalah produk dari cross-entropy biner untuk setiap unit output tunggal.

Entropi silang biner didefinisikan sebagai

masukkan deskripsi gambar di sini

dan lintas-entropi kategoris didefinisikan sebagai

masukkan deskripsi gambar di sini

di mana cindeks melebihi jumlah kelas

Whynote
sumber
Jawaban Anda menurut saya sangat benar, tapi ... Saya mencoba mengikuti jawaban @desertnaut dan melakukan tes itu: Dengan fungsi kehilangan binary_crossentropy dan metrcis ke kategorikal_accurency, saya memiliki presisi yang lebih baik yang menggunakan fungsi kerugian kategorikal_crossentropy dan metrik akurasi - dan saya tidak bisa menjelaskan itu ...
Metal3d
@ Metal3d: apa rumusan masalah Anda: multi-label atau single-label?
Whynote
label tunggal, dan sekarang saya menyadari mengapa itu bekerja lebih baik :)
Metal3d
Apakah Anda yakin bahwa entropi lintas biner dan kategoris didefinisikan seperti dalam rumus dalam jawaban ini?
nbro
@nbro, sebenarnya, cindeksnya berlebihan dalam rumus cross-entropy biner, tidak perlu ada di sana (karena hanya ada 2 kelas dan probabilitas masing-masing kelas tertanam y(x). Jika tidak, rumus-rumus itu harus benar, tetapi melihat mereka tidak kerugian, mereka adalah likelihood Jika Anda ingin kehilangan Anda harus mengambil. logini.
Whynote
40

Saya menemukan masalah "terbalik" - Saya mendapatkan hasil yang baik denganategical_crossentropy (dengan 2 kelas) dan buruk dengan binary_crossentropy. Tampaknya masalah itu dengan fungsi aktivasi yang salah. Pengaturan yang benar adalah:

  • untuk binary_crossentropy: aktivasi sigmoid, target skalar
  • untuk categorical_crossentropy: aktivasi softmax, target enkode satu-panas
Alexander Svetkin
sumber
4
Apakah Anda yakin tentang target skalar untuk binary_crossentropy. Sepertinya Anda harus menggunakan target yang disandikan "banyak-panas" (misalnya [0 1 0 0 1 1]).
Dmitry
5
Tentu. Lihat dengan keras.io/losses/#usage-of-loss-functions , katanya: "ketika menggunakan loss kategorikal_crossentropi, target Anda harus dalam format kategorikal (misalnya jika Anda memiliki 10 kelas, target untuk setiap sampel harus 10). -dimensi vektor yang semuanya nol harapkan untuk 1 pada indeks yang sesuai dengan kelas sampel) "
Alexander Svetkin
1
Tetapi kita berbicara tentang binary_crossentropy - bukanategorical_crossentropy.
Dmitry
Jawaban ini tampaknya tidak konsisten dengan stackoverflow.com/a/49175655/3924118 , di mana penulis mengatakan bahwa target harus dikodekan satu kali, sedangkan, dalam jawaban Anda, Anda menyarankan mereka harus skalar. Anda harus mengklarifikasi ini.
nbro
@AlexanderSvetkin, target harus dikodekan satu kali di mana saja, tidak hanya ketika menggunakan lintas-entropi kategoris
Whynote
28

Ini kasus yang sangat menarik. Sebenarnya dalam pengaturan Anda, pernyataan berikut ini benar:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

Ini berarti bahwa hingga faktor penggandaan konstan, kerugian Anda setara. Perilaku aneh yang Anda amati selama fase pelatihan mungkin menjadi contoh dari fenomena berikut:

  1. Pada awalnya kelas yang paling sering mendominasi kerugian - jadi jaringan belajar untuk memprediksi sebagian besar kelas ini untuk setiap contoh.
  2. Setelah mempelajari pola yang paling sering mulai membedakan kelas yang kurang sering. Tetapi ketika Anda menggunakan adam- tingkat pembelajaran memiliki nilai yang jauh lebih kecil daripada yang ada di awal pelatihan (itu karena sifat pengoptimal ini). Itu membuat pelatihan lebih lambat dan mencegah jaringan Anda dari mis. Meninggalkan minimum lokal yang buruk menjadi kurang mungkin.

Itu sebabnya faktor konstan ini dapat membantu jika terjadi binary_crossentropy. Setelah banyak zaman - nilai laju pembelajaran lebih besar daripada dalam categorical_crossentropykasus. Saya biasanya memulai kembali pelatihan (dan fase pembelajaran) beberapa kali ketika saya memperhatikan perilaku tersebut atau / dan menyesuaikan bobot kelas menggunakan pola berikut:

class_weight = 1 / class_frequency

Hal ini membuat kerugian dari kelas yang kurang sering menyeimbangkan pengaruh kerugian kelas yang dominan pada awal pelatihan dan di bagian selanjutnya dari proses optimisasi.

EDIT:

Sebenarnya - saya memeriksa itu meskipun dalam kasus matematika:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

harus memegang - dalam kasus kerasitu tidak benar, karena kerassecara otomatis menormalkan semua output untuk jumlah hingga 1. Inilah alasan sebenarnya di balik perilaku aneh ini karena dalam kasus multiklasifikasi, normalisasi seperti itu membahayakan pelatihan.

Marcin Możejko
sumber
Apakah jawaban saya membantu Anda?
Marcin Możejko
1
Ini adalah penjelasan yang sangat masuk akal. Tapi saya tidak yakin itu benar-benar alasan utama. Karena saya juga mengamati di beberapa siswa saya melakukan perilaku aneh ini ketika menerapkan binary-X-ent bukannya cat-X-ent (yang merupakan kesalahan). Dan ini benar bahkan ketika pelatihan hanya untuk 2 zaman! Menggunakan class_weight dengan prior kelas terbalik tidak membantu. Mungkin penyetelan tingkat pembelajaran yang teliti akan membantu, tetapi nilai-nilai standar tampaknya mendukung bin-X-ent. Saya pikir pertanyaan ini patut diselidiki lebih lanjut ...
xtof54
1
Tunggu, jangan minta maaf, saya tidak mendapatkan pembaruan Anda: softmax selalu membuat output berjumlah 1, jadi kami tidak peduli tentang itu? Dan mengapa pelatihan ini membahayakan, selama kita hanya memiliki satu kelas emas yang benar per contoh?
xtof54
20

Setelah mengomentari @Marcin jawaban, saya lebih hati-hati memeriksa salah satu kode siswa saya di mana saya menemukan perilaku aneh yang sama, bahkan setelah hanya 2 zaman! (Jadi penjelasan @ Marcin sangat tidak mungkin dalam kasus saya).

Dan saya menemukan bahwa jawabannya sebenarnya sangat sederhana: akurasi yang dihitung dengan metode Keras evaluatehanya salah ketika menggunakan binary_crossentropy dengan lebih dari 2 label. Anda dapat memeriksa sendiri dengan menghitung ulang keakuratannya (panggilan pertama metode Keras "memprediksi" dan kemudian menghitung jumlah jawaban yang benar yang dikembalikan oleh prediksi): Anda mendapatkan keakuratan yang sebenarnya, yang jauh lebih rendah daripada yang "dinilai" Keras.

xtof54
sumber
1
Saya melihat perilaku serupa pada iterasi pertama juga.
dolbi
10

contoh sederhana di bawah pengaturan multi-kelas untuk menggambarkan

misalkan Anda memiliki 4 kelas (satu kode dikodekan) dan di bawah ini hanya satu prediksi

true_label = [0,1,0,0] predict_label = [0,0,1,0]

saat menggunakan kategorical_crossentropy, akurasinya hanya 0, itu hanya peduli jika Anda mendapatkan kelas yang bersangkutan dengan benar.

namun ketika menggunakan binary_crossentropy, akurasi dihitung untuk semua kelas, itu akan menjadi 50% untuk prediksi ini. dan hasil akhir akan menjadi rata-rata dari akurasi individu untuk kedua kasus.

dianjurkan untuk menggunakan masalah kategorical_crossentropy untuk multi-kelas (kelas saling eksklusif) tetapi binary_crossentropy untuk masalah multi-label.

Bazinga
sumber
8

Karena ini adalah masalah multi-kelas, Anda harus menggunakan kategorical_crossentropy, entropi lintas biner akan menghasilkan hasil palsu, kemungkinan besar hanya akan mengevaluasi dua kelas pertama saja.

50% untuk masalah multi-kelas bisa sangat baik, tergantung pada jumlah kelas. Jika Anda memiliki n kelas, maka 100 / n adalah kinerja minimum yang dapat Anda peroleh dengan menghasilkan kelas acak.

Snoopy
sumber
2

saat menggunakan categorical_crossentropykerugian, target Anda harus dalam format kategorikal (misalnya jika Anda memiliki 10 kelas, target untuk setiap sampel harus berupa vektor 10 dimensi yang semuanya nol kecuali angka 1 pada indeks yang sesuai dengan kelas Sampel).

Priyansh
sumber
3
Bagaimana tepatnya ini menjawab pertanyaan?
desertnaut
2

Lihatlah persamaan Anda dapat menemukan bahwa entropi lintas biner tidak hanya menghukum label tersebut = 1, prediksi = 0, tetapi juga label = 0, prediksi = 1.

Namun lintas entropi kategoris hanya menghukum label tersebut = 1 tetapi diprediksi = 1. Itulah sebabnya kami membuat asumsi bahwa hanya ada SATU label positif.

Kuang Yan
sumber
1

Anda melewati array target bentuk (x-redup, y-redup) saat menggunakan sebagai kerugian categorical_crossentropy. categorical_crossentropymengharapkan target berupa matriks biner (1s dan 0s) dari bentuk (sampel, kelas). Jika target Anda adalah kelas integer, Anda dapat mengonversinya ke format yang diharapkan melalui:

from keras.utils import to_categorical
y_binary = to_categorical(y_int)

Atau, Anda dapat menggunakan fungsi kerugian sparse_categorical_crossentropysebagai gantinya, yang memang mengharapkan target bilangan bulat.

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
susan097
sumber
0

Binary_crossentropy (y_target, y_predict) tidak perlu diterapkan dalam masalah klasifikasi biner. .

Dalam kode sumber binary_crossentropy () , nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)fungsi TensorFlow sebenarnya digunakan. Dan, dalam dokumentasi , dikatakan bahwa:

Mengukur kesalahan probabilitas dalam tugas klasifikasi diskrit di mana setiap kelas independen dan tidak saling eksklusif. Misalnya, seseorang dapat melakukan klasifikasi multilabel di mana gambar dapat berisi gajah dan anjing secara bersamaan.

翟志伟
sumber