本文正在参加「金石计划 . 瓜分6万现金大奖」
前言
在任何深度学习项目中,配置损失函数都是确保模型以预期方式工作的最重要步骤之一。 损失函数可以为神经网络提供很多实用的灵活性,它将定义网络输出与网络其余部分的连接方式。
神经网络可以执行多种任务,从预测连续值(如每月支出)到对离散类别(如猫和狗)进行分类。 每个不同的任务将需要不同的损失类型,因为输出格式将不同。 具体任务将定义不同的损失函数。
接下来博主会细致讲解常见的损失函数,并结合代码使之更容易理解;
介绍
损失函数(loss function)是用来估量你模型的预测值 与真实值 的不一致程度,它是一个非负实值函数,通常使用 来表示,损失函数越小,模型的鲁棒性就越好。损失函数是经验风险函数的核心部分,也是结构风险函数重要组成部分。模型的结构风险函数包括了经验风险项和正则项,通常可以表示成如下式子:
其中,前面的均值函数表示的是经验风险函数, 代表的是损失函数,后面的 是正则化项(regularizer)或者叫惩罚项(penalty term),它可以是 ,也可以是 ,或者其他的正则函数。整个式子表示的意思是找到使目标函数最小时的 值。
从非常简化的角度来看,损失函数(J)可以定义为具有两个参数的函数:
- 预测输出;
- 实际输出。
如何使用损失函数呢?具体步骤:
- 用随机值初始化前向计算公式的参数;
- 代入样本,计算输出的预测值;
- 用损失函数计算预测值和标签值(真实值)的误差;
- 根据损失函数的导数,沿梯度最小方向将误差回传,修正前向计算公式中的各个权重值;
- 进入第2步重复,直到损失函数值达到一个满意的值就停止迭代。
分类损失
当神经网络试图预测离散值时,我们可以将其视为分类模型。 这可能是网络试图预测图像中存在哪种动物,或者电子邮件是否为垃圾邮件。 首先,让我们看看分类神经网络的输出表示方式。
输出层的节点数将取决于数据中存在的类数。 每个节点将代表一个类。 每个输出节点的值本质上表示该类别为正确类别的概率。
Pr(Class 1) = Probability of Class 1 being the correct class
一旦获得所有不同类别的概率,我们就将具有最高概率的类别视为该实例的预测类别。 首先,让我们探讨如何进行二进制分类。
二进制分类
在二进制分类中,即使我们将在两个类之间进行预测,在输出层中也将只有一个节点。 为了获得概率格式的输出,我们需要应用一个激活函数。 由于概率要求取0到1之间的值,因此我们将使用S型函数,该函数可以将任何实际值压缩为0到1之间的值。
随着 的输入变大并趋向于无穷大, 的输出趋向于1。随着 的输入变小而趋向于负无穷大,输出将趋于0。现在我们保证总会得到 一个介于0到1之间的值,这正是我们需要的值,因为我们需要概率。
根据公式编写 函数:
def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s
我们用于二进制分类的损失函数称为二进制交叉熵(BCE)。 该功能有效地惩罚了用于二进制分类任务的神经网络。
我们可以在数学上将整个损失函数表示为一个方程式,如下所示:
此损失函数也称为对数损失。 这就是为二进制分类神经网络设计损失函数的方式。 现在,让我们继续来看如何为多类别分类网络定义损失。
多类别分类
当我们需要我们的模型每次预测一个可能的类输出时,多类分类是合适的。 现在,由于我们仍在处理概率,因此仅将 应用于所有输出节点可能有意义,以便我们为所有输出获得介于0–1之间的值,但这是有问题的。 在考虑多个类别的概率时,我们需要确保所有单个概率的总和等于1,因为这是定义概率的方式。 应用 形不能确保总和始终等于1,因此我们需要使用另一个激活函数。
根据公式编写 函数:
import numpy as np
def softmax(x):
# 计算每行的最大值
row_max = np.max(x)
# 每行元素都需要减去对应的最大值,否则求 exp(x) 会溢出,导致 inf 情况
x = x - row_max
# 计算 e 的指数次幂
x_exp = np.exp(x)
x_sum = np.sum(x_exp)
s = x_exp / x_sum
return s
softmax(np.array([[3, 0.8, 0.96]]))
# array([[0.80591096, 0.08929748, 0.10479156]])
如图所示,我们只是将所有值传递给指数函数。 之后,要确保它们都在0–1的范围内,并确保所有输出值的总和等于1,我们只需将每个指数除以所有指数的总和即可。
那么,为什么在归一化每个值之前必须将它们传递给指数呢? 为什么我们不能仅将值本身标准化? 这是因为 的目标是确保一个值非常高(接近1),而所有其他值都非常低(接近0)。 Softmax使用指数来确保发生这种情况。 然后我们在归一化,因为我们需要概率。
这种损失称为分类交叉熵。 现在,让我们进入一种称为多标签分类的特殊分类情况。
多标签分类
当模型需要预测多个类别作为输出时,便完成了多标签分类。 例如,假设您正在训练神经网络,以预测某些食物图片中的成分。 我们需要预测多种成分,因此 中会有多个1。
为此,我们不能使用 ,因为 始终只会迫使一个类别变为1,而其他类别变为0。因此,由于我们试图预测每个类别的个体概率,因此可以简单地在所有输出节点值上保持 。
至于损失,我们可以直接在每个节点上使用对数损失进行求和,类似于在多类分类中所做的。
既然我们已经介绍了分类,现在让我们介绍回归损失函数。
回归损失
在回归中,我们的模型正在尝试预测连续值。 回归模型的一些示例是:
- 房价预测
- 年龄预测
在回归模型中,我们的神经网络将为每个我们试图预测的连续值提供一个输出节点。 通过在输出值和真实值之间进行直接比较来计算回归损失。
我们用于回归模型的最流行的损失函数是均方误差损失函数。 在此,我们仅计算 和 之差的平方,并对所有数据求平均值。 假设有 个数据点:
在这里, 和 指的是数据集中第 个 值,以及来自神经网络的相同数据的相应 。
根据公式编写 函数:
def mean_squared_error(y_true, y_pred):
sq_error = (y_pred - y_true) ** 2
sum_sq_error = np.sum(sq_error)
mse = sum_sq_error / y_true.size
return mse
y_true = [[0, 0, 1], [0, 1, 0], [1, 0, 0]]
y_pred = [[0.3, 0.3, 0.4], [0.3, 0.4, 0.3], [0.1, 0.2, 0.7]]
mean_squared_error(np.array(y_pred), np.array(y_true))
# 0.2688888888888889
实战
我们希望根据图片动物的轮廓、颜色等特征,来预测动物的类别,有三种可预测类别:猫、狗、猪。假设我们当前有两个模型(参数不同),这两个模型都是通过 / 的方式得到对于每个预测结果的概率值:
模型1:
预测 | 真实 | 是否正确 |
---|---|---|
0.3 0.3 0.4 | 0 0 1 (猪) | 正确 |
0.3 0.4 0.3 | 0 1 0 (狗) | 正确 |
0.1 0.2 0.7 | 1 0 0 (猫) | 错误 |
模型2:
预测 | 真实 | 是否正确 |
---|---|---|
0.1 0.2 0.7 | 0 0 1 (猪) | 正确 |
0.1 0.7 0.2 | 0 1 0 (狗) | 正确 |
0.3 0.4 0.3 | 1 0 0 (猫) | 错误 |
- 模型1对于样本1和样本2以非常微弱的优势判断正确,对于样本3的判断则彻底错误。
- 模型2对于样本1和样本2判断非常准确,对于样本3判断错误,但是相对来说没有错得太离谱。
有了模型之后,我们需要通过定义损失函数来判断模型在样本上的表现:
分类损失
模型1:
模型2:
from sklearn.metrics import log_loss
y_true = [[0, 0, 1], [0, 1, 0], [1, 0, 0]]
y_pred_1 = [[0.3, 0.3, 0.4], [0.3, 0.4, 0.3], [0.1, 0.2, 0.7]]
y_pred_2 = [[0.1, 0.2, 0.7], [0.1, 0.7, 0.2], [0.3, 0.4, 0.3]]
print(log_loss(y_true, y_pred_1))
print(log_loss(y_true, y_pred_2))
回归损失
模型1:
模型2:
from sklearn.metrics import mean_squared_error
y_true = [[0, 0, 1], [0, 1, 0], [1, 0, 0]]
y_pred_1 = [[0.3, 0.3, 0.4], [0.3, 0.4, 0.3], [0.1, 0.2, 0.7]]
y_pred_2 = [[0.1, 0.2, 0.7], [0.1, 0.7, 0.2], [0.3, 0.4, 0.3]]
print("模型1:", mean_squared_error(y_true, y_pred_1))
print("模型2:", mean_squared_error(y_true, y_pred_2))
不难发现,不同的损失函数对模型的表现反馈是不同的,因此,在实际场景中,要根据切实需要选择损失函数!
后记
以上就是 浅谈损失函数 的全部内容了,介绍了损失函数的概念以及常用的损失函数,通过图文与代码结合,细致地讲述了损失函数的要点,希望大家有所收获!
📝 上篇精讲:【AI】浅析恶意文件静态检测及部分问题解决思路
💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注;
👍 创作不易,请多多支持;
🔥 系列专栏:AI