【发布时间】:2020-01-17 19:34:01
【问题描述】:
在回答this question 之后,我在 tensorflow 2.0 中遇到了一些有趣但令人困惑的发现。 logits 的渐变对我来说看起来不正确。假设我们在这里有logits 和labels。
logits = tf.Variable([[0.8, 0.1, 0.1]], dtype=tf.float32)
labels = tf.constant([[1, 0, 0]],dtype=tf.float32)
with tf.GradientTape(persistent=True) as tape:
loss = tf.reduce_sum(tf.keras.losses.categorical_crossentropy(labels, logits,
from_logits=False))
grads = tape.gradient(loss, logits)
print(grads)
由于logits已经是概率分布,所以我在损失函数中设置了from_logits=False。
我认为 tensorflow 会使用loss=-\Sigma_i(p_i)\log(q_i) 来计算损失,如果我们在q_i 上推导,我们将得到-p_i/q_i 的导数。所以,预期的毕业生应该是[-1.25,0,0]。但是,张量流将返回 [-0.25,1,1]。
看了tf.categorical_crossentropy的源码后发现,即使我们设置了from_logits=False,它还是归一化了概率。这将改变最终的梯度表达式。具体来说,渐变将是-p_i/q_i+p_i/sum_j(q_j)。如果p_i=1 和sum_j(q_j)=1,最终的梯度将加一。这就是为什么梯度会是 -0.25,但是,我还没弄清楚为什么最后两个梯度会是 1。
为了证明所有梯度都增加了1/sum_j(q_j),我做了一个logits,它不是概率分布,仍然设置from_logits=False。
logits = tf.Variable([[0.5, 0.1, 0.1]], dtype=tf.float32)
labels = tf.constant([[1, 0, 0]],dtype=tf.float32)
with tf.GradientTape(persistent=True) as tape:
loss = tf.reduce_sum(tf.keras.losses.categorical_crossentropy(labels, logits,
from_logits=False))
grads = tape.gradient(loss, logits)
print(grads)
tensorflow返回的grads是[-0.57142866,1.4285713,1.4285713 ],我觉得应该是[-2,0,0]。
显示所有梯度都增加了1/(0.5+0.1+0.1)。对于p_i==1,渐变增加1/(0.5+0.1+0.1) 对我来说是有意义的。但是不明白为什么p_i==0,渐变还是增加了1/(0.5+0.1+0.1)。
更新
感谢@OverLordGoldDragon 的善意提醒。标准化概率后,正确的梯度公式应该是-p_i/q_i+1/sum_j(q_j)。所以问题中的行为是预期的。
【问题讨论】:
-
有趣的问题;还需要答案吗?
-
是的,请!我还没弄明白。
-
问题:
-p_i/q_i+p_i/sum_j(q_j)是您派生出来的,还是取自文本?问因为我实际上并不知道渐变的“公式” - 我有自己的推导,但它似乎与你的相矛盾 -
你是对的!我又推导出来了,公式应该是
-p_i/q_i+1/sum_j(q_j),也就是说每个渐变都会增加1/sum_j(q_j)。谢谢!我想当我问这个问题时,我错过了sum而不是p之一。
标签: python tensorflow deep-learning