Fork me on GitHub

Keras中custom loss function的使用

我在最近的研究中使用keras建立神经网络模型。但是我的模型有一定的特殊性。其loss function不是将多个样本的loss求平均的形式,比如MSE。我的loss function需要根据一个外部索引对样本进行分类,对每一个样本集生成一个loss,再将这些loss求和或求平均得到最终的loss function。这个叫custom loss function (定制化的损失函数),实际上就是自己写一个loss function来代替keras默认的loss function。以下是我写好的loss function.

1
2
3
4
5
6
7
8
9
10
11
12
13
def gen_loss(group):
if (all([v == 0 for v in group.label])):
loss = K.any([v > thre for v in group.pred])
elif (all([v == 1 for v in group.label])):
loss = K.all([v < thre for v in group.pred])
else:
loss = K.any([v > thre for v in group[group.label == 0].pred]) + K.all([v < thre for v in group[group.label == 1].pred])
return(loss)
def my_obj(y_true, y_pred):
print y_true.shape,y_pred.shape,type(y_true),type(y_pred)
df = DataFrame({'sn':train.sn,'label':y_true,'pred':y_pred})
return sum(df.groupby('sn').apply(gen_loss))

这里引入了train.sn来进行分组,再根据一个事先确定的thre计算每个group中的loss,最后将每个组的loss求和。然而这个loss function在使用时出现了迭代超过最大次数的错误。我从源码调查其故障原因。实际上loss function写完之后的训练过程只有两行代码

1
2
model.compile(loss = my_obj, optimizer='adam', metrics=['accuracy'])
model.fit(data_train, label_train, nb_epoch=10, batch_size=100)

我们从model.compile开始入手。model对象是用model = Sequential()来建立的,这里Sequential()并没有对loss进行处理,而是继承了其父类Model对loss的处理函数。

我们看到Model类,这个类首先将我们定义的函数加入模型中loss_function = objectives.get(loss)

然后在_standardize_user_data中有一个check_loss_and_target_compatibility(y, self.loss_functions, self.internal_output_shapes)的检查的部分。这里y是一个输出。这里主要检查了几个默认的loss function以及长度是否一致。这都没有什么问题,说明在model.compile中loss function没有问题。

进入model.fit。fit函数也是在model类(training.py)中定义的,我们主要看这个函数

No pain, No gain