当前位置:   article > 正文

深度学习 -- 损失函数学习

深度学习 -- 损失函数学习

活动地址:CSDN21天学习挑战赛

1、什么是损失函数

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

2、为什么使用损失函数

损失函数使用主要是在模型的训练阶段,每个批次的训练数据送入模型后,通过前向传播输出预测值,然后损失函数会计算出预测值和真实值之间的差异值,也就是损失值。得到损失值之后,模型通过反向传播去更新各个参数,来降低真实值与预测值之间的损失,使得模型生成的预测值往真实值方向靠拢,从而达到学习的目的。

3、损失函数

3.1 基于距离度量的损失函数

基于距离度量的损失函数通常将输入数据映射到基于距离度量的特征空间上,如欧氏空间、汉明空间等,将映射后的样本看作空间上的点,采用合适的损失函数度量特征空间上样本真实值和模型预测值之间的距离。特征空间上两个点的距离越小,模型的预测性能越好

3.1.1 L1_Loss

有几个别称:

  • L1 范数损失
  • 最小绝对值偏差(LAD)
  • 最小绝对值误差(LAE)

最常看到的MAE也是指L1 Loss损失函数。 它是把目标值y与模型输出f(x)(估计值) 做绝对值得到的误差。
在这里插入图片描述
代码实现:

import numpy as np
# 自定义实现
def L1Loss(x:list,y:list):
    """
    x:list,代表模型预测的一组数据
    y:list,代表真实样本对应的一组数据
    """
    assert len(x)==len(y)
    x=np.array(x)
    y=np.array(y)
    loss=np.sum(np.abs(x - y)) / len(x)
    return loss

# tensorflow版本
y_true = np.random.randint(0, 2, size=(2, 3))
y_pred = np.random.random(size=(2, 3))
loss = tf.keras.losses.mean_squared_error(y_true, y_pred)

# Pytorch版本
loss = nn.L1Loss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

什么时候使用?

  1. 回归任务
  2. 简单的模型
  3. 由于神经网络通常是解决复杂问题,所以很少使用。
3.1.2 L2_Loss

有几个别称:

  • L2 范数损失
  • 最小均方值偏差(LSD)
  • 最小均方值误差(LSE)
    最常看到的均方误差损失函数(MSE)也是指L2 Loss损失函数

它是把目标值y 与模型输出f(x)(估计值) 做差然后平方得到的误差
在这里插入图片描述
什么时候使用?

  1. 回归任务
  2. 数值特征不大
  3. 问题维度不高

值越小,表示预测模型描述的样本数据具有越好的精确度。

代码实现:

import numpy as np
# 自定义实现
def MSELoss(x:list,y:list):
    """
    x:list,代表模型预测的一组数据
    y:list,代表真实样本对应的一组数据
    """
    assert len(x)==len(y)
    x=np.array(x)
    y=np.array(y)
    loss=np.sum(np.square(x - y)) / len(x)
    return loss

#计算过程举例
x=[1,2]
y=[0,1]
loss=((1-0**2 +2-1**2)÷2=1+1)÷2=1

# sklearn版本
from sklearn import metrics
 
# MAPE需要自己实现
def mape(y_true, y_pred):
    return np.mean(np.abs((y_pred - y_true) / y_true))
 
y_true = np.array([1.0, 5.0, 4.0, 3.0, 2.0, 5.0, -3.0])
y_pred = np.array([1.0, 4.5, 3.8, 3.2, 3.0, 4.8, -2.2])
  
MSE = metrics.mean_squared_error(y_true, y_pred)

# Tensorflow2.0版
y_true=tf.convert_to_tensor(y)
y_pred=tf.convert_to_tensor(x)
mse_loss = tf.keras.losses.MSE(y_true, y_pred) # y_true, y_pred都是张量格式

# pytorch版本
y_true=torch.tensor(y)
y_pred=torch.tensor(x)
mse_fc = torch.nn.MSELoss(y_true, y_pred)
mse_loss = mse_fc(x,y)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
L2损失函数L1损失函数
不是非常的鲁棒(robust)鲁棒
稳定解不稳定解
总是一个解可能多个解
3.1.3 Smooth L1损失函数在这里插入图片描述

Smooth L1损失是由Girshick R在Fast R-CNN中提出的,主要用在目标检测中防止梯度爆炸。

代码实现:

def Smooth_L1(x,y):
    assert len(x)==len(y)
    loss=0
    for i_x,i_y in zip(x,y):
        tmp = abs(i_y-i_x)
        if tmp<1:
            loss+=0.5*(tmp**2)
        else:
            loss+=tmp-0.5
    return loss

# tensorflow版本
from keras import backend as K
import numpy as np

def smooth_L1_loss(y_true, y_pred):
    THRESHOLD = K.variable(1.0)
    mae = K.abs(y_true-y_pred)
    flag = K.greater(mae, THRESHOLD)
    loss = K.mean(K.switch(flag, (mae - 0.5), K.pow(mae, 2)), axis=-1)
    return loss
