Caffe SigmoidCrossEntropyLoss层损失函数

6
我正在查看Caffe的SigmoidCrossEntropyLoss层文档的代码,有些困惑。文档将损失函数列为逻辑损失(我可以在此处复制它,但是没有LaTeX,公式会很难读。请查看文档链接,在页面顶部)。
然而,代码本身(Forward_cpu(...))显示了不同的公式。
Dtype loss = 0;
for (int i = 0; i < count; ++i) {
    loss -= input_data[i] * (target[i] - (input_data[i] >= 0)) -
        log(1 + exp(input_data[i] - 2 * input_data[i] * (input_data[i] >= 0)));
}
top[0]->mutable_cpu_data()[0] = loss / num;

这是因为已经对输入应用了Sigmoid函数吗?然而,即便如此,"(input_data[i] >= 0)"这段代码也让我感到困惑。这些代码似乎代替了文档中的损失公式中的p_hat,后者应该是通过Sigmoid函数压缩的预测值。那么为什么它们只采用二进制阈值呢?更令人困惑的是,这个损失函数预测[0,1]输出,所以除非它100%确定不是,否则"(input_data[i] >= 0)"将会是1。请问有人能解释一下这个问题吗?
1个回答

6

SigmoidCrossEntropy层在caffe中将两个步骤(Sigmoid + CrossEntropy)结合在一起,对input_data执行一组代码:

Dtype loss = 0;
for (int i = 0; i < count; ++i) {
    loss -= input_data[i] * (target[i] - (input_data[i] >= 0)) -
        log(1 + exp(input_data[i] - 2 * input_data[i] * (input_data[i] >= 0)));
}
top[0]->mutable_cpu_data()[0] = loss / num;

实际上,无论input_data >= 0是否成立,上述代码在数学上总是等价于以下代码:

Dtype loss = 0;
for (int i = 0; i < count; ++i) {
    loss -= input_data[i] * (target[i] - 1) -
        log(1 + exp(-input_data[i]);
}
top[0]->mutable_cpu_data()[0] = loss / num;

这段代码基于一个简单的数学公式,在对input_data应用SigmoidCrossEntropy后进行一些数学组合。

但是caffe使用的第一段代码具有更好的数值稳定性,并且冒更少的溢出风险,因为它避免在input_data的绝对值过大时计算一个巨大的exp(input_data)(或exp(-input_data))。这就是为什么你在caffe中看到了那段代码。


如果使用软地面实况标签(即[0,1]而不是{0,1}),是否需要更改任何内容? - marcman
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Dale
我认为我理解为什么会出现这种情况,但实际上,当我对每个标签进行归一化时,我开始得到NaN损失,尽管这可能是学习率问题。 - marcman
如果输入到损失函数的数据过大,您可以考虑将图像数据从[0,255]重新缩放为[0,1]。@marcman - Dale
嗨,我是Caffe的新手。你能解释一下top[0]是什么以及为什么要使用top[0]->mutable_cpu_data()[0]吗?谢谢。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接