三、损失函数



前言


  • 在深度学习中, 损失函数是用来衡量模型参数的质量的函数, 衡量的方式是比较网络输出和真实输出的差异:
  • 在这里插入图片描述

一、分类问题的损失函数

1.1 二分类损失函数

1.1.1 数学定义

  • 处理二分类问题的时候,我们使用 sigmoid 激活函数,使用二分类的交叉熵损失函数:
    L ( y , y ^ ) = − [ y l o g ( y ^ ) + ( 1 − y ) l o g ( 1 − y ^ ) ] L(y, \hat y)=−[ylog( \hat y )+(1−y)log(1− \hat y)] L(y,y^)=[ylog(y^)+(1y)log(1y^)]
  • 这里的 l o g log log 是以自然常数 e e e(约等于2.71828)为底的,即自然对数
  • 模型输出的预测概率为 y ^ \hat y y^ (在 0 到 1 之间),真实的标签为 y y y (取值为 0 或 1)

1.1.2 函数解释:

  • y = 1 y = 1 y=1 的时候,也就是真实值为 1 的时候
    L ( 1 , y ^ ) = − l o g ( y ^ ) L(1, \hat y) =−log(\hat y) L(1,y^)=log(y^)

    • 此时如果模型预测的 y ^ \hat y y^ 越接近 1,损失值 L L L 越小;如果越接近0,损失值 L L L 越大。
  • y = 0 y = 0 y=0 的时候,也就是真实值为 1 的时候
    L ( 0 , y ^ ) = − l o g ( 1 − y ^ ) L(0, \hat y) =−log(1-\hat y) L(0,y^)=log(1y^)

    • 此时如果模型预测的 y ^ \hat y y^ 越接近 0,损失值 L L L 越小;如果越接近1,损失值 L L L 越大。

1.1.3 性质

  • 非负性:交叉熵损失函数总是非负的,即 L ( y , y ^ ) ≥ 0 L(y, \hat y )≥0 L(y,y^)0
  • 严格凸函数:在 y ^ \hat y y^ 的定义域(0, 1)内,交叉熵损失函数是严格凸的,因此有助于优化过程找到全局最优解。
  • 对数尺度:由于使用对数函数,交叉熵损失函数对预测概率的微小变化非常敏感,这使得它在梯度下降等优化算法中表现良好。

1.1.4 计算演示

  • 假设我们有一个样本,真实标签 y = 1 y=1 y=1,模型预测的概率为 y ^ \hat y y^ =0.9:
    L ( 1 , 0.9 ) = − l o g ( 0.9 ) = − l n ( 0.9 ) ≈ 0.1054 L(1,0.9)=−log(0.9)= -ln(0.9)≈0.1054 L(1,0.9)=log(0.9)=ln(0.9)0.1054
  • 真实标签 y = 1 y=1 y=1,如果模型预测的概率为 y ^ \hat y y^ = 0.5:
    L ( 1 , 0.5 ) = − l o g ( 0.5 ) = − l n ( 0.5 ) ≈ 0.6931 L(1,0.5)=−log(0.5)= -ln(0.5)≈0.6931 L(1,0.5)=log(0.5)=ln(0.5)0.6931
  • 可以看到,当预测概率接近真实标签时,损失值较小;反之,损失值较大。

1.1.5 代码演示

代码演示 :

import torch
from torch import nn

def my_BCELoss():
    # 1 设置真实值和预测值
    # 预测值是sigmoid输出的结果
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    y_true = torch.tensor([0, 1, 0], dtype=torch.float32)
    # 2 实例化二分类交叉熵损失
    criterion = nn.BCELoss()
    # 3 计算损失
    my_loss = criterion(y_pred, y_true).detach().numpy()
    # detach() 用于将损失函数从计算图中分离出来, numpy() 将tensor转成numpy,
    # 这样打印出来就会是个数字 
    print('loss:', my_loss)


if __name__ == '__main__':
    my_BCELoss()   # loss: 0.6867941

1.2 多分类损失函数