# 或者 (keras中的huber_loss跟这个一样,不确定是否正确,知道的大佬请帮忙解答一下)
tf.keras.losses.Huber(
    delta=1.0,
    reduction=losses_utils.ReductionV2.AUTO,
    name='huber_loss'
)
#参数看API:https://www.tensorflow.org/api_docs/python/tf/keras/losses/Huber

# Pytorch版本
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean', beta=1.0)
# 参数看API: https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
3.1.4 L1,L2以及Smooth L1对比

首先给出各个损失函数的数学定义,假设 x x x 为预测值与真实值之间的差值:

L1 loss表示预测值和真实值之差的绝对值
L2 loss表示与测值和真实值之差的平方
SmoothL1L1类似,但在预测值与真实值差异非常小时,调整为 0.5 x 2 0.5x^2 0.5x2

但是,L1和L2有各自的缺点不足,而SmoothL1综合了二者的优点:

  • L2对离群点非常敏感,会出现与真实值差异较大的预测值主导loss的情况,最终造成梯度爆炸;
  • L1对离群点相对鲁棒,但其导数为常数,且在0处不可导;这会导致训练后期预测值与真实值差异很小时,L1难以继续收敛;
  • SmoothL1结合了L2和L1的优点,对噪声鲁棒,在0处可导可以收敛到更高的精度;

从3个损失函数各自的导数也能看出其特征:

  • 对于L2损失函数,其导数与 x x x成正比;这就导致训练初期,预测值与真实值差异过大时,损失函数的梯度非常大,梯度爆炸导致训练不稳定;
  • 对于L1损失函数,其导数为常数;这就导致训练后期,预测值与真是差异很小时,损失函数的导数绝对值仍然为1,而如果learning rate不变,损失函数将在稳定值附近波动,难以继续收敛达到更高精度;
  • 对于SmoothL1损失函数,在 x x x较小时对梯度会变小,而在 x x x很大时其梯度的绝对值达到上限1,梯度不会爆炸。可以说,SmoothL1避开了L1和L2损失的缺陷,因此SmoothL1用的也比较广泛。

最后,3种损失函数的图像如下:
在这里插入图片描述

3.2 基于概率分布度量的损失函数

基于概率分布度量的损失函数是将样本间的相似性转化为随机事件出现的可能性,即通过度量样本的真实分布与它估计的分布之间的距离,判断两者的相似度,一般用于涉及概率分布或预测类别出现的概率的应用问题中,在分类问题中尤为常用。

3.2.1 基础知识

信息量
信息量来衡量一个事件的不确定性,一个事件发生的概率越大,不确定性越小,则其携带的信息量就越小。
在这里插入图片描述

熵用来衡量一个系统的混乱程度,代表系统中信息量的总和;熵值越大,表明这个系统的不确定性就越大。

信息量是衡量某个事件的不确定性,而熵是衡量一个系统(所有事件)的不确定性。
计算公式:
在这里插入图片描述
p ( x i ) p(x_i) p(xi)是事件 X = x i X=x_i X=xi的概率, − l o g ( p ( x i ) ) -log(p(x_i)) log(p(xi))为事件 X = x i X=x_i X=xi的信息量

可以看出,熵是信息量的期望值,是一个随机变量(一个系统,事件所有可能性)不确定性的度量。熵值越大,随机变量的取值就越难确定,系统也就越不稳定;熵值越小,随机变量的取值也就越容易确定,系统越稳定。

相对熵 Relative entropy
相对熵也称为KL散度(Kullback-Leibler divergence),表示同一个随机变量的两个不同分布间的距离。

p ( x ) p(x) p(x), q ( x ) q(x) q(x)分别是 离散随机变量X的两个概率分布,则p对q的相对熵是:
在这里插入图片描述
相对熵具有以下性质:

  • 如果 p ( x ) p(x) p(x) q ( x ) q(x) q(x)的分布相同,则其相对熵等于0
  • D K L ( p ∥ q ) ≠ D K L ( q ∥ p ) D_{KL}(p∥q)≠D_{KL}(q∥p) DKL(pq)=DKL(qp),也就是相对熵不具有对称性
  • D K L ( p ∥ q ) ≥ 0 D_{KL}(p∥q)≥0 DKL(pq)0

总的来说,相对熵是用来衡量同一个随机变量的两个不同分布之间的距离。在实际应用中,假如 p ( x ) p(x) p(x)是目标真实的分布,而 q ( x ) q(x) q(x)是预测得来的分布,为了让这两个分布尽可能的相同的,就需要最小化KL散度。

