Tensorflow 交叉熵损失函数 Cross Entropy Loss
这是旧版本的,新版本已经有变化,(废弃)

Tensorflow 提供的用于分类的 ops 有:

  • tf.nn.sigmoid_cross_entropy_with_logits
  • tf.nn.softmax
  • tf.nn.log_softmax
  • tf.nn.softmax_cross_entropy_with_logits
  • tf.nn.softmax_cross_entropy_with_logits_v2 - identical to the base version, except it allows gradient propagation into the labels.
  • tf.nn.sparse_softmax_cross_entropy_with_logits
  • tf.nn.weighted_cross_entropy_with_logits

其中, 交叉熵相关的损失函数有:

注: logits 表示未归一化处理的概率, 一般是 softmax 的输入, 网络输出层的输出结果.

根据应用场景中,分类目标的独立性与互斥性, 可以选择 sigmoid 或者 softmax 来实现.

1. sigmoid_cross_entropy_with_logits

作用:
计算给定 logits 的交叉熵(也叫 logistic loss).
用于离散分类任务中, 计算概率误差. 其中每个类别标签class间是相互独立, 且不互斥的.
例如, multilabel classification 问题, 每张图片中可能同时包含一头大象和一只狗.

用法:

tf.nn.sigmoid_cross_entropy_with_logits(
      _sentinel=None, # Used to prevent positional parameters. 内部参数, 不使用.
      labels=None,  # 与 logits 类型和尺寸一样的张量
      logits=None,  # type float32 or float64 的张量
      name=None )   #  op 名字, 可选参数.

