トピックごとにテキストを分類するようにCNNをトレーニングしようとしています。 binary_crossentropyを使用すると、80%のaccが得られ、Categorical_crossentropの場合、50%のaccが得られます。
これがなぜなのかわかりません。それはマルチクラスの問題です、それは私がカテゴリカルを使用しなければならないことを意味し、バイナリの結果は無意味ですか?
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'))
それから
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'])
は期待したものを生成しませんが、その理由はバイナリクロスエントロピーの使用ではありません(少なくとも原理的には、完全に有効な損失関数です)。
何故ですか? metrics source code をチェックすると、Kerasは単一の精度メトリックを定義しませんが、binary_accuracy
およびcategorical_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精度を得ながら、バイナリ関数のクロスエントロピーを損失関数として使用します(少なくとも原則としてこれは問題ではありません)。次のようにモデルのコンパイルで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
UPDATE:投稿後、この問題は this answer で既に特定されていることがわかりました。
本当に面白いケースです。実際にあなたの設定では、次のことが当てはまります。
binary_crossentropy = len(class_id_index) * categorical_crossentropy
これは、損失が一定の乗数までは等価であることを意味します。トレーニング段階で観察している奇妙な行動は、次のような現象の一例です。
adam
を使用している場合、学習率はトレーニングの開始時よりもずっと小さい値になります(これはこのオプティマイザの性質によるものです)。それはトレーニングを遅くし、あなたのネットワークが貧弱な極小値を残す可能性が低くなります。binary_crossentropy
の場合、この定数の要素が役立つのはそのためです。多くのエポックの後 - 学習率の値はcategorical_crossentropy
の場合よりも大きくなります。このような行動に気付いたとき、または次のパターンを使用してクラスの重みを調整したときに、通常、トレーニング(および学習段階)を数回再開します。
class_weight = 1 / class_frequency
これは、訓練の開始時および最適化プロセスのさらなる部分において支配的なクラスの損失の影響をバランスさせる、それほど頻繁ではないクラスからの損失を生じさせる。
編集:
実際 - 数学の場合であっても、私はそれをチェックしました:
binary_crossentropy = len(class_id_index) * categorical_crossentropy
keras
は自動的にすべての出力を正規化して1
になるように正規化するため、keras
の場合は正しくありません。これはこのような奇妙な振る舞いの背後にある実際の理由です。多重分類の場合、このような正規化はトレーニングに害を与えるからです。
「反転」問題に遭遇しました。(2つのクラスを含む)Categorical_crossentropyでは良い結果が得られ、binary_crossentropyでは悪い結果が得られました。問題は間違った起動機能にあるようです。正しい設定は次のとおりです。
binary_crossentropy
:シグモイド活性化、スカラーターゲットcategorical_crossentropy
の場合:softmaxアクティベーション、ワンホットエンコードターゲットそれはすべてあなたが扱っている分類問題の種類によります。主に3つのカテゴリがあります。
前者の場合、バイナリクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。
2番目のケースでは、カテゴリカルクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。
最後のケースでは、バイナリクロスエントロピーを使用し、ターゲットをワンホットベクトルとしてエンコードする必要があります。各出力ニューロン(またはユニット)は、個別のランダムバイナリ変数と見なされ、出力ベクトル全体に対する損失は、単一バイナリ変数の損失の積になります。それ故、それは各単一出力ユニットに対する2進クロスエントロピーの積である。
バイナリクロスエントロピーはそのように定義されます: バイナリクロスエントロピー そしてカテゴリカルクロスエントロピーはそのように定義されます: カテゴリクロスエントロピー
@Marcinの答えをコメントした後、私は2つのエポックの後でさえも、私が同じ奇妙なふるまいを見つけた私の学生のコードの1つをもっと注意深くチェックしました! (つまり、@ Marcinの説明は私の場合はあまりありませんでした)。
そして、答えは実際には非常に単純であることがわかりました。Kerasの方法evaluate
で計算された精度は、2つ以上のラベルを持つbinary_crossentropyを使用する場合には明らかに間違っています。あなたは自分自身で精度を再計算することでそれをチェックすることができます(最初にKerasのメソッド "predict"を呼び出し、次にpredictから返される正解の数を計算します):あなたは真の精度を得ます。
説明するためのマルチクラス設定の下の簡単な例
4つのクラス(onehot encoded)があり、以下が1つの予測であるとします。
true_label = [0,1,0,0] predict_label = [0,0,1,0]
categorical_crossentropyを使うとき、正確さはちょうど0です、それはあなたが関係するクラスを正しく得たかどうかだけ気にします。
ただし、binary_crossentropyを使用すると、精度はすべてのクラスに対して計算され、この予測では50%になります。そして最終的な結果は、どちらの場合も個々の精度の平均になります。
複数クラス(クラスは相互に排他的)の問題にはCategorical_crossentropyを使用し、複数ラベルの問題にはbinary_crossentropyを使用することをお勧めします。
これはマルチクラスの問題であるため、Categorical_crossentropyを使用する必要があります。バイナリクロスエントロピーでは偽の結果が生成され、最初の2つのクラスのみが評価される可能性があります。
マルチクラス問題の50%は、クラスの数によっては、かなり良い場合があります。 n個のクラスがある場合、100/nはランダムクラスを出力することによって得られる最小のパフォーマンスです。
categorical_crossentropy
の損失を使用する場合、ターゲットはカテゴリカル形式にする必要があります(たとえば、10個のクラスがある場合、各サンプルのターゲットは、次のクラスに対応するインデックスの1を除くすべてゼロの10次元ベクトルになります。標本、見本)。
categorical_crossentropy
を損失として使用している間、形状(x-dim、y-dim)のターゲット配列を渡しています。 categorical_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'])
式を見ると、 バイナリクロスエントロピー だけでなく、それらのラベル= 1、予測= 0、ラベル= 0、予測= 1も罰せられます。
しかし カテゴリカルクロスエントロピー はそれらのラベルを1だけ罰するが予測は1にします。それで、1つのラベルのみがポジティブであると仮定します。