Keras 自定义 RMSLE 指标
Keras custom RMSLE metric
如何在 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
.
通过在 numpy 实现中使用列表 (to_sum
),我怀疑您的 numpy 数组的形状为 (length,)
。
而在 Keras 上,由于您使用 axis=0
和 axis=1
得到了不同的结果,您可能得到了类似于 (length,1)
的形状。
此外,在创建 to_sum
列表时,您使用的是 y[i]
和 y_pred[i]
,这意味着您在 numpy 实现中从 axis=0
中获取元素.
numpy 实现还对计算 sum(to_sum)
中的平均值的所有内容求和。所以,你真的不需要在 K.mean
中使用任何 axis
。
如果您确定模型的输出形状是 (length,)
或 (length,1)
,则可以只使用 K.mean(value)
而无需传递轴参数。
我运行遇到了同样的问题并进行了搜索,这是我找到的
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
如何在 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
.
通过在 numpy 实现中使用列表 (to_sum
),我怀疑您的 numpy 数组的形状为 (length,)
。
而在 Keras 上,由于您使用 axis=0
和 axis=1
得到了不同的结果,您可能得到了类似于 (length,1)
的形状。
此外,在创建 to_sum
列表时,您使用的是 y[i]
和 y_pred[i]
,这意味着您在 numpy 实现中从 axis=0
中获取元素.
numpy 实现还对计算 sum(to_sum)
中的平均值的所有内容求和。所以,你真的不需要在 K.mean
中使用任何 axis
。
如果您确定模型的输出形状是 (length,)
或 (length,1)
,则可以只使用 K.mean(value)
而无需传递轴参数。
我运行遇到了同样的问题并进行了搜索,这是我找到的
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