繁体   English   中英

带有样本权重的 Keras 中的自定义损失函数

[英]Custom Loss Function in Keras with Sample Weights

我是 Tensorflow 和 Keras 的新手。 我想在自定义损失函数中使用样本权重。

如果我理解正确,这篇文章( 在 Keras 中带有权重的自定义损失函数)建议将权重作为网络的输入。 除此之外:Keras 中的自定义加权损失函数,用于权衡每个元素

我想知道我是否遗漏了什么(我也不想将权重定义为全局变量)。 我也有点惊讶没有直接使用它的方法,因为 Loss 类 _ _ call _ _ 方法接受 sample_weight 作为参数,但如果我理解正确,损失函数必须只有参数 y_true 和 y_pred。

从文档( https://keras.io/api/losses/#creating-custom-losses ),但是:

创建自定义损失任何具有签名 loss_fn(y_true, y_pred) 的可调用函数返回损失数组(输入批次中的一个样本)都可以作为损失传递给 compile()。 请注意,任何此类损失都会自动支持样本加权。

听起来应该能够通过 model.fit(..., sample_weight=sample_weight) 方法使用样本加权。

在这篇文章中( Keras 中的自定义损失函数应该为批次返回单个损失值还是为训练批次中的每个样本返回一系列损失? )对损失函数的输出大小进行了长时间的讨论。

最后,还提到当创建自定义损失函数时,应该返回损失数组(单个样本损失)。 它们的减少由框架处理。

在我看来,如果 custom_loss(y_true, y_pred) 返回一个大小为 (batch_size, ) 的张量,那么应该能够在 fit 方法中使用 sample_weight 。 我错过了什么?

非常感谢您的帮助!

代码片段:

class NegLogLikMixedGaussian(Loss):
    """
    Negative Log-Likelihood of Mixed Gaussian with:
        num_components: number of components
        mu: means of the Gaussian components
        sg: standard deviations of the Gaussian components
    """

    def __init__(self, num_params=NUM_PARAMS_MG,
                 num_components=2, name='neg_log_lik_mixed_gaussian'):
        super(NegLogLikMixedGaussian, self).__init__(name=name)
        self.num_params = num_params
        self.num_components = num_components

    def call(self, y_true, p_predict):
        """
        Rem: for MDN the output of the networks are _parameters_ of the
        predicted distribution, _not_ point-estimates

        Parameters
        ----------
        y_true: (batch_size, 1)
            Observed value of the random variable
        p_predict: (batch_size, num_components)
            Output parameters of the network given some input

        Returns
        -------
        Negative log likelihood of the batch (batch_size, 1)

        """
        alpha, mu, sg = tf.split(p_predict,
                                 num_or_size_splits=self.num_params, axis=1)
        gm = tfd.MixtureSameFamily(
            mixture_distribution=tfd.Categorical(probs=alpha),
            components_distribution=tfd.Normal(loc=mu, scale=sg))
        log_likelihood = tf.transpose(gm.log_prob(tf.transpose(y_true)))
        return -tf.reduce_mean(log_likelihood, axis=-1)

我当时希望能够使用:

model.compile(optimizer=Adam(learning_rate=0.005),
                  loss=NegLogLikMixedGaussian(
                      num_components=2, num_params=3))

和:


# For testing purposes
sample_weight = np.ones(len(y_train)) / len(dh.y_train_scaled)  # this should give same results as un-weighted

# Some non-trivial weights
sample_weights = np.zeros(len(y_train))
sample_weights[:5] = 1
# This will give me same results as above


model.fit(x_train, y_train, sample_weight=sample_weight,
                      batch_size=128, epochs=10)

你的代码是正确的,除了一些细节,如果我理解你想要做什么。 样本权重应该是维度(样本数量),而损失应该是维度(batch_size)。 样本权重可以传递给 fit 方法,它似乎有效。 在您的自定义损失类中, num_components 和 num_params 已初始化,但在 call 方法中仅使用了两个参数之一。 我不确定我是否理解张量的维度(alpha、mu、sg),它是否具有维度(batch_size、3、num_components)并由模型预测? 以下是根据我对您的问题的理解,改编自您的代码。

import tensorflow as tf
import numpy as np
from tensorflow.keras.losses import Loss, BinaryCrossentropy
from tensorflow.keras import Model, Input
from tensorflow.keras.layers import Dense, Concatenate

import tensorflow_probability as tfp
tfd = tfp.distributions

# parameters
num_components = 2
num_samples = 1001
num_features = 10

# synthetic data
x_train = np.random.normal(size=(num_samples, num_features))
y_train = np.random.normal(size=(num_samples, 1, num_components))

print(x_train.shape)
print(y_train.shape)

class NegLogLikMixedGaussian(Loss):
    """
    Negative Log-Likelihood of Mixed Gaussian with:
        num_components: number of components
        mu: means of the Gaussian components
        sg: standard deviations of the Gaussian components
    """

    def __init__(self, num_components=2, name='neg_log_lik_mixed_gaussian'):
        super(NegLogLikMixedGaussian, self).__init__(name=name)
        self.num_components = num_components

    def call(self, y_true, p_predict):
        """
        Rem: for MDN the output of the networks are _parameters_ of the
        predicted distribution, _not_ point-estimates

        Parameters
        ----------
        y_true: (batch_size, 1, num_components)
            Observed value of the random variable
        p_predict: (batch_size, 3, num_components)
            Output parameters of the network given some input

        Returns
        -------
        Negative log likelihood of the batch (batch_size, 1)

        """
        alpha, mu, sg = tf.split(p_predict, num_or_size_splits=3, axis=1)
        gm = tfd.MixtureSameFamily(
            mixture_distribution=tfd.Categorical(probs=alpha),
            components_distribution=tfd.Normal(loc=mu, scale=sg))
        log_likelihood = gm.log_prob(y_true)
        return -tf.reduce_mean(log_likelihood, axis=[1, 2])

# the model (simple predicting (alpha, mu, sigma))
input = Input((num_features,))
alpha = tf.expand_dims(Dense(num_components, 'relu')(input), axis=1)+0.0001
# normalization
alpha = alpha/tf.reduce_sum(alpha, axis=2, keepdims=True)
mu = tf.expand_dims(Dense(num_components)(input), axis=1)
# sg > 0
sg = tf.expand_dims(Dense(num_components, 'relu')(input), axis=1)+ 0.0001

outputs = Concatenate(axis=1)([alpha, mu, sg])

model = Model(inputs=input, outputs=outputs, name='gmm_params')
model.compile(optimizer='adam', loss=NegLogLikMixedGaussian(num_components=num_components), run_eagerly=False)

sample_weight=np.ones((num_samples, ))
sample_weight[500:] = 0.

model.fit(x_train, y_train, batch_size=16, epochs=20, sample_weight=sample_weight)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM