赞
踩
###前言
Keras本身提供了很多常用的loss函数(即目标函数),但这些损失函数都是比较基本的、通用的。有时候我们需要根据自己所做的任务来自定义损失函数,虽然Keras是一个很高级的封装,自定义loss还是比较简单的。这里记录一下自定义loss的方法,一为助记、二为助人。
###官方定义的损失函数
####第一种方式:自定义一个函数
自定义loss函数之前,我们可以看看Keras官方是如何定义loss的,进入keras/keras/losses.py
文件,我们可以看到很多Keras自带loss的实现代码。比如最简单的均方误差损失函数:
def mean_squared_error(y_true, y_pred):
return K.mean(K.square(y_pred - y_true), axis=-1)
其中y_true
为网络给出的预测值,y_true
即是标签,两者均为tensor
。在loss中直接操作这两个变量即可实现自己想要的loss。例如,我们将其改为四次方的平均值来作为新的loss:
def mean_squared_error2(y_true, y_pred):
return K.mean(K.square(K.square(y_pred-y_true)),axis=-1)
在model编译阶段将loss指定为我们自定义的函数:
model.compile(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)
model.compile(loss=mycrossentropy,
optimizer=keras.optimizers.Adadelta(),
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 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)# KL-Divergence Loss return K.mean(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)
vae.compile(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的扩展性
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。