什么是logit ?softmax和softmax_cross_entropy_with_logits有什么区别?

tensorflow API文档中,它们使用一个名为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做什么,但不知道其他的。举个例子会很有帮助。

226384 次浏览

softmax+logits仅仅意味着该函数对早期层的未缩放输出进行操作,并且理解单位的相对缩放是线性的。这意味着,特别是,输入的总和可能不等于1,这些值是概率(你可能有一个5的输入)。在内部,它首先对未缩放的输出应用softmax,然后,然后计算这些值与他们“应该”的交叉熵。正如标签所定义的那样。

tf.nn.softmax产生将softmax函数应用于输入张量的结果。softmax“squishes"它通过将输入解释为对数概率(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]]

有关为什么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](第一个维度被视为批处理)。

如果你想做优化来最小化交叉熵,你在最后一层之后进行软max,你应该使用tf.nn.softmax_cross_entropy_with_logits而不是自己做,因为它以数学正确的方式涵盖了数值不稳定的角落情况。否则,你就会在这里和那里加上小的。

<强>编辑2016-02-07: 如果你有单类标签,一个对象只能属于一个类,你现在可以考虑使用tf.nn.sparse_softmax_cross_entropy_with_logits,这样你就不必把标签转换成密集的单热数组。该函数是在0.6.0版本后添加的

tf.nn.softmax通过softmax层计算正向传播。当你计算模型输出的概率时,你可以在模型的评价期间使用它。

tf.nn.softmax_cross_entropy_with_logits计算softmax层的开销。它只在培训期间使用。

对数是模型的非归一化对数概率输出(在应用softmax归一化之前输出的值)。

短版:

假设你有两个张量,其中y_hat包含每个类的计算分数(例如,从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中的分数解释为非标准化的对数概率,那么它们是分对数

此外,总交叉熵损失计算如下:

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函数,它将输入解释为非归一化的对数概率(又名分对数),并输出归一化的线性概率。

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中的概率分布?我们可以使用叉损失来测量误差。

交叉熵损失公式

我们可以逐行计算交叉熵损失,并查看结果。下面我们可以看到,训练实例1的损失为0.479,而训练实例2的损失更高,为1.200。这个结果是有意义的,因为在上面的例子中,y_hat_softmax表明训练实例1的最高概率是“Class 2”,它与y_true中的训练实例1匹配;然而,训练实例2的预测显示“Class 1”的概率最高,这与真实的类“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_1total_loss_2产生的结果本质上是相同的,只是在最后的数字上有一些小的差异。然而,你也可以使用第二种方法:它只需要少一行代码,积累的数值错误也更少,因为softmax是在softmax_cross_entropy_with_logits()中为你完成的。

以上答案对所问问题有足够的描述。

除此之外,Tensorflow还优化了应用激活函数,然后使用自己的激活和代价函数计算代价的操作。因此,使用tf.nn.softmax_cross_entropy()优于tf.nn.softmax(); tf.nn.cross_entropy()是一个很好的实践

在资源密集型模型中,你可以发现它们之间的显著差异。

Tensorflow 2.0兼容答案: dgastackoverflowuser2010的解释非常详细地介绍了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中的函数:

  1. tf.nn.softmax
  2. tf.nn.softmax_cross_entropy_with_logits
  3. tf.nn.sparse_softmax_cross_entropy_with_logits

从1迁移时各自的函数。X到2.x:

  1. tf.compat.v2.nn.softmax
  2. tf.compat.v2.nn.softmax_cross_entropy_with_logits
  3. tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits

有关从1迁移的更多信息。X到2。x,请参考这个迁移向导

还有一件事我肯定想强调,因为logit只是一个原始输出,通常是最后一层的输出。这也可以是负值。如果我们使用它作为“交叉熵”评估,如下所述:

-tf.reduce_sum(y_true * tf.log(logits))

那么它将不起作用。因为log (-ve)没有定义。 所以使用softmax激活,将克服这个问题

这是我的理解,如果错了请指正。

学期的数学动机

当我们希望在0和1之间约束输出时,但我们的模型体系结构输出的是不受约束的值,我们可以添加一个规范化层来实现这一点。

一个常见的选择是乙状结肠函数。1在二元分类中,这通常是逻辑函数,在多类任务中,这是多项逻辑函数(又名softmax).2

如果我们想将新最终层的输出解释为“概率”,那么(隐含地)sigmoid的无约束输入必须是inverse-sigmoid(概率)。在逻辑情况下,这相当于我们的概率的log-odds(即几率的对数),也就是< >强分对数< / >强:

这就是为什么在Tensorflow中softmax的参数被称为logits——因为在假设softmax是模型中的最后一层,并且输出p被解释为概率的情况下,该层的输入x可解释为logit:

enter image description here enter image description here
< / div >

普遍的术语

在机器学习中,有一种倾向于概括从数学/统计/计算机科学中借来的术语,因此在Tensorflow中logit(通过类比)被用作许多归一化函数输入的同义词。


  1. 虽然它有很好的属性,例如易于微导,以及前面提到的概率解释,但它有点任意的
  2. softmax可能更准确地称为soft参数max,因为它是argmax函数的平滑近似

对数是神经网络的非标准化输出。Softmax是一个归一化函数,它压缩神经网络的输出,使它们都在0到1之间,并且和为1。Softmax_cross_entropy_with_logits是一个损失函数,它接收神经网络的输出(在它们被softmax压缩后)和这些输出的真实标签,并返回一个损失值。