损失loss示例
loss_mask = tf.greater(click_label, -1000)
loss_mask = tf.logical_and(loss_mask, tf.logical_not(is_othsene_mask))
label = tf.cast(tf.greater(label, 0.5), label.dtype)
loss = tf.reshape(tf.nn.sigmoid_cross_entropy_with_logits(labels=label, logits=logit), [-1, 1])
loss = (1.0 - fake_impr_mask) * loss + fake_impr_mask * loss * fake_impr_coef
loss = tf.reduce_sum(tf.boolean_mask(loss, loss_mask))
Tensorflow:tensor数据类型转换、计算和变换-CSDN博客
基础
损失函数
示例说明:计算multilabel时的BinaryCrossentropy
tf.keras.losses.BinaryCrossentropy原码:
@tf_export('keras.backend.binary_crossentropy')
def binary_crossentropy(target, output, from_logits=False):
"""Binary crossentropy between an output tensor and a target tensor.
Arguments:
target: A tensor with the same shape as `output`.
output: A tensor.
from_logits: Whether `output` is expected to be a logits tensor.
By default, we consider that `output`
encodes a probability distribution.
Returns:
A tensor.
"""
# Note: nn.sigmoid_cross_entropy_with_logits
# expects logits, Keras expects probabilities.
if not from_logits:
# transform back to logits
epsilon_ = _to_tensor(epsilon(), output.dtype.base_dtype)
output = clip_ops.clip_by_value(output, epsilon_, 1 - epsilon_)
output = math_ops.log(output / (1 - output))
return nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)
normalized cross entropy
def normalized_cross_entropy(self, predict_tensor, target_tensor, real_p=0.187):
per_entry_cross_ent = tf.nn.sigmoid_cross_entropy_with_logits(logits=predict_tensor, labels=target_tensor)
hmax_entry = - real_p * tf.log(real_p) - (1 - real_p) * tf.log(1.0 - real_p)
normalize_entry_cross_ent = per_entry_cross_ent / hmax_entry
return normalize_entry_cross_ent
[损失函数loss_loss函数_-柚子皮-的博客-CSDN博客]
示例
1 如果输入是未激活的logits = tf.layers.dense(output, units=num_labels, activation=None)
loss = tf.keras.losses.binary_crossentropy(labels=labels, logits=logits, from_logits=True)
或者 loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=labels, logits=logits)。
即Use an activation function and use the raw outputs (logits) for the sigmoid_crossentropy_with_logits
function.
2 如果输入是激活后的outputs = tf.layers.dense(output, units=num_labels, activation='sigmoid')
则loss = tf.keras.losses.binary_crossentropy(labels, outputs)。
其内部逻辑为先将outputs通过反sigmoid操作转成logits,再使用loss = tf.nn.sigmoid_cross_entropy_with_logits(labels, logits)。
所以有时为了效率,如果能直接用logits还是用1来实现Crossentropy计算吧。
TensorFlow交叉熵函数
TensorFlow针对分类问题,实现了四个交叉熵函数,分别是tf.nn.sigmoid_cross_entropy_with_logits、tf.nn.softmax_cross_entropy_with_logits、tf.nn.sparse_softmax_cross_entropy_with_logits、tf.nn.weighted_cross_entropy_with_logits。
sigmoid_cross_entropy_with_logits详解
我们先看sigmoid_cross_entropy_with_logits[tf.nn.sigmoid_cross_entropy_with_logits],它的实现和交叉熵算法定义是一样的。
tf.nn.sigmoid_cross_entropy_with_logits(
_sentinel=None, labels=None, logits=None, name=None)
函数的输入是logits和labels,logits就是神经网络模型中的 W * X矩阵,注意不需要经过sigmoid,而labels的shape和logits相同,就是正确的label值,例如这个模型一次要判断100张图是否包含10种动物,这两个输入的shape都是[100, 10]。注释中还提到这10个分类之间是独立的、不要求是互斥,这种问题我们成为多目标multi-label,例如判断图片中是否包含10种动物,label值可以包含多个1或0个1。
For brevity, let x = logits, z = labels. The logistic loss is
z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x))
sigmoid_cross_entropy_with_logits的代码实现实际逻辑:max(x, 0) - x * z + log(1 + exp(-abs(x))),推导参考[tf/nn/sigmoid_cross_entropy_with_logits]
对于多标签分类问题,目标是将每个输出标签视作一个独立伯努利分布,而且我们需要独立地惩罚每个输出节点。
还有一种问题是多分类问题multi-class,例如我们对年龄特征分为5段,只允许5个值有且只有1个值为1,这种问题就不可以直接用这个函数。例如年轻取值范围在0~4,目标值也在0~4,这里如果经过sigmoid后预测值就限制在0到1之间,而且公式中的1 - z就会出现负数,仔细想一下0到4之间还不存在线性关系,如果直接把label值带入计算肯定会有非常大的误差。因此对于多分类问题是不能直接代入的,那其实我们可以灵活变通,把5个年龄段的预测用onehot encoding变成5维的label,训练时当做5个不同的目标来训练即可,但不保证只有一个为1。对于这类问题TensorFlow又提供了基于Softmax的交叉熵函数。
softmax_cross_entropy_with_logits详解
将弃用,取代为tf.nn.softmax_cross_entropy_with_logits_v2:
tf.nn.softmax_cross_entropy_with_logits_v2(
labels,
logits,
axis=None,
name=None,
dim=None
)
Softmax本身的算法很简单,就是把所有值用e的n次方计算出来,求和后算每个值占的比率,保证总和为1,一般我们可以认为Softmax出来的就是confidence也就是概率,算法实现如下。
This function performs the equivalent of
softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)
softmax_cross_entropy_with_logits和sigmoid_cross_entropy_with_logits很不一样,输入是类似的logits和lables的shape一样,但这里要求分类的结果是互斥的,保证只有一个字段有值,例如CIFAR-10中图片只能分一类而不像前面判断是否包含多类动物。想一下问什么会有这样的限制?在函数头的注释中我们看到,这个函数传入的logits是unscaled的,既不做sigmoid也不做softmax,因为函数实现会在内部更高效得使用softmax,对于任意的输入经过softmax都会变成和为1的概率预测值,这个值就可以代入变形的Cross Entroy算法- y * ln(a) - (1 - y) * ln(1 - a)算法中,得到有意义的Loss值了。
如果是多目标问题,经过softmax就不会得到多个和为1的概率,而且label有多个1也无法计算交叉熵,因此这个函数只适合单目标的二分类或者多分类问题。并且它只计算了某个类别标签为1时的loss及梯度,而忽略了为0时的loss,而每个输出又相互独立,不像softmax函数那样有归一化的限制。所以multi-label是一定不能使用CE作为loss函数的。
再补充一点,对于多分类问题,例如我们的年龄分为5类,并且人工编码为0、1、2、3、4,因为输出值是5维的特征,因此我们需要人工做onehot encoding分别编码为00001、00010、00100、01000、10000,才可以作为这个函数的输入。理论上我们不做onehot encoding也可以,做成和为1的概率分布也可以,但需要保证是和为1,和不为1的实际含义不明确,TensorFlow的C++代码实现计划检查这些参数,可以提前提醒用户避免误用。
sparse_softmax_cross_entropy_with_logits详解
sparse_softmax_cross_entropy_with_logits是softmax_cross_entropy_with_logits的易用版本,除了输入参数不同,作用和算法实现都是一样的。
前面提到softmax_cross_entropy_with_logits的输入必须是类似onehot encoding的多维特征,但CIFAR-10、ImageNet和大部分分类场景都只有一个分类目标(单分类),label值都是从0编码的整数,每次转成onehot encoding比较麻烦。
sparse_softmax_cross_entropy_with_logits,它的第一个参数logits和前面一样,shape是[batch_size, num_classes];而第二个参数labels的shape改为[batch_size],值必须是从0开始编码的int32或int64,且值范围是[0, num_class)。最后在内部高效实现类似的onehot encoding,这只是简化用户的输入而已,当然如果用户已经做了onehot encoding那可以直接使用不带“sparse”的softmax_cross_entropy_with_logits函数。
keras中两种交叉熵损失函数
categorical cross entropy [tf.keras.losses.CategoricalCrossentropy]和 binary cross entropy[tf.keras.losses.BinaryCrossentropy],以下简称CE和BCE. 关于这两个函数的忠告就是:"CE用于多分类, BCE适用于二分类, 千万别用混了."
CE:
。。。。。。(1)
其中, x表示输入样本, C为待分类的类别总数, 这里我们以手写数字识别任务(MNIST-based)为例, 其输入出的类别数为10, 对应的C=10. 为第i个类别对应的真实标签, 为对应的模型输出值.
BCE:
.。。。。。。(2)
其中 , 即每个类别输出节点都对应一个BCE值.
看到这里, 大家会发现两者的shape并不相同,对于单个样本而言,CE是一个数值,而BCE是一个向量,其维度与输出类别的个数相同,即为C。但在Keras中,最终使用的是均值,即:
那如果是batch的情况呢?Keras中的做法是对batch中所有样本的loss求均值:
在tensorflow中则只提供原始的BCE(sigmoid_cross_entropy_with_logits)和CE(softmax_cross_entropy_with_logits_v2),这也给开发人员提供了更大的灵活性。
另外,再补充一点,keras使用tensorflow作为backend时,默认情况下CE的实现调用的是自己内部实现的计算方法,而没有像之前想象的那样调用的tensorflow对应的函数。
from:-柚子皮-