【AI】浅谈损失函数 前言 介绍 分类损失 回归损失 实战

本文正在参加「金石计划 . 瓜分6万现金大奖」

前言

在任何深度学习项目中,配置损失函数都是确保模型以预期方式工作的最重要步骤之一。 损失函数可以为神经网络提供很多实用的灵活性,它将定义网络输出与网络其余部分的连接方式。

神经网络可以执行多种任务,从预测连续值(如每月支出)到对离散类别(如猫和狗)进行分类。 每个不同的任务将需要不同的损失类型,因为输出格式将不同。 具体任务将定义不同的损失函数。

接下来博主会细致讲解常见的损失函数,并结合代码使之更容易理解;

介绍

损失函数(loss function)是用来估量你模型的预测值 f(x)f(x)f(x) 与真实值 YYY 的不一致程度,它是一个非负实值函数,通常使用 L(Y,f(x))L(Y, f(x))L(Y,f(x)) 来表示,损失函数越小,模型的鲁棒性就越好。损失函数是经验风险函数的核心部分,也是结构风险函数重要组成部分。模型的结构风险函数包括了经验风险项和正则项,通常可以表示成如下式子:

image.png

其中,前面的均值函数表示的是经验风险函数,LLL 代表的是损失函数,后面的 ΦΦΦ 是正则化项(regularizer)或者叫惩罚项(penalty term),它可以是 L1L1L1,也可以是 L2L2L2,或者其他的正则函数。整个式子表示的意思是找到使目标函数最小时的 θθθ 值。

从非常简化的角度来看,损失函数(J)可以定义为具有两个参数的函数:

  1. 预测输出;
  2. 实际输出。

image.png

如何使用损失函数呢?具体步骤:

  1. 用随机值初始化前向计算公式的参数;
  2. 代入样本,计算输出的预测值;
  3. 用损失函数计算预测值和标签值(真实值)的误差;
  4. 根据损失函数的导数,沿梯度最小方向将误差回传,修正前向计算公式中的各个权重值;
  5. 进入第2步重复,直到损失函数值达到一个满意的值就停止迭代。

分类损失

当神经网络试图预测离散值时,我们可以将其视为分类模型。 这可能是网络试图预测图像中存在哪种动物,或者电子邮件是否为垃圾邮件。 首先,让我们看看分类神经网络的输出表示方式。

image.png

输出层的节点数将取决于数据中存在的类数。 每个节点将代表一个类。 每个输出节点的值本质上表示该类别为正确类别的概率。

1
vbnet复制代码Pr(Class 1) = Probability of Class 1 being the correct class

一旦获得所有不同类别的概率,我们就将具有最高概率的类别视为该实例的预测类别。 首先,让我们探讨如何进行二进制分类。

二进制分类

在二进制分类中,即使我们将在两个类之间进行预测,在输出层中也将只有一个节点。 为了获得概率格式的输出,我们需要应用一个激活函数。 由于概率要求取0到1之间的值,因此我们将使用S型函数,该函数可以将任何实际值压缩为0到1之间的值。

image.png

Sigmoid(x)=11+e−x=ex1+exSigmoid(x) = \frac{1}{1+e^{-x}} = \frac{e^x}{1+e^x}Sigmoid(x)=1+e−x1=1+exex
随着 SigmoidSigmoidSigmoid 的输入变大并趋向于无穷大,SigmoidSigmoidSigmoid 的输出趋向于1。随着 SigmoidSigmoidSigmoid 的输入变小而趋向于负无穷大,输出将趋于0。现在我们保证总会得到 一个介于0到1之间的值,这正是我们需要的值,因为我们需要概率。

根据公式编写 SigmoidSigmoidSigmoid 函数:

1
2
3
py复制代码def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s

我们用于二进制分类的损失函数称为二进制交叉熵(BCE)。 该功能有效地惩罚了用于二进制分类任务的神经网络。

image.png

我们可以在数学上将整个损失函数表示为一个方程式,如下所示:

Loss=(Y)(−log⁡(Ypred))+(1−Y)(−log⁡(1−Ypred))Loss = (Y)(-\log(Y_{pred}))+(1-Y)(-\log(1-Y_{pred}))Loss=(Y)(−log(Ypred))+(1−Y)(−log(1−Ypred))
此损失函数也称为对数损失。 这就是为二进制分类神经网络设计损失函数的方式。 现在,让我们继续来看如何为多类别分类网络定义损失。

