对Keras自带Loss Function的深入研究


Posted in Python onMay 25, 2021

本文研究Keras自带的几个常用的Loss Function。

1. categorical_crossentropy VS. sparse_categorical_crossentropy

对Keras自带Loss Function的深入研究

对Keras自带Loss Function的深入研究

注意到二者的主要差别在于输入是否为integer tensor。在文档中,我们还可以找到关于二者如何选择的描述:

对Keras自带Loss Function的深入研究

解释一下这里的Integer target 与 Categorical target,实际上Integer target经过独热编码就变成了Categorical target,举例说明:

(类别数5)
Integer target: [1,2,4]
Categorical target: [[0. 1. 0. 0. 0.]
					 [0. 0. 1. 0. 0.]
					 [0. 0. 0. 0. 1.]]

在Keras中提供了to_categorical方法来实现二者的转化:

from keras.utils import to_categorical
categorical_labels = to_categorical(int_labels, num_classes=None)

注意categorical_crossentropy和sparse_categorical_crossentropy的输入参数output,都是softmax输出的tensor。我们都知道softmax的输出服从多项分布,

因此categorical_crossentropy和sparse_categorical_crossentropy应当应用于多分类问题。

我们再看看这两个的源码,来验证一下:

https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/keras/backend.py
--------------------------------------------------------------------------------------------------------------------
def categorical_crossentropy(target, output, from_logits=False, axis=-1):
  """Categorical crossentropy between an output tensor and a target tensor.
  Arguments:
      target: A tensor of the same shape as `output`.
      output: A tensor resulting from a softmax
          (unless `from_logits` is True, in which
          case `output` is expected to be the logits).
      from_logits: Boolean, whether `output` is the
          result of a softmax, or is a tensor of logits.
      axis: Int specifying the channels axis. `axis=-1` corresponds to data
          format `channels_last', and `axis=1` corresponds to data format
          `channels_first`.
  Returns:
      Output tensor.
  Raises:
      ValueError: if `axis` is neither -1 nor one of the axes of `output`.
  """
  rank = len(output.shape)
  axis = axis % rank
  # Note: nn.softmax_cross_entropy_with_logits_v2
  # expects logits, Keras expects probabilities.
  if not from_logits:
    # scale preds so that the class probas of each sample sum to 1
    output = output / math_ops.reduce_sum(output, axis, True)
    # manual computation of crossentropy
    epsilon_ = _to_tensor(epsilon(), output.dtype.base_dtype)
    output = clip_ops.clip_by_value(output, epsilon_, 1. - epsilon_)
    return -math_ops.reduce_sum(target * math_ops.log(output), axis)
  else:
    return nn.softmax_cross_entropy_with_logits_v2(labels=target, logits=output)
--------------------------------------------------------------------------------------------------------------------
def sparse_categorical_crossentropy(target, output, from_logits=False, axis=-1):
  """Categorical crossentropy with integer targets.
  Arguments:
      target: An integer tensor.
      output: A tensor resulting from a softmax
          (unless `from_logits` is True, in which
          case `output` is expected to be the logits).
      from_logits: Boolean, whether `output` is the
          result of a softmax, or is a tensor of logits.
      axis: Int specifying the channels axis. `axis=-1` corresponds to data
          format `channels_last', and `axis=1` corresponds to data format
          `channels_first`.
  Returns:
      Output tensor.
  Raises:
      ValueError: if `axis` is neither -1 nor one of the axes of `output`.
  """
  rank = len(output.shape)
  axis = axis % rank
  if axis != rank - 1:
    permutation = list(range(axis)) + list(range(axis + 1, rank)) + [axis]
    output = array_ops.transpose(output, perm=permutation)
  # Note: nn.sparse_softmax_cross_entropy_with_logits
  # expects logits, Keras expects probabilities.
  if not from_logits:
    epsilon_ = _to_tensor(epsilon(), output.dtype.base_dtype)
    output = clip_ops.clip_by_value(output, epsilon_, 1 - epsilon_)
    output = math_ops.log(output)
  output_shape = output.shape
  targets = cast(flatten(target), 'int64')
  logits = array_ops.reshape(output, [-1, int(output_shape[-1])])
  res = nn.sparse_softmax_cross_entropy_with_logits(
      labels=targets, logits=logits)
  if len(output_shape) >= 3:
    # If our output includes timesteps or spatial dimensions we need to reshape
    return array_ops.reshape(res, array_ops.shape(output)[:-1])
  else:
    return res

