Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何选择合适的损失函数

如何选择合适的损失函数

作者头像
zhangjiqun
发布于 2024-12-14 02:42:06
发布于 2024-12-14 02:42:06
2410
举报
文章被收录于专栏:计算机工具计算机工具

如何选择合适的损失函数

机器学习中的所有算法都依赖于最小化或最大化某一个函数,我们称之为“目标函数”。最小化的这组函数被称为“损失函数”。损失函数是衡量预测模型预测期望结果表现的指标。寻找函数最小值的最常用方法是“梯度下降”。把损失函数想象成起伏的山脉,梯度下降就像从山顶滑下,目的是到达山脉的最低点。

没有一个损失函数可以适用于所有类型的数据。损失函数的选择取决于许多因素,包括是否有离群点,机器学习算法的选择,运行梯度下降的时间效率,是否易于找到函数的导数,以及预测结果的置信度。这个博客的目的是帮助你了解不同的损失函数

损失函数可以大致分为两类:分类损失(Classification Loss)和回归损失(Regression Loss)。下面这篇博文,就将重点介绍5种回归损失。

图片
图片

回归函数预测实数值,分类函数预测标签

▌回归损失

1、均方误差,二次损失,L2损失(Mean Square Error, Quadratic Loss, L2 Loss)

均方误差(MSE)是最常用的回归损失函数。MSE是目标变量与预测值之间距离平方之和。

图片
图片

下面是一个MSE函数的图,其中真实目标值为100,预测值在-10,000至10,000之间。预测值(X轴)= 100时,MSE损失(Y轴)达到其最小值。损失范围为0至∞。

MSE损失(Y轴)与预测值(X轴)关系图

2、平均绝对误差,L1损失(Mean Absolute Error, L1 Loss)

平均绝对误差(MAE)是另一种用于回归模型的损失函数。MAE是目标变量和预测变量之间差异绝对值之和。因此,它在一组预测中衡量误差的平均大小,而不考虑误差的方向。(如果我们也考虑方向,那将被称为平均偏差(Mean Bias Error, MBE),它是残差或误差之和)。损失范围也是0到∞。

图片
图片

MAE损失(Y轴)与预测值(X轴)关系图

3、MSE vs MAE (L2损失 vs L1损失)

简而言之, 使用平方误差更容易求解,但使用绝对误差对离群点更加鲁棒。但是,知其然更要知其所以然!

每当我们训练机器学习模型时,我们的目标就是找到最小化损失函数的点。当然,当预测值正好等于真实值时,这两个损失函数都达到最小值。

下面让我们快速过一遍两个损失函数的Python代码。我们可以编写自己的函数或使用sklearn的内置度量函数:

#true:真正的目标变量数组 #pred:预测数组 ** def mse(true, pred): return np.sum(((true – pred)**2)) ** def mae(true, pred): return np.sum(np.abs(true – pred)) ** #也可以在sklearn中使用 ** from sklearn.metrics import mean_squared_error from sklearn.metrics import mean_absolute_error

让我们来看看两个例子的MAE值和RMSE值(RMSE,Root Mean Square Error,均方根误差,它只是MSE的平方根,使其与MAE的数值范围相同)。在第一个例子中,预测值接近真实值,观测值之间误差的方差较小。第二个例子中,有一个异常观测值,误差很高。

图片
图片

左:误差彼此接近 右:有一个误差和其他误差相差很远

我们从中观察到什么?我们该如何选择使用哪种损失函数?

由于MSE对误差(e)进行平方操作(y - y_predicted = e),如果e> 1,误差的值会增加很多。如果我们的数据中有一个离群点,e的值将会很高,将会远远大于|e|。这将使得和以MAE为损失的模型相比,以MSE为损失的模型会赋予更高的权重给离群点。在上面的第二个例子中,以RMSE为损失的模型将被调整以最小化这个离群数据点,但是却是以牺牲其他正常数据点的预测效果为代价,这最终会降低模型的整体性能。

MAE损失适用于训练数据被离群点损坏的时候(即,在训练数据而非测试数据中,我们错误地获得了不切实际的过大正值或负值)。

直观来说,我们可以像这样考虑:对所有的观测数据,如果我们只给一个预测结果来最小化MSE,那么该预测值应该是所有目标值的均值。但是如果我们试图最小化MAE,那么这个预测就是所有目标值的中位数。我们知道中位数对于离群点比平均值更鲁棒,这使得MAE比MSE更加鲁棒。