多类别分类

当我们需要我们的模型每次预测一个可能的类输出时,多类分类是合适的。 现在,由于我们仍在处理概率,因此仅将 sigmoidsigmoidsigmoid 应用于所有输出节点可能有意义,以便我们为所有输出获得介于0–1之间的值,但这是有问题的。 在考虑多个类别的概率时,我们需要确保所有单个概率的总和等于1,因为这是定义概率的方式。 应用 SSS 形不能确保总和始终等于1,因此我们需要使用另一个激活函数。

未命名文件.png

Softmax(yi)=eyi∑i=0neyiSoftmax(y_i) = \frac{e^{y_i}}{\sum^n_{i=0}e^{y_i}}Softmax(yi)=∑i=0neyieyi
根据公式编写 SoftmaxSoftmaxSoftmax 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
py复制代码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,我们只需将每个指数除以所有指数的总和即可。

那么,为什么在归一化每个值之前必须将它们传递给指数呢? 为什么我们不能仅将值本身标准化? 这是因为 softmaxsoftmaxsoftmax 的目标是确保一个值非常高(接近1),而所有其他值都非常低(接近0)。 Softmax使用指数来确保发生这种情况。 然后我们在归一化,因为我们需要概率。

这种损失称为分类交叉熵。 现在,让我们进入一种称为多标签分类的特殊分类情况。

多标签分类

当模型需要预测多个类别作为输出时,便完成了多标签分类。 例如,假设您正在训练神经网络,以预测某些食物图片中的成分。 我们需要预测多种成分,因此 YYY 中会有多个1。

为此,我们不能使用 softmaxsoftmaxsoftmax,因为 softmaxsoftmaxsoftmax 始终只会迫使一个类别变为1,而其他类别变为0。因此,由于我们试图预测每个类别的个体概率,因此可以简单地在所有输出节点值上保持 sigmoidsigmoidsigmoid。

至于损失,我们可以直接在每个节点上使用对数损失进行求和,类似于在多类分类中所做的。

既然我们已经介绍了分类,现在让我们介绍回归损失函数。

回归损失

在回归中,我们的模型正在尝试预测连续值。 回归模型的一些示例是:

  • 房价预测
  • 年龄预测

在回归模型中,我们的神经网络将为每个我们试图预测的连续值提供一个输出节点。 通过在输出值和真实值之间进行直接比较来计算回归损失。

我们用于回归模型的最流行的损失函数是均方误差损失函数。 在此,我们仅计算 YYY 和 YpredY_{pred}Ypred 之差的平方,并对所有数据求平均值。 假设有 nnn 个数据点:

Loss=1n∗∑i=0n(Yi−Ypredi)2Loss = \frac{1}{n}*\sum^n_{i=0}(Y_i-Y_{pred_i})^2Loss=n1∗i=0∑n(Yi−Ypredi)2
在这里,YiY_iYi 和 YprediY_{pred_i}Ypredi 指的是数据集中第 iii 个 YYY 值,以及来自神经网络的相同数据的相应 YpredY_{pred}Ypred。

根据公式编写 MSEMSEMSE 函数:

1
2
3
4
5
6
7
8
9
10
py复制代码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

实战

我们希望根据图片动物的轮廓、颜色等特征,来预测动物的类别,有三种可预测类别:猫、狗、猪。假设我们当前有两个模型(参数不同),这两个模型都是通过 sigmoidsigmoidsigmoid / softmaxsoftmaxsoftmax 的方式得到对于每个预测结果的概率值:

模型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:

sample1Loss=−(0×log⁡0.3+0×log⁡0.3+1×log⁡0.4)=0.91sample2Loss=−(0×log⁡0.3+1×log⁡0.4+0×log⁡0.3)=0.91sample3Loss=−(1×log⁡0.1+0×log⁡0.2+0×log⁡0.7)=2.30L=0.91+0.91+2.33=1.37sample1 \quad Loss = -(0\times\log0.3+0\times\log0.3+1\times\log0.4) = 0.91\
sample2 \quad Loss = -(0\times\log0.3+1\times\log0.4+0\times\log0.3) = 0.91\
sample3 \quad Loss = -(1\times\log0.1+0\times\log0.2+0\times\log0.7) = 2.30\
\quad
\
L = \frac{0.91+0.91+2.3}{3}=1.37sample1Loss=−(0×log0.3+0×log0.3+1×log0.4)=0.91sample2Loss=−(0×log0.3+1×log0.4+0×log0.3)=0.91sample3Loss=−(1×log0.1+0×log0.2+0×log0.7)=2.30L=30.91+0.91+2.3=1.37
模型2:

