前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【AI】浅谈损失函数

【AI】浅谈损失函数

作者头像
sidiot
发布2023-08-31 14:05:26
2600
发布2023-08-31 14:05:26
举报
文章被收录于专栏:技术大杂烩技术大杂烩

前言

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

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

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

介绍

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

image.png
image.png

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

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

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

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

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

分类损失

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

image.png
image.png

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

代码语言:javascript
复制
Pr(Class 1) = Probability of Class 1 being the correct class

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

二进制分类

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

image.png
image.png

随着 Sigmoid的输入变大并趋向于无穷大,Sigmoid 的输出趋向于1。随着 Sigmoid的输入变小而趋向于负无穷大,输出将趋于0。现在我们保证总会得到 一个介于0到1之间的值,这正是我们需要的值,因为我们需要概率。

根据公式编写 Sigmoid函数:

代码语言:javascript
复制
def sigmoid(x):
    s = 1 / (1 + np.exp(-x))
    return s

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

image.png
image.png

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

此损失函数也称为对数损失。 这就是为二进制分类神经网络设计损失函数的方式。 现在,让我们继续来看如何为多类别分类网络定义损失。

多类别分类

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

未命名文件.png
未命名文件.png

根据公式编写 Softmax函数:

代码语言:javascript
复制
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,我们只需将每个指数除以所有指数的总和即可。

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

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

多标签分类

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

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

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

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

回归损失

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

  • 房价预测
  • 年龄预测

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

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

在这里,Yi 和 Ypredi 指的是数据集中第 i个 Y 值,以及来自神经网络的相同数据的相应 Ypred​。

根据公式编写 MSE 函数:

代码语言:javascript
复制
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

实战

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

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

代码语言:javascript
复制
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
image.png

回归损失

模型1:

模型2:

代码语言:javascript
复制
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
image.png

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

后记

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 介绍
  • 分类损失
    • 二进制分类
      • 多类别分类
        • 多标签分类
        • 回归损失
        • 实战
        • 后记
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档