categorical_crossentropy计算交叉熵时使用的是nn.softmax_cross_entropy_with_logits_v2( labels=targets, logits=logits),而sparse_categorical_crossentropy使用的是nn.sparse_softmax_cross_entropy_with_logits( labels=targets, logits=logits),二者本质并无区别,只是对输入参数logits的要求不同,v2要求的是logits与labels格式相同(即元素也是独热的),而sparse则要求logits的元素是个数值,与上面Integer format和Categorical format的对比含义类似。

综上所述,categorical_crossentropy和sparse_categorical_crossentropy只不过是输入参数target类型上的区别,其loss的计算在本质上没有区别,就是交叉熵;二者是针对多分类(Multi-class)任务的。

2. Binary_crossentropy

对Keras自带Loss Function的深入研究

二元交叉熵,从名字中我们可以看出,这个loss function可能是适用于二分类的。文档中并没有详细说明,那么直接看看源码吧:

https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/keras/backend.py
--------------------------------------------------------------------------------------------------------------------
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)

可以看到源码中计算使用了nn.sigmoid_cross_entropy_with_logits,熟悉tensorflow的应该比较熟悉这个损失函数了,它可以用于简单的二分类,也可以用于多标签任务,而且应用广泛,在样本合理的情况下(如不存在类别不均衡等问题)的情况下,通常可以直接使用。

补充:keras自定义loss function的简单方法

首先看一下Keras中我们常用到的目标函数(如mse,mae等)是如何定义的

from keras import backend as K
def mean_squared_error(y_true, y_pred):
    return K.mean(K.square(y_pred - y_true), axis=-1)
def mean_absolute_error(y_true, y_pred):
    return K.mean(K.abs(y_pred - y_true), axis=-1)
def mean_absolute_percentage_error(y_true, y_pred):
    diff = K.abs((y_true - y_pred) / K.clip(K.abs(y_true), K.epsilon(), np.inf))
    return 100. * K.mean(diff, axis=-1)
def categorical_crossentropy(y_true, y_pred):
    '''Expects a binary class matrix instead of a vector of scalar classes.
    '''
    return K.categorical_crossentropy(y_pred, y_true)
def sparse_categorical_crossentropy(y_true, y_pred):
    '''expects an array of integer classes.
    Note: labels shape must have the same number of dimensions as output shape.
    If you get a shape error, add a length-1 dimension to labels.
    '''
    return K.sparse_categorical_crossentropy(y_pred, y_true)
def binary_crossentropy(y_true, y_pred):
    return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
def kullback_leibler_divergence(y_true, y_pred):
    y_true = K.clip(y_true, K.epsilon(), 1)
    y_pred = K.clip(y_pred, K.epsilon(), 1)
    return K.sum(y_true * K.log(y_true / y_pred), axis=-1)
def poisson(y_true, y_pred):
    return K.mean(y_pred - y_true * K.log(y_pred + K.epsilon()), axis=-1)
def cosine_proximity(y_true, y_pred):
    y_true = K.l2_normalize(y_true, axis=-1)
    y_pred = K.l2_normalize(y_pred, axis=-1)
    return -K.mean(y_true * y_pred, axis=-1)

所以仿照以上的方法,可以自己定义特定任务的目标函数。比如:定义预测值与真实值的差

from keras import backend as K
def new_loss(y_true,y_pred):
    return K.mean((y_pred-y_true),axis = -1)

然后,应用你自己定义的目标函数进行编译

from keras import backend as K
def my_loss(y_true,y_pred):
    return K.mean((y_pred-y_true),axis = -1)
