Neden binary_crossentropy ve categorical_crossentropy aynı problem için farklı performanslar veriyor?


160

Metni konuya göre sınıflandırmak için bir CNN eğitmeye çalışıyorum. İkili çapraz entropi kullandığımda ~% 80 doğruluk elde ediyorum, kategorik çapraz entropi ile ~% 50 doğruluk elde ediyorum.

Bunun neden olduğunu anlamıyorum. Bu çok sınıflı bir sorun, kategorik çapraz entropi kullanmak zorunda olduğum ve ikili çapraz entropi ile sonuçların anlamsız olduğu anlamına gelmiyor mu?

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'))

Sonra ben ya categorical_crossentropykayıp fonksiyonu olarak kullanarak böyle derlemek :

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

veya

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

Sezgisel olarak neden kategorik çapraz entropiyi kullanmak istediğimi anlamıyorum, ikili ile neden iyi, kategorik ile kötü sonuçlar aldığımı anlamıyorum.


10
Çok sınıflı bir sorunsa kullanmanız gerekir categorical_crossentropy. Ayrıca etiketlerin kategorik biçime dönüştürülmesi gerekir. to_categoricalBunu yapmak için bakın . Ayrıca burada kategorik ve ikili çapraz geçişlerin tanımlarına bakınız .
Özerk

Etiketlerim kategoriktir, to_categorical (her sınıf için bir sıcak vektör) kullanılarak oluşturulur. Bu ikili çapraz-entropiden ~% 80 doğruluk sadece sahte bir sayı anlamına mı geliyor?
Daniel Messias

Sanırım. Kategorik etiketleri yani bir sıcak vektör kullanıyorsanız, o zaman istersiniz categorical_crossentropy. İki sınıfınız varsa, bunlar 0, 1ikili etiketlerde ve 10, 01kategorik etiket biçiminde temsil edilir .
Özerk

1
Bence sadece vektördeki ilk sayı ile karşılaştırıyor ve gerisini görmezden geliyor.
Thomas Pinetz

2
@NilavBaranGhosh Temsil, iki sınıfı içeren kategorik bir sınıflandırma için [[1, 0], [0, 1]] olacaktır (bahsettiğiniz gibi [[0, 0], [0, 1]] değil). Dense(1, activation='softmax')çünkü ikili sınıflandırma yanlıştır. Unutmayın, softmax çıkışı bire denk gelen bir olasılık dağılımıdır. İkili sınıflandırmaya sahip yalnızca bir çıkış nöronuna sahip olmak istiyorsanız, ikili çapraz entropili sigmoid kullanın.
Otonom

Yanıtlar:


204

Kategorik ve ikili çapraz entropi arasındaki bu bariz performans çelişkinin nedeni kullanıcı xtof54 zaten rapor verdi budur altında onun cevabını , yani:

evaluate2'den fazla etiketi olan binary_crossentropy kullanılırken Keras yöntemiyle hesaplanan doğruluk çok basit

Bu konuyla ilgili daha fazla ayrıntı vermek, temeldeki meseleyi göstermek, açıklamak ve bir çözüm sunmak istiyorum.

Bu davranış bir hata değildir; bunun altında yatan neden, sadece model derlemenize dahil ettiğinizde, seçtiğiniz kayıp fonksiyonuna bağlı olarak, Keras'ın hangi doğruluğu kullanacağını gerçekten tahmin etmesinde oldukça ince ve belgelenmemiş bir konudur metrics=['accuracy']. Başka bir deyişle, ilk derleme seçeneğiniz

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

geçerli, ikinciniz:

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

beklediğiniz şeyi üretmeyecektir, ancak bunun nedeni ikili çapraz entropinin (en azından prensipte kesinlikle geçerli bir kayıp fonksiyonudur) kullanılması değildir.

Neden? Metriklerin kaynak kodunu kontrol ederseniz , Keras tek bir doğruluk metriği tanımlamaz, ancak aralarında binary_accuracyve categorical_accuracy. Ne olur kaputun altında size zarar fonksiyonu olarak ikili çapraz entropi seçmiş ve belirli doğruluk metrik (yanlış ...) infers sen ilgilenen olduğunu keras belirtilmemiş beri, yani binary_accuracy, ve bu döndürür budur - aslında ilginizi çekerkencategorical_accuracy .

