Керрас пользовательские метрики 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.