Python 机器学习算法:7 种损失函数
您已经在给定的数据集上训练了机器学习模型,并准备将其交付给您的客户。但是,如何确定哪种模型可以提供最佳结果呢?是否有指标或技术可以帮助您快速评估数据集中的模型?
当然有,总之机器学习中的损失函数可以解决上述问题。
损失函数是我们喜欢使用的机器学习算法的核心。但大多数初学者和爱好者不知道如何以及在哪里使用它们。
它们并不难理解,但可以提高你对机器学习算法的理解。那么,什么是损失函数以及如何理解它们的含义?
在本文中,我讨论了机器学习中使用的 7 个常见损失函数,并解释了每个函数的使用方式。
目录
- 什么是损失函数? (Kullback Leibler 散度损失)
1。什么是损失函数?
假设你在山顶,需要下山。你如何决定走哪个方向?
这就是我所做的:
- 环顾四周,看看所有可能的方法
- 拒绝上面的方法。因为这些路径实际上会消耗更多的能量,让下山的任务变得更加困难
- 最后,走我认为最陡的路径路径最陡的路径
关于我判断我的决定是否 -使过程成为一种好的或坏的直觉,这正是损失函数可以做的。
损失函数将决策映射到其相关成本
有关山路的决策将花费我们的精力和时间。采取退出路线的决定将使我们受益。因此,下降的成本更小。
在监督机器学习算法中,我们希望在学习过程中最小化每个训练样本的误差。这是通过使用梯度下降等一些优化策略来完成的。而这个误差就来自于损失函数。
损失函数和成本函数有什么区别?
这里强调一点,虽然成本函数和损失函数是同义词并且可以互换使用,但它们是不同的。
损失函数用于单个训练样本。有时也称为误差函数(误差函数)。另一方面,成本函数是整个训练数据集的平均损失(平均函数)。优化策略旨在最小化成本函数。
2。回归损失函数
此时你一定对线性回归非常熟悉了。它涉及对因变量 Y 和多个自变量 X_i 之间的线性关系进行建模。因此,我们将空间中的直线或超平面拟合到该数据。
Y = a0 a1 * X1 a2 * X2 .... an * Xn
我们找到系数 a0, a1,...,以及给定的数据点。
我们使用著名的波士顿住房数据集来理解这个概念。为简单起见,我们将仅使用一个特征 - 每套住宅的平均房间数 (X) - 来预测因变量 - 售价为 1,000 美元的房屋的中值 (Y)。
我们使用梯度下降(梯度下降)作为寻找回归线的优化策略。我不会详细介绍梯度下降,但这里提醒一下权重更新规则:
这里,θ_j 是要更新的权重,α 是学习率,J 是成本函数。成本函数由 θ 参数化。我们的目标是找到使总成本最小的 θ 值。
我为每个损失函数定义了以下步骤:
- 写出预测函数 f(X) 的表达式并确定我们需要找到的参数
- 确定每个训练样本 计算损失
- 求成本函数的表达式(所有样本的平均损失)
- 求与每个未知参数相关的成本函数的梯度
- 确定学习率,使权重以固定的次数迭代更新规则
2.1。 Squared Error Loss
每个训练样本的平方误差损失(也称为L2 Loss)是实际值与预测值之间差值的平方:
成本函数对应于平均值这些 平方误差的 (MSE)。
建议大家尝试自己计算一下梯度,引用下面的代码
def update_weights_MSE(m, b, X, Y, learning_rate): m_deriv = 0 b_deriv = 0 N = len(X) for i in range(N): # 计算偏导数为 # -2x(y - (mx b)) m_deriv = -2*X[i] * (Y[i] - (m*X[i] b)) # -2(y - (mx b)) b_deriv = -2*(Y[i] - (m*X[i] b)) # 我们减去它,因为导数指向最陡的上升方向 m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
在波士顿住房数据上,以不同的学习率迭代500次,得到下图:
我们来谈谈又是 MSE 损失函数,它是一个二次函数(形式为 ax^2 bx c),其值大于或等于 0。二次函数的图形如下所示:
二次函数只有全局最小值。由于没有局部最小值,我们永远不会停留在其中。因此,梯度下降保证收敛到全局最小值(如果它收敛的话)。
MSE 损失函数通过平方误差来惩罚模型的大误差。对更大的数进行平方会使其变得更大。但需要注意的一点是,这一属性使得 MSE 成本函数对于异常值的鲁棒性较差。 因此,如果我们的数据容易受到许多异常值的影响,我们不应该使用它。
2.2。绝对误差损失
每个训练样本的绝对误差是预测值与实际值之间的距离,无论符号如何。绝对误差也称为 L1 损失:
正如我之前所说,成本是这些绝对误差的平均值 (MAE)。
与 MSE 相比,MAE 成本对于异常值更加稳健 。然而,处理数学方程中的绝对或模运算符并不容易。我们可以认为这是MAE的一个缺点。
以下是MAE成本更新权重的代码
def update_weights_MAE(m, b, X, Y, learning_rate): m_deriv = 0 b_deriv = 0 N = len(X) for i in range(N): #计算偏导数 # -x(y - (mx b)) / |mx b| m_deriv = - X[i] * (Y[i] - (m*X[i] b)) / abs(Y[i] - (m*X[i] b)) # -(y - (mx b)) / |mx b| b_deriv = -(Y[i] - (m*X[i] b)) / abs(Y[i] - (m*X[i] b)) #我们减去它,因为导数指向最陡的上升方向 m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
在不同学习率下迭代500次后,我们得到下图:
2.3。 Huber 损失
Huber 损失结合了 MSE 和 MAE 的最佳特性。对于小误差,它是二次的,否则是线性的(其梯度相同)。 Huber损失必须确定δ参数:
def update_weights_Huber(m, b, X, Y, delta, learning_rate): m_deriv = 0 b_deriv = 0 N = len(X) for i in range(N): # 小值的二次导数,大值的线性导数 if abs(Y[i] - m*X[i] - b) <= delta: m_deriv = -X[i] * (Y[i] - (m*X[i] b)) b_deriv = - (Y[i] - (m*X[i] b)) else: m_deriv = delta * X[i] * ((m*X[i] b) - Y[i]) / abs((m*X[i] b) - Y[i]) b_deriv = delta * ((m*X[i] b) - Y[i]) / abs((m*X[i] b) - Y[i]) #我们减去它,因为导数指向最陡的上升方向 m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
我们以0.0001的学习率对δ参数的不同值进行500次权重更新迭代,得到下图:
Huber损失对于异常值的处理能力强于MSE。 它用于鲁棒回归、M估计和加性模型。 Huber 损失的变体也可以用于分类。
3。二元分类损失函数
顾名思义。二元分类是指将元素分配给两个类别之一。分类基于应用于输入特征向量的规则。二元分类的一个示例是根据电子邮件的主题将电子邮件分类为垃圾邮件或非垃圾邮件。
我在乳腺癌数据集^2上说明了这些二元分类损失函数。
我们希望将肿瘤分类为“恶性(Malignant)”或“良性(Benign)”的平均特征等。 ,我们将仅使用两个输入特征(X_1 并用于分类。Y 是二进制的,0(恶性)或 1(良性)。 ?通常,我们使用熵来表示无序或不确定性。测量具有概率分布 p(X) 的随机变量 X:
使用负号使最终结果为正数。
概率分布的熵值越大,分布的不确定性越大。此外,较小的值表示更安全的分布。
这使得二元交叉熵适合作为损失函数(,您希望将其值最小化)。我们使用 二元交叉熵损失 作为输出概率为 p 的分类模型。
元素属于第1类(或正类)的概率=p元素属于第0类(或负类)的概率=1-p
则输出标签y的交叉熵损失和与预测概率p(可取值0和1)定义为:
这也称为log-loss(对数损失)。为了计算概率 p,我们可以使用 sigmoid 函数。这里z是我们输入函数的函数:
sigmoid函数的范围是[0,1],这使得它适合计算概率。
建议大家在引用以下代码时尝试自己计算梯度
def update_weights_BCE(m1, m2, b, X1, X2, Y, learning_rate): m1_deriv = 0 m2_deriv = 0 b_deriv = 0 N = len(X1) for i in range(N): s = 1 / (1 / (1 math.exp(-m1*X1[i] - m2*X2[i] - b))) # 计算偏导数 m1_deriv = -X1[i] * (s - Y[i]) m2_deriv = -X2[i] * (s - Y[i]) b_deriv = -(s - Y[i]) # 我们减去它,因为导数指向最陡的上升方向 m1 -= (m1_deriv / float(N)) * learning_rate m2 -= (m2_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m1, m2, b
使用权重更新规则对不同的alpha值进行1000次迭代,得到如下图像:
3.2。铰链损失
铰链损失主要使用支持向量机(SVM),类标签为-1和1。因此,请确保数据集中“恶性”类的标签从0更改为-1 。
铰链损失不仅会惩罚错误的预测,还会惩罚不确定的正确预测。
数据对 (x,y) 的铰链损失如图所示:
def update_weights_Hinge(m1, m2, b, X1, X2, Y, learning_rate): m1_deriv = 0 m2_deriv = 0 b_deriv = 0 N = len(X1) for i in range(N): # 计算偏导数 if Y[i]*(m1*X1[i] m2*X2[i] b) <= 1: m1_deriv = -X1[i] * Y[i] m2_deriv = -X2[i] * Y[i] b_deriv = -Y[i] # 否则偏导数为0 # 我们减去它,因为导数指向最陡的上升方向 m1 -= (m1_deriv / float(N)) * learning_rate m2 -= (m2_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_ratereturn m1, m2, b
使用更新函数以三个不同的 alpha 值进行 2000 次迭代后,我们得到下图:
铰链损失简化了 SVM 运算的数学运算,同时最大化损失(与对数损失相比)。当我们想要做出实时决策而不是过度关注准确性时可以使用它。
4。多分类损失函数
电子邮件不仅被分类为垃圾邮件或垃圾邮件(这已经不是90年代了!)。它们被分为各种其他类别——工作、家庭、社交、促销等。我们使用 2 个特征 X_1 萼长度 和特征或 Virginica
我们的任务是使用神经网络模型和 Keras 中的 Adam 优化器实现分类器。这是因为随着参数数量的增加,数学以及代码变得难以理解。
这是我们数据的线图:
4.1。多类交叉熵损失
多类交叉熵损失是二元交叉熵损失的推广。输入向量层的损失具有相同数量的节点。” Google 开发者博客
最后,我们的输出是给定输入的概率最高的类。
我们构建一个具有输入层和输出层的模型并用不同的学习率进行编译,在 model.compile() 语句中指定损失函数为“categorical_crossentropy”:
# 导入包from keras.layers import Densefrom keras.models import Sequentialfrom keras.optimizers import adam#alpha设置为0.001,如adam优化器中的lr参数所示# 创建模型model_alpha1 = Sequential()model_alpha1.add(Dense(50, input_dim=2, activation=\'relu\'))model_alpha1.add(Dense(3, activation=\'softmax\'))# 编译模型opt_alpha1 = adam(lr=0.001)model_alpha1.compile(loss=\'categorical_crossentropy\', optimizer=opt_alpha1, metrics=[\'accuracy\'])# 拟合模型# dummy_Y是one-hot形式编码的# history_alpha1用于为绘图的验证和准确性评分history_alpha1 = model_alpha1.fit(dataX, dummy_Y, validation_data=(dataX, dummy_Y), epochs=200, verbose=0)
不同学习率下训练 200 轮后的成本和准确率图表如下:
4.2.KL- 散度
KL 散度 一种概率分布与另一种概率分布差异的度量。KL 散度为零意味着分布相同。即:
因此,不能使用 KL 散度作为距离度量。近似目标变量相对于输入特征的真实概率分布 P。由于 KL 散度是不对称的,我们可以通过两种方式实现这一点:
第一种方法是使用监督学习,第二种方法用于强化学习。 KL 散度在功能上类似于多类交叉熵。 KL散度也可以称为P相对于Q的相对熵:采用了交叉熵。损失。
# 导入包from keras.layers import Densefrom keras.models import Sequentialfrom keras.optimizers import adam# alpha设置为0.001,如adam优化器中的lr参数所示# 创建模型model_alpha1 = Sequential()model_alpha1.add(Dense(50, input_dim=2, activation=\'relu\'))model_alpha1.add(Dense(3, activation=\'softmax\'))# 编译模型opt_alpha1 = adam(lr=0.001)model_alpha1.compile(loss=\'kullback_leibler_divergence\', optimizer=opt_alpha1, metrics=[\'accuracy\'])# 拟合模型# dummy_Y是one-hot形式编码的# history_alpha1用于为绘图的验证和准确性评分history_alpha1 = model_alpha1.fit(dataX, dummy_Y, validation_data=(dataX, dummy_Y), epochs=200, verbose=0)
不同学习率下200轮训练后的成本和准确率图如下:
与多类分类相比,KL散度更常用于逼近复杂函数。在使用深度生成模型(例如变分自动编码器(VAE))时,我们经常使用 KL 散度。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。