###前言
Keras本身提供了很多常用的loss函数(即目标函数),但这些损失函数都是比较基本的、通用的。有时候我们需要根据自己所做的任务来自定义损失函数,虽然Keras是一个很高级的封装,自定义loss还是比较简单的。这里记录一下自定义loss的方法,一为助记、二为助人。
###官方定义的损失函数
####第一种方式:自定义一个函数
自定义loss函数之前,我们可以看看Keras官方是如何定义loss的,进入keras/keras/
文件,我们可以看到很多Keras自带loss的实现代码。比如最简单的均方误差损失函数:
def mean_squared_error(y_true, y_pred):
return ((y_pred - y_true), axis=-1)
其中y_true
为网络给出的预测值,y_true
即是标签,两者均为tensor
。在loss中直接操作这两个变量即可实现自己想要的loss。例如,我们将其改为四次方的平均值来作为新的loss:
def mean_squared_error2(y_true, y_pred):
return (((y_pred-y_true)),axis=-1)
在model编译阶段将loss指定为我们自定义的函数:
(optimizer='rmsprop',loss=mean_squared_error2)
####实践
以keras/examples/mnist_cnn.py
为例,按照第一种方式修改loss。将原本的交叉熵损失函数进行改进,新的损失函数为:
l
o
s
s
=
−
(
1
−
ε
)
l
o
g
(
e
z
1
/
Z
)
−
ε
∑
i
=
1
3
l
o
g
(
e
z
i
/
Z
)
,
Z
=
e
z
1
+
e
z
2
+
e
z
3
loss=−(1−ε)log(e^{z1}/Z)−ε∑i=\frac{1}{3}log(e^{zi}/Z),Z=e^{z1}+e^{z2}+e^{z3}
loss=−(1−ε)log(ez1/Z)−ε∑i=31log(ezi/Z),Z=ez1+ez2+ez3
新的损失函数定义详见这篇blog
对应的keras代码为:
#custom loss
def mycrossentropy(y_true, y_pred, e=0.1):
return (1-e)*K.categorical_crossentropy(y_pred,y_true) + e*K.categorical_crossentropy(y_pred, K.ones_like(y_pred)/num_classes)
(loss=mycrossentropy,
optimizer=(),
metrics=['accuracy'])
两种loss对应的准确率曲线如下:(5 epochs)
其中虚线表示损失,实线表示acc,发现新的损失函数并没有原有的交叉熵损失函数效果好(其实都很好,只是差一点),可能是因为mnist数据太过简单了,体现不出新的损失函数的优点。这些说明我们要根据自己的实际任务来设计loss,不同的loss函数有不同的适用范围。
####第二种方式:自定义一个层次
在Keras自带的examples中又发现了另外一种定义loss函数的例子,该例子将新的损失函数定义为一个层次来使用。在keras/examples/variational_autoencoder.py
文件中:
# Custom loss layer
class CustomVariationalLayer(Layer):
def __init__(self, **kwargs):
self.is_placeholder = True
super(CustomVariationalLayer, self).__init__(**kwargs)
def vae_loss(self, x, x_decoded_mean):
xent_loss = original_dim * metrics.binary_crossentropy(x, x_decoded_mean)#Square Loss
kl_loss = - 0.5 * (1 + z_log_var - (z_mean) - (z_log_var), axis=-1)# KL-Divergence Loss
return (xent_loss + kl_loss)
def call(self, inputs):
x = inputs[0]
x_decoded_mean = inputs[1]
loss = self.vae_loss(x, x_decoded_mean)
self.add_loss(loss, inputs=inputs)
# We won't actually use the output.
return x
新的loss包含均方差和KL散度,该官方代码的解析可以跳转到另一篇bolg:Keras官方示例代码解释(1):variational autoencoder
该自定义层次的使用如下:
y = CustomVariationalLayer()([x, x_decoded_mean])
vae = Model(x, y)
(optimizer='rmsprop', loss=None)
第一句代码的x
为输入数据,x_decoded_mean
为网络的输出数据(除开loss层的最后一层)。在compile
函数中指定’loss’为None
,表示loss已经作为一个层次在网络中了,不需要在这里指定loss。
有关自定义层可以参考官方中文文档中的编写自己的层
####实践
在variational_autoencoder.py
的基础上,对比loss1=均方差
和loss2=均方差+KL散度(即自定义的loss层)
。实验结果如下:(10 epochs)
可以看出,使用loss2
得到的重建结果要好于loss1
的情况。
###后记
自定义loss函数或者说自定义层是将CNN用于特定任务的第一步,与君共勉。
参考资料:
keras 自定义 loss损失函数, sample在loss上的加权 和 metric
Keras中自定义复杂的loss函数
TensorFlow四种Cross Entropy算法实现和应用
如何利用Keras的扩展性