You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在损失函数中对真阳性加权?基于TensorFlow二元交叉熵方案

如何在损失函数中对真阳性相关错误(假阴性)进行加权?

这问题在样本不平衡的任务里太常见了——比如医疗诊断中漏诊(假阴性)的代价远高于误诊(假阳性),这时候我们就需要给假阴性对应的损失项加权重,让模型更重视正样本的预测。咱们从TensorFlow里最常用的二元交叉熵(BCE)开始拆解:

首先是标准的二元交叉熵损失公式:
$$\mathcal{L}(\mathbf y, \mathbf t)=-\frac {1}{N}\sum_n \left[ t_n\log y_n + (1-t_n)\log (1-y_n) \right]$$
其中:

  • $t_n \in {0,1}$:第n个样本的真实标签(1代表正样本,0代表负样本)
  • $y_n \in [0,1]$:模型对第n个样本的预测概率
  • $N$:总样本数

这里要明确:公式里的第一项$t_n\log y_n$对应的是假阴性的损失——当$t_n=1$(真实是正样本)但$y_n$趋近于0(模型预测成负样本)时,这一项的绝对值会变得很大,也就是损失很高。如果我们需要进一步加重对假阴性的惩罚,就可以给这一项引入权重。

加权版二元交叉熵

我们给正样本对应的损失项引入权重$\mathbf c_n$(可以是全局统一值,也可以是每个样本的单独权重),公式就变成:
$$\mathcal{L}(\mathbf y, \mathbf c, \mathbf t)=-\frac {1}{N}\sum_n \left[ c_n \cdot t_n\log y_n + (1-t_n)\log (1-y_n) \right]$$

  • 如果是针对整个正样本类别加权,比如正样本占比只有10%,可以把$c_n$设为固定值$c = \frac{\text{负样本数量}}{\text{正样本数量}}$(比如9),这样就能平衡正负样本的损失贡献。
  • 如果是针对单个样本的个性化权重(比如某些正样本的优先级更高),可以给每个样本分配对应的$c_n$。

TensorFlow中的实现方式

1. 使用内置损失函数的class_weight参数

如果是类别级别的加权,直接用tf.keras.losses.BinaryCrossentropy配合模型拟合时的class_weight参数就可以:

import tensorflow as tf

# 假设正样本权重设为9,负样本为1
class_weights = {0: 1.0, 1: 9.0}

model.compile(
    optimizer='adam',
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),
    metrics=['accuracy']
)

model.fit(x_train, y_train, class_weight=class_weights, epochs=10)

2. 自定义加权损失函数

如果需要更灵活的样本级加权,或者手动控制损失计算逻辑,可以自定义损失函数:

def weighted_bce(positive_weight):
    def loss(y_true, y_pred):
        # 加入极小值避免log(0)的数值问题
        y_pred = tf.clip_by_value(y_pred, 1e-7, 1 - 1e-7)
        # 正样本损失项(假阴性惩罚)
        pos_loss = y_true * tf.math.log(y_pred) * positive_weight
        # 负样本损失项
        neg_loss = (1 - y_true) * tf.math.log(1 - y_pred)
        # 计算平均损失并取反(BCE是负对数似然)
        return -tf.reduce_mean(pos_loss + neg_loss)
    return loss

# 使用时传入正样本权重
model.compile(optimizer='adam', loss=weighted_bce(positive_weight=9.0))

3. 样本级加权的自定义损失

如果每个样本都有单独的权重,可以把权重作为输入传入(需要调整模型的输入结构):

def sample_weighted_bce(y_true, y_pred, sample_weights):
    y_pred = tf.clip_by_value(y_pred, 1e-7, 1 - 1e-7)
    pos_loss = y_true * tf.math.log(y_pred)
    neg_loss = (1 - y_true) * tf.math.log(1 - y_pred)
    # 给每个样本的损失乘以对应的权重
    weighted_loss = sample_weights * (pos_loss + neg_loss)
    return -tf.reduce_mean(weighted_loss)

内容的提问来源于stack exchange,提问作者Nickpick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:10:56