keras的回调函数的学习

损失函数(Loss)

在学习深度学习中,有一个很重要的部分——损失函数;在已知的深度学习框架中,都预置了常用的损失函数:binary-crossentropymean_squared_errormean_absolute_errormean_absolute_percentage_errormean_squared_logarithmic_errorcategorical_crossentropy……这些损失函数是在构建模型中最长用到的损失函数了;像深度学习入门的几个经典例子——[0-9]的手写数字识别、识别图片中的狗和猫,这两个经典模型中用到的损失函数就是categorical-crossentropy[用于多分类的交叉熵]和binary-crossentropy[用于二分类的交叉熵];又比如时序回归问题(rnn递归神经网络)中又常常用到的是mean_squared_errormean_absolute_percentage_error等等。

损失函数的重要性在于与待解决问题的实际贴合,每一种问题都有适合的损失函数来进行优化:分类问题我们不会采用时序回归预测的损失函数;时序回归预测我们不会采用分类的损失函数。每一个损失函数都有适合的问题模型,因此,对于深度学习框架中的几个预置的损失函数,就是常见的深度学习模型所经常采用的。但是,有时候,我们需要的损失函数需要对已有的损失函数进行变形,亦或者是我们有一个新的,更好的损失函数,但是框架中并没有这个损失函数的实现,那么这个时候应该如何解决?

对于我这个用keras深度学习框架的学习者来说,上面这个问题是比较常见到的,因此需要手动去实现自定义的损失函数;损失函数的定义,实际上就是操作tensor(张量,你可以参考向量的概念去理解),具体操作如下

引入keras的backend

1
from keras import backend as K

利用实现的基本数学操作去实现损失函数的定义,假设我们需要计算真实值与预测值之间的差

1
2
def my_loss(y_true,y_pred):
return K.mean((y_pred-y_true),axis = -1)

y_true是真实值,y_pred是预测值,K.mean()在给定轴上求张量元素之均值,axis=-1表示按每行来计算;具体更多的数学基本操作都在keras.io

性能评估(Mertices)

一个模型的好不好,可能我们从损失函数来看,并不是那么清楚,因此,就有一个性能评估(Mertices)。性能评估器可以看作是对一个模型好坏的度量,像分类问题,可以用accuracy(正确率)来判断、回归预测问题可以用mean_suqared_error(均方差)来判断;但是,就像损失函数一样,有时候性能评估我们会采用其他的度量方式,像PR-AUCROC-AUC等等,那么这个,在keras的框架中是没有预置的,那要怎么实现呢?这时候就要用到keras的回调函数这一个函数了。

回调函数是一组在训练的特定阶段被调用的函数集,就比如一个分类模型在每一个epochs结束后,进行一次计算,计算出本次epochs的accuracy;如果有30个epochs,那么就会出现30次accuracy。一个好的模型,accuracy会呈现上升的趋势,所以,我们又可以从每一次epochs的mertices计算中看出模型的变化情况。

现在以二分类来说,有acuracyPR-AUC两种mertices,当二分类为平衡分类时,这两种mertices都可以;但是,如果是对于不平衡分类(某个或某些类别下的样本数远大于另一些类别下的样本数目。即类别不平衡)的情况下,则更多采用精度-召回曲线下面积来充当性能评估器(PR-AUC的值越接近1,则表明该模型越好)。凑巧的是,keras并没有实现PR-AU的计算,sklearn机器学习库中有相关的实现,因此,我们可以利用keras的回调函数的方法,利用sklern来实现PR-AUC的计算。创建一个python对象,去继承keras.callbacks.Callback回调函数对象,在on_batch_end()on_epochs_end实现相关mertices的计算,并且,可以通过self.validation_data获取每一次epchs的从batch中抽取出部分数据用来充当验证集的数据(并在每个epoch结束后测试的模型的指标,如损失函数、精确度等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from keras import backend as K
from keras.callbacks import Callback
from sklearn.metrics import average_precision_score


class PRAucEvaluation(Callback):
def __init__(self, predict_batch_size=1024, include_on_batch=False):
super(PRAucEvaluation, self).__init__()
self.predict_batch_size = predict_batch_size
self.include_on_batch = include_on_batch

def on_batch_begin(self, batch, logs={}):
pass

def on_batch_end(self, batch, logs={}):
if (self.include_on_batch):
logs['pr_auc_val'] = float('-inf')
if (self.validation_data):
logs['pr_auc_val'] = average_precision_score(self.validation_data[1],
self.model.predict(self.validation_data[0], batch_size=self.predict_batch_size))

def on_train_begin(self, logs={}):
if not ('pr_auc_val' in self.params['metrics']):
self.params['metrics'].append('pr_auc_val')

def on_train_end(self, logs={}):
pass

def on_epoch_begin(self, epoch, logs={}):
pass

def on_epoch_end(self, epoch, logs={}):
logs['pr_auc_val'] = float('-inf')
if (self.validation_data):
logs['pr_auc_val'] = average_precision_score(self.validation_data[1],
self.model.predict(self.validation_data[0],
batch_size=self.predict_batch_size))