如何在 TensorFlow 中选择交叉熵损失?
How to choose cross-entropy loss in TensorFlow?
分类问题,例如逻辑回归或多项式
逻辑回归,优化 交叉熵 损失。
通常,交叉熵层在 softmax 层之后,
产生概率分布。
在tensorflow中,至少有十几种不同的交叉熵损失函数:
tf.losses.softmax_cross_entropy
tf.losses.sparse_softmax_cross_entropy
tf.losses.sigmoid_cross_entropy
tf.contrib.losses.softmax_cross_entropy
tf.contrib.losses.sigmoid_cross_entropy
tf.nn.softmax_cross_entropy_with_logits
tf.nn.sigmoid_cross_entropy_with_logits
- ...
哪一个只适用于二元class化,哪一个适用于多class问题?什么时候应该使用 sigmoid
而不是 softmax
? sparse
函数与其他函数有何不同,为什么只有 softmax
?
相关(更多面向数学的)讨论:。
初步事实
在函数意义上,sigmoid is a partial case of the softmax function,当class的个数等于2时。它们都做同样的操作:将logits(见下文)转换为概率。
在简单的二进制class化中,两者没有太大区别,
然而,在多项式 classification 的情况下,sigmoid 允许处理
具有非排他性标签(a.k.a。多标签),而 softmax 交易
独占 classes(见下文)。
一个logit(也叫分数)是一个raw unscaled value associated with a class,在计算概率之前。就神经网络架构而言,这意味着 logit 是密集(全连接)层的输出。
Tensorflow 命名有点奇怪:下面的所有函数都接受对数,而不是概率,并自己应用转换(效率更高)。
Sigmoid 函数族
tf.nn.sigmoid_cross_entropy_with_logits
tf.nn.weighted_cross_entropy_with_logits
tf.losses.sigmoid_cross_entropy
tf.contrib.losses.sigmoid_cross_entropy
(已弃用)
如前所述,sigmoid
损失函数用于二进制 class化。
但是张量流函数更通用并且允许做
多标签 classification,当 classes 是独立的。
换句话说,tf.nn.sigmoid_cross_entropy_with_logits
解决了 N
一次二进制class化。
标签必须是单热编码的,或者可以包含软 class 概率。
tf.losses.sigmoid_cross_entropy
另外允许设置 批次权重 ,
即让一些例子比其他例子更重要。
tf.nn.weighted_cross_entropy_with_logits
允许设置 class 权重
(记住,class化是二进制的),即使正误差大于
消极的错误。这在训练数据不平衡时很有用。
Softmax 函数族
tf.nn.softmax_cross_entropy_with_logits
(在 1.5 中已弃用)
tf.nn.softmax_cross_entropy_with_logits_v2
tf.losses.softmax_cross_entropy
tf.contrib.losses.softmax_cross_entropy
(已弃用)
这些损失函数应该用于多项式互斥class化,
即从 N
class 中选择一个。 N = 2
.
时也适用
标签必须是单热编码的或者可以包含软 class 概率:
一个特定的例子可以属于 class A 有 50% 的概率和 class B
有 50% 的概率。请注意,严格来说并不意味着
它属于两个 classes,但可以这样解释概率。
就像在 sigmoid
家庭中一样,tf.losses.softmax_cross_entropy
允许
设置 批内权重 ,即使一些示例比其他示例更重要。
据我所知,从 tensorflow 1.3 开始,没有内置的方法来设置 class weights.
[UPD] 在 tensorflow 1.5 中,v2
版本 was introduced and the original softmax_cross_entropy_with_logits
loss got deprecated. The only difference between them is that in a newer version, backpropagation happens into both logits and labels (here's a discussion 为什么这可能有用)。
稀疏函数族
tf.nn.sparse_softmax_cross_entropy_with_logits
tf.losses.sparse_softmax_cross_entropy
tf.contrib.losses.sparse_softmax_cross_entropy
(已弃用)
和上面普通的softmax
一样,这些损失函数应该用于
多项式互斥class化,即从N
class中选出一个。
区别在于标签编码:classes 被指定为整数(class 索引),
不是单热向量。显然,这不允许软 classes,但它
当有数千或数百万 classes 时,可以节省一些内存。
但是,请注意 logits
参数仍必须包含每个 class 的对数,
因此它至少消耗 [batch_size, classes]
内存。
像上面一样,tf.losses
版本有一个 weights
参数允许
设置批内权重。
采样的 softmax 函数系列
这些函数为处理大量 classes 提供了另一种选择。
他们不是计算和比较精确的概率分布,而是计算
来自随机样本的损失估计。
参数 weights
和 biases
指定一个单独的全连接层
用于计算所选样本的对数。
像上面一样,labels
不是单热编码,而是具有 [batch_size, num_true]
.
的形状
采样函数仅适用于训练。在测试时间,建议
使用标准 softmax
损失(稀疏或单热)来获得实际分布。
另一种损失是tf.nn.nce_loss
,它执行噪声对比估计(如果您有兴趣,请参阅此very detailed discussion)。我已经将此函数包含在 softmax 系列中,因为 NCE 保证在极限内逼近 softmax。
但是,对于 1.5 版本,必须使用 softmax_cross_entropy_with_logits_v2
代替,同时使用其参数与 argument key=...
,例如
softmax_cross_entropy_with_logits_v2(_sentinel=None, labels=y,
logits=my_prediction, dim=-1, name=None)
虽然被接受的答案包含的信息比要求的信息多得多,但我觉得分享一些通用的经验法则会使答案更加紧凑和直观:
- 只有一个真正的损失函数。这是 交叉熵 (CE)。对于 binary classification 的特殊情况,这种损失称为 binary CE (请注意,公式不会改变)并且对于非二进制或 multi-class 情况 相同的称为 分类 CE( CCE)。稀疏函数是分类 CE 的一种特殊情况,其中预期值不是单热编码而是整数
- 我们有 softmax 公式,它是 multi-[=104 的激活函数=]场景。对于 binary 场景,相同的公式被赋予一个特殊的名称 - sigmoid激活
- 由于在处理对数函数时有时会出现数值不稳定(对于极值),TF建议将激活层和损失层合并为一个函数。这个组合函数在数值上更稳定。 TF提供了这些组合函数,它们以_with_logits
为后缀
有了这个,现在让我们处理一些情况。假设有一个简单的 二进制 class化问题 - 图像中是否存在猫?激活函数和损失函数的选择是什么?这将是一个 sigmoid 激活和一个(二进制)CE。所以可以使用 sigmoid_cross_entropy 或更优选 sigmoid_cross_entropy_with_logits。后者结合了激活函数和损失函数,应该是数值稳定的。
multi-class classification 怎么样?假设我们想知道图像中是否存在猫、狗或驴。激活函数和损失函数的选择是什么?这将是一个 softmax 激活和一个(分类)CE。所以可以使用 softmax_cross_entropy 或更优选 softmax_cross_entropy_with_logits。我们假设期望值是单热编码的(100 或 010 或 001)。如果(出于某种奇怪的原因)情况并非如此,并且预期值为整数(1 或 2 或 3),您可以使用上述函数的 'sparse' 对应项。
可能还有第三种情况。我们可以有一个 多标签 class 化 。所以在同一张图片中可能有一只狗和一只猫。我们如何处理这个?这里的技巧是将这种情况视为多个二进制 class 化问题 - 基本上是猫或没有猫/狗或没有狗和驴或没有驴。找出 3 个(二进制 class 化)中每一个的损失,然后将它们相加。所以本质上这归结为使用 sigmoid_cross_entropy_with_logits 损失。
这回答了您提出的 3 个具体问题。上面共享的功能都是需要的。您可以忽略已弃用且不应使用的 tf.contrib 系列。
分类问题,例如逻辑回归或多项式 逻辑回归,优化 交叉熵 损失。 通常,交叉熵层在 softmax 层之后, 产生概率分布。
在tensorflow中,至少有十几种不同的交叉熵损失函数:
tf.losses.softmax_cross_entropy
tf.losses.sparse_softmax_cross_entropy
tf.losses.sigmoid_cross_entropy
tf.contrib.losses.softmax_cross_entropy
tf.contrib.losses.sigmoid_cross_entropy
tf.nn.softmax_cross_entropy_with_logits
tf.nn.sigmoid_cross_entropy_with_logits
- ...
哪一个只适用于二元class化,哪一个适用于多class问题?什么时候应该使用 sigmoid
而不是 softmax
? sparse
函数与其他函数有何不同,为什么只有 softmax
?
相关(更多面向数学的)讨论:
初步事实
在函数意义上,sigmoid is a partial case of the softmax function,当class的个数等于2时。它们都做同样的操作:将logits(见下文)转换为概率。
在简单的二进制class化中,两者没有太大区别, 然而,在多项式 classification 的情况下,sigmoid 允许处理 具有非排他性标签(a.k.a。多标签),而 softmax 交易 独占 classes(见下文)。
一个logit(也叫分数)是一个raw unscaled value associated with a class,在计算概率之前。就神经网络架构而言,这意味着 logit 是密集(全连接)层的输出。
Tensorflow 命名有点奇怪:下面的所有函数都接受对数,而不是概率,并自己应用转换(效率更高)。
Sigmoid 函数族
tf.nn.sigmoid_cross_entropy_with_logits
tf.nn.weighted_cross_entropy_with_logits
tf.losses.sigmoid_cross_entropy
tf.contrib.losses.sigmoid_cross_entropy
(已弃用)
如前所述,sigmoid
损失函数用于二进制 class化。
但是张量流函数更通用并且允许做
多标签 classification,当 classes 是独立的。
换句话说,tf.nn.sigmoid_cross_entropy_with_logits
解决了 N
一次二进制class化。
标签必须是单热编码的,或者可以包含软 class 概率。
tf.losses.sigmoid_cross_entropy
另外允许设置 批次权重 ,
即让一些例子比其他例子更重要。
tf.nn.weighted_cross_entropy_with_logits
允许设置 class 权重
(记住,class化是二进制的),即使正误差大于
消极的错误。这在训练数据不平衡时很有用。
Softmax 函数族
tf.nn.softmax_cross_entropy_with_logits
(在 1.5 中已弃用)tf.nn.softmax_cross_entropy_with_logits_v2
tf.losses.softmax_cross_entropy
tf.contrib.losses.softmax_cross_entropy
(已弃用)
这些损失函数应该用于多项式互斥class化,
即从 N
class 中选择一个。 N = 2
.
标签必须是单热编码的或者可以包含软 class 概率: 一个特定的例子可以属于 class A 有 50% 的概率和 class B 有 50% 的概率。请注意,严格来说并不意味着 它属于两个 classes,但可以这样解释概率。
就像在 sigmoid
家庭中一样,tf.losses.softmax_cross_entropy
允许
设置 批内权重 ,即使一些示例比其他示例更重要。
据我所知,从 tensorflow 1.3 开始,没有内置的方法来设置 class weights.
[UPD] 在 tensorflow 1.5 中,v2
版本 was introduced and the original softmax_cross_entropy_with_logits
loss got deprecated. The only difference between them is that in a newer version, backpropagation happens into both logits and labels (here's a discussion 为什么这可能有用)。
稀疏函数族
tf.nn.sparse_softmax_cross_entropy_with_logits
tf.losses.sparse_softmax_cross_entropy
tf.contrib.losses.sparse_softmax_cross_entropy
(已弃用)
和上面普通的softmax
一样,这些损失函数应该用于
多项式互斥class化,即从N
class中选出一个。
区别在于标签编码:classes 被指定为整数(class 索引),
不是单热向量。显然,这不允许软 classes,但它
当有数千或数百万 classes 时,可以节省一些内存。
但是,请注意 logits
参数仍必须包含每个 class 的对数,
因此它至少消耗 [batch_size, classes]
内存。
像上面一样,tf.losses
版本有一个 weights
参数允许
设置批内权重。
采样的 softmax 函数系列
这些函数为处理大量 classes 提供了另一种选择。 他们不是计算和比较精确的概率分布,而是计算 来自随机样本的损失估计。
参数 weights
和 biases
指定一个单独的全连接层
用于计算所选样本的对数。
像上面一样,labels
不是单热编码,而是具有 [batch_size, num_true]
.
采样函数仅适用于训练。在测试时间,建议
使用标准 softmax
损失(稀疏或单热)来获得实际分布。
另一种损失是tf.nn.nce_loss
,它执行噪声对比估计(如果您有兴趣,请参阅此very detailed discussion)。我已经将此函数包含在 softmax 系列中,因为 NCE 保证在极限内逼近 softmax。
但是,对于 1.5 版本,必须使用 softmax_cross_entropy_with_logits_v2
代替,同时使用其参数与 argument key=...
,例如
softmax_cross_entropy_with_logits_v2(_sentinel=None, labels=y,
logits=my_prediction, dim=-1, name=None)
虽然被接受的答案包含的信息比要求的信息多得多,但我觉得分享一些通用的经验法则会使答案更加紧凑和直观:
- 只有一个真正的损失函数。这是 交叉熵 (CE)。对于 binary classification 的特殊情况,这种损失称为 binary CE (请注意,公式不会改变)并且对于非二进制或 multi-class 情况 相同的称为 分类 CE( CCE)。稀疏函数是分类 CE 的一种特殊情况,其中预期值不是单热编码而是整数
- 我们有 softmax 公式,它是 multi-[=104 的激活函数=]场景。对于 binary 场景,相同的公式被赋予一个特殊的名称 - sigmoid激活
- 由于在处理对数函数时有时会出现数值不稳定(对于极值),TF建议将激活层和损失层合并为一个函数。这个组合函数在数值上更稳定。 TF提供了这些组合函数,它们以_with_logits 为后缀
有了这个,现在让我们处理一些情况。假设有一个简单的 二进制 class化问题 - 图像中是否存在猫?激活函数和损失函数的选择是什么?这将是一个 sigmoid 激活和一个(二进制)CE。所以可以使用 sigmoid_cross_entropy 或更优选 sigmoid_cross_entropy_with_logits。后者结合了激活函数和损失函数,应该是数值稳定的。
multi-class classification 怎么样?假设我们想知道图像中是否存在猫、狗或驴。激活函数和损失函数的选择是什么?这将是一个 softmax 激活和一个(分类)CE。所以可以使用 softmax_cross_entropy 或更优选 softmax_cross_entropy_with_logits。我们假设期望值是单热编码的(100 或 010 或 001)。如果(出于某种奇怪的原因)情况并非如此,并且预期值为整数(1 或 2 或 3),您可以使用上述函数的 'sparse' 对应项。
可能还有第三种情况。我们可以有一个 多标签 class 化 。所以在同一张图片中可能有一只狗和一只猫。我们如何处理这个?这里的技巧是将这种情况视为多个二进制 class 化问题 - 基本上是猫或没有猫/狗或没有狗和驴或没有驴。找出 3 个(二进制 class 化)中每一个的损失,然后将它们相加。所以本质上这归结为使用 sigmoid_cross_entropy_with_logits 损失。
这回答了您提出的 3 个具体问题。上面共享的功能都是需要的。您可以忽略已弃用且不应使用的 tf.contrib 系列。