binary_crossentropyとcategorical_crossentropyが同じ問題に対して異なるパフォーマンスを提供するのはなぜですか?


160

CNNをトレーニングして、テキストをトピックごとに分類しようとしています。バイナリクロスエントロピーを使用すると、最大80%の精度が得られます。カテゴリカルクロスエントロピーでは、最大50%の精度が得られます。

なぜなのかわかりません。これはマルチクラスの問題です。それは、カテゴリクロスエントロピーを使用する必要があり、バイナリクロスエントロピーを使用した結果は無意味であることを意味しませんか?

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

次にcategorical_crossentropy、損失関数として次のようにコンパイルします。

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

または

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

直観的には、カテゴリカルクロスエントロピーを使用する理由は理にかなっていますが、バイナリで良い結果が得られ、カテゴリで悪い結果が得られる理由がわかりません。


10
マルチクラスの問題である場合は、を使用する必要がありますcategorical_crossentropy。また、ラベルはカテゴリー形式に変換する必要があります。to_categoricalこれを行うには参照してください。ここでは、カテゴリおよびバイナリのクロスエントロピーの定義も参照してください。
自律的な

私のラベルはカテゴリ型で、to_categoricalを使用して作成されています(クラスごとに1つのホットベクトル)。これは、バイナリクロスエントロピーの最大80%の精度が単なる偽の数値であることを意味しますか?
Daniel Messias 2017

私はそう思う。あなたは1つのホットベクトル、すなわち、カテゴリラベルを使用する場合は、したいですcategorical_crossentropy。2つのクラスがある場合、それらは0, 1バイナリラベルおよび10, 01カテゴリカルラベル形式で表されます。
自律的な

1
私は彼がベクトルの最初の数と比較し、残りを無視すると思います。
Thomas Pinetz 2017

2
@NilavBaranGhosh 2つのクラスを含むカテゴリ分類の場合、表現は[[1、0]、[0、1]]になります(言及したように[[0、0]、[0、1]]ではありません)。Dense(1, activation='softmax')バイナリ分類は単に間違っています。softmax出力は、合計が1になる確率分布であることを覚えておいてください。バイナリ分類の出力ニューロンを1つだけにする場合は、バイナリクロスエントロピーのシグモイドを使用します。
自律

回答:


204

カテゴリカルとバイナリのクロスエントロピーの間にこの明らかなパフォーマンスの不一致がある理由は、ユーザーxtof54が以下の回答ですでに報告したものです。

evaluate2つ以上のラベルを持つbinary_crossentropyを使用する場合、Keras メソッドで計算された精度は明らかに間違っています

これについて詳しく説明し、実際の根本的な問題を示し、それを説明し、解決策を提供したいと思います。

この動作はバグではありません。根本的な理由は、モデルのコンパイルに単純に含める場合、選択した損失関数に応じて、Kerasが実際にどの精度を使用するかを推測する、かなり微妙で文書化されていない問題metrics=['accuracy']です。つまり、最初のコンパイルオプション

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

有効です、2番目のもの:

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

期待どおりの結果は得られませんが、その理由はバイナリクロスエントロピーの使用ではありません(少なくとも原則として、これは絶対的に有効な損失関数です)。

何故ですか?あなたがチェックした場合のメトリックのソースコードを、Kerasは、メトリック、単一の精度を定義しますが、いくつかの異なるもの、それらの間はありませんbinary_accuracycategorical_accuracyフードの下で何が起こるかというと、損失関数としてバイナリクロスエントロピーを選択し、特定の精度メトリックを指定していないため、Keras(間違って...)は、あなたがに興味があると推測しbinary_accuracy、これが返すものです-実際、あなたはに興味がありcategorical_accuracyます。

KerasのMNIST CNNの例を使用して、次の変更を加えて、これが当てはまることを確認します。

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    

これを修正するには、つまり、実際にバイナリクロスエントロピーを損失関数として使用し(私が言ったように、少なくとも原則としてこれには何も問題はありません)、手元の問題で必要とされるカテゴリカルな精度を取得するにcategorical_accuracyは、次のようにモデルのコンパイル:

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

MNISTの例では、上で示したようにテストセットをトレーニング、スコアリング、および予測した後、2つのメトリックは同じになるはずです。

# 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    

システム設定:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

更新:私の投稿の後に、この問題がこの回答ですでに特定されていることがわかりました


1
loss='categorical_crossentropy', metrics=['categorical_accuracy']マルチクラス分類に使用して何か問題がありますか?これは私の直感でしょう
NeStack

2
@NeStack何も問題がないだけでなく、これは名目上の組み合わせです。
砂漠の飛行士

