二元交叉熵损失适用场景及TensorFlow实现相关技术问询
嘿,我来帮你理清这两个关于TensorFlow二元交叉熵损失的问题,都是猫狗二分类场景下的常见疑问,咱们一个个说:
你在Github和官网搜索没找到?其实公式藏在API文档的细节里,而且源码的计算逻辑完全对应标准的二元交叉熵公式(还有数值稳定的优化版本)。
首先,二元交叉熵的核心逻辑分两种情况,取决于from_logits参数:
当
from_logits=False时(默认),模型输出已经是经过sigmoid激活的概率值(范围0-1),损失公式是:
$$\text{Loss} = -\frac{1}{N} \sum_{i=1}^N \left[ y_i \cdot \log(\hat{y}_i) + (1 - y_i) \cdot \log(1 - \hat{y}_i) \right]$$
其中$y_i$是真实标签(0或1),$\hat{y}_i$是模型预测的概率。当
from_logits=True时,模型输出是未经过激活的logits(任意实数),为了避免直接计算sigmoid时的数值溢出,TensorFlow会用数值稳定的等价公式计算:
$$\text{Loss} = -\frac{1}{N} \sum_{i=1}^N \left[ y_i \cdot \log(\sigma(\text{logits}_i)) + (1 - y_i) \cdot \log(1 - \sigma(\text{logits}i)) \right]$$
而$\sigma(x) = \frac{1}{1 + e^{-x}}$,代入后可以简化为更稳定的形式:
$$\text{Loss} = -\frac{1}{N} \sum{i=1}^N \left[ \max(\text{logits}_i, 0) - y_i \cdot \text{logits}_i + \log(1 + e^{-|\text{logits}_i|}) \right]$$
如果你想看源码实现,可以在TensorFlow的Github仓库里找tf.keras.losses.BinaryCrossentropy的call方法,里面就是按照这个数值稳定的公式来写的,避免了直接计算sigmoid可能带来的梯度消失或溢出问题。
from_logits=True时目标标签的正确格式 对于猫狗二分类任务,正确的目标标签应该是单值的常量张量(比如[1]代表猫,[0]代表狗),而不是独热向量[[0,1]]。
为什么你用独热向量也能生效?其实是TensorFlow在底层做了自动适配,但这不是规范用法:
- 当你传入独热向量
[[0,1]]时,TensorFlow会把它当成形状为(batch_size, 2)的输入,而BinaryCrossentropy会默认对最后一维做处理,但实际上二元交叉熵是针对二分类(每个样本只有一个类别标签),独热向量是多分类(分类数>2)的用法。 - 正确的做法是让
y_true的形状和模型输出的y_pred一致:如果你的模型最后一层输出是(batch_size, 1)的logits,那么y_true也应该是(batch_size, 1)的张量,每个元素是0或1。
总结一下,tf.keras.losses.BinaryCrossentropy(from_logits=True)对应的损失公式就是上面提到的数值稳定版本,标签用单值0/1张量是规范且高效的做法。
内容的提问来源于stack exchange,提问作者Dato Nefaridze

