前言
有时候,我们需要往模型里面添加一些自定义的loss。
这些自定义的loss主要分为两大类:
- loss是基于样本的正确标签 y r e a l y_{real} yreal 和预测的logit y p r e d y_{pred} ypred 计算得到。这种loss主要集中在对分类损失的改进上,例如Focal Loss等。
- loss需要模型的中间层信息参与运算。这种loss常见的就是对权重的正则化项,高级一点还有对抗机器学习里面的FGSM的对抗学习正则化项。
其中,第一类loss可以通过自定义loss函数,或者loss类,然后在模型compile的时候指定损失就可以了。
第二类loss则不能通过模型compile()函数来指定,而需要调用add_loss()
函数来指定。
第一类loss必须能够通过 y r e a l y_{real} yreal 和 y p r e d y_{pred} ypred,以及某些额外的超参数 得到计算得到。
这种函数的输入是两个参数 y r e a l y_{real} yreal 和 y p r e d y_{pred} ypred, 输出是一个tensor,tensor的必须得是对每个样本都输出一个值。
定义好之后,在model的compile里面指定就是了。
例如:
alpha1=0.2
alpha2=0.5
def custom_loss_function(y_true, y_pred):
squared_difference = tf.square(y_true - y_pred)
##如果计算过程需要用上超参数,则先在全局作用域定义超参数,然后在函数里面直接使用这些超参数。
return tf.reduce_mean(squared_difference, axis=-1)
model.compile(optimizer='adam', loss=custom_loss_function)
再比如 Focal Loss的定义:
其中 γ \gamma γ 是一个超参数,用于调和loss,我们可以在实现的时候把它定义为一个全局的参数,然后再函数里面使用它就可以了。
第二类loss则是需要神经网络本身参与计算,例如L2正则化啥的。
这类loss的定义,一般是在网络搭建的后面,因为这些loss的计算能够方便的访问到中间层的输出或权重。
这种loss没有像第一类loss一样有输入输出的约定,loss一般就是用某个函数封装的任意计算图。
定义好loss之后,把调用模型的add_loss
函数把这部分计算图加到模型即可。
compile里面指定的loss和add_loss指定的loss的关系:
在keras的model.compile函数源码中可以看到如下的代码:
with K.name_scope('loss'):
for i in range(len(self.outputs)):
if i in skip_target_indices:
continue
y_true = self.targets[i]
y_pred = self.outputs[i]
weighted_loss = weighted_losses[i]
sample_weight = sample_weights[i]
mask = masks[i]
loss_weight = loss_weights_list[i]
with K.name_scope(self.output_names[i] + '_loss'):
output_loss = weighted_loss(y_true, y_pred,
sample_weight, mask)
if len(self.outputs) > 1:
self.metrics_tensors.append(output_loss)
self.metrics_names.append(self.output_names[i] + '_loss')
if total_loss is None:
total_loss = loss_weight * output_loss
else:
total_loss += loss_weight * output_loss
if total_loss is None:
if not self.losses:
raise ValueError('The model cannot be compiled '
'because it has no loss to optimize.')
else:
total_loss = 0.
# Add regularization penalties
# and other layer-specific losses.
for loss_tensor in self.losses:
total_loss += loss_tensor
前面是计算compile里面指定的loss,然后再把self.losses
里面损失加起来。
而self.losses
就是模型(包括它使用到所有层)通过add_loss
函数添加的损失。