损失函数实际上是我们经常使用的这些技术的核心, 本文介绍了多种损失函数, 他们的工作位置以及如何在 Python 中进行编码
前言
首先想象一下一个场景 - 你已经在给定的数据集上训练了一个机器学习模型, 并且已经准备将其放在客户面前. 但是, 这个时候你应该如何确定该模型会给出很好的结果呢? 是否有一种度量标准或技术可以帮助你快速评估数据集中的模型?
当然有了 - 简单的说, 这就是损失函数在机器学习中发挥作用的地方.
损失函数是我们喜欢使用的机器学习算法的核心. 但是可以看到大多数初学者和爱好者对如何使用损失函数们以及在哪里使用损失函数感到非常困惑.
损失函数并不是那么的难以理解, 并且如果掌握了它将无限地增强你对机器学习算法的理解. 那么, 损失函数是什么, 我们应该如何把握损失函数的意义呢?
在本文中, 我们将讨论机器学习中使用的 7 种常见的损失函数, 并说明每个函数中在什么地方使用. 我们将在本文中介绍很多内容, 所以让我们现在开始吧!
什么是损失函数?
假设你现在在山顶上, 这个时候需要往下走. 你应该怎么决定你往哪个方向走?
假如是我的话, 我会这么做:
首先环顾四周, 看看所有有可能的道路
然后拒绝那些向上的路. 这是因为这些路径实际上会消耗我更多的精力, 并使我的任务更加困难
最后, 选择我认为最容易下坡的那条路
我刚刚只是凭借我的直接来判断我的决定的么? 当然不是, 这些决定正是损失函数所提供的.
损失函数将决策映射到相关的成本上.
决策认为上坡会浪费我们的精力和时间. 决定认为向下对我们来说更有利. 因此, 它具有负成本.
在有监督的机器学习算法中, 我们希望在学习过程中将每个训练样本的误差最小化. 这可以通过一些优化策略 (例如梯度下降) 来完成. 这个误差就来自损失函数.
损失函数和成本函数有什么区别?
首先需要在这里强调一下, 尽管成本函数和损失函数是同义词, 可以互换使用, 但是它们是不同的.
损失函数仅用于单个训练样本. 有时也称为错误函数. 另一方面, 成本函数是整个训练数据集的平均损失. 优化策略的目标是最小化成本函数.
回归损失函数
此时, 你应该非常熟悉线性回归了. 它涉及对因变量 Y 和几个自变量 X_i 之间的线性关系建模. 因此, 我们实际上在这些变量上在空间上拟合了一条空间线.
我们将使用给定的数据点来找到系数 a0,a1,...,an.
我们将使用著名的波士顿住房数据集来理解这一概念. 为了简单起见, 我们将只使用一个特征 - 每个住宅的平均房间数(X), 来预测因变量, 以 1000 美元为单位的房屋的中位数价值(Y).
我们将使用 "梯度下降" 作为一个优化策略来找到回归线. 我不会详细介绍有关 "梯度下降" 的复杂细节, 但是这里有一个关于权重更新规则的提示 ":
在这里, theta_j 是要更新的权重, alpha 是学习率, J 是成本函数. 成本函数由 theta 参数化. 我们的目标是找到产生最小总成本的 theta 值.
我已经定义了以下每个损失函数要遵循的步骤:
为我们的预测函数 f(X)编写表达式, 并确定我们需要查找的参数
确定每个训练样本要使用的损失函数
查找成本函数的表达式 - 所有样本的平均损失
查找成本函数相对于每个未知参数的梯度
确定学习率并对固定次数的迭代运行权重更新规则
1. 平方误差损失
每个训练样本的平方误差损失 (也称为 L2 损失) 是实际值与预测值之差的平方:
相应的成本函数是这些平方误差 (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): # Calculate partial derivatives # -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)) # We subtract because the derivatives point in direction of steepest ascent m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
我在波士顿数据上使用了这段代码, 以获取 500 次迭代中不同的学习率值:
接下来你可以尝试以 0.1 的学习率再次运行该代码 500 次迭代.
让我们再多谈一下 MSE 损失函数. 它是一个二次函数
其中 a> 0), 还记得它的是什么样子么?
二次函数仅具有全局最小值. 由于没有局部最小值, 因此我们永远不会陷入局部最小值的困境. 因此, 它始终可以确保 "梯度下降" 收敛 (如果它完全收敛) 到全局最小值.
MSE 损失函数通过对错误进行平方来惩罚模型, 以免产生大的错误. 平方大会使它更大, 对吗? 但是在这里有一个警告. 此属性使 MSE 成本函数对异常值的鲁棒性 (Robust) 降低. 因此, 如果我们的数据容易出现异常值, 则不应使用此方法.
2. 绝对误差损失
每个训练样本的绝对误差是预测值与实际值之间的距离, 而与符号无关. 绝对误差也称为 L1 损失:
正如我之前提到的, 代价是这些绝对误差 (MAE) 的均值.
与 MSE 相比, MAE 成本对于异常值更为稳健. 但是, 在处理数学方程中的绝对或模运算并不容易. 我相信你们中的很多人都会同意这一点! 我们可以认为这是 MAE 的一个缺点.
这是带有 MAE 成本的 update_weight 函数的代码:
def update_weights_MAE(m, b, X, Y, learning_rate): m_deriv = 0 b_deriv = 0 N = len(X) for i in range(N): # Calculate partial derivatives # -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)) # We subtract because the derivatives point in direction of steepest ascent m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
在以不同的学习率运行代码 500 次的迭代后, 我们得到以下图表:
3.Huber Loss
Huber 损失综合了 MSE 和 MAE 的优质性能. 对于较小的误差, 它是平方的; 对于其他误差, 它是线性的(对于梯度, 也是类似). 由其 delta 参数进行标识:
上方是针对较小的误差是平方的, 下方是针对其他误差为线性的.
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): # derivative of quadratic for small values and of linear for large values 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]) # We subtract because the derivatives point in direction of steepest ascent m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b
对于 delta 参数的不同值, 我们以 0.0001 的学习率获得了 500 次权重更新的迭代, 获得了如下图表:[
与 MSE 相比, Huber 损失对异常值的鲁棒性更高. 它被使用与稳健回归, M - 估计和叠加模型. 在分类中也使用了 Huber Loss 的一种变体.
二分类损失函数
从看到这个名字就应该不言自明了. 二分类是指将一个对象分配给两个类别中的一个. 这种分类基于应用于输入特征向量的规则. 例如, 根据电子邮件的主题, 将电子邮件分为垃圾邮件或非垃圾邮件, 这是一种二进制分类.
我将在乳腺癌数据集上说明这些二分类损失函数.
我们希望根据平均半径, 面积, 周长等特征将肿瘤分类为 "恶性" 或 "良性". 为简化起见, 我们将仅使用两个输入特征 (X1 和 X2), 即 "最差面积" 和 "平均对称" 进行分类. 目标值 Y 可以为 0(恶性) 或 1(良性).
这是我们数据的散点图:
1. 二元交叉熵损失
让我们首先了解 "熵" 一词. 通常, 我们使用熵来表示混乱或不确定性. 对于具有概率分布 p(X)的随机变量 X 进行测量:
负号是用于使总量为正的.
概率分布的熵值越大, 表示分布的不确定性越大. 同样, 较小的值表示更确定的分布.
这使得二元交叉熵适合作为损失函数 - 使其值最小化. 我们将二进制交叉熵损失用于分类模型, 该模型输出一个概率 p.
元素属于 1 类 (或正类) 的概率 = p 然后, 元素属于 0 类 (或负类) 的概率 = 1-p
然后, 输出标签 y(可以取值 0 和 1)和预测概率 p 的交叉熵损失定义为:
这也称为对数丢失. 要计算概率 p, 我们可以使用 Sigmoid 函数. 在此, z 是我们输入特性的函数:
Sigmoid 函数的范围是[0,1], 使其适合于计算概率.
尝试自己输入一下代码, 然再后查看下面的 update_weight 函数的代码.
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))) # Calculate partial derivatives m1_deriv += -X1[i] * (s - Y[i]) m2_deriv += -X2[i] * (s - Y[i]) b_deriv += -(s - Y[i]) # We subtract because the derivatives point in direction of steepest ascent 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
关于使用权重更新规则进行 1000 次迭代(具有不同的 alpha 值), 我得到以下图表:
2. 铰链损失(Hinge Loss)
铰链损失主要用于支持标签为 - 1 和 1 的支持向量机 (SVM) 分类器. 因此, 请确保将数据集中 "Malignant" 类的标签从 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): # Calculate partial derivatives 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] # else derivatives are zero # We subtract because the derivatives point in direction of steepest ascent 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 值对 2000 次迭代运行 update 函数之后, 我们获得了以下图:
铰链损失简化了 SVM 的数学运算, 同时使损失最大化(与对数损失相比). 当我们要做出实时决策而并不是高度关注准确性时, 就可以使用它.
多类分类损失函数
现在电子邮件不只是被归类为垃圾邮件或非垃圾邮件(现在已经不是 90 年代了!). 它们可以被分为其他各种类别 - 工作, 家庭, 社交, 晋升等. 在现在邮件分类是一个多类别分类用例.
我们将使用鸢尾花数据集来了解其余两个损失函数. 我们将使用 2 个特征 X1(萼片长度)和特征 X2(花瓣宽度)来预测鸢尾花 (Setosa,Versicolor 或 Virginica) 的类别(Y)
我们的任务是使用神经网络模型和 keras 中内置的 Adam 优化器来实现分类. 这是因为随着参数数量的增加, 数学以及代码将变得难以理解.
这是我们数据的散点图:
1. 多分类交叉熵损失
多分类交叉熵损失是二分类交叉熵损失的概括. 输入向量 Xi 和相应的单编码目标向量 Yi 的损耗为:
我们使用 softmax 函数来找到概率 p_ij:
"Softmax 是通过在输出层之前的神经网络层实现的. Softmax 层必须具有与输出层相同数量的节点."
最后, 我们的输出是给定输入具有较大概率的类别.
我们使用一个输入层和一个输出层来进行构建模型, 并以不同的学习率对其进行编译. 在 model.compile()语句中将损失参数指定为 "categorical_crossentropy":
# importing requirements from keras.layers import Dense from keras.models import Sequential from keras.optimizers import adam # alpha = 0.001 as given in the lr parameter in adam() optimizer # build the model model_alpha1 = Sequential() model_alpha1.add(Dense(50, input_dim=2, activation='relu')) model_alpha1.add(Dense(3, activation='softmax')) # compile the model opt_alpha1 = adam(lr=0.001) model_alpha1.compile(loss='categorical_crossentropy', optimizer=opt_alpha1, metrics=['accuracy']) # fit the model # dummy_Y is the one-hot encoded # history_alpha1 is used to score the validation and accuracy scores for plotting history_alpha1 = model_alpha1.fit(dataX, dummy_Y, validation_data=(dataX, dummy_Y), epochs=200, verbose=0)
这是经过 200 个时期训练后的成本和准确率图:
2. KL 散度(KL-Divergence)
KL 散度是度量一个概率分布与另一个分布之间的差异的指标. KL 散度为零表示分布相同.
请注意, 散度函数不是对称的.
这就是为什么 KL 散度不能用作距离度量的原因.
我将介绍使用 KL - 散度作为损失函数而不涉及其数学的基本方法. 我们想要得到目标变量关于输入特征的真实概率分布 P 的近似值, 给出一个近似分布 q. 由于 kl 散度不是对称的, 我们可以用两种方法来实现:
第一种方法用于监督学习中, 第二种方法用于强化学习中. KL - 散度在功能上类似于多分类交叉熵, 并且也称为 P 相对于 Q 的相对熵:
我们像以前对多类交叉熵损失所做的那样, 在 compile()函数中将'kullbackleiblerdivergence'指定为损失参数的值.
# importing requirements from keras.layers import Dense from keras.models import Sequential from keras.optimizers import adam # alpha = 0.001 as given in the lr parameter in adam() optimizer # build the model model_alpha1 = Sequential() model_alpha1.add(Dense(50, input_dim=2, activation='relu')) model_alpha1.add(Dense(3, activation='softmax')) # compile the model opt_alpha1 = adam(lr=0.001) model_alpha1.compile(loss='kullback_leibler_divergence', optimizer=opt_alpha1, metrics=['accuracy']) # fit the model # dummy_Y is the one-hot encoded # history_alpha1 is used to score the validation and accuracy scores for plotting history_alpha1 = model_alpha1.fit(dataX, dummy_Y, validation_data=(dataX, dummy_Y), epochs=200, verbose=0)
与多类分类相比, KL - 散度更常用于近似复杂函数. 我们在使用深度自动生成模型 (如变分自动编码器(VAE)) 时经常遇到 KL - 散度.
结语
哇! 到这里为止我们已经讲了很多了. 一直看到最后的你, 给你自己一点鼓励吧. 这篇文章中是我们通常在机器学习中使用的损失函数的详细列表.
在这里呢建议你在继续进行机器学习的过程中, 多读几遍. 因为这不是一次努力就可以全部理解的. 需要一些阅读时间和经验才能了解这些损失函数的工作方式和位置.
来源: http://developer.51cto.com/art/201911/605750.htm