【问题标题】:Model with normalized binary cross entropy loss does not converge具有归一化二元交叉熵损失的模型不收敛
【发布时间】:2022-11-18 14:07:29
【问题描述】:

我正在尝试为本文之后的分类任务实施归一化二进制交叉熵:Normalized Loss Functions for Deep Learning with Noisy Labels。 数学计算如下:

这是我的实现:

import tensorflow as tf
from keras.utils import losses_utils

class NormalizedBinaryCrossentropy(tf.keras.losses.Loss):
    def __init__(
            self,
            from_logits=False,
            label_smoothing=0.0,
            axis=-1,
            reduction=tf.keras.losses.Reduction.NONE,
            name="normalized_binary_crossentropy",
            **kwargs
    ):
        super().__init__(
            reduction=reduction, name=name
        )
        self.from_logits = from_logits
        self._epsilon = tf.keras.backend.epsilon()

    def call(self, target, logits):
        if tf.is_tensor(logits) and tf.is_tensor(target):
            logits, target = losses_utils.squeeze_or_expand_dimensions(
                logits, target
            )
        logits = tf.convert_to_tensor(logits)
        target = tf.cast(target, logits.dtype)

        if self.from_logits:
            logits = tf.math.sigmoid(logits)

        logits = tf.clip_by_value(logits, self._epsilon, 1.0 - self._epsilon)

        numer = target * tf.math.log(logits) + (1 - target) * tf.math.log(1 - logits)
        denom = - (tf.math.log(logits) + tf.math.log(1 - logits))
        return - numer / denom

    def get_config(self):
        config = super().get_config()
        config.update({"from_logits": self._from_logits})
        return config

我正在使用这种损失来训练二元分类器(CTR 预测器),但模型的损失并没有减少,ROC-AUC 保持在 ~0.49-0.5。为了验证分子的实现,我尝试通过删除分母来进行训练并且它工作正常。

# Example Usage

labels = np.array([[0], [1], [0], [0], [0]]).astype(np.int64)

logits = np.array([[-1.024], [2.506], [1.43], [0.004], [-2.0]]).astype(np.float64)

tf_nce = NormalizedBinaryCrossentropy(
    reduction=tf.keras.losses.Reduction.NONE,
    from_logits=True
)
tf_nce(labels, logits)

#<tf.Tensor: shape=(5, 1), dtype=float64, numpy=
# array([[0.18737159],
#  [0.02945536],
#  [0.88459308],
#  [0.50144269],
#  [0.05631594]])>

我手动检查了一些极端情况,发现损失没有达到 nans 或 0s。

谁能帮我调试为什么模型无法收敛于这种损失?我对损失函数或实现的理解有问题吗?

编辑 1:模型架构是具有 6 个任务的多门混合专家。所有 6 个任务都是二进制分类,将所有任务的损失加在一起得到最终损失。

【问题讨论】:

    标签: tensorflow keras deep-learning loss-function


    【解决方案1】:

    如上所述,论文中提到的一件事是损失的范数应包含在两者之间[0 ~ 1]但是因为你的损失违反了这个条件Normalized Binary Cross Entropy另一个原因是你除以错误的分母,你必须将它除以你的logits 的交叉熵,为此取你的logits 的BinaryCrossEntropy()。所以,这些可能是你的功能没有减少的原因......我对你的代码做了一些改变以满足这个规范属性......

    import tensorflow as tf
    from keras.utils import losses_utils
    
    class NormalizedBinaryCrossentropy(tf.keras.losses.Loss):
        def __init__(
                self,
                from_logits=False,
                label_smoothing=0.0,
                axis=-1,
                reduction=tf.keras.losses.Reduction.NONE,
                name="normalized_binary_crossentropy",
                **kwargs
        ):
            super().__init__(
                reduction=reduction, name=name
            )
            self.from_logits = from_logits
            self._epsilon = tf.keras.backend.epsilon()
    
        def call(self, target, logits):
            if tf.is_tensor(logits) and tf.is_tensor(target):
                logits, target = losses_utils.squeeze_or_expand_dimensions(
                    logits, target
                )
            logits = tf.convert_to_tensor(logits)
            target = tf.cast(target, logits.dtype)
    
            if self.from_logits:
                logits = tf.nn.sigmoid(logits)
    
            logits = tf.clip_by_value(logits, self._epsilon, 1.0 - self._epsilon)
            print(logits)
            numer = target * tf.math.log(logits) + (1 - target) * tf.math.log(1 - logits)
            logits = tf.clip_by_value(logits, self._epsilon, 1.0 - self._epsilon)
    
            numer = target * tf.math.log(logits) + (1 - target) * tf.math.log(1 - logits)
            denom = - (tf.math.log(logits) + tf.math.log(1 - logits))
            return  -numer * denom / tf.reduce_sum(denom)
    
        def get_config(self):
            config = super().get_config()
            config.update({"from_logits": self._from_logits})
            return config
    

    【讨论】:

    • 感谢您的回复!我试过这种损失,但损失似乎在增加,并且 roc-auc 出现在~.40
    • 我已经编辑了答案,请检查一下。
    • 首先阅读介绍...
    • 正如我在 cmets 中提到的那样,我将建议您采用平均损失。
    • 刚刚尝试了与您分享的相同的损失,但仍然无效。并且交叉熵损失 > 1(我刚才在 100s 中得到它)。在我分享的示例上运行它,即使返回一些值 >1 和一些负值。
    猜你喜欢
    • 2021-11-25
    • 2018-09-12
    • 2021-09-12
    • 2020-12-08
    • 2020-09-30
    • 2021-07-23
    • 2021-08-25
    • 1970-01-01
    • 2020-03-03
    相关资源
    最近更新 更多