计算交叉熵损失时,在tf.losses.categorical_crossentropy()中设置from_logits=True。默认为 false,这意味着您直接使用-p*log(q) 计算交叉熵损失。通过设置from_logits=True,您正在使用-p*log(softmax(q)) 来计算损失。
更新:
只要找到一个有趣的结果。
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)
毕业生将是tf.Tensor([[-0.25 1. 1. ]], shape=(1, 3), dtype=float32)
之前,我认为 tensorflow 会使用loss=-\Sigma_i(p_i)\log(q_i) 来计算损失,如果我们在q_i 上推导,我们将得到导数是-p_i/q_i。所以,预期的毕业生应该是[-1.25, 0, 0]。但是输出的grads看起来都增加了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 = 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)
毕业生是tf.Tensor([[-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)。