keras中的loss、optimizer、metrics用法
用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参数获取优化器的实例:
defget(identifier): #如果后端是tensorflow并且使用的是tensorflow自带的优化器实例,可以直接使用tensorflow原生的优化器 ifK.backend()=='tensorflow': #WrapTFoptimizerinstances ifisinstance(identifier,tf.train.Optimizer): returnTFOptimizer(identifier) #如果以json串的形式定义optimizer并进行参数配置 ifisinstance(identifier,dict): returndeserialize(identifier) elifisinstance(identifier,six.string_types): #如果以字符串形式指定optimizer,那么使用优化器的默认配置参数 config={'class_name':str(identifier),'config':{}} returndeserialize(config) ifisinstance(identifier,Optimizer): #如果使用keras封装的Optimizer的实例 returnidentifier else: raiseValueError('Couldnotinterpretoptimizeridentifier:'+ str(identifier))
其中,deserilize(config)函数的作用就是把optimizer反序列化制造一个实例。
loss
keras.losses函数也有一个get(identifier)方法。其中需要注意以下一点:
如果identifier是可调用的一个函数名,也就是一个自定义的损失函数,这个损失函数返回值是一个张量。这样就轻而易举的实现了自定义损失函数。除了使用str和dict类型的identifier,我们也可以直接使用keras.losses包下面的损失函数。
defget(identifier): ifidentifierisNone: returnNone ifisinstance(identifier,six.string_types): identifier=str(identifier) returndeserialize(identifier) ifisinstance(identifier,dict): returndeserialize(identifier) elifcallable(identifier): returnidentifier else: raiseValueError('Couldnotinterpret' 'lossfunctionidentifier:',identifier)
metrics
在model.compile()函数中,optimizer和loss都是单数形式,只有metrics是复数形式。因为一个模型只能指明一个optimizer和loss,却可以指明多个metrics。metrics也是三者中处理逻辑最为复杂的一个。
在keras最核心的地方keras.engine.train.py中有如下处理metrics的函数。这个函数其实就做了两件事:
根据输入的metric找到具体的metric对应的函数
计算metric张量
在寻找metric对应函数时,有两种步骤:
使用字符串形式指明准确率和交叉熵
使用keras.metrics.py中的函数
defhandle_metrics(metrics,weights=None): metric_name_prefix='weighted_'ifweightsisnotNoneelse'' formetricinmetrics: #如果metrics是最常见的那种:accuracy,交叉熵 ifmetricin('accuracy','acc','crossentropy','ce'): #customhandlingofaccuracy/crossentropy #(becauseofclassmodeduality) output_shape=K.int_shape(self.outputs[i]) #如果输出维度是1或者损失函数是二分类损失函数,那么说明是个二分类问题,应该使用二分类的accuracy和二分类的的交叉熵 if(output_shape[-1]==1or self.loss_functions[i]==losses.binary_crossentropy): #case:binaryaccuracy/crossentropy ifmetricin('accuracy','acc'): metric_fn=metrics_module.binary_accuracy elifmetricin('crossentropy','ce'): metric_fn=metrics_module.binary_crossentropy #如果损失函数是sparse_categorical_crossentropy,那么目标y_input就不是one-hot的,所以就需要使用sparse的多类准去率和sparse的多类交叉熵 elifself.loss_functions[i]==losses.sparse_categorical_crossentropy: #case:categoricalaccuracy/crossentropy #withsparsetargets ifmetricin('accuracy','acc'): metric_fn=metrics_module.sparse_categorical_accuracy elifmetricin('crossentropy','ce'): metric_fn=metrics_module.sparse_categorical_crossentropy else: #case:categoricalaccuracy/crossentropy ifmetricin('accuracy','acc'): metric_fn=metrics_module.categorical_accuracy elifmetricin('crossentropy','ce'): metric_fn=metrics_module.categorical_crossentropy ifmetricin('accuracy','acc'): suffix='acc' elifmetricin('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) #Getmetricnameasstring ifhasattr(metric_fn,'name'): metric_name=metric_fn.name else: metric_name=metric_fn.__name__ metric_name=metric_name_prefix+metric_name withK.name_scope(metric_name): metric_result=weighted_metric_fn(y_true,y_pred, weights=weights, mask=masks[i]) #Appendtoself.metrics_names,self.metric_tensors, #self.stateful_metric_names iflen(self.output_names)>1: metric_name=self.output_names[i]+'_'+metric_name #Dedupename j=1 base_metric_name=metric_name whilemetric_nameinself.metrics_names: metric_name=base_metric_name+'_'+str(j) j+=1 self.metrics_names.append(metric_name) self.metrics_tensors.append(metric_result) #Keeptrackofstateupdatescreatedby #statefulmetrics(i.e.metricslayers). ifisinstance(metric_fn,Layer)andmetric_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函数。
defget(identifier): ifisinstance(identifier,dict): config={'class_name':str(identifier),'config':{}} returndeserialize(config) elifisinstance(identifier,six.string_types): returndeserialize(str(identifier)) elifcallable(identifier): returnidentifier else: raiseValueError('Couldnotinterpret' 'metricfunctionidentifier:',identifier)
如果identifier是字符串或者字典,那么会根据identifier反序列化出一个metric函数。
如果identifier本身就是一个函数名,那么就直接返回这个函数名。这种方式就为自定义metric提供了巨大便利。
keras中的设计哲学堪称完美。
以上这篇keras中的loss、optimizer、metrics用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。