我正在构建一个简单的 CNN 用于二值图像分类,并且从 model.evaluate() 获得的 AUC 远高于从 model.predict() + roc_auc_score() 获得的 AUC.
整个笔记本是here https://github.com/pro100olga/dlaicourse/blob/master/evaluate_predict.ipynb.
编译模型并输出 model.fit():
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=0.001),
metrics=['AUC'])
history = model.fit(
train_generator,
steps_per_epoch=8,
epochs=5,
verbose=1)
纪元 1/5
8/8 [================================] - 21s 3s/步 - 损失:6.7315 - auc:0.5143
纪元 2/5
8/8 [================================] - 15s 2s/步 - 损失:0.6626 - auc:0.6983
纪元 3/5
8/8 [================================] - 18s 2s/步 - 损失:0.4296 - auc:0.8777
纪元 4/5
8/8 [================================] - 14s 2s/步 - 损失:0.2330 - auc:0.9606
纪元 5/5
8/8 [================================] - 18s 2s/步 - 损失:0.1985 - auc:0.9767
然后 model.evaluate() 给出类似的东西:
model.evaluate(train_generator)
9/9 [================================] - 10s 1s/步 - 损失:0.3056 - auc:0.9956
但直接从 model.predict() 方法计算出的 AUC 会低两倍:
from sklearn import metrics
x = model.predict(train_generator)
metrics.roc_auc_score(train_generator.labels, x)
0.5006148007590132
我读过几篇关于类似问题的帖子(比如this https://stackoverflow.com/questions/57212021/getting-different-results-from-keras-model-evaluate-and-model-predict, this https://stackoverflow.com/questions/44476706/what-is-the-difference-between-keras-model-evaluate-and-model-predict, this https://stackoverflow.com/questions/49903706/keras-predict-gives-different-error-than-evaluate-loss-different-from-metrics并且github上的广泛讨论 https://github.com/keras-team/keras/issues/6977),但他们描述的原因与我的情况无关:
- 使用binary_crossentropy进行多类任务(不是我的情况)
- 由于使用批量与整体而导致评估和预测之间的差异
数据集(不应像我的情况那样导致如此剧烈的下降)
- 使用批量归一化和正则化(不是我的情况,也应该
不会造成这么大的下降)
非常感谢任何建议。谢谢!
编辑!解决方案我已经找到了解决方案here https://github.com/keras-team/keras/issues/3296,我只需要打电话
train_generator.reset()
在 model.predict 之前,并在 flow_from_directory() 函数中设置 shuffle = False 。差异的原因是生成器输出从不同位置开始的批次,因此标签和预测将不匹配,因为它们与不同的对象相关。所以问题不在于评估或预测方法,而在于生成器。
EDIT 2如果使用 flow_from_directory() 创建生成器,则使用 train_generator.reset() 并不方便,因为它需要在 flow_from_directory 中设置 shuffle = False,但这会在训练期间创建包含单个类的批次,从而影响学习。所以我最终在运行预测之前重新定义了 train_generator 。