问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

神经网络中的损失函数详解:从SVM到交叉熵

创作时间:
作者:
@小白创作中心

神经网络中的损失函数详解:从SVM到交叉熵

引用
CSDN
1.
https://m.blog.csdn.net/weixin_51385258/article/details/143981094

损失函数是神经网络训练中的核心概念,用于衡量模型预测结果与真实结果之间的差异。本文将详细介绍分类任务和回归任务中常用的损失函数,包括SVM损失、交叉熵损失、MAE损失、MSE损失和Smooth L1损失等,并通过代码示例展示如何在PyTorch中实现这些损失函数。

损失函数

在深度学习中,损失函数是用来衡量模型参数的质量的函数,衡量的方式是比较网络输出和真实输出的差异:

损失函数在不同的文献中名称是不一样的,主要有以下几种命名方式:

1 分类任务损失函数

1.1 损失函数回顾

损失函数是用来告诉我们当前分类器性能好坏的评价函数,是用于指导分类器权重调整的指导性函数,通过该函数可以知道该如何改进权重系数。之前机器学习中的一些损失函数,例如解决二分类问题的逻辑回归中用到的对数似然损失、SVM中的合页损失等等。

  • 对数似然损失
  • Hinge损失

多分类问题的损失该如何去衡量?下面会进行通常会使用的两种方式作对比,这里介绍在图像识别中最常用的两个损失——多类别SVM损失(合页损失hinge loss)和交叉熵损失,分别对应多类别SVM分类器和Softmax分类器

1.1 多分类 - SVM损失

函数通过f ( x i , W ) f(x_i,W)f(xi ,W)计算分数,我们在这里写成s ss,对于某一个样本i,某个j目标类别分数记作s j = f ( x i , W ) j s_j = f(x_i,W)_jsj =f(xi ,W)j

下图使我们得到的线性模型预测分数结果

  • 求每个类别的SVM损失

对于第一张图片来讲,损失计算为

那么同理第二张图片的损失为

最后一个损失结果

  • 平均Hinge损失

最终得到5.27的分数大小,Loss反映了真实分类所得分数与其他分类分数的差别,也就是说,如果真实分类所得分数比分类为其他类的分数要低,但是分数低多少,要想真实分类的分数最高,差距在哪,即是通过损失函数的l值反映出来了。同时,如果分类正确的分数比其他的分类分数高于1,即使正确分类的分数发生微小变化(相差仍然大于1),那么Hinge Loss仍然有效,损失函数值不会发生变化。

多分类支持向量机损失希望正确分类的分数至少高于其他分类的分数,如果错误分类的分数-正确分类的分数很小即超过上述的红色区域,则不会加入损失;如果在红色区域内部,那么会累积损失。

当然这里为了方便理解,并没有去考虑正则化项的影响,有时候使用L2-SVM损失效果会更好些。

1.2 多分类 - 交叉熵损失(softmax损失)

在多分类任务通常使用softmax将logits转换为概率的形式,所以多分类的交叉熵损失也叫做softmax损失,它的计算方法是:

其中:

  • y是样本x属于某一个类别的真实概率,如果采用one-hot编码,那么y i y_iyi 就表示该样本的标签(one-hot编码之后)
  • 而f(x)是样本属于某一类别的预测分数
  • S是softmax激活函数,将属于某一类别的预测分数转换成概率
  • L用来衡量真实值y和预测值f(x)之间差异性的损失结果
  • 求和:对于所有样本的交叉熵进行求和

例子1:

它的损失如何计算?


0log(0.10)+0log(0.05)+0log(0.15)+0log(0.10)+0log(0.05)+0log(0.20)+1log(0.10)+0log(0.05)+0log(0.10)+0log(0.10)

例子2:

  • 神经元输出对于不同分类的预测结果,经过softmax之后,将预测结果转换为预测不同类别的概率值。经过softmax之后,对于不同类别的预测结果的加和为1,也就是对于正确类别的预测概率越高,预测为错误类别的概率越小。所以softmax之后,正样本的预测概率越大,损失越小。

