机器通过损失函数进行学习。这是一种评估特定算法对给定的数据 建模程度的方法。如果预测值与真实值之前偏离较远,那么损失函数便会得到一个比较大的值。在一些优化函数的辅助下,损失函数逐渐学会减少预测值与真实值之间的这种误差。
机器学习中的所有算法都依赖于最小化或最大化某一个函数,我们称之为“目标函数”。最小化的这组函数被称为“损失函数”。损失函数是衡量预测模型预测结果表现的指标。寻找函数最小值最常用的方法是“梯度下降”。把损失函数想象成起伏的山脉,梯度下降就好比从山顶滑下,寻找山脉的最低点(目的)。
在实际应用中,并没有一个通用的,对所有的机器学习算法都表现的很不错的损失函数(或者说没有一个损失函数可以适用于所有类型的数据)。针对特定问题选择某种损失函数需要考虑到到许多因素,包括是否有离群点,机器学习算法的选择,运行梯度下降的时间效率,是否易于找到函数的导数,以及预测结果的置信度等。
从学习任务的类型出发,可以从广义上将损失函数分为两大类——分类损失(Classification Loss)和回归损失(Regression Loss)。在分类任务中,我们要从类别值有限的数据集中预测输出,比如给定一个手写数字图像的大数据集,将其分为 0~9 中的一个。而回归问题处理的则是连续值的预测问题,例如给定房屋面积、房间数量,去预测房屋价格。
回归损失
1. 均方误差(Mean Square Error), 二次损失(Quadratic Loss), L2 损失(L2 Loss)
均方误差(MSE)是最常用的回归损失函数。其数学公式如:
均方误差(MSE)度量的是预测值和实际观测值之间差的平方和求平局。它只考虑误差的平均大小,不考虑其方向。但由于经过平方,与真实值偏离较多的预测值会比偏离较少的预测值受到更为严重的惩罚。再加上 MSE 的数学特性很好,这使得计算梯度变得更容易。
下面是一个MSE函数的图,其中真实目标值为 100,预测值在 -10,000 至 10,000之间。预测值(X轴)= 100 时,MSE 损失(Y轴)达到其最小值。损失范围为 0 至 ∞。
import numpy as np
y_true = np.array([0.000, 0.166, 0.333])
y_pre = np.array([0.000, 0.255, 0.986])
def rmse(predictions, targets):
differents = predictions - targets
differents_square = differents ** 2
mean_of_differents_square = differents_square.mean()
rmse_val = np.sqrt(mean_of_differents_square) # 计算平方根
return rmse_val
print("d is:" + str(["%.6f" % i for i in y_true])) # d is:[\'0.000000\', \'0.166000\', \'0.333000\']
print("p is:" + str(["%.6f" % j for j in y_pre])) # p is:[\'0.000000\', \'0.255000\', \'0.986000\']
rmse_val = rmse(y_pre, y_true)
print("rmse is " + str(rmse_val)) # rmse is 0.38049529125426335
print("rmse is %.6s" % rmse_val ) # rmse is 0.3804
2. 平均绝对误差(Mean Absolute Error), L1损失(L1 Loss)
平均绝对误差(MAE)是另一种用于回归模型的损失函数。和 MSE 一样,这种度量方法也是在不考虑方向(如果考虑方向,那将被称为平均偏差(Mean Bias Error, MBE),它是残差或误差之和)的情况下衡量误差大小。但和 MSE 的不同之处在于,MAE 需要像线性规划这样更复杂的工具来计算梯度。此外,MAE 对异常值更加稳健,因为它不使用平方。损失范围也是 0 到 ∞。
1 import numpy as np
2
3 y_true = np.array([0.000, 0.166, 0.333])
4 y_pre = np.array([0.000, 0.255, 0.986])
5
6 print("d is: " + str(["%.8f" % elem for elem in y_true]))
7 print("p is: " + str(["%.8f" % elem for elem in y_pre]))
8
9 def mae(predictions, targets):
10 differences = predictions - targets
11 absolute_differences = np.absolute(differences)
12 mean_of_absolute_differences = absolute_differences.mean()
13 return mean_of_absolute_differences
14
15 mae_error = mae(y_pre, y_true)
16 print("mae error is:", mae_error)
均方误差(MSE) VS 平均绝对误差(MAE)
具体来说,MSE计算更加简便,MAE对异常点(离群点)拥有更好的鲁棒性。
具体原因:当我们在训练一个机器学习模型的时候,我们的目标就是找到是损失函数达到极小值的点。当预测值等于真实值时,则损失函数达到最小。由于 MSE 对误差(e)进行平方操作(y_true - y_pre = e),当 e> 1,那么误差值会进一步增大。如果我们的数据中存在一个异常点,那么e 值将会很大,e的平方将会远远大于 |e|。这将使得和以 MAE 为损失的模型相比,以 MSE 为损失的模型会赋予更高的权重给异常点。例如用RMSE(MSE的平方根,同MAE在同一量级中)为损失的模型会以牺牲其他样本的误差为代价,朝着减小异常点误差的方向更新。然而这就会降低模型的整体性能。
如果训练数据被异常点所污染,那么MAE损失就更好用(比如,在训练数据中存在大量错误的反例和正例样本,在测试集中没有这个问题)。
直观上可以这样理解:对所有的观测数据,如果我们只给一个预测值来最小化 MSE,那么该预测值应该是所有目标值的均值。但是如果我们试图最小化 MAE,那么这个预测值就是所有目标值的中位数。众所周知,对异常值而言,中位数比均值更加鲁棒,因此MAE对于异常值也比MSE更稳定。然而MAE存在一个严重的问题(特别是对于神经网络):梯度更新始终相同,也就是说,即使对于很小的损失值,梯度值也有可能很大。这样不利于模型的学习。为了解决这个缺陷,可以使用变化的学习率,在损失接近最小值时降低学习率。而MSE在这种情况下的表现就很好,即便使用固定的学习率也可以有效收敛。MSE损失的梯度随损失增大而增大,而损失趋于0时则会减小。这使得在训练结束时,使用MSE模型的结果会更精确。
如果异常点会影响业务、并且需要被检测出来,那么我们应该使用 MSE。另一方面,如果我们认为异常点仅仅代表数据损坏,那么我们应该选择 MAE 作为损失。总而言之,处理异常点时,L1损失函数更稳定,但它的导数不连续,因此求解效率较低。L2损失函数对异常点更敏感,通过令其导数为0,可以得到更稳定的封闭解。
二者兼有的问题是:在某些情况下,上述两种损失函数都不能满足需求。例如,若数据中90%的样本对应的目标值为150,剩下10%在0到30之间。那么使用MAE作为损失函数的模型可能会忽视10%的异常点,而对所有样本的预测值都为150。这是因为模型会按中位数来预测。而使用MSE的模型则会给出很多介于0到30的预测值,因为模型会向异常点偏移。上述两种结果在许多商业场景中都是不可取的。这些情况下应该怎么办呢?最简单的办法是对目标变量进行变换。而另一种办法则是换一个损失函数。如Huber损失,Log-Cosh损失,分位数损失。也有些时候可以将利用MAE与MSE训练出的模型进行融合。
3. 平均偏差误差(mean bias error)
与其它损失函数相比,这个函数在机器学习领域没有那么常见。它与 MAE 相似,唯一的区别是这个函数没有用绝对值。用这个函数需要注意的一点是,正负误差可以互相抵消。尽管在实际应用中没那么准确,但它可以确定模型存在正偏差还是负偏差。
4. 平滑的平均绝对误差(Huber Loss)
Huber Loss对数据异常点的敏感度低于均方误差损失,它降低了对离群点的惩罚程度。它在0处可导。基本上它是绝对误差,当误差很小时,误差是二次形式的。误差何时需要变成二次形式取决于超参数(delta),该超参数可以进行微调。当