Keras:大一次编码:binary_crossentropy或categorical_crossentropy

Tut*_*non 1 python machine-learning neural-network deep-learning keras

我正在训练一个文本分类模型,其中输入数据包含4096个词频-反向文档频率。

我的输出是416个可能的类别。每段数据都有3个类别,因此在413个零(单热编码)数组中有3个类别

我的模型如下所示:

model = Sequential()
model.add(Dense(2048, activation="relu", input_dim=X.shape[1]))
model.add(Dense(512, activation="relu"))
model.add(Dense(416, activation="sigmoid"))
Run Code Online (Sandbox Code Playgroud)

当我进行binary_crossentropy损失训练时,经过一个时期后,损失为0.185,准确度为96%。5个历元后,损耗为0.037,精度为99.3%。我猜这是错误的,因为我的标签中有很多0,可以正确分类。

当我进行categorical_crossentropy损失训练时,它在前几个时期的损失为15.0,准确度低于5%,而在经过数个(超过50个)时期的损失为5.0,准确度为12%之前。

其中哪一种最适合我的情况(带有多个1的大型一键编码)?这些分数告诉我什么?

编辑:这些是model.compile()语句:

model.compile(loss='categorical_crossentropy',
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)

model.compile(loss='binary_crossentropy',
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)

des*_*aut 5

In short: the (high) accuracy reported when you use loss='binary_crossentropy' is not the correct one, as you already have guessed. For your problem, the recommended loss is categorical_crossentropy.


In long:

The underlying reason for this behavior is a rather subtle & undocumented issue at how Keras actually guesses which accuracy to use, depending on the loss function you have selected, when you include simply metrics=['accuracy'] in your model compilation, as you have. In other words, while your first compilation option

model.compile(loss='categorical_crossentropy',
          optimizer=keras.optimizers.Adam(),
          metrics=['accuracy']
Run Code Online (Sandbox Code Playgroud)

is valid, your second one:

model.compile(loss='binary_crossentropy',
          optimizer=keras.optimizers.Adam(),
          metrics=['accuracy'])
Run Code Online (Sandbox Code Playgroud)

will not produce what you expect, but the reason is not the use of binary cross entropy (which, at least in principle, is an absolutely valid loss function).

Why is that? If you check the metrics source code, Keras does not define a single accuracy metric, but several different ones, among them binary_accuracy and categorical_accuracy. What happens under the hood is that, since you have selected loss='binary_crossentropy' and have not specified a particular accuracy metric, Keras (wrongly...) infers that you are interested in the binary_accuracy, and this is what it returns - while in fact you are interested in the categorical_accuracy.

Let's verify that this is the case, using the MNIST CNN example in Keras, with the following modification:

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    
Run Code Online (Sandbox Code Playgroud)

Arguably, the verification of the above behavior with your own data should be straightforward.

And just for the completeness of the discussion, if, for whatever reason, you insist in using binary cross entropy as your loss function (as I said, nothing wrong with this, at least in principle) while still getting the categorical accuracy required by the problem at hand, you should ask explicitly for categorical_accuracy in the model compilation as follows:

from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
Run Code Online (Sandbox Code Playgroud)

In the MNIST example, after training, scoring, and predicting the test set as I show above, the two metrics now are the same, as they should be:

# 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    
Run Code Online (Sandbox Code Playgroud)

System setup:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4
Run Code Online (Sandbox Code Playgroud)