问题 Keras自定义RMSLE指标


如何在Keras中实施此指标?我的代码下面给出了错误的结果! 请注意,我正在通过exp(x) - 1撤消先前的log(x + 1)变换,负面预测也会被剪切为0:

def rmsle_cust(y_true, y_pred):
    first_log = K.clip(K.exp(y_pred) - 1.0, 0, None)
    second_log = K.clip(K.exp(y_true) - 1.0, 0, None)
    return K.sqrt(K.mean(K.square(K.log(first_log + 1.) - K.log(second_log + 1.)), axis=-1)

为了比较,这是标准的numpy实现:

def rmsle_cust_py(y, y_pred, **kwargs):
    # undo 1 + log
    y = np.exp(y) - 1
    y_pred = np.exp(y_pred) - 1

    y_pred[y_pred < 0] = 0.0
    to_sum = [(math.log(y_pred[i] + 1) - math.log(y[i] + 1)) ** 2.0 for i,pred in enumerate(y_pred)]
    return (sum(to_sum) * (1.0/len(y))) ** 0.5

我做错了什么?谢谢!

编辑:设置 axis=0 似乎给出了一个非常接近正确值的值,但我不确定,因为我似乎使用了所有代码 axis=-1


12896
2017-11-30 21:34


起源



答案:


我遇到了同样的问题并搜索了它,这是我发现的

https://www.kaggle.com/jpopham91/rmlse-vectorized

修改了一下后,这似乎对我有用,rmsle_K 方法实现 Keras 和 TensorFlow

import numpy as np
import math
from keras import backend as K
import tensorflow as tf

def rmsle(y, y0):
    assert len(y) == len(y0)
    return np.sqrt(np.mean(np.power(np.log1p(y)-np.log1p(y0), 2)))

def rmsle_loop(y, y0):
    assert len(y) == len(y0)
    terms_to_sum = [(math.log(y0[i] + 1) - math.log(y[i] + 1)) ** 2.0 for i,pred in enumerate(y0)]
    return (sum(terms_to_sum) * (1.0/len(y))) ** 0.5

def rmsle_K(y, y0):
    return K.sqrt(K.mean(K.square(tf.log1p(y) - tf.log1p(y0))))

r = rmsle(y=[5, 20, 12], y0=[8, 16, 12])
r1 = rmsle_loop(y=[5, 20, 12], y0=[8, 16, 12])
r2 = rmsle_K(y=[5., 20., 12.], y0=[8., 16., 12.])

print(r)

print(r1)

sess = tf.Session()

print(sess.run(r2))

结果:

使用TensorFlow后端

0.263978210565

0.263978210565

0.263978

7
2017-12-03 00:07



谢谢,但是exp(x) - 1转换怎么样? - Fernando
@Fernando我认为你不需要那种转变 kaggle.com/wiki/RootMeanSquaredLogarithmicError - LYu
我需要因为我的模型适合log(x + 1),所以我需要通过exp(x) - 1转换回来,然后应用RMSLE。 - Fernando
最小化日志错误也会最小化实际错误,因为日志函数是单调变换? - Saedeas


答案:


我遇到了同样的问题并搜索了它,这是我发现的

https://www.kaggle.com/jpopham91/rmlse-vectorized

修改了一下后,这似乎对我有用,rmsle_K 方法实现 Keras 和 TensorFlow

import numpy as np
import math
from keras import backend as K
import tensorflow as tf

def rmsle(y, y0):
    assert len(y) == len(y0)
    return np.sqrt(np.mean(np.power(np.log1p(y)-np.log1p(y0), 2)))

def rmsle_loop(y, y0):
    assert len(y) == len(y0)
    terms_to_sum = [(math.log(y0[i] + 1) - math.log(y[i] + 1)) ** 2.0 for i,pred in enumerate(y0)]
    return (sum(terms_to_sum) * (1.0/len(y))) ** 0.5

def rmsle_K(y, y0):
    return K.sqrt(K.mean(K.square(tf.log1p(y) - tf.log1p(y0))))

r = rmsle(y=[5, 20, 12], y0=[8, 16, 12])
r1 = rmsle_loop(y=[5, 20, 12], y0=[8, 16, 12])
r2 = rmsle_K(y=[5., 20., 12.], y0=[8., 16., 12.])

print(r)

print(r1)

sess = tf.Session()

print(sess.run(r2))

结果:

使用TensorFlow后端

0.263978210565

0.263978210565

0.263978

7
2017-12-03 00:07



谢谢,但是exp(x) - 1转换怎么样? - Fernando
@Fernando我认为你不需要那种转变 kaggle.com/wiki/RootMeanSquaredLogarithmicError - LYu
我需要因为我的模型适合log(x + 1),所以我需要通过exp(x) - 1转换回来,然后应用RMSLE。 - Fernando
最小化日志错误也会最小化实际错误,因为日志函数是单调变换? - Saedeas


通过使用清单(to_sum在numpy实现中,我怀疑你的numpy数组有形状 (length,)

而在Keras,因为你有不同的结果 axis=0 和 axis=1,你可能有一些形状像 (length,1)

另外,在创建时 to_sum 列表,你正在使用 y[i] 和 y_pred[i],这意味着你要从中获取元素 axis=0 在numpy实现。

numpy实现还总结了计算平均值的所有内容 sum(to_sum)。所以,你真的不需要使用任何 axis 在里面 K.mean

如果您确定模型的输出形状是其中之一 (length,) 要么 (length,1),你可以使用 K.mean(value) 没有传递轴参数。


3
2017-12-02 23:53



我注意到了,但是Keras给同一个(y,y_pred)对的结果略有不同。我不知道为什么。 - Fernando