Keras中model.evaluate与model.predict测试结果不一致的原因咨询
问题原因分析
你的问题核心在于自定义RMSE指标的计算逻辑和Keras model.evaluate() 方法的默认行为不匹配,具体拆解如下:
1. 自定义RMSE的计算逻辑问题
你定义的RMSE函数是对单个batch内的样本计算RMSE:
def RMSE(output, target): return K.sqrt(K.mean((output - target) ** 2))
这个函数会针对每个输入的batch,先计算该batch内的均方误差(MSE),再开根号得到这个batch的RMSE。
2. model.evaluate() 的默认行为
Keras的evaluate()方法默认会:
- 将测试集按指定的
batch_size分成多个小batch - 对每个batch单独计算你定义的RMSE指标
- 最终返回所有batch的RMSE的平均值
而你通过model.predict()后手动计算的RMSE,是先计算整个测试集所有样本的MSE,再开根号,这和evaluate()的计算逻辑完全不同:
- 数学上,多个batch的RMSE的平均值 ≠ 整个数据集的RMSE
- 只有当
batch_size等于测试集总样本数时,evaluate()只计算一次RMSE(即整个数据集的RMSE),这时候结果才和手动计算一致。
3. 不同batch_size的结果差异解释
- batch_size=1:每个batch是单个样本,此时该batch的RMSE就是样本的绝对误差(因为单个样本的MSE是
(y_pred-y_true)²,开根号就是|y_pred-y_true|),evaluate()返回的是所有样本绝对误差的平均值,这和全局RMSE完全不是同一个统计量,所以结果差异极大。 - 默认batch_size(32):将测试集分成多个32样本的batch,计算每个batch的RMSE后取平均,这个平均值和全局RMSE存在偏差。
- batch_size=n_test:整个测试集作为一个batch,此时计算的RMSE就是全局RMSE,和
predict()后手动计算的结果一致。
解决方法
如果希望evaluate()返回的RMSE和手动计算的全局RMSE一致,需要修改指标的计算逻辑,让它先累积整个数据集的MSE,最后再开根号。可以用Keras的Metric类来实现:
class GlobalRMSE(tf.keras.metrics.Metric): def __init__(self, name='rmse', **kwargs): super().__init__(name=name, **kwargs) self.total_sse = self.add_weight(name='total_sse', initializer='zeros') self.count = self.add_weight(name='count', initializer='zeros') def update_state(self, y_true, y_pred, sample_weight=None): sse = K.sum(K.square(y_pred - y_true)) self.total_sse.assign_add(sse) count = K.cast(K.shape(y_true)[0], dtype=K.floatx()) self.count.assign_add(count) def result(self): return K.sqrt(self.total_sse / self.count) def reset_state(self): self.total_sse.assign(0.0) self.count.assign(0.0)
然后在编译模型时使用这个自定义指标:
m.compile(loss=RMSE, optimizer='adam', metrics=[GlobalRMSE()])
这样无论设置什么batch_size,evaluate()返回的RMSE都会和手动计算的全局RMSE一致。
内容的提问来源于stack exchange,提问作者Qiuyu Gu
相关产品推荐
相关产品推荐

