使用交叉熵时如何处理 log(0)

Posted

技术标签:

【中文标题】使用交叉熵时如何处理 log(0)【英文标题】:How to handle log(0) when using cross entropy 【发布时间】:2018-10-05 17:09:55 【问题描述】:

为了使案例简单直观,我将使用二进制(0和1)分类进行说明。

损失函数

loss = np.multiply(np.log(predY), Y) + np.multiply((1 - Y), np.log(1 - predY)) #cross entropy
cost = -np.sum(loss)/m #num of examples in batch is m

Y的概率

predY 是使用 sigmoid 计算的,logits 可以被认为是到达分类步骤之前神经网络的结果

predY = sigmoid(logits) #binary case

def sigmoid(X):
    return 1/(1 + np.exp(-X))

问题

假设我们正在运行一个前馈网络。

输入:[3, 5]:3 是示例数,5 是特征大小(制造数据)

隐藏单元数:100(只有 1 个隐藏层)

迭代次数:10000

这样的安排被设置为过拟合。当它过拟合时,我们可以完美地预测训练样本的概率;换句话说,sigmoid 输出 1 或 0,精确的数字,因为指数会爆炸。如果是这种情况,我们将有 np.log(0)undefined。您通常如何处理这个问题?

【问题讨论】:

对于二元分类,Y 是否只包含值 0 和 1? @WarrenWeckesser 正确。 【参考方案1】:

如果你不介意对 scipy 的依赖,可以使用scipy.special.xlogy。您将替换表达式

np.multiply(np.log(predY), Y) + np.multiply((1 - Y), np.log(1 - predY))

xlogy(Y, predY) + xlogy(1 - Y, 1 - predY)

如果您希望 predY 包含非常小的值,则在第二项中使用 scipy.special.xlog1py 可能会获得更好的数值结果:

xlogy(Y, predY) + xlog1py(1 - Y, -predY)

或者,知道Y 中的值是0 或1,您可以用完全不同的方式计算成本:

Yis1 = Y == 1
cost = -(np.log(predY[Yis1]).sum() + np.log(1 - predY[~Yis1]).sum())/m

【讨论】:

事实上 tensorflow 确实提供了它自己的函数版本为tf.math.xlogy。也许它是新的,但在发布此答案时并未添加。【参考方案2】:

处理 log(x) 和 y / x 的一种常用方法是添加一个小常数(如 Jakub 所写),其中 x 始终为非负但可以变为 0。 p>

您还可以剪辑值(例如tf.clip_by_valuenp.clip)。

【讨论】:

【参考方案3】:

您通常如何处理这个问题?

predY 中添加一个小数字(例如 1e-15) - 这个数字不会使预测产生太大影响,它解决了 log(0) 问题。

顺便说一句,如果您的算法输出 0 和 1,检查返回概率的直方图可能很有用 - 当算法确定某事正在发生时,它可能是过度拟合的迹象。

【讨论】:

以上是关于使用交叉熵时如何处理 log(0)的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow交叉熵计算错误

机器学习:交叉熵损失函数

交叉熵损失函数详解

如何处理交叉导入?

交叉熵误差函数

深度学习系列36:交叉熵笔记