交叉熵 Cross Entropy
p ( x ) p(x) p(x), q ( x ) q(x) q(x)分别是 离散随机变量X的两个概率分布,其中 p ( x ) p(x) p(x)是目标分布, p p p q q q的交叉熵可以看做是,使用分布 q ( x ) q(x) q(x) 表示目标分布 p ( x ) p(x) p(x)的困难程度:
在这里插入图片描述
将熵、相对熵以及交叉熵的公式放到一起,
在这里插入图片描述
通过上面三个公式就可以得到
D K L ( p , q ) = H ( p , q ) − H ( p ) D_{KL}(p,q)=H(p,q)−H(p) DKL(p,q)=H(p,q)H(p)
在机器学习中,目标的分布 p ( x ) p(x) p(x) 通常是训练数据的分布是固定,即是 H ( p ) H(p) H(p) 是一个常量。这样两个分布的交叉熵 H ( p , q ) H(p,q) H(p,q) 也就等价于最小化这两个分布的相对熵 D K L ( p ∥ q ) D_{KL}(p∥q) DKL(pq)。设 p ( x ) p(x) p(x) 是目标分布(训练数据的分布),我们的目标的就让训练得到的分布 q ( x ) q(x) q(x)尽可能的接近 p ( x ) p(x) p(x),这时候就可以最小化 D K L ( p ∥ q ) D_{KL}(p∥q) DKL(pq),等价于最小化交叉熵 H ( p , q ) H(p,q) H(p,q)

3.2.2 KL散度函数(相对熵)

在这里插入图片描述
公式中Y代表真实值,f(x)代表预测值。

KL散度( Kullback-Leibler divergence)也被称为相对熵,是一种非对称度量方法,常用于度量两个概率分布之间的距离。KL散度也可以衡量两个随机分布之间的距离,两个随机分布的相似度越高的,它们的KL散度越小,当两个随机分布的差别增大时,它们的KL散度也会增大,因此KL散度可以用于比较文本标签或图像的相似性。基于KL散度的演化损失函数有JS散度函数。JS散度也称JS距离,用于衡量两个概率分布之间的相似度,它是基于KL散度的一种变形,消除了KL散度非对称的问题,与KL散度相比,它使得相似度判别更加准确。

相对熵是恒大于等于0的。当且仅当两分布相同时,相对熵等于0。

代码实现:

def kl_loss(y_true:list,y_pred:list):
    """
    y_true,y_pred,分别是两个概率分布
    比如:px=[0.1,0.2,0.8]
          py=[0.3,0.3,0.4]
    """
    assert len(y_true)==len(y_pred)
    KL=0
    for y,fx in zip(y_true,y_pred):
        KL+=y*np.log(y/fx)
    return KL

# tensorflow版本
y_true = [[0, 1], [0, 0]]
y_pred = [[0.6, 0.4], [0.4, 0.6]]
## Using 'auto'/'sum_over_batch_size' reduction type.
kl = tf.keras.losses.KLDivergence()
kl(y_true, y_pred).numpy()

# Pytorch版本
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False)
# API: https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
3.2.3 交叉熵损失

多分类任务中输出的是目标属于每个类别的概率,所有类别概率的和为1,其中概率最大的类别就是目标所属的分类。 softmax 函数能将一个向量的每个分量映射到 [ 0 , 1 ] [0,1] [0,1]区间,并且对整个向量的输出做了归一化,保证所有分量输出的和为1,正好满足多分类任务的输出要求。所以,在多分类中,在最后就需要将提取的到特征经过 softmax 函数的,输出为每个类别的概率,然后再使用交叉熵 作为损失函数。

softmax 函数定义如下:
在这里插入图片描述
其中,输入的向量为 z i ( i = 1 , 2 , … , n ) z_i(i=1,2,…,n) zi(i=1,2,,n)
更直观的参见下图
在这里插入图片描述
通过前面的特征提取到的特征向量为 ( z 1 , z 2 , … , z k ) (z_1,z_2,…,z_k) (z1,z2,,zk) ,将向量输入到 softmax 函数中,即可得到目标属于每个类别的概率,概率最大的就是预测得到的目标的类别。

交叉熵损失函数刻画了实际输出概率与期望输出概率之间的相似度,也就是交叉熵的值越小,两个概率分布就越接近,特别是在正负样本不均衡的分类问题中,常用交叉熵作为损失函数。目前,交叉熵损失函数是卷积神经网络中最常使用的分类损失函数,它可以有效避免梯度消散。在二分类情况下也叫做对数损失函数。

代码实现:

def CrossEntropy_loss(y_true:list,y_pred:list):
    """
    y_true,y_pred,分别是两个概率分布
    比如:px=[0.1,0.2,0.8]
          py=[0.3,0.3,0.4]
    """
    assert len(y_true)==len(y_pred)
    loss=0
    for y,fx in zip(y_true,y_pred):
        loss+=-y * np.log(fx)
    return loss

# tensorflow版本
tf.keras.losses.CategoricalCrossentropy(
    from_logits=False,
    label_smoothing=0.0,
    axis=-1,
    reduction=losses_utils.ReductionV2.AUTO,
    name='categorical_crossentropy'
)
# API: https://www.tensorflow.org/api_docs/python/tf/keras/losses/CategoricalCrossentropy

# Pytorch版本
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean', label_smoothing=0.0)

torch.nn.LogSoftmax
torch.nn.NLLLoss
# API: 
# https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html
# https://pytorch.org/docs/stable/generated/torch.nn.LogSoftmax.html
# https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

交叉熵学习引用地址

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/430557
推荐阅读
相关标签
  

闽ICP备14008679号