1.1.1 数学定义

  • 处理多分类的问题的时候,我们就不能使用二分类的损失函数,我们需要使用多分类的损失函数,在多分类任务通常使用 softmax 将 logits(原始分数输出) 转换为概率的形式,所以多分类的交叉熵损失也叫做softmax损失,它的计算方法是:
    H ( y , y ^ ) = − ∑ i = 1 N y i l o g ( y ^ i ) H(y, \hat y)=−\sum_{i=1}^{N}y_ilog(\hat y_i) H(y,y^)=i=1Nyilog(y^i)
    y ^ i = s o f t m a x ( f ( x i ) ) \hat y_i = softmax(f(x_i)) y^i=softmax(f(xi))
    • f ( x i ) f(x_i) f(xi) 是对第 i 个类别的预测分数
    • y ^ i \hat y_i y^i 是预测为第 i 类的概率
    • y y y 是真实的标签分布,通常表示为 one-hot 编码向量,即只有一个元素为 1(表示真实类别),其余元素为 0,也可以不进行 热编码,在下边的代码演示中有提及
    • y ^ \hat y y^ 是模型预测的概率分布,由模型的输出层经过softmax函数转换得到,表示每个类别的预测概率
    • N N N是类别的总数
    • 这里的 l o g log log 是以自然常数 e e e(约等于2.71828)为底的,即自然对数

注意:我们不能在网络层的输出层通过softmax函数进行激活,这是因为多分类损失函数会对输入的结果先进行softmax变化,所以会影响损失值的大小,还有准确率

1.1.2 性质与特点

  • 非负性:交叉熵损失总是非负的,当且仅当预测分布与真实分布完全一致时,损失为 0
  • 敏感性:交叉熵损失函数对正确分类的概率非常敏感。如果实际类别的预测概率低(即接近于0),那么损失将会非常高
  • 非对称性:在处理极端概率(接近0或1)时,交叉熵损失表现出明显的非对称性。特别是当预测概率趋近于0时,损失会迅速增加
  • 凸性:交叉熵损失函数是凸函数,这有助于保证优化过程的稳定性和有效性
  • 适合多类别问题:交叉熵损失函数能够很好地处理多类别分类问题,通过分别计算每个类别的损失并求和来得到总损失

1.1.3 计算演示

  • 例子背景

    • 假设我们有一个三分类问题(例如,识别图像中的猫、狗或鸟),并且我们有一个训练好的神经网络模型。模型的输出层有3个神经元,每个神经元对应一个类别的预测得分(也称为logits)。这些得分通过softmax函数转换为概率分布,表示每个类别的预测概率。
  • 数据与标签

    • 假设我们有一个输入图像,其真实标签是“狗”(在one-hot编码中表示为[0, 1, 0])。模型对该图像的预测输出(经过softmax之前的logits)为[2.0, 1.0, 0.1],经过softmax转换后的概率分布为[0.33, 0.50, 0.17]。
  • 计算交叉熵损失

    • 真实标签(one-hot编码):y = [0, 1, 0]

    • 预测概率: y ^ \hat y y^ = [0.33, 0.50, 0.17]

    • 交叉熵损失的计算公式为:
      H ( y , y ^ ) = − ∑ i = 1 N y i l o g ( y ^ i ) H(y, \hat y)=−\sum_{i=1}^{N}y_ilog(\hat y_i) H(y,y^)=i=1Nyilog(y^i)

    • 将真实标签和预测概率代入公式中,我们得到:
      H ( y , y ^ ) = − ( 0 ⋅ l o g ( 0.33 ) + 1 ⋅ l o g ( 0.50 ) + 0 ⋅ l o g ( 0.17 ) ) = − l o g ( 0.50 ) ≈ 0.693 H(y, \hat y)=−(0⋅log(0.33)+1⋅log(0.50)+0⋅log(0.17)) =−log(0.50) ≈0.693 H(y,y^)=(0log(0.33)+1log(0.50)+0log(0.17))=log(0.50)0.693

  • 因此,该输入图像的交叉熵损失约为0.693。这个值表示模型预测的概率分布与真实标签分布之间的差异程度。损失值越小,表示模型的预测越准确。

1.1.4 代码演示

代码演示 :

import torch
from torch import nn

