用keras搭好模型架构之后的下一步,就是执行编译操作。在编译时,经常需要指定三个参数

  • loss
  • optimizer
  • metrics

这三个参数有两类选择:

  • 使用字符串
  • 使用标识符,如keras.losses,keras.optimizers,metrics包下面的函数

例如:

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])

因为有时可以使用字符串,有时可以使用标识符,令人很想知道背后是如何操作的。下面分别针对optimizer,loss,metrics三种对象的获取进行研究。

optimizer

一个模型只能有一个optimizer,在执行编译的时候只能指定一个optimizer。

在keras.optimizers.py中,有一个get函数,用于根据用户传进来的optimizer参数获取优化器的实例:

def get(identifier):
# 如果后端是tensorflow并且使用的是tensorflow自带的优化器实例,可以直接使用tensorflow原生的优化器
if K.backend() == 'tensorflow':
# Wrap TF optimizer instances
if isinstance(identifier, tf.train.Optimizer):
return TFOptimizer(identifier)
# 如果以json串的形式定义optimizer并进行参数配置
if isinstance(identifier, dict):
return deserialize(identifier)
elif isinstance(identifier, six.string_types):
# 如果以字符串形式指定optimizer,那么使用优化器的默认配置参数
config = {'class_name': str(identifier), 'config': {}}
return deserialize(config)
if isinstance(identifier, Optimizer):
# 如果使用keras封装的Optimizer的实例
return identifier
else:
raise ValueError('Could not interpret optimizer identifier: ' +
str(identifier))

其中,deserilize(config)函数的作用就是把optimizer反序列化制造一个实例。

loss

keras.losses函数也有一个get(identifier)方法。其中需要注意以下一点:

如果identifier是可调用的一个函数名,也就是一个自定义的损失函数,这个损失函数返回值是一个张量。这样就轻而易举的实现了自定义损失函数。除了使用str和dict类型的identifier,我们也可以直接使用keras.losses包下面的损失函数。

def get(identifier):
if identifier is None:
return None
if isinstance(identifier, six.string_types):
identifier = str(identifier)
return deserialize(identifier)
if isinstance(identifier, dict):
return deserialize(identifier)
elif callable(identifier):
return identifier
else:
raise ValueError('Could not interpret '
'loss function identifier:', identifier)

metrics

在model.compile()函数中,optimizer和loss都是单数形式,只有metrics是复数形式。因为一个模型只能指明一个optimizer和loss,却可以指明多个metrics。metrics也是三者中处理逻辑最为复杂的一个。

在keras最核心的地方keras.engine.train.py中有如下处理metrics的函数。这个函数其实就做了两件事:

  • 根据输入的metric找到具体的metric对应的函数
  • 计算metric张量

在寻找metric对应函数时,有两种步骤:

  • 使用字符串形式指明准确率和交叉熵
  • 使用keras.metrics.py中的函数
