博客专栏

EEPW首页 > 博客 > 独家 | 使用TensorFlow 2创建自定义损失函数

独家 | 使用TensorFlow 2创建自定义损失函数

发布人:数据派THU 时间:2021-05-26 来源:工程师 发布文章

作者:Arjun Sarkar

翻译:陈之炎

校对:欧阳锦

1.png

神经网络利用训练数据,将一组输入映射成一组输出,它通过使用某种形式的优化算法,如梯度下降、随机梯度下降、AdaGrad、AdaDelta等等来实现,其中最新的算法包括Adam、Nadam或RMSProp。梯度下降中的“梯度”是指误差梯度。每次迭代之后,网络将其预测输出与实际输出进行比较,然后计算出“误差”。

通常,对于神经网络,寻求的是将误差最小化。将误差最小化的目标函数通常称之为成本函数或损失函数,由“损失函数”计算出的值称为“损失”。在各种问题中使用的典型损失函数有:

均方误差;

均方对数误差;

二元交叉熵;

分类交叉熵;

稀疏分类交叉熵。

Tensorflow已经包含了上述损失函数,直接调用它们即可,如下所示:

1. 将损失函数当作字符串进行调用

model.compile (loss = ‘binary_crossentropy’,optimizer = ‘adam’, metrics = [‘accuracy’])

2. 将损失函数当作对象进行调用

from tensorflow.keras.losses importmean_squared_error
model.compile(loss = mean_squared_error,optimizer=’sgd’)

将损失函数当作对象进行调用的优点是可以在损失函数中传递阈值等参数。

from tensorflow.keras.losses import mean_squared_error
model.compile (loss=mean_squared_error(param=value),optimizer = ‘sgd’)

利用现有函数创建自定义损失函数:

利用现有函数创建损失函数,首先需要定义损失函数,它将接受两个参数,y_true(真实标签/输出)和y_pred(预测标签/输出)。

def loss_function(y_true, y_pred):
***some calculation***
return loss

创建均方误差损失函数 (RMSE):

定义损失函数名称-my_rmse。目的是返回目标(y_true)与预测(y_pred)之间的均方误差。

RMSE的公式为:

2.jpg

  • 误差:真实标签与预测标签之间的差异。

  • sqr_error:误差的平方。

  • mean_sqr_error:误差平方的均值。

  • sqrt_mean_sqr_error:误差平方均值的平方根(均方根误差)。

3.png

创建Huber损失函数:

4.png图2:Huber损失函数(绿色)和平方误差损失函数(蓝色)(来源:Qwertyus— Own work,CCBY-SA4.0,https://commons.wikimedia.org/w/index.php?curid=34836380)

Huber损失函数的计算公式:

5.jpg

在此处,δ是阈值,a是误差(将计算出a,即实际标签和预测标签之间的差异)。

当|a|≤δ时,loss = 1/2*(a)²

当 |a|>δ时,loss = δ(|a|—(1/2)*δ)

源代码:

6.png

详细说明:

首先,定义一个函数—— my huber loss,它需要两个参数:y_true和y_pred,

设置阈值threshold = 1。

计算误差error a = y_true-y_pred。接下来,检查误差的绝对值是否小于或等于阈值,is_small_error返回一个布尔值(真或假)。

当|a|≤δ时,loss= 1/2*(a)²,计算small_error_loss, 误差的平方除以2。否则,当|a| >δ时,则损失等于δ(|a|-(1/2)*δ),用big_error_loss来计算这个值。

最后,在返回语句中,首先检查is_small_error是真还是假,如果它为真,函数返回small_error_loss,否则返回big_error_loss,使用tf.where来实现。

可以使用下述代码来编译模型:

7.png

在上述代码中,将阈值设为1。

如果需要调整超参数(阈值),并在编译过程中加入一个新的阈值的话,必须使用wrapper函数进行封装,也就是说,将损失函数封装成另一个外部函数。在这里需要用到封装函数(wrapper function),因为损失函数在默认情况下只能接受y_true和y_pred值,而且不能向原始损失函数添加任何其他参数。

使用封装后的Huber损失函数

封装函数的源代码:

8.png

此时,阈值不是硬编码,可以在模型编译过程中传递该阈值。

9.png

使用类实现Huber损失函数(OOP)

10.png

其中,MyHuberLoss是类名称,随后从tensorflow.keras.losses继承父类“Loss”, MyHuberLoss继承了Loss类,之后可以将MyHuberLoss当作损失函数来使用。

__init__   初始化该类中的对象。执行类实例化对象时调用函数,init函数返回阈值,调用函数得到y_true和y_pred参数,将阈值声明为一个类变量,可以给它赋一个初始值。

在__init__函数中,将阈值设置为self.threshold。在调用函数中,self.threshold引用所有的阈值类变量。在model.compile中使用这个损失函数:

11.png

创建对比性损失(用于Siamese网络):

12.jpg

Siamese网络可以用来比较两幅图像是否相似,Siamese网络使用的损失函数为对比性损失。

在上文的公式中,Y_true是关于图像相似性细节的张量,如果图像相似,则为1,如果图像不相似,则为0。

D是图像对之间的欧氏距离的张量。边际为一个常量,用它来设置将图像区别为相似或不同的最小距离。如果为Y_true=1,则方程的第一部分为D²,第二部分为0,所以,当Y_true接近1时,D²的权重则更重。

如果Y_true=0,则方程的第一部分变为0,第二部分会产生一些结果,这给了最大项更多的权重,给了D平方项更少的权重,此时,最大项在损失计算中占了优势。

使用封装器函数实现对比损失函数:

13.png

结论

在Tensorflow中没有的损失函数都可以利用函数、包装函数或类似的类来创建。

原文标题:

Creating custom Loss functionsusing TensorFlow 2

原文链接:

https://towardsdatascience.com/creating-custom-loss-functions-using-tensorflow-2-96c123d5ce6c

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

负离子发生器相关文章:负离子发生器原理
离子色谱仪相关文章:离子色谱仪原理


关键词: Python

相关推荐

技术专区

关闭