什么是逻辑? softmax 和 softmax_cross_entropy_with_logits 有什么区别?
What are logits? What is the difference between softmax and softmax_cross_entropy_with_logits?
在 tensorflow API docs 中,他们使用了一个名为 logits
的关键字。它是什么?很多方法都是这样写的:
tf.nn.softmax(logits, name=None)
如果 logits
只是一个通用的 Tensor
输入,为什么它被命名为 logits
?
其次,下面两种方法有什么区别?
tf.nn.softmax(logits, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
我知道 tf.nn.softmax
的作用,但不知道另一个。一个例子会很有帮助。
softmax+logits 只是意味着该函数对较早层的未缩放输出进行操作,并且理解单位的相对比例是线性的。特别是,这意味着输入的总和可能不等于 1,即值是 而不是 的概率(您的输入可能为 5)。在内部,它首先将 softmax 应用于未缩放的输出,然后计算这些值与标签定义的“应该”值的交叉熵。
tf.nn.softmax
产生将 softmax function 应用于输入张量的结果。 softmax“挤压”输入使得 sum(input) = 1
,它通过将输入解释为对数概率 (logits) 然后将它们转换回 0 到 1 之间的原始概率来进行映射。 softmax与输入相同:
a = tf.constant(np.array([[.1, .3, .5, .9]]))
print s.run(tf.nn.softmax(a))
[[ 0.16838508 0.205666 0.25120102 0.37474789]]
请参阅 this answer 了解为什么 softmax 在 DNN 中被广泛使用的更多信息。
tf.nn.softmax_cross_entropy_with_logits
在应用 softmax 函数后将 softmax 步骤与交叉熵损失的计算相结合,但它以一种更数学上谨慎的方式将它们结合在一起。它类似于以下结果:
sm = tf.nn.softmax(x)
ce = cross_entropy(sm)
交叉熵是一个汇总指标:它对所有元素求和。 tf.nn.softmax_cross_entropy_with_logits
在形状 [2,5]
张量上的输出是形状 [2,1]
(第一个维度被视为批处理)。
如果你想做优化以最小化交叉熵 AND 你在最后一层之后进行 softmaxing,你应该使用 tf.nn.softmax_cross_entropy_with_logits
而不是自己做,因为它以数学上正确的方式涵盖了数值上不稳定的极端情况。否则,您最终会通过在各处添加小 epsilon 来破解它。
2016-02-07 编辑:
如果您有单个 class 标签,其中一个对象只能属于一个 class,您现在可以考虑使用 tf.nn.sparse_softmax_cross_entropy_with_logits
,这样您就不必将标签转换为密集单热阵列。此功能是0.6.0版本后添加的
tf.nn.softmax
计算通过 softmax 层的前向传播。当您计算模型输出的概率时,您可以在模型的 评估 期间使用它。
tf.nn.softmax_cross_entropy_with_logits
计算 softmax 层的成本。它仅在 训练 期间使用。
logits 是 未规范化的对数概率 输出模型(应用 softmax 规范化之前输出的值)。
短版:
假设您有两个张量,其中 y_hat
包含每个 class 的计算得分(例如,来自 y = W*x +b)并且 y_true
包含单热编码的真实标签。
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
如果您将 y_hat
中的分数解释为非标准化对数概率,则它们是 logits.
此外,以这种方式计算的总交叉熵损失:
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))
长版:
在神经网络的输出层,您可能会计算一个数组,其中包含每个训练实例的 class 分数,例如来自计算 y_hat = W*x + b
的分数。作为示例,下面我创建了一个 y_hat
作为 2 x 3 数组,其中行对应于训练实例,列对应于 classes。所以这里有 2 个训练实例和 3 个 classes.
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 输出的含义很重要。下面我显示了一个 table 更清楚地表示上面的输出。可以看出,例如训练实例1为"Class 2"的概率为0.619。每个训练实例的 class 概率被归一化,因此每行的总和为 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
所以现在我们有每个训练实例的 class 概率,我们可以在其中使用每行的 argmax() 来生成最终的 class 化。从上面,我们可以生成训练实例 1 属于 "Class 2",训练实例 2 属于 "Class 1"。
这些 class说明是否正确?我们需要根据训练集中的真实标签进行测量。您将需要一个单热编码的 y_true
数组,其中行再次是训练实例,列是 classes。下面我创建了一个示例 y_true
one-hot 数组,其中训练实例 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
中的概率分布?我们可以用cross-entropy loss来衡量误差。
我们可以逐行计算交叉熵损失并查看结果。下面我们可以看到训练实例 1 的损失为 0.479,而训练实例 2 的损失更高,为 1.200。这个结果是有道理的,因为在我们上面的例子中,y_hat_softmax
表明训练实例 1 的最高概率是 "Class 2",这与 y_true
中的训练实例 1 匹配;然而,训练实例 2 的预测显示 "Class 1" 的概率最高,这与真实的 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()
.
内部为您完成的
以上答案对所提问题有足够的描述。
除此之外,Tensorflow 优化了应用激活函数然后使用其自身的激活计算成本的操作,然后是成本函数。因此,最好使用:tf.nn.softmax_cross_entropy()
over tf.nn.softmax(); tf.nn.cross_entropy()
您可以在资源密集型模型中发现它们之间的显着差异。
Tensorflow 2.0 Compatible Answer: dga
和Whosebuguser2010
的解释很详细,关于Logits和相关函数。
所有这些函数在 Tensorflow 1.x
中使用时都可以正常工作,但是如果您将代码从 1.x (1.14, 1.15, etc)
到 2.x (2.0, 2.1, etc..)
,使用这些函数会导致错误。
因此,为了社区的利益,如果我们从 1.x to 2.x
迁移,请为我们上面讨论的所有功能指定 2.0 兼容调用。
1.x中的函数:
tf.nn.softmax
tf.nn.softmax_cross_entropy_with_logits
tf.nn.sparse_softmax_cross_entropy_with_logits
从1.x迁移到2.x时的各自功能:
tf.compat.v2.nn.softmax
tf.compat.v2.nn.softmax_cross_entropy_with_logits
tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits
有关从 1.x 迁移到 2.x 的更多信息,请参阅此 Migration Guide。
还有一件事我绝对想强调,因为 logit 只是原始输出,通常是最后一层的输出。这也可以是负值。如果我们按原样使用它进行 "cross entropy" 评估,如下所述:
-tf.reduce_sum(y_true * tf.log(logits))
那就不行了。由于未定义 -ve 的日志。
所以使用 o softmax 激活,将克服这个问题。
这是我的理解,如有错误请指正
学期的数学动机
当我们希望将输出约束在 0 和 1 之间,但我们的模型架构输出不受约束的值时,我们可以添加规范化层来强制执行此操作。
一个常见的选择是 sigmoid 函数。1 在二进制 classification 中,这通常是逻辑函数,在 multi-class 任务多项逻辑函数 (a.k.a softmax).2
如果我们想将新的最后一层的输出解释为 'probabilities',那么(暗示)我们的 sigmoid 的无约束输入必须是 inverse-sigmoid
(概率)。在逻辑案例中,这相当于我们概率的 log-odds(即 odds) a.k.a. logit:
的对数
这就是为什么 softmax
的参数在 Tensorflow 中被称为 logits
- 因为假设 softmax
是模型中的最后一层,并且输出 p被解释为概率,该层的输入x被解释为logit:
广义术语
在机器学习中,倾向于概括从 maths/stats/computer 科学中借用的术语,因此在 Tensorflow 中 logit
(通过类比)被用作许多规范化函数的输入的同义词。
- 虽然它具有易于区分和上述概率解释等良好特性,但它有点 arbitrary。
softmax
可能更准确地称为 softargmax,因为它是 smooth approximation of the argmax function.
在 tensorflow API docs 中,他们使用了一个名为 logits
的关键字。它是什么?很多方法都是这样写的:
tf.nn.softmax(logits, name=None)
如果 logits
只是一个通用的 Tensor
输入,为什么它被命名为 logits
?
其次,下面两种方法有什么区别?
tf.nn.softmax(logits, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
我知道 tf.nn.softmax
的作用,但不知道另一个。一个例子会很有帮助。
softmax+logits 只是意味着该函数对较早层的未缩放输出进行操作,并且理解单位的相对比例是线性的。特别是,这意味着输入的总和可能不等于 1,即值是 而不是 的概率(您的输入可能为 5)。在内部,它首先将 softmax 应用于未缩放的输出,然后计算这些值与标签定义的“应该”值的交叉熵。
tf.nn.softmax
产生将 softmax function 应用于输入张量的结果。 softmax“挤压”输入使得 sum(input) = 1
,它通过将输入解释为对数概率 (logits) 然后将它们转换回 0 到 1 之间的原始概率来进行映射。 softmax与输入相同:
a = tf.constant(np.array([[.1, .3, .5, .9]]))
print s.run(tf.nn.softmax(a))
[[ 0.16838508 0.205666 0.25120102 0.37474789]]
请参阅 this answer 了解为什么 softmax 在 DNN 中被广泛使用的更多信息。
tf.nn.softmax_cross_entropy_with_logits
在应用 softmax 函数后将 softmax 步骤与交叉熵损失的计算相结合,但它以一种更数学上谨慎的方式将它们结合在一起。它类似于以下结果:
sm = tf.nn.softmax(x)
ce = cross_entropy(sm)
交叉熵是一个汇总指标:它对所有元素求和。 tf.nn.softmax_cross_entropy_with_logits
在形状 [2,5]
张量上的输出是形状 [2,1]
(第一个维度被视为批处理)。
如果你想做优化以最小化交叉熵 AND 你在最后一层之后进行 softmaxing,你应该使用 tf.nn.softmax_cross_entropy_with_logits
而不是自己做,因为它以数学上正确的方式涵盖了数值上不稳定的极端情况。否则,您最终会通过在各处添加小 epsilon 来破解它。
2016-02-07 编辑:
如果您有单个 class 标签,其中一个对象只能属于一个 class,您现在可以考虑使用 tf.nn.sparse_softmax_cross_entropy_with_logits
,这样您就不必将标签转换为密集单热阵列。此功能是0.6.0版本后添加的
tf.nn.softmax
计算通过 softmax 层的前向传播。当您计算模型输出的概率时,您可以在模型的 评估 期间使用它。
tf.nn.softmax_cross_entropy_with_logits
计算 softmax 层的成本。它仅在 训练 期间使用。
logits 是 未规范化的对数概率 输出模型(应用 softmax 规范化之前输出的值)。
短版:
假设您有两个张量,其中 y_hat
包含每个 class 的计算得分(例如,来自 y = W*x +b)并且 y_true
包含单热编码的真实标签。
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
如果您将 y_hat
中的分数解释为非标准化对数概率,则它们是 logits.
此外,以这种方式计算的总交叉熵损失:
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))
长版:
在神经网络的输出层,您可能会计算一个数组,其中包含每个训练实例的 class 分数,例如来自计算 y_hat = W*x + b
的分数。作为示例,下面我创建了一个 y_hat
作为 2 x 3 数组,其中行对应于训练实例,列对应于 classes。所以这里有 2 个训练实例和 3 个 classes.
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 输出的含义很重要。下面我显示了一个 table 更清楚地表示上面的输出。可以看出,例如训练实例1为"Class 2"的概率为0.619。每个训练实例的 class 概率被归一化,因此每行的总和为 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
所以现在我们有每个训练实例的 class 概率,我们可以在其中使用每行的 argmax() 来生成最终的 class 化。从上面,我们可以生成训练实例 1 属于 "Class 2",训练实例 2 属于 "Class 1"。
这些 class说明是否正确?我们需要根据训练集中的真实标签进行测量。您将需要一个单热编码的 y_true
数组,其中行再次是训练实例,列是 classes。下面我创建了一个示例 y_true
one-hot 数组,其中训练实例 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
中的概率分布?我们可以用cross-entropy loss来衡量误差。
我们可以逐行计算交叉熵损失并查看结果。下面我们可以看到训练实例 1 的损失为 0.479,而训练实例 2 的损失更高,为 1.200。这个结果是有道理的,因为在我们上面的例子中,y_hat_softmax
表明训练实例 1 的最高概率是 "Class 2",这与 y_true
中的训练实例 1 匹配;然而,训练实例 2 的预测显示 "Class 1" 的概率最高,这与真实的 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()
.
以上答案对所提问题有足够的描述。
除此之外,Tensorflow 优化了应用激活函数然后使用其自身的激活计算成本的操作,然后是成本函数。因此,最好使用:tf.nn.softmax_cross_entropy()
over tf.nn.softmax(); tf.nn.cross_entropy()
您可以在资源密集型模型中发现它们之间的显着差异。
Tensorflow 2.0 Compatible Answer: dga
和Whosebuguser2010
的解释很详细,关于Logits和相关函数。
所有这些函数在 Tensorflow 1.x
中使用时都可以正常工作,但是如果您将代码从 1.x (1.14, 1.15, etc)
到 2.x (2.0, 2.1, etc..)
,使用这些函数会导致错误。
因此,为了社区的利益,如果我们从 1.x to 2.x
迁移,请为我们上面讨论的所有功能指定 2.0 兼容调用。
1.x中的函数:
tf.nn.softmax
tf.nn.softmax_cross_entropy_with_logits
tf.nn.sparse_softmax_cross_entropy_with_logits
从1.x迁移到2.x时的各自功能:
tf.compat.v2.nn.softmax
tf.compat.v2.nn.softmax_cross_entropy_with_logits
tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits
有关从 1.x 迁移到 2.x 的更多信息,请参阅此 Migration Guide。
还有一件事我绝对想强调,因为 logit 只是原始输出,通常是最后一层的输出。这也可以是负值。如果我们按原样使用它进行 "cross entropy" 评估,如下所述:
-tf.reduce_sum(y_true * tf.log(logits))
那就不行了。由于未定义 -ve 的日志。 所以使用 o softmax 激活,将克服这个问题。
这是我的理解,如有错误请指正
学期的数学动机
当我们希望将输出约束在 0 和 1 之间,但我们的模型架构输出不受约束的值时,我们可以添加规范化层来强制执行此操作。
一个常见的选择是 sigmoid 函数。1 在二进制 classification 中,这通常是逻辑函数,在 multi-class 任务多项逻辑函数 (a.k.a softmax).2
如果我们想将新的最后一层的输出解释为 'probabilities',那么(暗示)我们的 sigmoid 的无约束输入必须是 inverse-sigmoid
(概率)。在逻辑案例中,这相当于我们概率的 log-odds(即 odds) a.k.a. logit:
这就是为什么 softmax
的参数在 Tensorflow 中被称为 logits
- 因为假设 softmax
是模型中的最后一层,并且输出 p被解释为概率,该层的输入x被解释为logit:
广义术语
在机器学习中,倾向于概括从 maths/stats/computer 科学中借用的术语,因此在 Tensorflow 中 logit
(通过类比)被用作许多规范化函数的输入的同义词。
- 虽然它具有易于区分和上述概率解释等良好特性,但它有点 arbitrary。
softmax
可能更准确地称为 softargmax,因为它是 smooth approximation of the argmax function.