计算过程:
记 ${ x = logits, z = labels }$, 有:
${ L = z *-log(sigmoid(x)) + (1- z) *-log(1 - sigmoid(x)) }$
${ L = z *-log(1 / (1 + exp(-x))) + (1- z) *-log(exp(-x) / (1 + exp(-x))) }$
${ L = z * log(1 + exp(-x)) + (1- z) * (-log(exp(-x)) + log(1 + exp(-x))) }$
${ L = z * log(1 + exp(-x)) + (1- z) * (x + log(1 + exp(-x)) }$
${ L = (1- z) * x + log(1 + exp(-x)) }$
${ L = x- x * z + log(1 + exp(-x)) }$
当 ${ x < 0 }$, 为了避免 ${ exp(-x) }$ 溢出, 有,
${ L = x- x * z + log(1 + exp(-x)) }$
${ L = log(exp(x))- x * z + log(1 + exp(-x)) }$
${ L =- x * z + log(1 + exp(x)) }$
因此, 为了数值稳定性和避免溢出, 得到如下等价形式:
${ L = max(x, 0)- x * z + log(1 + exp(-abs(x))) }$

2. weighted_cross_entropy_with_logits

作用:
计算加权交叉熵.
类似于 sigmoid_cross_entropy_with_logits(). 除了 pos_weight.
pos_weights 参数的作用是平衡 recall 和 precision, 调整相对于 negative 误差的 positive 误差的代价函数权重.

用法:

tf.nn.weighted_cross_entropy_with_logits(
      targets,
      logits,     # float32 or float64 类型的张量
      pos_weight, # 作用于 positive 样本的系数.
      name=None )

交叉熵代价函数的一般形式是,

${ L = targets *-log(sigmoid(logits)) + (1- targets) *-log(1- sigmoid(logits))}$

pos_weights > 1 时可以减少假阴样本计数(false negative count), 即提高 recall.
pos_weights < 1 时可以减少假阳样本计数( false positive count), 即提高 precision.

pos_weight 作为 positive targets 项的乘法系数, 即:

${ L = targets *-log(sigmoid(logits)) * pos\_weight + (1- targets) * -log(1- sigmoid(logits)) }$

假设, x = logits, z = targets, q = pos_weight, 有:

${ L = qz *-log(sigmoid(x)) + (1- z) *-log(1- sigmoid(x)) }$

${ L = qz *-log(1 / (1 + exp(-x))) + (1- z) *-log(exp(-x) / (1 + exp(-x)))}$

${ L = qz * log(1 + exp(-x)) + (1- z) * (-log(exp(-x)) + log(1 + exp(-x)))}$

${ L = qz * log(1 + exp(-x)) + (1- z) * (x + log(1 + exp(-x))}$

${ L = (1- z) * x + (qz + 1- z) * log(1 + exp(-x))}$

${ L = (1- z) * x + (1 + (q - 1) * z) * log(1 + exp(-x))}$

考虑到数值计算稳定性和避免溢出, 令 ${ l = (1 + (q- 1) * z) }$, 则有:

${ L = (1- z) * x + l * (log(1 + exp(-abs(x))) + max(-x, 0)) }$

3. softmax_cross_entropy_with_logits(弃用)

作用:
计算 logits 和 labels 间的 softmax 交叉熵.
用于离散分类任务中, 计算概率误差. 其中, 所有类别是互斥的(每一个样本只能有一个类别class).
例如, CIFAR-10 数据集中,每张图片有且只能有一个类别标签, 图片只能包含一只狗或一辆卡车, 而不能二者都有.
只适用于单目标的二分类或多分类问题.

虽然所有的类别classes 是互斥的, 但它们对应的概率不须如此.
要求是, labels 的每一行是一个有效的概率分布. 否则, 梯度计算会不正确.
如果是唯一 labels, 即每个样本只能有一个类别标签class, 则可见: sparse_softmax_cross_entropy_with_logits.
该 op 内部对 logits 有 softmax 处理, 效率更高, 因此其输入需要未归一化的 logits.
不需使用 softmax 的输出. 否则, 结果会不正确.

用法:

tf.nn.softmax_cross_entropy_with_logits(
      _sentinel=None,
      labels=None,  # labels[i] 的每一行必须是有效的概率分布.
      logits=None,  # unscaled log 概率值.
      dim=-1,  # 类别class 的维度. 默认为 -1, 表示最后一维.
      name=None )

4.softmax_cross_entropy_with_logits_v2

作用:
同 softmax_cross_entropy_with_logits.
logits 和 labels 都会进行BP. 为了避免 labels 的BP, 在送入该函数之前, 将 label 张量传递一个 stop_gradients 参数.

用法:

tf.nn.softmax_cross_entropy_with_logits_v2(
      _sentinel=None,
      labels=None,
      logits=None,
      dim=-1,
      name=None )

5. sparse_softmax_cross_entropy_with_logits

作用:
计算 logits 和labels 间的稀疏 softmax 交叉熵.
用于离散分类任务中, 计算概率误差. 其中所有类别是互斥的(每个样本仅有一个类别标签class).
例如, CIFAR-10 数据集中,每张图片有且只能有一个类别标签, 图片只能包含一只狗或一辆卡车, 而不能二者都有.
同 softmax_cross_entropy_with_logits 和 softmax_cross_entropy_with_logits_v2.

对于该 op, 给定 label 的概率被认为是互斥的. 所以, 不能有 soft 类别classes,
且,对于logits 每一行(即, minibatch 内的每个样本), labels 向量必须给定其对应的单个类别class 的特定索引.
对于每个样本是概率分布的 soft softmax 分类任务, 则可见 softmax_cross_entropy_with_logits.
该 op 内部对 logits 有 softmax 处理, 效率更高, 因此其输入需要未归一化的 logits.
不需使用 softmax 的输出. 否则, 结果会不正确.
一种常用场景是, logits - [batch_size, num_classes], labels - [batch_size].
也支持高维场景.

用法:

tf.nn.sparse_softmax_cross_entropy_with_logits(
      _sentinel=None,
      labels=None,      
      logits=None,
      name=None
    )

labels - 类型为 int32 or int64 的张量, 尺寸为 [d_0, d_1, ..., d_{r-1}], 其中, r 是 labels 的 rank.
labels 中的每个元素值都必须是 [0, num_classes] 内的索引值. 否则,在 CPU 运行时会出现异常;GPU 运行时对应的 loss 和梯度会返回 NaN.
logits - 类型为 int32 or int64 的张量, 尺寸为 [d_0, d_1, ..., d_{r-1}], unscaled log 概率值.

Related

[1] - TensorFlow四种Cross Entropy算法实现和应用

[2] - 机器学习 - 交叉熵Cross Entropy

[3] - Caffe Loss 层 - SigmoidCrossEntropyLoss 推导与Python实现

[4] - Caffe Loss层 - SoftmaxWithLossLayer

Last modification:October 25th, 2018 at 11:33 am