淘先锋技术网

首页 1 2 3 4 5 6 7

前言

有时候,我们需要往模型里面添加一些自定义的loss。
这些自定义的loss主要分为两大类:

  1. loss是基于样本的正确标签 y r e a l y_{real} yreal 和预测的logit y p r e d y_{pred} ypred 计算得到。这种loss主要集中在对分类损失的改进上,例如Focal Loss等。
  2. 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 函数添加的损失。