1. ホーム
  2. machine-learning

[解決済み】同じ問題で binary_crossentropy と categorical_crossentropy が異なる性能を示すのはなぜか?

2022-04-13 04:34:18

質問

私は、テキストをトピックごとに分類する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'])

直感的には、なぜカテゴリカルクロスエントロピーを使いたいのか理解できるのですが、なぜバイナリで良い結果が得られ、カテゴリカルで悪い結果が得られるのか理解できません。

どのように解決するのですか?

バイナリクロスエントロピーとカテゴリカルクロスエントロピーの性能差の原因は、ユーザーxtof54がすでに 彼の回答は以下の通りです。 すなわち

Kerasのメソッドで計算された精度 evaluate は、単に 2つ以上のラベルでbinary_crossentropyを使用した場合、間違っています。

もっと詳しく、実際に根本的な問題を示し、それを説明し、改善策を提示したいと思います。

この動作はバグではありません。根本的な理由は、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 .

ということを検証してみましょう。 MNIST CNNの例 をKerasで実行し、以下のように修正しました。

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

アップデイト : 投稿後、この問題がすでに この回答 .