简短来说,当使用带有超过2个标签的binary_crossentropy时,用Keras方法计算出的精度是完全错误的。
我想对此进行详细说明,加以解释,并提供补救措施。
这不是bug。根本原因是这是一个相当微妙的问题。即Keras实际上是猜测使用哪种精度的,这取决于当你在模型编译metrics=['accuracy'] 时选择的损失函数。
换句话说,当你的第一个编译
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
是有效的,你的第二个:
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
不会产生你期望的结果,但是原因不是使用二进制交叉熵(至少在原理上是绝对有效的损失函数)。
这是为什么?如果你检查度量源代码,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_accuracy:
from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
在MNIST的示例中,经过如上所示的训练,评分和预测测试集之后,两个指标现在相同,它们应该是:
# 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