简而言之,当您使用
loss='binary_crossentropy'
时报告的(高)准确性并不正确,正如您已经猜到的那样。对于您的问题,建议使用
categorical_crossentropy
。
详细地说,这种行为的潜在原因是一个相当微妙且未记录的问题,即 Keras 实际上是如何“猜测”要使用哪个准确率,具体取决于您选择的损失函数,当您在模型编译中包含简单的
metrics=['accuracy']
时。换句话说,虽然您的第一个编译选项
model.compile(loss='categorical_crossentropy',
optimizer=keras.optimizers.Adam(),
metrics=['accuracy']
如果您的第一个选项是有效的,那么您的第二个选项应该:
model.compile(loss='binary_crossentropy',
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'])
如果您使用二元交叉熵(至少在原则上是完全有效的损失函数),那么期望的结果可能不会产生,但原因并非在于其使用方式。
为什么呢?如果您查看度量源代码,就会发现Keras并没有定义单个准确率度量,而是有许多不同的度量方法,其中包括binary_accuracy
和categorical_accuracy
。在底层实现中发生了什么是这样的,由于您选择了loss='binary_crossentropy'
并且没有指定一个特定的准确率度量,Keras(错误地……)推断出您对binary_accuracy
感兴趣,并返回该值——而实际上您想要的是categorical_accuracy
。
让我们使用Keras中的MNIST CNN示例进行验证,进行以下修改:
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=2,
verbose=1,
validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
score[1]
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
score[1]==acc
可以说,使用自己的数据验证上述行为应该是很简单的。
为了讨论完整性,如果由于某种原因您坚持使用二元交叉熵作为损失函数(我说过,至少在原则上没有问题),同时仍然获得所需的分类准确度,则应在模型编译中明确要求categorical_accuracy
,如下所示:
from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
在MNIST示例中,经过训练、评分和预测测试集,如我上面所示,现在两个指标是相同的,这正是应该的:
score = model.evaluate(x_test, y_test, verbose=0)
score[1]
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
score[1]==acc
系统设置:
Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4