【问题标题】:(Custom) Percentile MSE Loss function(自定义)百分比 MSE 损失函数
【发布时间】:2020-06-27 16:08:06
【问题描述】:

我有一个 Keras 模型,它具有输入 x_1、...、x_n 和 d 维输出 f(x_1)、...、f(x_n)。我正在研究 d 维目标 y_1,...,y_n 的回归问题。

我想最小化损失函数: 对于介于 0 和 1 之间的固定元参数 a,返回 |f(x_i)-y_i|^2 的第 a^th(经验)分位数。

这是我目前编写的代码:

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

一个问题是我想避免使用 tensorflow_probability,我希望在 Keras 上完成整个实现。

但是,我不知道怎么做。

【问题讨论】:

  • 你能正确描述输入和输出的形状吗?目前太模棱两可了。也许如果您打印模型摘要?你想要批处理维度上的百分位数还是另一个维度?
  • 我想要批处理维度中的百分位数。这里我模型的输出形状是 (None, 1) 。
  • Ok :) -- 当你说它必须完全在 Keras 上完成时,你的意思是你根本不能使用 tensorflow 吗?还是关于“tensorflow_probability”(我不知道)是一个外部包? -- 我可以用tensorflow给你解决方案吗?
  • 确定 TensorFlow 没问题。我最近在 TensorFlow 上编写代码然后将其放入 Keras 时遇到了一个问题(所以我有点害怕:P)
  • 您想要百分位数的“值”还是“包含在该百分位数中的所有元素”?

标签: python keras loss-function quantile risk-analysis


【解决方案1】:

要获取高于该百分位数的“所有元素”,您将需要不同的答案:

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)²,是108 输入中的前两个k。

【讨论】:

  • tfp.stats.percentile 的源代码中,a comment 表示应将p 转换为float64,否则可能会为大型数组计算错误的索引。通过使用K.floatx(),如果这是默认的浮点类型,您不会冒使用float32 的风险吗?
  • 老实说,我认为您不会对此有任何问题。你的批量大小是多少? (请注意,它将分批完成)。你也可以试试float64,没问题。
【解决方案2】:

对于您的特定用例,您可以使用以下函数,它是tfp.stats.percentile 的简化版本(他们使用Apache License 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))

【讨论】:

  • 但这是否平均 a 及以上的所有分位数?
  • @AnnieTheKatsu 它提供了类似于您在问题中包含的tfp.stats.percentile 函数的p-th percentile。如果您希望所有元素高于或低于某个百分位数,则需要进行小修改,这已在 the other answer 中实现。
猜你喜欢
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 2019-06-25
  • 2018-11-06
  • 1970-01-01
  • 2021-05-02
  • 2021-01-24
  • 1970-01-01
相关资源
最近更新 更多