为何使用相同x_train时model.predict的准确率远低于model.fit?
1. 模型包含训练/推理行为不一致的层
这是最常见的诱发原因,如果你的模型用到了Dropout、BatchNormalization、随机数据增强等层,这些层在训练和推理阶段的计算逻辑完全不同:
- BatchNormalization训练时用当前batch的均值方差做归一化,推理时用训练阶段累计的滑动平均均值方差
- Dropout训练时随机失活神经元,推理时保留全部神经元
- 如果是自定义层,没有在
call方法中正确处理training参数的话,会导致推理阶段依然执行训练时的随机逻辑,直接拉低预测准确率
排查方法
打印模型结构确认是否包含上述层,如果你使用了自定义层,检查call方法是否正确区分了训练/推理逻辑。
2. 损失函数参数与模型输出不匹配的隐藏问题
你在编译时设置了SparseCategoricalCrossentropy(from_logits=False),要求模型最后一层输出归一化后的概率值:
- 如果你的模型最后一层没有加
Softmax激活,输出的是未归一化的logits,虽然argmax取值的位置理论上不受影响,但如果模型训练过程中因为输出分布异常导致拟合了错误的模式,也可能出现推理准确率异常 - 检查你模型最后一层的神经元数量是否和实际类别数完全一致,比如你有8类标签,最后一层必须设置8个神经元
排查方法
将损失函数的from_logits参数改为True,同时删除最后一层的Softmax激活(如果有的话),重新训练后再验证准确率差异。
3. 标签体系不匹配
使用SparseCategoricalCrossentropy要求标签是从0开始的连续整数:
- 如果你通过
dicTipos映射后的标签是从1开始计数(比如18),而模型最后一层输出的类别索引是07,就会出现argmax得到的结果和标签完全对不上的情况 - 训练时如果标签值超过了输出层神经元数量-1,TensorFlow会默认忽略越界损失,反而会让拟合过程出现伪高准确率的情况
排查方法
打印y_train的最小值、最大值和唯一值,确认标签范围是0 ~ 类别数-1,如果是从1开始的,统一减1后再重新训练。
4. 准确率计算逻辑错误
如果你的y_train是shape为(样本数, 1)的二维数组,而rounded_predictions是shape为(样本数,)的一维数组,二者做相等比较的时候会触发广播机制,得到的是shape为(样本数, 样本数)的布尔矩阵,sum计算的结果完全错误,导致准确率计算不准。
排查方法
打印y_train.shape和rounded_predictions.shape,确保二者维度一致,都是一维数组,如果y_train是二维的,用y_train = y_train.reshape(-1)降维后再计算准确率。
5. fit输出的准确率是平滑后的结果
Keras在训练过程中输出的epoch准确率是逐batch的移动平均值,会对波动做平滑处理,和全量数据集一次性推理得到的准确率本身就有差异,虽然一般不会出现99%到12%的巨大差距,也可以作为排查项。
排查方法
训练结束后直接调用model.evaluate(x_train, y_train)得到的准确率才是官方计算的全量训练集准确率,和你自己用predict计算的结果做对比:如果evaluate结果和fit输出接近,说明是你自己写的准确率计算逻辑有问题;如果evaluate结果和predict计算的结果接近,说明fit的输出是平滑后的误差,问题出在模型本身。
内容的提问来源于stack exchange,提问作者Wilber C

