TensorFlow中的S形跟S形交叉熵和Sigmoid_cross_entropy_with_logits有什么区别?
classification
machine-learning
tensorflow
9
0

当尝试通过S型激活函数获得交叉熵时,两者之间存在差异

  1. loss1 = -tf.reduce_sum(p*tf.log(q), 1)
  2. loss2 = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q),1)

但是使用softmax激活功能时它们是相同的。

以下是示例代码:

import tensorflow as tf

sess2 = tf.InteractiveSession()
p = tf.placeholder(tf.float32, shape=[None, 5])
logit_q = tf.placeholder(tf.float32, shape=[None, 5])
q = tf.nn.sigmoid(logit_q)
sess.run(tf.global_variables_initializer())

feed_dict = {p: [[0, 0, 0, 1, 0], [1,0,0,0,0]], logit_q: [[0.2, 0.2, 0.2, 0.2, 0.2], [0.3, 0.3, 0.2, 0.1, 0.1]]}
loss1 = -tf.reduce_sum(p*tf.log(q),1).eval(feed_dict)
loss2 = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q),1).eval(feed_dict)

print(p.eval(feed_dict), "\n", q.eval(feed_dict))
print("\n",loss1, "\n", loss2)
参考资料:
Stack Overflow
收藏
评论
共 1 个回答
高赞 时间 活跃

您将二元多类问题的交叉熵弄混了。

多类交叉熵

您使用的公式是正确的,它直接对应于tf.nn.softmax_cross_entropy_with_logits

-tf.reduce_sum(p * tf.log(q), axis=1)

预期pq是N个类别上的概率分布。特别是,N可以为2,如以下示例所示:

p = tf.placeholder(tf.float32, shape=[None, 2])
logit_q = tf.placeholder(tf.float32, shape=[None, 2])
q = tf.nn.softmax(logit_q)

feed_dict = {
  p: [[0, 1],
      [1, 0],
      [1, 0]],
  logit_q: [[0.2, 0.8],
            [0.7, 0.3],
            [0.5, 0.5]]
}

prob1 = -tf.reduce_sum(p * tf.log(q), axis=1)
prob2 = tf.nn.softmax_cross_entropy_with_logits(labels=p, logits=logit_q)
print(prob1.eval(feed_dict))  # [ 0.43748799  0.51301527  0.69314718]
print(prob2.eval(feed_dict))  # [ 0.43748799  0.51301527  0.69314718]

请注意, q正在计算tf.nn.softmax ,即输出概率分布。因此,它仍然是多类交叉熵公式,仅适用于N = 2。

二元交叉熵

这次正确的公式是

p * -tf.log(q) + (1 - p) * -tf.log(1 - q)

尽管从数学上讲这只是多类情况的一部分,但pq含义却有所不同。在最简单的情况下,每个pq是一个数字,对应于A类的概率。

重要说明 :不要对通用的p * -tf.log(q)部分和和感到困惑。先前的p是一个热向量,现在是一个数字,零或一。 q -这是一个概率分布,现在是一个数字(概率)。

如果p是一个向量,则每个单独的分量都被视为独立的二进制分类 。请参阅此答案 ,概述tensorflow中softmax和Sigmoid函数之间的区别。因此,定义p = [0, 0, 0, 1, 0]并不意味着一个热向量,而是5个不同的特征,其中4个处于关闭状态,而1个处于打开状态。定义q = [0.2, 0.2, 0.2, 0.2, 0.2]表示5个特征中的每一个均以20%的概率打开。

这解释了在交叉熵之前使用sigmoid函数的目的:其目的是将对数压缩到[0, 1]区间。

上面的公式仍然适用于多个独立功能,而这正是tf.nn.sigmoid_cross_entropy_with_logits计算结果:

p = tf.placeholder(tf.float32, shape=[None, 5])
logit_q = tf.placeholder(tf.float32, shape=[None, 5])
q = tf.nn.sigmoid(logit_q)

feed_dict = {
  p: [[0, 0, 0, 1, 0],
      [1, 0, 0, 0, 0]],
  logit_q: [[0.2, 0.2, 0.2, 0.2, 0.2],
            [0.3, 0.3, 0.2, 0.1, 0.1]]
}

prob1 = -p * tf.log(q)
prob2 = p * -tf.log(q) + (1 - p) * -tf.log(1 - q)
prob3 = p * -tf.log(tf.sigmoid(logit_q)) + (1-p) * -tf.log(1-tf.sigmoid(logit_q))
prob4 = tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q)
print(prob1.eval(feed_dict))
print(prob2.eval(feed_dict))
print(prob3.eval(feed_dict))
print(prob4.eval(feed_dict))

您应该看到最后三个张量相等,而prob1只是交叉熵的一部分,因此仅当p1时,它才包含正确的值:

[[ 0.          0.          0.          0.59813893  0.        ]
 [ 0.55435514  0.          0.          0.          0.        ]]
[[ 0.79813886  0.79813886  0.79813886  0.59813887  0.79813886]
 [ 0.5543552   0.85435522  0.79813886  0.74439669  0.74439669]]
[[ 0.7981388   0.7981388   0.7981388   0.59813893  0.7981388 ]
 [ 0.55435514  0.85435534  0.7981388   0.74439663  0.74439663]]
[[ 0.7981388   0.7981388   0.7981388   0.59813893  0.7981388 ]
 [ 0.55435514  0.85435534  0.7981388   0.74439663  0.74439663]]

现在应该清楚的是,尽管在多类情况下这是一个有效的公式,但沿axis=1-p * tf.log(q)和在这种设置下没有意义。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号