(自定义)百分位 MSE 损失函数
(Custom) Percentile MSE Loss function
我有一个 Keras 模型,它有输入 x_1,...,x_n 和 d 维输出 f(x_1),...,f(x_n).我正在研究 d 维目标 y_1,...,y_n.
的回归问题
我想最小化损失函数:
对于介于 0 和 1 之间的固定元参数 a,return |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 上完成。
但是,我不知道怎么做。
对于您的特定用例,您可以使用以下函数,它是 tfp.stats.percentile
(they use 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))
要使 "all elements" 高于该百分位数,您将需要不同的答案:
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。
我有一个 Keras 模型,它有输入 x_1,...,x_n 和 d 维输出 f(x_1),...,f(x_n).我正在研究 d 维目标 y_1,...,y_n.
的回归问题我想最小化损失函数:
对于介于 0 和 1 之间的固定元参数 a,return |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 上完成。
但是,我不知道怎么做。
对于您的特定用例,您可以使用以下函数,它是 tfp.stats.percentile
(they use 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))
要使 "all elements" 高于该百分位数,您将需要不同的答案:
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。