短版:
假设您有两个张量,其中y_hat包含每个类的计算分数(例如,从y = W*x +b开始),y_true包含单热编码的true标签。
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
如果将y_hat中的分数解释为非标准化的对数概率,那么它们就是对数。
此外,总交叉熵损失计算如下:
y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))
本质上等同于用函数softmax_cross_entropy_with_logits()计算的总交叉熵损失:
total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
长版:
在神经网络的输出层,你可能会计算一个数组,其中包含每个训练实例的类分数,例如从计算y_hat = W*x + b。作为一个例子,下面我创建了一个2 x 3的y_hat数组,其中行对应训练实例,列对应类。这里有2个训练实例和3个类。
import tensorflow as tf
import numpy as np
sess = tf.Session()
# Create example y_hat.
y_hat = tf.convert_to_tensor(np.array([[0.5, 1.5, 0.1],[2.2, 1.3, 1.7]]))
sess.run(y_hat)
# array([[ 0.5, 1.5, 0.1],
# [ 2.2, 1.3, 1.7]])
注意,这些值不是归一化的(即行加起来不等于1)。为了将它们归一化,我们可以应用softmax函数,它将输入解释为非归一化的对数概率(又名logits),并将输出解释为归一化的线性概率。
y_hat_softmax = tf.nn.softmax(y_hat)
sess.run(y_hat_softmax)
# array([[ 0.227863 , 0.61939586, 0.15274114],
# [ 0.49674623, 0.20196195, 0.30129182]])
充分理解softmax输出的含义是很重要的。下面我展示了一个更清楚地表示上面输出的表。可以看出,例如,训练实例1为“Class 2”的概率为0.619。每个训练实例的类概率是标准化的,所以每一行的和是1.0。
Pr(Class 1) Pr(Class 2) Pr(Class 3)
,--------------------------------------
Training instance 1 | 0.227863 | 0.61939586 | 0.15274114
Training instance 2 | 0.49674623 | 0.20196195 | 0.30129182
现在我们有了每个训练实例的类概率,我们可以使用每行的argmax()来生成最终的分类。从上面,我们可以生成训练实例1属于“类2”,训练实例2属于“类1”。
这些分类正确吗?我们需要与训练集中的真实标签进行比较。您将需要一个单热编码的y_true数组,其中的行是训练实例,列是类。下面我创建了一个示例y_true单热数组,其中训练实例1的真标签是“Class 2”,训练实例2的真标签是“Class 3”。
y_true = tf.convert_to_tensor(np.array([[0.0, 1.0, 0.0],[0.0, 0.0, 1.0]]))
sess.run(y_true)
# array([[ 0., 1., 0.],
# [ 0., 0., 1.]])
y_hat_softmax中的概率分布是否接近y_true中的概率分布?我们可以用交叉熵损失来测量误差。
We can compute the cross-entropy loss on a row-wise basis and see the results. Below we can see that training instance 1 has a loss of 0.479, while training instance 2 has a higher loss of 1.200. This result makes sense because in our example above, y_hat_softmax showed that training instance 1's highest probability was for "Class 2", which matches training instance 1 in y_true; however, the prediction for training instance 2 showed a highest probability for "Class 1", which does not match the true class "Class 3".
loss_per_instance_1 = -tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1])
sess.run(loss_per_instance_1)
# array([ 0.4790107 , 1.19967598])
我们真正想要的是所有训练实例的总损失。所以我们可以计算:
total_loss_1 = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1]))
sess.run(total_loss_1)
# 0.83934333897877944
使用softmax_cross_entropy_with_logits ()
我们可以使用tf.nn.softmax_cross_entropy_with_logits()函数来计算总交叉熵损失,如下所示。
loss_per_instance_2 = tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true)
sess.run(loss_per_instance_2)
# array([ 0.4790107 , 1.19967598])
total_loss_2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
sess.run(total_loss_2)
# 0.83934333897877922
请注意,total_loss_1和total_loss_2产生的结果本质上是相同的,只是在最后的数字上有一些微小的差异。但是,您也可以使用第二种方法:它只需要少一行代码,积累的数值错误也更少,因为softmax是在softmax_cross_entropy_with_logits()中为您完成的。