Aşağıdaki değişiklikle Keras'taki MNIST CNN örneğini kullanarak durumun böyle olduğunu doğrulayalım :

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    

Bunu düzeltmek için, yani gerçekten ikili çapraz entropiyi kayıp fonksiyonunuz olarak kullanmak için (dediğim gibi, bununla ilgili yanlış bir şey, en azından prensip olarak), yine de problemin gerektirdiği kategorik doğruluğu elde ederken categorical_accuracy, model derleme aşağıdaki gibi:

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

MNIST örneğinde, yukarıda gösterdiğim gibi test setini antrenman, puanlama ve tahmin ettikten sonra, şimdi iki ölçüm şu olması gerektiği gibi aynıdır:

# 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    

Sistem kurulumu:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

GÜNCELLEME : Görevimden sonra, bu sorunun bu cevapta zaten tespit edildiğini keşfettim .


1
Çok loss='categorical_crossentropy', metrics=['categorical_accuracy']sınıflı sınıflandırmada kullanımla ilgili bir sorun mu var ? Bu benim sezgim olurdu
NeStack

2
@NeStack Sadece yanlış bir şey yok, ama bu nominal kombinasyon.
desertnaut

1
Söylediklerinize göre, kayıp = 'binary_crossentropy' kullandığım sürece, aynı getirileri elde edeceğim daha önemli değil metrikler = 'binary_accuracy' veya metrics = 'accuracy'?
BioCoder

2
@BioCoder tam olarak
desertnaut

54

Her şey uğraştığınız sınıflandırma sorununun türüne bağlıdır. Üç ana kategori vardır

  • ikili sınıflandırma (iki hedef sınıf),
  • çok sınıflı sınıflandırma (ikiden fazla özel hedef),
  • birden fazla hedef sınıfın aynı anda açık olabileceği çoklu etiket sınıflandırması (ikiden fazla münhasır olmayan hedef).

İlk durumda, ikili çapraz entropi kullanılmalı ve hedefler tek sıcak vektörler olarak kodlanmalıdır.

İkinci durumda, kategorik çapraz entropi kullanılmalı ve hedefler tek sıcak vektörler olarak kodlanmalıdır.

Son durumda, ikili çapraz entropi kullanılmalı ve hedefler tek sıcak vektörler olarak kodlanmalıdır. Her çıkış nöronu (veya birimi) ayrı bir rastgele ikili değişken olarak kabul edilir ve çıkışların tüm vektörü için kayıp, tekli ikili değişkenlerin kaybının ürünüdür. Bu nedenle, her bir çıktı birimi için ikili çapraz entropinin ürünüdür.

İkili çapraz entropi şu şekilde tanımlanır:

resim açıklamasını buraya girin

ve kategorik çapraz entropi şu şekilde tanımlanır:

resim açıklamasını buraya girin

nerede cendeks sınıflarının sayısı üzerinden çalışıyor


Cevabınız bana çok doğru görünüyor, ama ... @desertnaut cevabını takip etmeye çalıştım ve şu testleri yaptım: binary_crossentropy kayıp fonksiyonu ve categorical_accurency metrcis ile kategorik_crossentropy kayıp fonksiyonu ve accurency metrikleri kullanarak daha iyi bir hassasiyet var - ve açıklayamam bu ...
Metal3d

@ Metal3d: probleminizin formülasyonu nedir: çoklu etiket veya tek etiket?
Whynote

tek etiketli ve şimdi bunun neden daha iyi çalıştığını
anlıyorum

İkili ve kategorik çapraz entropilerin bu cevaptaki formüllerde olduğu gibi tanımlandığından emin misiniz?
nbro