使用MAE损失(特别是对于神经网络)的一个大问题是它的梯度始终是相同的,这意味着即使对于小的损失值,其梯度也是大的。这对模型的学习可不好。为了解决这个问题,我们可以使用随着接近最小值而减小的动态学习率。MSE在这种情况下的表现很好,即使采用固定的学习率也会收敛。MSE损失的梯度在损失值较高时会比较大,随着损失接近0时而下降,从而使其在训练结束时更加精确。

决定使用哪种损失函数?

如果离群点是会影响业务、而且是应该被检测到的异常值,那么我们应该使用MSE。L2
如果我们认为离群点仅仅代表数据损坏,那么我们应该选择MAE作为损失。L1

我建议阅读下面这篇文章,其中有一项很好的研究,比较了在存在和不存在离群点的情况下使用L1损失和L2损失的回归模型的性能。请记住,L1和L2损失分别是MAE和MSE的另一个名称而已。

地址: http://rishy.github.io/ml/2015/07/28/l1-vs-l2-loss/

L1损失对异常值更加稳健,但其导数并不连续,因此求解效率很低。L2损失对异常值敏感,但给出了更稳定的闭式解(closed form solution)(通过将其导数设置为0)

两种损失函数的问题:可能会出现这样的情况,即任何一种损失函数都不能给出理想的预测。例如,如果我们数据中90%的观测数据的真实目标值是150,其余10%的真实目标值在0-30之间。那么,一个以MAE为损失的模型可能对所有观测数据都预测为150,而忽略10%的离群情况,因为它会尝试去接近中值。同样地,以MSE为损失的模型会给出许多范围在0到30的预测,因为它被离群点弄糊涂了。这两种结果在许多业务中都是不可取的。

在这种情况下怎么做?一个简单的解决办法是转换目标变量。另一种方法是尝试不同的损失函数。这是我们的第三个损失函数——Huber Loss——被提出的动机。

3、Huber Loss,平滑的平均绝对误差

Huber Loss对数据离群点的敏感度低于平方误差损失。它在0处也可导。基本上它是绝对误差,当误差很小时,误差是二次形式的。误差何时需要变成二次形式取决于一个超参数,(delta),该超参数可以进行微调。当 𝛿 ~ 0时, Huber Loss接近MAE,当 𝛿 ~ ∞(很大的数)时,Huber Loss接近MSE。

Huber Loss(Y轴)与预测值(X轴)关系图。真值= 0

delta的选择非常重要,因为它决定了你认为什么数据是离群点。大于delta的残差用L1最小化(对较大的离群点较不敏感),而小于delta的残差则可以“很合适地”用L2最小化。

为什么使用Huber Loss?

使用MAE训练神经网络的一个大问题是经常会遇到很大的梯度,使用梯度下降时可能导致训练结束时错过最小值。对于MSE,梯度会随着损失接近最小值而降低,从而使其更加精确。

在这种情况下,Huber Loss可能会非常有用,因为它会使最小值附近弯曲,从而降低梯度。另外它比MSE对异常值更鲁棒。因此,它结合了MSE和MAE的优良特性。但是,Huber Loss的问题是我们可能需要迭代地训练超参数delta。

4、Log-Cosh Loss

Log-cosh是用于回归任务的另一种损失函数,它比L2更加平滑。Log-cosh是预测误差的双曲余弦的对数。

图片
图片
图片
图片

Log-cosh Loss(Y轴)与预测值(X轴)关系图。真值= 0

优点:log(cosh(x))对于小的x来说,其大约等于 (x ** 2) / 2,而对于大的x来说,其大约等于 abs(x) - log(2)。这意味着'logcosh'的作用大部分与均方误差一样,但不会受到偶尔出现的极端不正确预测的强烈影响。它具有Huber Loss的所有优点,和Huber Loss不同之处在于,其处处二次可导。

为什么我们需要二阶导数?许多机器学习模型的实现(如XGBoost)使用牛顿方法来寻找最优解,这就是为什么需要二阶导数(Hessian)的原因。对于像XGBoost这样的机器学习框架,二阶可导函数更有利。

图片
图片

XGBoost中使用的目标函数。注意其对一阶和二阶导数的依赖性。

但Log-chsh Loss并不完美。它仍然存在梯度和Hessian问题,对于误差很大的预测,其梯度和hessian是恒定的。因此会导致XGBoost中没有分裂。

Huber和Log-cosh损失函数的Python代码:

def sm_mae(true, pred, delta): """ true: array of true values pred: array of predicted values returns: smoothed mean absolute error loss """ loss = np.where(np.abs(true-pred) < delta , 0.5*((true-pred)**2), delta*np.abs(true - pred) - 0.5*(delta**2)) return np.sum(loss) def logcosh(true, pred): loss = np.log(np.cosh(pred - true)) return np.sum(loss)

