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

共 3723字,需浏览 8分钟

 ·

2021-05-23 14:02


作者:Arjun Sarkar

翻译:陈之炎

校对:欧阳锦


本文约1900字,建议阅读8分钟
本文带你学习使用Python中的wrapper函数和OOP来编写自定义损失函数。
        
标签:TensorFlow 2,损失函数
 

图1:梯度下降算法(来源:公共域,https://commons.wikimedia.org/w/index.php?curid=521422 )

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

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

  • 均方对数误差;

  • 二元交叉熵;

  • 分类交叉熵;

  • 稀疏分类交叉熵。


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

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


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

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

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

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

from tensorflow.keras.losses import mean_squared_errormodel.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的公式为:


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

  • sqr_error:误差的平方。

  • mean_sqr_error:误差平方的均值。

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



创建Huber损失函数:


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

Huber损失函数的计算公式:


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

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

源代码:


详细说明:

首先,定义一个函数—— 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来实现。

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


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

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

使用封装后的Huber损失函数


封装函数的源代码:


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


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



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

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

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


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



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

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

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

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

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



结论


在Tensorflow中没有的损失函数都可以利用函数、包装函数或类似的类来创建。
 
原文标题:
Creating custom Loss functionsusing TensorFlow 2
原文链接:
https://towardsdatascience.com/creating-custom-loss-functions-using-tensorflow-2-96c123d5ce6c   

编辑:黄继彦
校对:林亦霖




译者简介




陈之炎,北京交通大学通信与控制工程专业毕业,获得工学硕士学位,历任长城计算机软件与系统公司工程师,大唐微电子公司工程师,现任北京吾译超群科技有限公司技术支持。目前从事智能化翻译教学系统的运营和维护,在人工智能深度学习和自然语言处理(NLP)方面积累有一定的经验。业余时间喜爱翻译创作,翻译作品主要有:IEC-ISO 7816、伊拉克石油工程项目、新财税主义宣言等等,其中中译英作品“新财税主义宣言”在GLOBAL TIMES正式发表。能够利用业余时间加入到THU 数据派平台的翻译志愿者小组,希望能和大家一起交流分享,共同进步。

翻译组招募信息

工作内容:需要一颗细致的心,将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生,或在海外从事相关工作,或对自己外语水平有信心的朋友欢迎加入翻译小组。

你能得到:定期的翻译培训提高志愿者的翻译水平,提高对于数据科学前沿的认知,海外的朋友可以和国内技术应用发展保持联系,THU数据派产学研的背景为志愿者带来好的发展机遇。

其他福利:来自于名企的数据科学工作者,北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。


点击文末“阅读原文”加入数据派团队~



转载须知

如需转载,请在开篇显著位置注明作者和出处(转自:数据派ID:DatapiTHU),并在文章结尾放置数据派醒目二维码。有原创标识文章,请发送【文章名称-待授权公众号名称及ID】至联系邮箱,申请白名单授权并按要求编辑。

发布后请将链接反馈至联系邮箱(见下方)。未经许可的转载以及改编者,我们将依法追究其法律责任。



点击“阅读原文”拥抱组织



浏览 45
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报