1
あなたが言ったことによると、私がloss = 'binary_crossentropy'を使用している限り、同じ戻り値は得られません。
BioCoder

2
@BioCoder正確
desertnaut

54

それはすべて、あなたが扱っている分類問題のタイプに依存します。3つの主なカテゴリがあります

  • バイナリ分類(2つのターゲットクラス)、
  • マルチクラス分類(3つ以上の排他的ターゲット)、
  • マルチラベル分類(3つ以上の非排他的ターゲット)。複数のターゲットクラスを同時にオンにすることができます。

最初のケースでは、バイナリクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。

2番目のケースでは、カテゴリカルクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。

最後のケースでは、バイナリクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。各出力ニューロン(またはユニット)は個別のランダムバイナリ変数と見なされ、出力のベクトル全体の損失は単一のバイナリ変数の損失の積です。したがって、これは、各単一出力ユニットのバイナリクロスエントロピーの積です。

バイナリクロスエントロピーは次のように定義されます。

ここに画像の説明を入力してください

そして、カテゴリーのクロスエントロピーは次のように定義されます

ここに画像の説明を入力してください

cクラスの数に対して実行されているインデックスはどこですか


あなたの答えは私には本当のようですが...私は@desertnautの答えを試してそのテストを行いました:categorical_accurencyへのbinary_crossentropy損失関数とメトリスを使用すると、categorical_crossentropy損失関数と精度メトリックスを使用するよりも精度が高くなります-説明できませんthat ...
Metal3d 2018年

@ Metal3d:問題の定式化は何ですか:マルチラベルまたはシングルラベル?
Whynote 2018年

シングルレーベル、そしてそれがなぜうまくいくのか今では気づきました:)
Metal3d 2018年

バイナリおよびカテゴリーのクロスエントロピーがこの回答の式のように定義されていることを確認しますか?
nbro

@nbro、実際には、cインデックスはバイナリクロスエントロピーの式では冗長y(x)です。クラスは2つしかなく、各クラスの確率はに埋め込まれているため、存在する必要はありません。それ以外の場合、これらの式は正しいはずですが、予告ものは、それらが尤度あり、損失はありませんあなたは損をしたい場合は、あなたが取る必要がある。logこれらの。
Whynote

40

「逆転した」問題に遭遇しました—(2つのクラスで)categorical_crossentropyで良い結果が得られ、binary_crossentropyで悪い結果が出ていました。アクティベーション機能に問題があったようです。正しい設定は次のとおりです。

  • for binary_crossentropy:シグモイドアクティベーション、スカラーターゲット
  • 対象categorical_crossentropy:softmaxアクティベーション、ワンホットエンコードターゲット

4
binary_crossentropyのスカラーターゲットについて確信がありますか?「非常にホットな」エンコードされたターゲット([0 1 0 0 1 1]など)を使用する必要があるようです。
ドミトリー

5
承知しました。keras.io/losses/#usage-of-loss-functionsを参照してください:「categorical_crossentropy損失を使用する場合、ターゲットはカテゴリ形式である必要があります(たとえば、クラスが10の場合、各サンプルのターゲットは10でなければなりませんすべてゼロの3次元ベクトルは、サンプルのクラスに対応するインデックスで1を期待します) "
Alexander Svetkin

1
ただし、categorical_crossentropyではなく、binary_crossentropyについて話しています。
ドミトリー

この回答はstackoverflow.com/a/49175655/3924118と一致していないようです。著者はターゲットをワンホットエンコードする必要があると述べていますが、回答では、それらはスカラーである必要があることを示唆しています。これを明確にする必要があります。
nbro

@AlexanderSvetkin、ターゲットは、カテゴリカルクロスエントロピーを使用するときだけでなく、どこでもワンホットエンコードされる必要があります
Whynote

28

それは本当に面白いケースです。実際の設定では、次のことが当てはまります。

binary_crossentropy = len(class_id_index) * categorical_crossentropy

これは、一定の増倍率まで、損失は同等であることを意味します。トレーニングフェーズ中に観察している奇妙な動作は、次の現象の例である可能性があります。

  1. 最初は、最も頻度の高いクラスが損失を支配しているため、ネットワークはすべての例でこのクラスをほとんど予測することを学習しています。
  2. 最も頻度の高いパターンを学習した後、頻度の低いクラスを区別し始めます。しかし、使用しているときadam-学習率は、トレーニングの最初の値よりもはるかに小さい値です(これは、このオプティマイザの性質によるものです)。これにより、トレーニングが遅くなり、ネットワークがローカルミニマムを低くするなどの可能性が低くなります。