5、Quantile Loss(分位数损失)

在大多数真实预测问题中,我们通常想了解我们预测的不确定性。了解预测值的范围而不仅仅是单一的预测点可以显着改善许多业务问题的决策过程。

当我们有兴趣预测一个区间而不仅仅是预测一个点时,Quantile Loss函数就很有用。最小二乘回归的预测区间是基于这样一个假设:残差(y - y_hat)在独立变量的值之间具有不变的方差。我们不能相信线性回归模型,因为它违反了这一假设。当然,我们也不能仅仅认为这种情况一般使用非线性函数或基于树的模型就可以更好地建模,而简单地抛弃拟合线性回归模型作为基线的想法。这时,Quantile Loss就派上用场了。因为基于Quantile Loss的回归模型可以提供合理的预测区间,即使是对于具有非常数方差或非正态分布的残差亦是如此。

让我们看一个有效的例子,以更好地理解为什么基于Quantile Loss的回归模型对异方差数据表现良好。

Quantile 回归 vs 普通最小二乘(Ordinary Least Square, OLS)回归

图片
图片

左:线性关系b/w X1和Y,残差的方差恒定。右:线性关系b/w X2和Y,但Y的方差随着X2增加而变大(异方差)。

图片
图片

橙线表示两种情况下的OLS估计

Quantile回归:虚线表示基于0.05和0.95 分位数损失函数的回归估计

如上所示的Quantile回归代码在下面这个notebook中。

地址: https://github.com/groverpr/Machine-Learning/blob/master/notebooks/09_Quantile_Regression.ipynb

了解Quantile Loss函数

基于Quantile回归的目的是,在给定预测变量的某些值时,估计因变量的条件“分位数”。Quantile Loss实际上只是MAE的扩展形式(当分位数是第50个百分位时,Quantile Loss退化为MAE)。

Quantile Loss的思想是根据我们是打算给正误差还是负误差更多的值来选择分位数数值。损失函数根据所选quantile (γ)的值对高估和低估的预测值给予不同的惩罚值。举个例子,γ= 0.25的Quantile Loss函数给高估的预测值更多的惩罚,并试图使预测值略低于中位数。

图片
图片

γ 是给定的分位数,其值介于0和1之间。

图片
图片

Quantile Loss(Y轴)与预测值(X轴)关系图。真值为Y= 0

我们也可以使用这个损失函数来计算神经网络或基于树的模型的预测区间。下图是sklearn实现的梯度提升树回归。

图片
图片

使用Quantile Loss的预测区间(梯度提升回归)

上图显示的是sklearn库的GradientBoostingRegression中的quantile loss函数计算的90%预测区间。上限的计算使用了γ = 0.95,下限则是使用了γ = 0.05。

比较研究

“Gradient boosting machines, a tutorial”中提供了一个很好的比较研究。为了演示上述所有的损失函数的性质,研究人员创造了一个人工数据集,数据集从sinc(x)函数中采样,其中加入了两种人造模拟噪声:高斯噪声分量和脉冲噪声分量。脉冲噪声项是用来展示结果的鲁棒效果的。以下是使用不同损失函数来拟合GBM(Gradient Boosting Machine, 梯度提升回归)的结果。

图片
图片

连续损失函数:(A)MSE损失函数; (B)MAE损失函数; (C)Huber损失函数; (D)Quantile损失函数。用有噪声的sinc(x)数据来拟合平滑GBM的示例:(E)原始sinc(x)函数; (F)以MSE和MAE为损失拟合的平滑GBM; (G)以Huber Loss拟合的平滑GBM, = {4,2,1}; (H)以Quantile Loss拟合的平滑GBM。

模拟实验中的一些观察结果:

  • 以MAE为损失的模型预测较少受到脉冲噪声的影响,而以MSE为损失的模型的预测由于脉冲噪声造成的数据偏离而略有偏差。
  • 以Huber Loss为损失函数的模型,其预测对所选的超参数不太敏感。
  • Quantile Loss对相应的置信水平给出了很好的估计。

一张图画出所有损失函数

