(Пользовательский) Функция Percentile MSE Loss - PullRequest
5 голосов
/ 16 марта 2020

У меня есть модель Keras, у которой есть входы x_1, ..., x_n и d-мерные выходы f (x_1), ..., f (x_n). Я работаю над проблемой регрессии с d-мерными целями y_1, ..., y_n.

Я хотел бы минимизировать функцию потерь: для фиксированного мета-параметра a между 0 и 1, return а-й (эмпирический) квантиль |f(x_i)-y_i|^2.

Вот то, что я кодировал до сих пор:

def keras_custom_loss(y_true,y_predicted):
    SEs = K.square(y_true-y_predicted)
    out_custom = tfp.stats.percentile(SEs, 50.0, interpolation='midpoint')
    return out_custom

Одна проблема заключается в том, что я хотел бы избежать использования tenorflow_probability, и я хотел бы, чтобы вся реализация была выполнена на Keras.

Однако я не могу понять, как.

Ответы [ 2 ]

2 голосов
/ 16 марта 2020

Для того, чтобы взять «все элементы» выше этого процентиля, вам понадобится другой ответ:

import keras.backend as K
from keras.layers import *
from keras.models import Model
import numpy as np
import tensorflow as tf

def above_percentile(x, p): #assuming the input is flattened: (n,)

    samples = K.cast(K.shape(x)[0], K.floatx()) #batch size
    p =  (100. - p)/100.  #100% will return 0 elements, 0% will return all elements

    #samples to get:
    samples = K.cast(tf.math.floor(p * samples), 'int32')
        #you can choose tf.math.ceil above, it depends on whether you want to
        #include or exclude one element. Suppose you you want 33% top,
        #but it's only possible to get exactly 30% or 40% top:
        #floor will get 30% top and ceil will get 40% top.
        #(exact matches included in both cases)

    #selected samples
    values, indices = tf.math.top_k(x, samples)

    return values

def custom_loss(p):
    def loss(y_true, y_predicted):
        ses = K.square(y_true-y_predicted)
        above = above_percentile(K.flatten(ses), p)
        return K.mean(above)
    return loss

Тест:

dataX = np.array([2,3,1,4,7,10,8,5,6]).reshape((-1,1))
dataY = np.ones((9,1))


ins = Input((1,))
outs = Lambda(lambda x: x)(ins)
model = Model(ins, outs)

model.compile(optimizer='adam', loss = custom_loss(70.))
model.fit(dataX, dataY)

Потеря составит 65, что составляет 130/2 (жадный). И 130 = (10-1)² + (8-1)², будучи 10 и 8 двумя верхними k на входе.

2 голосов
/ 16 марта 2020

Для вашего конкретного случая использования c вы можете использовать следующую функцию, которая является упрощенной версией tfp.stats.percentile (они используют Apache Лицензия 2.0 ):

import tensorflow as tf

def percentile(x, p):
    with tf.name_scope('percentile'):
        y = tf.transpose(x)  # take percentile over batch dimension
        sorted_y = tf.sort(y)
        frac_idx = tf.cast(p, tf.float64) / 100. * (tf.cast(tf.shape(y)[-1], tf.float64) - 1.)
        return 0.5 * (  # using midpoint rule
            tf.gather(sorted_y, tf.math.ceil(frac_idx), axis=-1)
            + tf.gather(sorted_y, tf.math.floor(frac_idx), axis=-1))
...