sample1Loss=−(0×log⁡0.1+0×log⁡0.2+1×log⁡0.7)=0.35sample2Loss=−(0×log⁡0.1+1×log⁡0.7+0×log⁡0.2)=0.35sample3Loss=−(1×log⁡0.3+0×log⁡0.4+0×log⁡0.4)=1.20L=0.35+0.35+1.23=0.63sample1 \quad Loss = -(0\times\log0.1+0\times\log0.2+1\times\log0.7) = 0.35\
sample2 \quad Loss = -(0\times\log0.1+1\times\log0.7+0\times\log0.2) = 0.35\
sample3 \quad Loss = -(1\times\log0.3+0\times\log0.4+0\times\log0.4) = 1.20\
\quad
\
L = \frac{0.35+0.35+1.2}{3}=0.63sample1Loss=−(0×log0.1+0×log0.2+1×log0.7)=0.35sample2Loss=−(0×log0.1+1×log0.7+0×log0.2)=0.35sample3Loss=−(1×log0.3+0×log0.4+0×log0.4)=1.20L=30.35+0.35+1.2=0.63

1
2
3
4
5
6
7
py复制代码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))

image.png


回归损失

模型1:

sample1Loss=(0.3−0)2+(0.3−0)2+(0.4−1)23=0.18sample2Loss=(0.3−0)2+(0.4−1)2+(0.3−0)23=0.18sample3Loss=(0.1−1)2+(0.2−0)2+(0.7−0)23=0.45L=0.18+0.18+0.453=0.27sample1 \quad Loss = \frac{(0.3-0)^2 + (0.3-0)^2 + (0.4-1)^2}{3} = 0.18\
sample2 \quad Loss = \frac{(0.3-0)^2 + (0.4-1)^2 + (0.3-0)^2}{3} = 0.18\
sample3 \quad Loss = \frac{(0.1-1)^2 + (0.2-0)^2 + (0.7-0)^2}{3} = 0.45\
\quad
\
L = \frac{0.18+0.18+0.45}{3}=0.27sample1Loss=3(0.3−0)2+(0.3−0)2+(0.4−1)2=0.18sample2Loss=3(0.3−0)2+(0.4−1)2+(0.3−0)2=0.18sample3Loss=3(0.1−1)2+(0.2−0)2+(0.7−0)2=0.45L=30.18+0.18+0.45=0.27
模型2:

sample1Loss=(0.1−0)2+(0.2−0)2+(0.7−1)23=0.05sample2Loss=(0.1−0)2+(0.7−1)2+(0.2−0)23=0.05sample3Loss=(0.3−1)2+(0.4−0)2+(0.3−0)23=0.25L=0.05+0.05+0.253=0.11sample1 \quad Loss = \frac{(0.1-0)^2 + (0.2-0)^2 + (0.7-1)^2}{3} = 0.05\
sample2 \quad Loss = \frac{(0.1-0)^2 + (0.7-1)^2 + (0.2-0)^2}{3} = 0.05\
sample3 \quad Loss = \frac{(0.3-1)^2 + (0.4-0)^2 + (0.3-0)^2}{3} = 0.25\
\quad
\
L = \frac{0.05+0.05+0.25}{3}=0.11sample1Loss=3(0.1−0)2+(0.2−0)2+(0.7−1)2=0.05sample2Loss=3(0.1−0)2+(0.7−1)2+(0.2−0)2=0.05sample3Loss=3(0.3−1)2+(0.4−0)2+(0.3−0)2=0.25L=30.05+0.05+0.25=0.11

1
2
3
4
5
6
7
py复制代码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))

image.png


不难发现,不同的损失函数对模型的表现反馈是不同的,因此,在实际场景中,要根据切实需要选择损失函数!

后记

以上就是 浅谈损失函数 的全部内容了,介绍了损失函数的概念以及常用的损失函数,通过图文与代码结合,细致地讲述了损失函数的要点,希望大家有所收获!

📝 上篇精讲:【AI】浅析恶意文件静态检测及部分问题解决思路

💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注;

👍 创作不易,请多多支持;

🔥 系列专栏:AI

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%