从概率角度理解,我们的目的是最小化正确类别所对应的预测概率的对数的负值(损失值最小),如下图所示:


import pandas
import torch
import torch.nn as nn
import numpy as np
import pandas as pd
def test_05():
    # nn.CrossEntropyLoss()
    # 需要传入真实值,这里的真实值可以是热编码之后的标签,或者是类别值
    # nn.CrossEntropyLoss内部会对真实值进行热编码
    # 需要输入预测值:预测值送入的是logits
    # nn.CrossEntropyLoss内部集成了softmax,传入数据的时候不需要使用softmax对神经网络输出值进行处理
    # 真实值进行热编码的时候,热编码是从类别0开始进行编码的
    # 假设现在有两个类别,分别用1,2进行表示
    # 实际上在进行热编码的时候是从第0个类别开始的,所以内部的热编码有三位
    # 1 : 1 0 0
    # 2 : 0 1 0
    # 3 : 0 0 1
    y_true = torch.tensor([1,2],dtype=torch.int64)
    # 如果传入对标签进行热编码之后的结果
    # 上面解释了为什么两个类别,热编码需要有三个表示
    # y_true = torch.tensor([[0, 1, 0], [0, 0, 1]],dtype=torch.float32)
    # 如果标签值为4,8
    # 内部编码的时候需要将其转换为9个类别的one-hot编码
    # 4: 0 0 0 0 4 0 0 0 0
    # 8:0 0 0 0 0 0 0 0 9
    # y_true = torch.tensor([[0,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,1]])
    # y_true = torch.tensor([4,8]) # 两个样本,每个样本有8个分类,实际上crossentropy内部是9分类编码
    # 预测值
    y_pred = torch.tensor([[0.2,0.6,0.3],[0.1,0.8,0.1]],dtype=torch.float32)
    # 简单理解:有两个样本,每个样本有三个分类的预测值
    # 真实值,表示两个样本真实预测的类别
    criterion = nn.CrossEntropyLoss()
    loss = criterion(y_pred,y_true)
    print("交叉熵损失-->",loss)

1.3 二分类任务损失函数

在处理二分类任务时,我们不再使用softmax激活函数,而是使用sigmoid激活函数,那损失函数也相应的进行调整,使用二分类的交叉熵损失函数:

其中:

  • y是样本x属于某一个类别的真实概率
  • 而y^是样本属于某一类别的预测概率
  • L用来衡量真实值y与预测值y^之间差异性的损失结果。
  • 在pytorch中实现时使用nn.BCELoss() ,如下所示:

def test2():
    # 1 设置真实值和预测值
    # 预测值是sigmoid输出的结果
    # y_pred - 一维列表,表示对多个样本预测为正样本的概率
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    # y_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()
    print('loss:', my_loss)
  • 多分类任务的损失函数:y_pred通常是一个二维数组(batch_size,class_total),y_true是一个一维数组:(batch_size,)
  • 二分类任务的损失函数:y_pred通常是一个一维列表,y_true也是一个一维列表

2 回归任务损失函数

回归任务的激活函数,是恒等激活,相当于没有激活函数

2.1 MAE损失函数

Mean absolute loss(MAE)也被称为L1 Loss,是以绝对误差作为距离。损失函数公式:


# 计算算inputs与target之差的绝对值
def test3():
    # 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)

特点是:

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

2.2 MSE损失函数

Mean Squared Loss/ Quadratic Loss(MSE loss)也被称为L2 loss,或欧氏距离,它以误差的平方和的均值作为距离


def test4():
    # 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)

特点是:

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

2.3 Smooth L1损失函数

smooth L1说的是光滑之后的L1。损失函数公式:

其中:𝑥=f(x)−y 为真实值和预测值的差值。


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

从右图中可以看出,该函数实际上就是一个分段函数

  1. 在[-1,1]之间实际上就是L2损失,这样解决了L1的不光滑问题
  2. 在[-1,1]区间外,实际上就是L1损失,这样就解决了离群点梯度爆炸的问题
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号