# 多分类交叉熵损失,使用nn.CrossEntropyLoss()实现。nn.CrossEntropyLoss()=softmax + 损失计算
def my_CrossEntropyLoss():
    # 设置真实值: 可以是热编码后的结果也可以不进行热编码
    y_true = torch.tensor([[0, 1, 0], [0, 0, 1]], dtype=torch.float32)
    # 不解码的时候, 需要传入真实类别的tensor
    # 注意的类型必须是64位整型数据
    # 意思是 真实标签是 1(即第二类)真实标签是 2(即第三类) 
    # 对应下边的 y_pred 有 0.2 的概率是 0 有0.6 的概率是1 有0.2 的概率是 2
    # y_true = torch.tensor([1, 2], dtype=torch.int64)
    y_pred = torch.tensor([[0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], dtype=torch.float32)
    # 实例化交叉熵损失
    loss = nn.CrossEntropyLoss()
    # 计算损失结果
    my_loss = loss(y_pred, y_true).numpy()
    print('loss:', my_loss)

if __name__ == '__main__':
    my_CrossEntropyLoss()

二、回归问题的损失函数

2.1 MAE损失

  • Mean absolute loss(MAE)也被称为 L1 Loss,是以绝对误差作为距离。损失函数公式:
    L = 1 N ∑ i = 1 N ∣ y i − y ^ ∣ L = \frac{1}{N}\sum_{i=1}^{N} |y_i-\hat y| L=N1i=1Nyiy^

    • N N N 是样本数量
    • y i y_i yi 是第 i i i 个样本的真实值
    • y ^ \hat y y^ 是第 i i i 个样本的预测值
  • 特点:

    • 由于L1 loss具有稀疏性,为了惩罚较大的值,因此常常将其作为正则项添加到其他loss中作为约束。
    • L1 loss的最大问题是梯度在零点不平滑,导致会跳过极小值。
  • 图像

    • 在这里插入图片描述
  • 代码演示

代码演示 :

import torch
from torch import nn

def my_L1Loss():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MAE损失对象
    loss = nn.L1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

if __name__ == '__main__':
    my_L1Loss()

2.2 MSE损失

  • Mean Squared Loss/ Quadratic Loss(MSE loss)也被称为L2 loss,或欧氏距离,它以误差的平方和的均值作为距离,损失函数公式:
    L = 1 N ∑ i = 1 N ( y i − y ^ ) 2 L = \frac{1}{N}\sum_{i=1}^{N} (y_i-\hat y)^2 L=N1i=1N(yiy^)2

    • N N N 是样本数量
    • y i y_i yi 是第 i i i 个样本的真实值
    • y ^ \hat y y^ 是第 i i i 个样本的预测值
  • 特点:

    • .L2 loss也常常作为正则项
    • 当预测值与目标值相差很大时, 梯度容易爆炸
  • 图像

    • 在这里插入图片描述
  • 代码演示

代码演示 :

import torch
from torch import nn


def my_MSELoss():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MSE损失对象
    loss = nn.MSELoss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('myloss:', my_loss)


if __name__ == '__main__':
    my_MSELoss()

2.3 Smooth L1损失

  • smooth L1说的是光滑之后的L1。损失函数公式:
    Smooth L1 ( x ) = { 0.5 × x 2 if  ∣ x ∣ < 1 ∣ x ∣ − 0.5 otherwise \text{Smooth L1}(x) = \begin{cases} 0.5 \times x ^2 & \text{if } |x| < 1 \\ |x| - 0.5 & \text{otherwise} \end{cases} Smooth L1(x)={0.5×x2x0.5if x<1otherwise

    • 其中, x x x 就是真实值与预测值的差值
  • 图像

    • 在这里插入图片描述
  • 特点:从上述图像中我们可以看出

    • .在 [-1,1] 之间实际上就是 L2 损失,这样解决了 L1 的不光滑问题
    • 在 [-1,1 ] 区间外,实际上就是 L1 损失,这样就解决了离群点梯度爆炸的问题
  • 代码演示

代码演示 :

import torch
from torch import nn

def my_SmoothL1Loss():
    # 1 设置真实值和预测值
    y_true = torch.tensor([1, 1])
    y_pred = torch.tensor([0.6, 0.4], requires_grad=True)
    # 2 实例化smoothL1损失对象
    loss = nn.SmoothL1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

if __name__ == '__main__':
    my_SmoothL1Loss()

总结

  • 我们总结了神经网络中常用的损失函数,在不同的情况下,我们需要搭配不同的损失函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值