对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调用C++程序的方法详解
Jan 24 Python
Python判断文件或文件夹是否存在的三种方法
Jul 27 Python
Python Socket实现简单TCP Server/client功能示例
Aug 05 Python
深入理解Python中的*重复运算符
Oct 28 Python
Python编程实现双链表,栈,队列及二叉树的方法示例
Nov 01 Python
python 用lambda函数替换for循环的方法
Jun 09 Python
Python常见排序操作示例【字典、列表、指定元素等】
Aug 15 Python
Python魔法方法详解
Feb 13 Python
django配置连接数据库及原生sql语句的使用方法
Mar 03 Python
解决python3 requests headers参数不能有中文的问题
Aug 21 Python
Python 获取指定文件夹下的目录和文件的实现
Aug 30 Python
Python dict和defaultdict使用实例解析
Mar 12 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
PHP函数eval()介绍和使用示例
2014/08/20 PHP
跟我学Laravel之安装Laravel
2014/10/15 PHP
PHP中的Iterator迭代对象属性详解
2019/04/12 PHP
用javascript获取地址栏参数
2006/12/22 Javascript
jquery 实现的全选和反选
2009/04/15 Javascript
斜45度寻路实现函数
2009/08/20 Javascript
js中的string.format函数代码
2020/08/11 Javascript
jQuery中iframe的操作(点击按钮新增窗口)
2016/04/20 Javascript
js实现选项卡内容切换以及折叠和展开效果【推荐】
2017/01/08 Javascript
Angular4如何自定义首屏的加载动画详解
2017/07/26 Javascript
详解bootstrap导航栏.nav与.navbar区别
2017/11/23 Javascript
Angular实现点击按钮控制隐藏和显示功能示例
2017/12/29 Javascript
在vue项目中使用sass的配置方法
2018/03/20 Javascript
Puppet的一些技巧
2018/09/17 Javascript
Vue 中文本内容超出规定行数后展开收起的处理的实现方法
2019/04/28 Javascript
jquery插件开发模式实例详解
2019/07/20 jQuery
微信小程序用户登录和登录态维护的实现
2020/12/10 Javascript
[07:06]2018DOTA2国际邀请赛寻真——卫冕冠军Team Liquid
2018/08/10 DOTA
深入理解Python中字典的键的使用
2015/08/19 Python
python实现手机通讯录搜索功能
2018/02/22 Python
Django Rest framework之认证的实现代码
2018/12/17 Python
python实现狄克斯特拉算法
2019/01/17 Python
Python TestCase中的断言方法介绍
2019/05/02 Python
django 利用Q对象与F对象进行查询的实现
2020/05/15 Python
Python之字典对象的几种创建方法
2020/09/30 Python
css 如何让背景图片拉伸填充避免重复显示
2013/07/11 HTML / CSS
One.com挪威:北欧成长最快的网络托管公司
2016/11/19 全球购物
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
汉语言文学毕业生自荐信范文
2014/03/24 职场文书
初三学生语文考试作弊检讨书
2014/12/14 职场文书
中学生自我评价2015
2015/03/03 职场文书
校长个人总结
2015/03/03 职场文书
荒岛余生观后感
2015/06/09 职场文书
写作技巧:优秀文案必备的3种结构
2019/08/19 职场文书
Oracle安装TNS_ADMIN环境变量设置参考
2021/11/01 Oracle
Spring依赖注入多种类型数据的示例代码
2022/03/31 Java/Android