为什么 Keras 中的多类分类 binary_crossentropy 比 categorical_crossentropy 更准确?
Why is binary_crossentropy more accurate than categorical_crossentropy for multiclass classification in Keras?
我正在学习如何使用 Keras 创建卷积神经网络。我正在尝试获得 MNIST 数据集的高精度。
显然 categorical_crossentropy
超过 2 类,binary_crossentropy
超过 2 类。由于有 10 个数字,我应该使用 categorical_crossentropy
。然而,在训练和测试了数十个模型之后,binary_crossentropy
始终显着优于 categorical_crossentropy
。
在 Kaggle 上,我使用 binary_crossentropy
和 10 个时期获得了 99+% 的准确率。同时,我无法使用 categorical_crossentropy
达到 97% 以上,即使使用 30 个时期(这并不多,但我没有 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'])
首先,binary_crossentropy不是有两个class的时候。
之所以叫"binary"是因为它适配二进制输出,softmax的每一个数都是以0或1为目标的。
在这里,它检查输出的每个数字。
它不能解释你的结果,因为 categorical_entropy 利用了它是一个 class化问题的事实。
您确定在读取数据时每个样本只有一个 class 吗?这是我唯一能给出的解释。
简答:不是。
要看到这一点,只需尝试计算准确度 "by hand",您会发现它与 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 does not define a single accuracy metric, but several different ones, among them binary_accuracy
and categorical_accuracy
. What happens under the hood 是因为您选择了二元交叉熵作为损失函数并且没有指定特定的精度指标,Keras(错误地...)推断您对binary_accuracy
,这就是它 returns。
为了避免这种情况,即使用真正的二元交叉熵作为你的损失函数(原则上这没有错)同时仍然获得问题所需的分类精度hand(即 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 到一个类似的问题,这帮助我理解了这个问题...)
更新:在我 post 之后,我发现这个问题已经在 .
中发现
我正在学习如何使用 Keras 创建卷积神经网络。我正在尝试获得 MNIST 数据集的高精度。
显然 categorical_crossentropy
超过 2 类,binary_crossentropy
超过 2 类。由于有 10 个数字,我应该使用 categorical_crossentropy
。然而,在训练和测试了数十个模型之后,binary_crossentropy
始终显着优于 categorical_crossentropy
。
在 Kaggle 上,我使用 binary_crossentropy
和 10 个时期获得了 99+% 的准确率。同时,我无法使用 categorical_crossentropy
达到 97% 以上,即使使用 30 个时期(这并不多,但我没有 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'])
首先,binary_crossentropy不是有两个class的时候。
之所以叫"binary"是因为它适配二进制输出,softmax的每一个数都是以0或1为目标的。 在这里,它检查输出的每个数字。
它不能解释你的结果,因为 categorical_entropy 利用了它是一个 class化问题的事实。
您确定在读取数据时每个样本只有一个 class 吗?这是我唯一能给出的解释。
简答:不是。
要看到这一点,只需尝试计算准确度 "by hand",您会发现它与 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 does not define a single accuracy metric, but several different ones, among them binary_accuracy
and categorical_accuracy
. What happens under the hood 是因为您选择了二元交叉熵作为损失函数并且没有指定特定的精度指标,Keras(错误地...)推断您对binary_accuracy
,这就是它 returns。
为了避免这种情况,即使用真正的二元交叉熵作为你的损失函数(原则上这没有错)同时仍然获得问题所需的分类精度hand(即 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
更新:在我 post 之后,我发现这个问题已经在