在 Tensorflow 中创建加权 MSE 损失函数

问题描述 投票:0回答:3

我想使用

Tensorflow
训练循环神经网络。我的模型为每个训练样本输出一个 1 x 100 向量。假设
y = [y_1, y_2, ..., y_100]
是我训练样本
x
的输出,预期输出是
y'= [y'_1, y'_2, ..., y'_100]

我希望编写一个自定义损失函数来计算该特定样本的损失,如下所示:

Loss =  1/sum(weights) * sqrt(w_1*(y_1-y'_1)^2 + ... + w_100*(y_100-y'_100)^2)

其中

weights = [w_1,...,w_100]
是给定的权重数组。

有人可以帮助我实现这样的自定义损失函数吗? (我在训练时也使用小批量)

tensorflow keras loss-function
3个回答
4
投票

我想强调,根据你的问题,你有两种可能性:

[1] 如果所有样本的权重相等:

您可以构建一个损失包装器。这是一个虚拟示例:

n_sample = 200
X = np.random.uniform(0,1, (n_sample,10))
y = np.random.uniform(0,1, (n_sample,100))
W = np.random.uniform(0,1, (100,)).astype('float32')

def custom_loss_wrapper(weights):
    def loss(true, pred):
        sum_weights = tf.reduce_sum(weights) * tf.cast(tf.shape(pred)[0], tf.float32)
        resid = tf.sqrt(tf.reduce_sum(weights * tf.square(true - pred)))
        return resid/sum_weights
    return loss

inp = Input((10,))
x = Dense(256)(inp)
pred = Dense(100)(x)

model = Model(inp, pred)
model.compile('adam', loss=custom_loss_wrapper(W))

model.fit(X, y, epochs=3)

[2] 如果样本之间的权重不同:

您应该使用

add_loss
构建模型,以便动态考虑每个样本的权重。这是一个虚拟示例:

n_sample = 200
X = np.random.uniform(0,1, (n_sample,10))
y = np.random.uniform(0,1, (n_sample,100))
W = np.random.uniform(0,1, (n_sample,100))

def custom_loss(true, pred, weights):
    sum_weights = tf.reduce_sum(weights)
    resid = tf.sqrt(tf.reduce_sum(weights * tf.square(true - pred)))
    return resid/sum_weights

inp = Input((10,))
true = Input((100,))
weights = Input((100,))
x = Dense(256)(inp)
pred = Dense(100)(x)

model = Model([inp,true,weights], pred)
model.add_loss(custom_loss(true, pred, weights))
model.compile('adam', loss=None)

model.fit([X,y,W], y=None, epochs=3)

使用

add_loss
时,您应该将损失涉及的所有张量作为输入层传递,并将它们传递到损失内部进行计算。

在推理时,您可以像往常一样计算预测,只需删除真实值和权重作为输入:

final_model = Model(model.input[0], model.output)
final_model.predict(X)

3
投票

您可以通过以下方式实现自定义加权mse

import numpy as np 
from tensorflow.keras import backend as K 

def custom_mse(class_weights):
    def weighted_mse(gt, pred):
        # Formula: 
        # w_1*(y_1-y'_1)^2 + ... + w_100*(y_100-y'_100)^2 / sum(weights)
        return K.sum(class_weights * K.square(gt - pred)) / K.sum(class_weights)
    return weighted_mse

y_true  = np.array([[0., 1., 1, 0.], [0., 0., 1., 1.]])
y_pred  = np.array([[0., 1, 0., 1.], [1., 0., 1., 1.]])
weights = np.array([0.25, 0.50, 1., 0.75])

print(y_true.shape, y_pred.shape, weights.shape)
(2, 4) (2, 4) (4,)
loss = custom_mse(class_weights=weights)
loss(y_true, y_pred).numpy()
0.8

将其与模型编译一起使用。

model.compile(loss=custom_mse(weights))

这将使用提供的 weighted 矩阵计算 mse。然而,在你的问题中,你引用了

sqrt...
,我认为你的意思是root mse(rmse)。为此,您可以在
K.sqrt(K.sum(...)) / K.sum(...)
的自定义函数中使用
custom_mse


仅供参考,您可能还有兴趣在

class_weights
期间查看
sample_weights
Model. fit
。来自来源

  • class_weight:可选字典将类索引(整数)映射到权重(浮点)值,用于对损失进行加权 功能(仅在训练期间)。这对于告诉模型很有用 “更多地关注”来自代表性不足的班级的样本。

  • sample_weight:训练样本的可选 Numpy 权重数组,用于对损失函数进行加权(仅在训练期间)。 您可以传递一个长度相同的平面(一维)Numpy 数组 输入样本(权重和样本之间的 1:1 映射),或者在 对于时态数据,您可以传递形状为(样本, 序列长度),对每个时间步应用不同的权重 每个样本。当 x 是数据集时,不支持此参数, 生成器或

    keras.utils.Sequence
    实例,而是提供 Sample_weights 作为 x 的第三个元素。

还有

loss_weights
中的
Model.compile
,来自来源

loss_weights:指定标量系数(Python 浮点数)的可选列表或字典,用于对损失贡献进行加权 不同模型的输出。将通过以下方式最小化损失值 那么模型将是所有个体损失的加权和,加权 通过loss_weights系数。如果有一个列表,预计会有一个 1:1 映射到模型的输出。如果是字典,则预计会映射 将名称(字符串)输出为标量系数。


1
投票

加权均方误差损失函数的类版本。

class WeightedMSE(object):
    def __init__(self):
        pass

    def __call__(self, y_true, y_pred, weights):
        sum_weights = tf.reduce_sum(weights)
        resid = tf.reduce_sum(weights * tf.square(y_true - y_pred))
        return resid / sum_weights
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.