图片
图片
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Rafy 框架 - 使用 SqlTree 查询
本文介绍如何使用 Rafy 框架中的 Sql Tree 查询: 除了开发者常用的 Linq 查询,Rafy 框架还提供了 Sql 语法树的方式来进行查询。 这种查询方式下,开发者不需要直接编写真正的 Sql 语句,而是转而使用一套中间 Sql 语法树对象。这隔离了与具体数据库的耦合,使得开发者编写的查询可以跨越多种不同的数据库运行,甚至可以在非关系型数据库中运行。同时,框架还结合托管属性,提供了方便开发者使用的 API,并尽量保持与传统 Sql 相近的语法,使得开发者可以快速理解并编写。 本文包含以下章节:
用户1172223
2018/01/30
2.5K0
Rafy 领域实体框架设计 - 重构 ORM 中的 Sql 生成
前言 Rafy 领域实体框架作为一个使用领域驱动设计作为指导思想的开发框架,必然要处理领域实体到数据库表之间的映射,即包含了 ORM 的功能。由于在 09 年最初设计时,ORM 部分的设计并不是最重要的部分,那里 Rafy 的核心是产品线工程、模型驱动开发、界面生成等。所以当时,我们简单地采用了一个开源的小型 ORM 框架:《Lite ORM Library》。这个 ORM 框架可以生成比较简单的 Sql 语句,以处理一般性的情况。 随着不断使用,我们也不断对 ORM 的源码做了不少改动,让它在支持简单
用户1172223
2018/01/26
2.2K0
LINQ to SQL集成到应用程序中需考虑的一些问题
1、LINQ to SQL集成到应用程序中需考虑的一个问题, 到底应该返回IQueryable<T>还是IQueryable? 或许这个列表还应该继续扩展为T, List<T>, 对于Business
张善友
2018/01/19
1.3K0
MySQL 之索引类型
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。
小手冰凉
2020/05/09
1.3K0
MySQL 之索引类型
MySQL中的索引详讲
转载自 https://www.cnblogs.com/whgk/p/6179612.html
allsmallpig
2021/02/25
6070
深入浅出查询优化器
提示:公众号展示代码会自动折行,建议横屏阅读 「第一部分 查询优化器框架」 关系型数据库是一个通用系统软件,SQL作为一种结构化查询语言,用户不需要关注怎么做,只需要描述做什么,然后交由SQL引擎来处理。因为关系代数提供的等价性,同一个查询可以用不同的SQL语句描述。为防止用户所写的"不好的"SQL执行慢,这就需要查询优化器快速而准确地选择出一个效率较高的执行计划。 一般的查询优化器基于代价计算模型,包含SQL形态的变换,确定访问路径和多表连接顺序等几个重要的步骤。这些步骤被统一在一个优化器框架之内,相互
腾讯数据库技术
2021/06/02
2K0
《MySQL核心知识》第8章:索引
今天是《MySQL核心知识》专栏的第8章,今天为大家系统的讲讲MySQL中的索引技术,希望通过本章节的学习,小伙伴们能够举一反三,彻底掌握MySQL中的索引技术。好了,开始今天的正题吧。
冰河
2022/09/23
4950
《MySQL核心知识》第8章:索引
如何写优雅的SQL原生语句?
sql各语句执行顺序概览与讲解 项目实战中的一段sql说明讲解 sql语句中别名的使用 书写sql语句的注意事项 前言
coder_koala
2019/07/30
1.9K0
如何写优雅的SQL原生语句?
[转自JeffreyZhao]在LINQ to SQL中使用Translate方法以及修改查询用SQL
目前LINQ to SQL的资料不多——老赵的意思是,目前能找到的资料都难以摆脱“官方用法”的“阴影”。LINQ to SQL最权威的资料自然是MSDN,但是MSDN中的文档说明和实例总是显得“大开大阖”,依旧有清晰的“官方”烙印——这简直是一定的。不过从按照过往的经验,在某些时候如果不按照微软划定的道道来走,可能就会发现别样的风景。老赵在最近的项目中使用了LINQ to SQL作为数据层的基础,在LINQ to SQL开发方面积累了一定经验,也总结出了一些官方文档上并未提及的有用做法,特此和大家分享。
菩提树下的杨过
2018/01/24
5K0
[转自JeffreyZhao]在LINQ to SQL中使用Translate方法以及修改查询用SQL
都快2020年,你还没听说过SvelteJS?
React, Vue和Angular差不多占据了Web开发的大部分江山,可是最近半年Svelte[1]开始逐渐吸引越来越多人的眼球。这个Svelte框架到底有什么过人之处呢?本文将会为大家分析一下Svelte火起来的原因,并且通过使用Svelte去搭建一个简单的书店应用(bookshop)来帮助大家快速入门这门框架。
进击的大葱
2022/08/22
3.2K0
都快2020年,你还没听说过SvelteJS?
R语言重复测量数据的多重比较
使用的数据来自孙振球,徐勇勇《医学统计学》第4版。课本的电子版已上传到QQ群,加群即可免费获取!
医学和生信笔记
2022/11/15
1.1K0
R语言重复测量数据的多重比较
linq to sql中慎用Where<T>(Func<TSource, bool> predicate),小心被Linq给"骗"了!
近日在一个大型Web项目中,采用Linq to Sql替换原来的sqlcommand/sqldatareader方式来获取数据,上线后刚开始一切正常,但是随着访问量的增加,网站明显慢了很多,监测服务器CPU占用率/内存使用情况等性能指标却发现均在正常范围内,无意中在SqlServer Profier中跟踪数据库执行的sql语句时,发现有大量语句直接将整个表的数据全部提取出来了,而非仅返回分页中的当前页数据! 而这些SQL都是Linq自动翻译并最终提交到数据库的,查看了相关的代码,明明写着Skip(n
菩提树下的杨过
2018/01/24
1.1K0
学习正则表达式 - 提取和替换 XML 标签
        使用 lorem.dita 作为示例 XML 文档,通过正则表达式提取出该文档中的所有 XML 标签,并转换为简单的 XSLT 样式表。可以在 Github 中找到 lorem.dita 文件,地址是https://github.com/michaeljamesfitzgerald/Introducing-Regular-Expressions。为了节省篇幅,节选部分文本作为测试数据。
用户1148526
2023/10/14
8470
数据库查询优化技术(二):子查询优化
对应的是限制条件(格式类似“field<op>consant”, field表示列对象,op是操作符如"="、">"等)。
sunonzj
2022/06/21
3.3K0
数据库查询优化技术(二):子查询优化
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
在当今的大数据时代,数据库技术的选择对于企业的信息化发展至关重要。OceanBase作为一种高性能、高可用的分布式关系数据库,在与MySQL模式的兼容性方面展现出了显著的优势,为企业数据迁移、整合与升级提供了极大的便利。
公众号:码到三十五
2024/05/06
7680
深入OceanBase分布式数据库:MySQL 模式下的 SQL 基本操作
存储过程和触发器
2.举例 (数据表链接: spj库) ①创建存储过程p1,查询所有信息;运行之。
唔仄lo咚锵
2020/09/15
1.2K0
达观数据文辉:Hadoop和Hive使用经验
近十年来,随着Hadoop生态系统的不断完善,Hadoop早已成为大数据事实上的行业标准之一。面对当今互联网产生的巨大的TB甚至PB级原始数据,利用基于Hadoop的数据仓库解决方案Hive早已是Ha
达观数据
2018/03/30
1.5K0
ORM查询语言(OQL)简介--高级篇(续):庐山真貌
相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山真貌    PDF.NET框架的OQL经过“脱胎换骨”般的重构之后,引来了它华丽丽的新篇章,将“对象化的SQL”特征发挥到极致,与至于我在Q群里面说这应该算是OQL的“收山之作”了。然而,我这么说有什么依据?它的设计哲学是什么?它究竟是何样?由于本文篇幅较长,请听本篇慢慢道来,叙说它的庐山真面目! [有图有真相
用户1177503
2018/02/27
2.3K0
ORM查询语言(OQL)简介--高级篇(续):庐山真貌
Linq to Sql中Single写法不当可能引起的数据库查询性能低下
场景:需要从T_User表中返回指字条件的某条记录的某一个字段 在Linq中有二种理论上都行得通的写法,见下面的代码: Code using (dbUserDataContext db = new dbUserDataContext(Website.ConnStrdbUser))             { try {  //Guid _UserId = db.T_User.Single(c=>c.F_ID==new Guid("00000000-0000-0000-0000-000000000001"
菩提树下的杨过
2018/01/23
1.2K0
Hive性能优化统计每日IP CREATE TABLE ip_2014_12_29 AS SELECT COUNT(DISTINCT ip) AS IP FROM logdfs WHERE logda
Hive性能优化 1.概述   继续《那些年使用Hive踩过的坑》一文中的剩余部分,本篇博客赘述了在工作中总结Hive的常用优化手段和在工作中使用Hive出现的问题。下面开始本篇文章的优化介绍。 2.介绍   首先,我们来看看Hadoop的计算框架特性,在此特性下会衍生哪些问题? 数据量大不是问题,数据倾斜是个问题。 jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是map reduce作业初始化的时间是比较长的。 sum,
Albert陈凯
2018/04/04
1.7K0
Hive性能优化统计每日IP CREATE TABLE ip_2014_12_29 AS SELECT COUNT(DISTINCT ip) AS IP FROM logdfs WHERE logda
推荐阅读
相关推荐
Rafy 框架 - 使用 SqlTree 查询
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档