@nbro, aslında, cindeks ikili çapraz entropi formülünde gereksizdir, orada olması gerekmez (çünkü sadece 2 sınıf olduğundan ve her sınıfın olasılığı gömülüdür y(x). Aksi takdirde bu formüller doğru olmalıdır, ancak farkına log
varmayın

40

"Ters" bir sorunla karşılaştım - categorical_crossentropy (2 sınıf) ile iyi sonuçlar ve binary_crossentropy ile kötü sonuçlar alıyordum. Sorun yanlış aktivasyon fonksiyonu ile ilgili gibi görünüyor. Doğru ayarlar:

  • için binary_crossentropy: sigmoid aktivasyonu, skaler hedef
  • için categorical_crossentropy: softmax aktivasyonu, bir sıcak kodlanmış hedef

4
Binary_crossentropy için skaler hedef olduğundan emin misiniz? Görünüşe göre "çok sıcak" olarak kodlanmış hedef kullanmalısınız (örn. [0 1 0 0 1 1]).
Dmitry

5
Elbette. Bkz. Keras.io/losses/#usage-of-loss-functions , diyor ki: "categorical_crossentropy kaybını kullanırken, hedefleriniz kategorik formatta olmalıdır (örneğin 10 sınıfınız varsa, her örnek için hedef 10 olmalıdır sıfırlar olan üç boyutlu vektör, örnek sınıfına karşılık gelen dizinde bir 1 bekler) "
Alexander Svetkin

1
Ancak kategorik_krosentropi hakkında değil binary_krosentropi hakkında konuşuyoruz.
Dmitry

Bu yanıt , yazarın hedeflerin bir sıcak kodlanmış olması gerektiğini söylerken stackoverflow.com/a/49175655/3924118 ile tutarsız görünüyor , cevabınızda skaler olmalarını öneriyorsunuz. Bunu açıklığa kavuşturmalısınız.
nbro

@AlexanderSvetkin, hedef sadece kategorik çapraz entropi kullanırken değil, her yerde bir sıcak kodlanmış olmalıdır
Whynote

28

Gerçekten ilginç bir durum. Aslında kurulumunuzda aşağıdaki ifade doğrudur:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

Bu, sabit bir çarpma faktörüne kadar kayıplarınızın eşdeğer olduğu anlamına gelir. Bir eğitim aşamasında gözlemlediğiniz garip davranış, aşağıdaki bir fenomene örnek olabilir:

  1. Başlangıçta en sık görülen sınıf zarara hükmeder - bu nedenle ağ her örnek için çoğunlukla bu sınıfı tahmin etmeyi öğrenir.
  2. En sık rastlanan modeli öğrendikten sonra daha az sıklıkta yapılan sınıflar arasında ayrım yapmaya başlar. Ancak, kullandığınızda adam- öğrenme oranı, eğitimin başlangıcındakinden çok daha küçük bir değere sahiptir (bunun nedeni bu optimize edicinin doğası gereğidir). Bu, eğitimi yavaşlatır ve ağınızın, örneğin zayıf bir yerel minimum değeri daha az olası bırakmasını önler.

Bu nedenle bu sabit faktör yardımcı olabilir binary_crossentropy. Birçok çağdan sonra - öğrenme oranı değeri durumdan daha büyüktür categorical_crossentropy. Bu tür davranışları fark ettiğimde ve / ve aşağıdaki paterni kullanarak bir sınıf ağırlığını ayarladığımda eğitimi (ve öğrenme aşamasını) birkaç kez yeniden başlatırım:

class_weight = 1 / class_frequency

Bu, egzersizin başında ve bir optimizasyon sürecinin diğer bir bölümünde baskın bir sınıf kaybının etkisini dengeleyen daha az sıklıkta sınıflardan kayıp yapar.

DÜZENLE:

Aslında - matematik olsa bile kontrol ettim:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

tutacaktır - kerasdoğru değilse, kerastüm çıktıları otomatik olarak normalleştirecektir 1. Bu garip davranışın arkasındaki asıl sebep budur, çünkü çok sınıflandırma durumunda bu normalleştirme bir eğitime zarar verir.


Cevabım size yardımcı oldu mu?
Marcin Możejko

1
Bu çok akla yatkın bir açıklama. Ama bunun ana nedeni olduğundan emin değilim. Çünkü bazı öğrencilerimde, cat-X-ent yerine binary-X-ent uygularken bu garip davranışı gözlemledim (bu bir hatadır). Ve bu sadece 2 dönem antrenman yaparken bile geçerlidir! Class_weight öğesini ters sınıf öncelikleriyle kullanmak yardımcı olmadı. Öğrenme hızının titiz bir şekilde ayarlanması yardımcı olabilir, ancak varsayılan değerler bin-X-ent'i destekliyor gibi görünüyor. Sanırım bu soru daha fazla araştırmayı hak ediyor ...
xtof54

1
Bekle, özür dilerim, güncellemeni almıyorum: softmax her zaman çıktıların toplamını 1 yapıyor, bu yüzden umursamıyoruz? Ve örnek başına doğru olan tek bir altın sınıfımız olduğu sürece bu eğitime neden zarar veriyor?
xtof54

20

@Marcin cevabını yorumladıktan sonra, öğrencilerimin kodlarından birini, sadece 2 dönemden sonra bile aynı garip davranışı bulduğumdan daha dikkatli bir şekilde kontrol ettim! (Yani Marcin'in açıklaması benim durumumda pek olası değildi).

Ve cevabın aslında çok basit olduğunu gördüm: evaluateKeras yöntemiyle hesaplanan doğruluk , 2'den fazla etiketli binary_crossentropy kullanırken oldukça yanlış. Doğruluğu kendiniz yeniden hesaplayarak kontrol edebilirsiniz (önce Keras yöntemini "tahmin" olarak adlandırın ve sonra tahminle döndürülen doğru cevapların sayısını hesaplayın): Keras'ın "değerlendirdiğinden" çok daha düşük olan gerçek doğruluğu elde edersiniz.


1
İlk yinelemede de benzer davranışlar gördüm.
dolbi

10

göstermek için çok sınıflı bir ayar altında basit bir örnek

4 sınıfınız olduğunu varsayalım (onehot kodlanmış) ve aşağıda sadece bir tahmin var

true_label = [0,1,0,0] tahmin edilen_label = [0,0,1,0]

categorical_crossentropy kullanırken, doğruluk sadece 0'dır, sadece ilgili sınıfı doğru anlarsanız önemser.

ancak binary_crossentropy kullanılırken doğruluk tüm sınıflar için hesaplanır, bu tahmin için% 50 olur. ve nihai sonuç her iki durum için de bireysel doğrulukların ortalaması olacaktır.

çoklu sınıf (sınıflar birbirini dışlar) problemi için categorical_crossentropy, çoklu etiket problemi için binary_crossentropy kullanılması önerilir.


8

Çok sınıflı bir sorun olduğu için, categorical_crossentropy'yi kullanmalısınız, ikili çapraz entropi sahte sonuçlar üretecektir, büyük olasılıkla sadece sadece ilk iki sınıfı değerlendirecektir.

Çok sınıflı bir problem için% 50, sınıf sayısına bağlı olarak oldukça iyi olabilir. N sınıfınız varsa, rastgele bir sınıf çıkararak alabileceğiniz minimum performans 100 / n olur.


2

categorical_crossentropykaybı kullanırken hedefleriniz kategorik formatta olmalıdır (örneğin 10 sınıfınız varsa, her bir örnek için hedef, örneklem).


3
Bu soruyu tam olarak nasıl cevaplıyor?
desertnaut

2

Bu ikili çapraz entropiyi bulabileceğiniz denkleme bir göz atın sadece = 0 öngörülen bu etiket = 1, cezalandırmak değil, aynı zamanda = 0, = 1 tahmin etiketleyin.

Ancak kategorik çapraz entropi sadece = 1 etiketini cezalandırır ancak öngörülen = 1'dir. Bu yüzden sadece ONE etiketinin pozitif olduğunu varsayıyoruz.


1

Kayıp olarak kullanırken hedef bir şekil dizisi (x-dim, y-dim) geçiriyorsunuz categorical_crossentropy. categorical_crossentropyHedeflerin ikili matrisler (1s ve 0s) şeklinde (örnekler, sınıflar) olmasını bekler. Hedefleriniz tamsayı sınıflarıysa, bunları aşağıdaki biçime göre beklenen biçime dönüştürebilirsiniz:

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

Alternatif olarak, sparse_categorical_crossentropybunun yerine tamsayı hedefleri bekleyen kayıp işlevini kullanabilirsiniz .

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

0

Binary_crossentropy'nin (y_target, y_predict) ikili sınıflandırma probleminde uygulanması gerekmez. .

Kaynak kodunda binary_crossentropy () , nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)TensorFlow işlevi aslında kullanıldı. Ve belgelerde şöyle diyor:

Her sınıfın bağımsız olduğu ve birbirini dışlamadığı ayrı sınıflandırma görevlerindeki olasılık hatasını ölçer. Örneğin, bir resmin aynı anda hem fil hem de köpek içerebileceği çok etiketli sınıflandırma yapılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.