model.compile(optimizer=optimizers.RMSprop(lr),loss=my_loss,
metrics=['accuracy'])

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python通过属性手段实现只允许调用一次的示例讲解
Apr 21 Python
Django学习教程之静态文件的调用详解
May 08 Python
python实现对csv文件的列的内容读取
Jul 04 Python
python 不同方式读取文件速度不同的实例
Nov 09 Python
用python一行代码得到数组中某个元素的个数方法
Jan 28 Python
python ChainMap的使用和说明详解
Jun 11 Python
django删除表重建的实现方法
Aug 28 Python
Python实现TCP通信的示例代码
Sep 09 Python
Python2.x与3​​.x版本有哪些区别
Jul 09 Python
Python自动化之UnitTest框架实战记录
Sep 08 Python
python日志通过不同的等级打印不同的颜色(示例代码)
Jan 13 Python
python神经网络 tf.name_scope 和 tf.variable_scope 的区别
May 04 Python
pytorch中的model=model.to(device)使用说明
May 24 #Python
解决pytorch-gpu 安装失败的记录
May 24 #Python
如何解决.cuda()加载用时很长的问题
一劳永逸彻底解决pip install慢的办法
May 24 #Python
Django实现翻页的示例代码
May 24 #Python
pytorch--之halfTensor的使用详解
pandas DataFrame.shift()函数的具体使用
May 24 #Python
You might like
拼音码表的生成
2006/10/09 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
js前台分页显示后端JAVA数据响应
2013/03/18 Javascript
nodejs 提示‘xxx’ 不是内部或外部命令解决方法
2014/11/20 NodeJs
js使用split函数按照多个字符对字符串进行分割的方法
2015/03/20 Javascript
JQUERY的AJAX请求缓存里的数据问题处理
2016/02/23 Javascript
JavaScript驾驭网页-CSS与DOM
2016/03/24 Javascript
用Angular实时获取本地Localstorage数据,实现一个模拟后台数据登入的效果
2016/11/09 Javascript
jquery实现异步加载图片(懒加载图片一种方式)
2017/04/24 jQuery
React学习笔记之事件处理(二)
2017/07/02 Javascript
详解vue 模版组件的三种用法
2017/07/21 Javascript
Vue使用vux-ui自定义表单验证遇到的问题及解决方法
2018/05/10 Javascript
浅谈vue首屏加载优化
2018/06/28 Javascript
elementUI 设置input的只读或禁用的方法
2018/10/30 Javascript
Angular7中创建组件/自定义指令/管道的方法实例详解
2019/04/02 Javascript
js实现电灯开关效果
2021/01/19 Javascript
详解Vite的新体验
2021/02/22 Javascript
[02:32]DOTA2亚洲邀请赛 VG战队巡礼
2015/02/03 DOTA
Python中使用插入排序算法的简单分析与代码示例
2016/05/04 Python
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
Python内置函数—vars的具体使用方法
2017/12/04 Python
浅谈tensorflow1.0 池化层(pooling)和全连接层(dense)
2018/04/27 Python
Pycharm无法显示动态图片的解决方法
2018/10/28 Python
Python之NumPy(axis=0 与axis=1)区分详解
2019/05/27 Python
解决python super()调用多重继承函数的问题
2019/06/26 Python
Django使用unittest模块进行单元测试过程解析
2019/08/02 Python
django实现支付宝支付实例讲解
2019/10/17 Python
windows、linux下打包Python3程序详细方法
2020/03/17 Python
德国二手设计师时装和复古时装跳蚤市场:Mädchenflohmarkt
2020/11/09 全球购物
面料业务员岗位职责
2013/12/26 职场文书
计算机科学系职业生涯规划书
2014/03/08 职场文书
护理专科毕业自荐信范文
2014/04/21 职场文书
体育专业大学生职业生涯规划范文:打造自己的运动帝国
2014/09/12 职场文书
幸福家庭事迹材料
2014/12/20 职场文书
2016年重阳节慰问信
2015/12/01 职场文书
zabbix 代理服务器的部署与 zabbix-snmp 监控问题
2022/07/15 Servers