def handle_metrics(metrics, weights=None):
metric_name_prefix = 'weighted_' if weights is not None else '' for metric in metrics:
# 如果metrics是最常见的那种:accuracy,交叉熵
if metric in ('accuracy', 'acc', 'crossentropy', 'ce'):
# custom handling of accuracy/crossentropy
# (because of class mode duality)
output_shape = K.int_shape(self.outputs[i])
# 如果输出维度是1或者损失函数是二分类损失函数,那么说明是个二分类问题,应该使用二分类的accuracy和二分类的的交叉熵
if (output_shape[-1] == 1 or
self.loss_functions[i] == losses.binary_crossentropy):
# case: binary accuracy/crossentropy
if metric in ('accuracy', 'acc'):
metric_fn = metrics_module.binary_accuracy
elif metric in ('crossentropy', 'ce'):
metric_fn = metrics_module.binary_crossentropy
# 如果损失函数是sparse_categorical_crossentropy,那么目标y_input就不是one-hot的,所以就需要使用sparse的多类准去率和sparse的多类交叉熵
elif self.loss_functions[i] == losses.sparse_categorical_crossentropy:
# case: categorical accuracy/crossentropy
# with sparse targets
if metric in ('accuracy', 'acc'):
metric_fn = metrics_module.sparse_categorical_accuracy
elif metric in ('crossentropy', 'ce'):
metric_fn = metrics_module.sparse_categorical_crossentropy
else:
# case: categorical accuracy/crossentropy
if metric in ('accuracy', 'acc'):
metric_fn = metrics_module.categorical_accuracy
elif metric in ('crossentropy', 'ce'):
metric_fn = metrics_module.categorical_crossentropy
if metric in ('accuracy', 'acc'):
suffix = 'acc'
elif metric in ('crossentropy', 'ce'):
suffix = 'ce'
weighted_metric_fn = weighted_masked_objective(metric_fn)
metric_name = metric_name_prefix + suffix
else:
# 如果输入的metric不是字符串,那么就调用metrics模块获取
metric_fn = metrics_module.get(metric)
weighted_metric_fn = weighted_masked_objective(metric_fn)
# Get metric name as string
if hasattr(metric_fn, 'name'):
metric_name = metric_fn.name
else:
metric_name = metric_fn.__name__
metric_name = metric_name_prefix + metric_name with K.name_scope(metric_name):
metric_result = weighted_metric_fn(y_true, y_pred,
weights=weights,
mask=masks[i]) # Append to self.metrics_names, self.metric_tensors,
# self.stateful_metric_names
if len(self.output_names) > 1:
metric_name = self.output_names[i] + '_' + metric_name
# Dedupe name
j = 1
base_metric_name = metric_name
while metric_name in self.metrics_names:
metric_name = base_metric_name + '_' + str(j)
j += 1
self.metrics_names.append(metric_name)
self.metrics_tensors.append(metric_result) # Keep track of state updates created by
# stateful metrics (i.e. metrics layers).
if isinstance(metric_fn, Layer) and metric_fn.stateful:
self.stateful_metric_names.append(metric_name)
self.stateful_metric_functions.append(metric_fn)
self.metrics_updates += metric_fn.updates

无论怎么使用metric,最终都会变成metrics包下面的函数。当使用字符串形式指明accuracy和crossentropy时,keras会非常智能地确定应该使用metrics包下面的哪个函数。因为metrics包下的那些metric函数有不同的使用场景,例如:

  • 有的处理的是one-hot形式的y_input(数据的类别),有的处理的是非one-hot形式的y_input
  • 有的处理的是二分类问题的metric,有的处理的是多分类问题的metric

当使用字符串“accuracy”和“crossentropy”指明metric时,keras会根据损失函数、输出层的shape来确定具体应该使用哪个metric函数。在任何情况下,直接使用metrics下面的函数名是总不会出错的。

keras.metrics.py文件中也有一个get(identifier)函数用于获取metric函数。

def get(identifier):
if isinstance(identifier, dict):
config = {'class_name': str(identifier), 'config': {}}
return deserialize(config)
elif isinstance(identifier, six.string_types):
return deserialize(str(identifier))
elif callable(identifier):
return identifier
else:
raise ValueError('Could not interpret '
'metric function identifier:', identifier)

如果identifier是字符串或者字典,那么会根据identifier反序列化出一个metric函数。

如果identifier本身就是一个函数名,那么就直接返回这个函数名。这种方式就为自定义metric提供了巨大便利。

keras中的设计哲学堪称完美。

