Керрас пользовательские метрики RMSLE
как реализовать эту метрику в Keras? Мой код ниже дает неправильный результат! Обратите внимание, что я отменяю предыдущее преобразование log(x + 1) через exp(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
что я делаю не так? Спасибо!
EDIT: настройка axis=0
Кажется, дает значение, очень близкое к правильному, но я не уверен, так как весь код, который я, кажется, использует axis=-1
.
2 ответов
я столкнулся с той же проблемой и искал ее, вот что я нашел
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 backend
0.263978210565
0.263978210565
0.263978
С помощью списка (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)
. Итак, вам действительно не нужно использовать any axis
на K.mean
.
если вы убедитесь, что выходная форма вашей модели является либо (length,)
или (length,1)
, вы можете использовать просто K.mean(value)
без передачи параметра axis.