使用交叉熵时如何处理 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_value
或np.clip
)。
【讨论】:
【参考方案3】:您通常如何处理这个问题?
在predY
中添加一个小数字(例如 1e-15) - 这个数字不会使预测产生太大影响,它解决了 log(0) 问题。
顺便说一句,如果您的算法输出 0 和 1,检查返回概率的直方图可能很有用 - 当算法确定某事正在发生时,它可能是过度拟合的迹象。
【讨论】:
以上是关于使用交叉熵时如何处理 log(0)的主要内容,如果未能解决你的问题,请参考以下文章