keras中的loss、optimizer、metrics的更多相关文章

  1. 【tf.keras】tf.keras使用tensorflow中定义的optimizer

    Update:2019/09/21 使用 tf.keras 时,请使用 tf.keras.optimizers 里面的优化器,不要使用 tf.train 里面的优化器,不然学习率衰减会出现问题. 使用 ...

  2. keras中保存自定义层和loss

    在keras中保存模型有几种方式: (1):使用callbacks,可以保存训练中任意的模型,或选择最好的模型 logdir = './callbacks' if not os.path.exists ...

  3. Python机器学习笔记:深入理解Keras中序贯模型和函数模型

     先从sklearn说起吧,如果学习了sklearn的话,那么学习Keras相对来说比较容易.为什么这样说呢? 我们首先比较一下sklearn的机器学习大致使用流程和Keras的大致使用流程: skl ...

  4. Python机器学习笔记:深入学习Keras中Sequential模型及方法

    Sequential 序贯模型 序贯模型是函数式模型的简略版,为最简单的线性.从头到尾的结构顺序,不分叉,是多个网络层的线性堆叠. Keras实现了很多层,包括core核心层,Convolution卷 ...

  5. (数据科学学习手札44)在Keras中训练多层感知机

    一.简介 Keras是有着自主的一套前端控制语法,后端基于tensorflow和theano的深度学习框架,因为其搭建神经网络简单快捷明了的语法风格,可以帮助使用者更快捷的搭建自己的神经网络,堪称深度 ...

  6. Deep Learning 32: 自己写的keras的一个callbacks函数,解决keras中不能在每个epoch实时显示学习速率learning rate的问题

    一.问题: keras中不能在每个epoch实时显示学习速率learning rate,从而方便调试,实际上也是为了调试解决这个问题:Deep Learning 31: 不同版本的keras,对同样的 ...

  7. 在Keras中可视化LSTM

    作者|Praneet Bomma 编译|VK 来源|https://towardsdatascience.com/visualising-lstm-activations-in-keras-b5020 ...

  8. keras中seq2seq实现

    这里只是简单的一个例子 输入序列 目标序列 [13, 28, 18, 7, 9, 5] [18, 28, 13] [29, 44, 38, 15, 26, 22] [38, 44, 29] [27, ...

  9. keras中调用tensorboard:from keras.callbacks import TensorBoard

    from keras.models import Sequential from keras.layers import Dense from keras.wrappers.scikit_learn ...

随机推荐

  1. JQuery之ContextMenu(右键菜单)

    插件下载地址:http://www.trendskitchens.co.nz/jquery/contextmenu/jquery.contextmenu.r2.js压缩版:http://www.tre ...

  2. Lucene学习——IKAnalyzer中文分词

    一.环境 1.平台:MyEclipse8.5/JDK1.5 2.开源框架:Lucene3.6.1/IKAnalyzer2012 3.目的:测试IKAnalyzer的分词效果 二.开发调试 1.下载框架 ...

  3. JAVA-错误The type BookServiceImpl must implement the inherited abstract method

    错误原因 :是因为class继承了其他的类,没有导入过来,选择add unimplemented methods进行解决

  4. Linq-查询上一条下一条

    //下一条 int pollid = poll.Where(f => f.PollID < CurrentId).OrderByDescending(o => o.PollID).F ...

  5. 如何三招帮你排查Linux中的硬件问题

    下列贴士帮助你更快速更轻松地为Linux中的硬件排查故障.许多不同的因素可能导致Linux硬件出现问题:在你开始尝试诊断之前,了解最常见的问题以及最有可能找到原因的环节是明智之举. Linux服务器在 ...

  6. mke2fs 制作ext2文件系统image

    方法1: 利用/dev/ram1: linux下有很多ram,我们用ram1,首先把ram1格式化成ext2文件系统[root@gucuiwen babylinux]#   sudo mkfs.ext ...

  7. oauth2-server-php-docs 授权控制器

    授权控制器 概观 对于授权端点,要求用户使用authorization code(授权码授权类型)或access token(隐式授权类型)对客户端进行认证和重定向. 方法 handleAuthori ...

  8. pdo_mysql安装不了或是安装后用不了的修复教程

    目前发现wdOS及lanmp_wdcp的RPM包安装在部分系统下安装后,在安装pdo_mysql时无法安装或安装后无法使用的问题 如在安装时提示下如下 regenerate PHP parsers.c ...

  9. 解决input框中加入disabled="disabled"之后,改变字体的颜色(默认的是灰色)

    在input框中加入disabled="disabled"之后,字体默认的就变成灰色了 解决方案 input[disabled]{color:#fff;opacity:1} dis ...

  10. ReSharper修改命名风格

    默认情况下,ReSharper会建议你全局变量命名使用下划线开头,且第一个字母小写.否则,会给你标记出来,如下: 但我个人不喜欢这种风格,一般使用首字母大写且不带下划线,可以通过配置来调整:ReSha ...