このため、この定数係数は、 binary_crossentropyます。多くのエポックの後-学習率の値はcategorical_crossentropyケースよりも大きくなります。私は通常、そのような動作に気づいたり、次のパターンを使用してクラスの重みを調整したりしたときに、トレーニング(および学習フェーズ)を数回再開します。

class_weight = 1 / class_frequency

これにより、トレーニングの開始時と最適化プロセスのさらなる部分で、支配的なクラスの損失の影響のバランスをとる、頻度の低いクラスからの損失が発生します。

編集:

実際-私は数学の場合でもそれをチェックしました:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

保持する必要があります- kerasそれが真でない場合、kerasすべての出力を自動的に正規化して合計し1ます。これは、このような異常な動作の背後にある実際の理由です。複数分類の場合、そのような正規化はトレーニングに悪影響を及ぼします。


私の答えはあなたを助けましたか?
MarcinMożejko2017

1
これは非常にもっともらしい説明です。しかし、それが主な理由かどうかはわかりません。cat-X-entの代わりにbinary-X-entを適用すると、いくつかの生徒がこの奇妙な動作をすることも観察したためです(これは誤りです)。そして、これは2エポックのみのトレーニングの場合にも当てはまります。逆クラス事前分布でclass_weightを使用しても効果がありませんでした。学習率の厳密な調整が役立つ場合がありますが、デフォルト値はbin-X-entを優先するようです。この質問はもっと調査に値すると思います...
xtof54

1
待ってください、申し訳ありませんが、更新はありません。softmaxは常に出力の合計を1にするので、気にしませんか?そして、例ごとに正しいゴールドクラスが1つしかないのに、なぜこのトレーニングが害になるのでしょうか。
xtof54 2017年

20

@Marcinの回答にコメントした後、わずか2エポック後でも、同じ奇妙な動作を見つけた生徒のコードの1つをより注意深くチェックしました。(したがって、@ Marcinの説明は、私の場合はあまりありませんでした)。

そして、私は答えが実際には非常に単純であることを発見しました:evaluate2つを超えるラベルでbinary_crossentropyを使用する場合、Keras メソッドで計算された精度はまったく間違っています。精度を自分で再計算することで確認できます(最初にKerasのメソッド "predict"を呼び出して、predictから返される正解の数を計算します)。真の精度が得られます。


1
最初の反復でも同様の動作が見られました。
dolbi 2017

10

説明するためのマルチクラス設定での簡単な例

4つのクラス(onehotエンコード)があり、以下は1つの予測にすぎないとします

true_label = [0,1,0,0] predicted_label = [0,0,1,0]

categorical_crossentropyを使用する場合、精度は0になり、関係するクラスを正しく取得するかどうかのみが考慮されます。

ただし、binary_crossentropyを使用する場合、精度はすべてのクラスに対して計算され、この予測では50%になります。最終結果は、両方の場合の個々の精度の平均になります。

マルチクラス(クラスは相互に排他的)の問題にはcategorical_crossentropyを使用することをお勧めしますが、マルチラベルの問題にはbinary_crossentropyを使用することをお勧めします。


8

これはマルチクラスの問題であるため、categorical_crossentropyを使用する必要があります。バイナリクロスエントロピーは偽の結果を生成し、おそらく最初の2つのクラスのみを評価します。

マルチクラス問題の50%は、クラスの数によってはかなり良い場合があります。n個のクラスがある場合、ランダムなクラスを出力することで得られる最小パフォーマンスは100 / nです。


2

categorical_crossentropy損失を使用する場合、ターゲットはカテゴリ形式でなければなりません(たとえば、クラスが10の場合、各サンプルのターゲットは、クラスのクラスに対応するインデックスの1を除いてすべてゼロの10次元ベクトルでなければなりません。サンプル)。


3
これはどれほど正確に質問に答えますか?
砂漠の飛行士


1

lossとして使用しているときに、形状(x-dim、y-dim)のターゲット配列を渡していますcategorical_crossentropycategorical_crossentropyターゲットは形状(サンプル、クラス)のバイナリ行列(1と0)であると想定しています。ターゲットが整数クラスの場合は、次の方法でそれらを期待される形式に変換できます。

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

または、sparse_categorical_crossentropy代わりに損失関数を使用できます。これは、整数ターゲットを想定しています。

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

0

binary_crossentropy(y_target、y_predict)は、バイナリ分類問題に適用する必要はありません。。

binary_crossentropy()のソースコードでは、nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)TensorFlow関数が実際に使用されていました。そして、ドキュメントでは、それは言う:

各クラスが独立していて相互に排他的ではない離散分類タスクの確率誤差を測定します。たとえば、画像に象と犬の両方を同時に含めることができるマルチラベル分類を実行できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.