【问题标题】:Tensorflow Keras RMSE metric returns different results than my own built RMSE loss functionTensorflow Keras RMSE 指标返回的结果与我自己构建的 RMSE 损失函数不同
【发布时间】:2020-09-18 18:51:15
【问题描述】:

这是一个回归问题

我的自定义 RMSE 损失:

def root_mean_squared_error_loss(y_true, y_pred):
    return tf.keras.backend.sqrt(tf.keras.losses.MSE(y_true, y_pred))

训练代码示例,其中 create_model 返回一个密集的全连接顺序模型

from tensorflow.keras.metrics import RootMeanSquaredError
model = create_model()
model.compile(loss=root_mean_squared_error_loss, optimizer='adam', metrics=[RootMeanSquaredError()])

model.fit(train_.values,
          targets,
          validation_split=0.1,
          verbose=1,
          batch_size=32)
Train on 3478 samples, validate on 387 samples
Epoch 1/100
3478/3478 [==============================] - 2s 544us/sample - loss: 1.1983 - root_mean_squared_error: 0.7294 - val_loss: 0.7372 - val_root_mean_squared_error: 0.1274
Epoch 2/100
3478/3478 [==============================] - 1s 199us/sample - loss: 0.8371 - root_mean_squared_error: 0.3337 - val_loss: 0.7090 - val_root_mean_squared_error: 0.1288
Epoch 3/100
3478/3478 [==============================] - 1s 187us/sample - loss: 0.7336 - root_mean_squared_error: 0.2468 - val_loss: 0.6366 - val_root_mean_squared_error: 0.1062
Epoch 4/100
3478/3478 [==============================] - 1s 187us/sample - loss: 0.6668 - root_mean_squared_error: 0.2177 - val_loss: 0.5823 - val_root_mean_squared_error: 0.0818

我预计 loss 和 root_mean_squared_error 具有相同的值,为什么会有差异?

【问题讨论】:

    标签: python tensorflow keras tf.keras loss-function


    【解决方案1】:

    两个关键区别,来自source code

    1. RMSE 是一个 有状态 指标(它保留内存) - 你的指标是无状态的
    2. 平方根应用after 取全局平均值,而不是在axis=-1 之前的平均值,如MSE does
      • 由于 1,2 的参与度更高:相对于另一个运行量 count,取运行量 total 的平均值;两个数量都通过RMSE.reset_states() 重置。

    原始公式修复很容易 - 但集成有状态需要工作,这超出了本问题的范围;参考源代码查看how it's done。通过比较修复 2,如下所示。


    import numpy as np
    import tensorflow as tf
    from tensorflow.keras.metrics import RootMeanSquaredError as RMSE
    
    def root_mean_squared_error_loss(y_true, y_pred):
        return tf.sqrt(tf.reduce_mean(tf.math.squared_difference(y_true, y_pred)))
    
    np.random.seed(0)
    
    #%%###########################################################################
    rmse = RMSE(dtype='float64')
    rmsel = root_mean_squared_error_loss
    
    x1 = np.random.randn(32, 10)
    y1 = np.random.randn(32, 10)
    x2 = np.random.randn(32, 10)
    y2 = np.random.randn(32, 10)
    
    #%%###########################################################################
    print("TensorFlow RMSE:")
    print(rmse(x1, y1))
    print(rmse(x2, y2))
    print("=" * 46)
    print(rmse(x1, y1))
    print(rmse(x2, y2))
    
    print("\nMy RMSE:")
    print(rmsel(x1, y1))
    print(rmsel(x2, y2))
    
    TensorFlow RMSE:
    tf.Tensor(1.4132492562096124, shape=(), dtype=float64)
    tf.Tensor(1.3875944990740972, shape=(), dtype=float64)
    ==============================================
    tf.Tensor(1.3961984634354354, shape=(), dtype=float64)  # same inputs, different result
    tf.Tensor(1.3875944990740972, shape=(), dtype=float64)  # same inputs, different result
    
    My RMSE:
    tf.Tensor(1.4132492562096124, shape=(), dtype=float64)  # first result agrees
    tf.Tensor(1.3614563994283353, shape=(), dtype=float64)  # second differs since stateless
    

    【讨论】:

    • 我的函数和你重写的函数都会产生相同的输出。至于状态,我直接使用了“mse”损失函数,一个时期结束时的结果也不等于 RMSE 的平方。据我了解,该指标是在 epoch 结束时评估的,而每批都有损失函数。
    • @ma7555 不,我们的函数没有相同的输出 - 用你的替换我的并运行上面的代码。 MSE 也是一种无状态指标,因此使用它并不能解决您的问题。我建议采用基于类的方法,跟踪 totalcount,其逻辑与 TF 相同。
    • ok 所以 'mse' 也是无状态的,也就是说在 epoch 结束时打印的数字实际上是最后一批 'mse',但差别还是很大的。在第一纪元结束时,这些数字是:val_loss: 5.6630 - val_root_mean_squared_error: 0.1597
    • @ma7555 最后打印的值是整个时期的平均值,而不是最后一批的平均值。差异确实很大,但 RMSE 的工作相当不直观;如果没有看到实际的模型和数据,就不能说太多(不能使用随机噪声,因为它的损失行为显着不同)。无论如何,这本身就是一个问题。
    猜你喜欢
    • 2017-10-06
    • 2020-01-12
    • 2020-09-11
    • 2021-02-18
    • 2018-10-28
    • 2017-12-29
    • 1970-01-01
    • 2020-01-27
    • 2019-01-20
    相关资源
    最近更新 更多