为啥对于 Keras 中的多类分类, binary_crossentropy 比 categorical_crossentropy 更准确?

Posted

技术标签:

【中文标题】为啥对于 Keras 中的多类分类, binary_crossentropy 比 categorical_crossentropy 更准确?【英文标题】:Why is binary_crossentropy more accurate than categorical_crossentropy for multiclass classification in Keras?为什么对于 Keras 中的多类分类, binary_crossentropy 比 categorical_crossentropy 更准确? 【发布时间】:2017-05-10 16:52:53 【问题描述】:

我正在学习如何使用 Keras 创建卷积神经网络。我正在尝试获得 MNIST 数据集的高精度。

显然categorical_crossentropy 用于 2 个以上的课程,binary_crossentropy 用于 2 个课程。由于有 10 位数字,我应该使用categorical_crossentropy。然而,在训练和测试了数十个模型之后,binary_crossentropy 的性能始终明显优于categorical_crossentropy

在 Kaggle 上,我使用 binary_crossentropy 和 10 个 epoch 获得了 99+% 的准确率。同时,使用categorical_crossentropy,即使使用 30 个 epoch,我也无法达到 97% 以上(虽然不多,但我没有 GPU,所以训练需要很长时间)。

这是我的模型现在的样子:

model = Sequential()
model.add(Convolution2D(100, 5, 5, border_mode='valid', input_shape=(28, 28, 1), init='glorot_uniform', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(100, 3, 3, init='glorot_uniform', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))
model.add(Flatten())
model.add(Dense(100, init='glorot_uniform', activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(100, init='glorot_uniform', activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(10, init='glorot_uniform', activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='adamax', metrics=['accuracy'])

【问题讨论】:

【参考方案1】:

简答:不是

要看到这一点,只需尝试“手动”计算准确度,您会发现它与 Keras 使用model.evaluate 方法报告的不同:

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.99794011611938471

# 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.98999999999999999

似乎的原因是一个相当微妙的问题,即 Keras 如何真正猜测使用哪种准确度,具体取决于您选择的损失函数,当您在您的模型编译中简单地包含 metrics=['accuracy']

如果你检查source code,Keras 并没有定义一个单一的准确度指标,而是几个不同的指标,其中有binary_accuracycategorical_accuracy。 under the hood 发生的情况是,由于您选择二元交叉熵作为损失函数并且没有指定特定的准确度指标,Keras(错误地......)推断您对 binary_accuracy 感兴趣,这就是它返回。

为了避免这种情况,即使用二元交叉熵作为损失函数(原则上没有错),同时仍然获得手头问题所需的分类准确度(即 MNIST 分类),您应该在模型编译中明确要求categorical_accuracy,如下所示:

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

如上所示,在训练、评分和预测测试集之后,这两个指标现在是相同的,它们应该是:

sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000 == score[1]
# True

(HT to this great answer 到一个类似的问题,这有助于我理解这个问题......)

更新:在我发帖后,我发现this answer 已经发现了这个问题。

【讨论】:

【参考方案2】:

首先,当有两个类时,binary_crossentropy 是不存在的。

之所以叫“binary”,是因为它适用于二进制输出,softmax的每个数字都是针对0或1的。 在这里,它检查输出的每个数字。

它没有解释你的结果,因为 categorical_entropy 利用了它是一个分类问题的事实。

您确定在读取数据时每个样本只有一个类吗?这是我唯一能给出的一种解释。

【讨论】:

以上是关于为啥对于 Keras 中的多类分类, binary_crossentropy 比 categorical_crossentropy 更准确?的主要内容,如果未能解决你的问题,请参考以下文章

在有监督的多类分类中,为啥使用宏 F1 分数而不是平衡精度?

为多类分类python tensorflow keras设置偏差

Keras Python 中的分类

Keras每一步的多步LSTM批量训练分类

Encog中的多类SVM分类

python中的多类分类