xingchenshanyao / NNLearning

这里只是学习深度学习过程中的一些记录
4 stars 0 forks source link

损失函数-focal loss #22

Open xingchenshanyao opened 1 year ago

xingchenshanyao commented 1 year ago

参考来源:

https://blog.csdn.net/EmilyHoward/article/details/118367495
https://blog.csdn.net/weixin_57643648/article/details/122704657
https://blog.csdn.net/Xiaobai_rabbit0/article/details/111032136
xingchenshanyao commented 1 year ago

博客一

1. 什么是损失函数 损失函数用来评价模型的预测值和真实值不一样的程度,损失函数越小,通常模型的性能越好。不同的模型用的损失函数一般也不一样。

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

3. 损失函数的分类

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

3.1.1 均方误差损失函数(MSE) image 在回归问题中,均方误差损失函数用于度量样本点到回归曲线的距离,通过最小化平方损失使样本点可以更好地拟合回归曲线。均方误差损失函数(MSE)的值越小,表示预测模型描述的样本数据具有越好的精确度。由于无参数、计算成本低和具有明确物理意义等优点,MSE已成为一种优秀的距离度量方法。尽管MSE在图像和语音处理方面表现较弱,但它仍是评价信号质量的标准,在回归问题中,MSE常被作为模型的经验损失或算法的性能指标。

3.1.2 L2损失函数 image L2损失又被称为欧氏距离,是一种常用的距离度量方法,通常用于度量数据点之间的相似度。由于L2损失具有凸性和可微性,且在独立、同分布的高斯噪声情况下,它能提供最大似然估计,使得它成为回归问题、模式识别、图像处理中最常使用的损失函数。

3.1.3 L1损失函数 image L1损失又称为曼哈顿距离,表示残差的绝对值之和。L1损失函数对离群点有很好的鲁棒性,但它在残差为零处却不可导。另一个缺点是更新的梯度始终相同,也就是说,即使很小的损失值,梯度也很大,这样不利于模型的收敛。针对它的收敛问题,一般的解决办法是在优化算法中使用变化的学习率,在损失接近最小值时降低学习率。

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

3.1.5 huber损失函数 image huber损失是平方损失和绝对损失的综合,它克服了平方损失和绝对损失的缺点,不仅使损失函数具有连续的导数,而且利用MSE梯度随误差减小的特性,可取得更精确的最小值。尽管huber损失对异常点具有更好的鲁棒性,但是,它不仅引入了额外的参数,而且选择合适的参数比较困难,这也增加了训练和调试的工作量。

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

3.2.1 KL散度函数(相对熵) image 公式中Y代表真实值,f(x)代表预测值。

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

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

3.2.2 交叉熵损失 image 交叉熵是信息论中的一个概念,最初用于估算平均编码长度,引入机器学习后,用于评估当前训练得到的概率分布与真实分布的差异情况。为了使神经网络的每一层输出从线性组合转为非线性逼近,以提高模型的预测精度,在以交叉熵为损失函数的神经网络模型中一般选用tanh、sigmoid、softmax或ReLU作为激活函数。

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

当正负样本不均衡的时候,通常会在交叉熵损失函数类别前面加个参数α image

3.2.3 softmax损失函数 image 从标准形式上看,softmax损失函数应归到对数损失的范畴,在监督学习中,由于它被广泛使用,所以单独形成一个类别。softmax损失函数本质上是逻辑回归模型在多分类任务上的一种延伸,常作为CNN模型的损失函数。softmax损失函数的本质是将一个k维的任意实数向量x映射成另一个k维的实数向量,其中,输出向量中的每个元素的取值范围都是(0,1),即softmax损失函数输出每个类别的预测概率。由于softmax损失函数具有类间可分性,被广泛用于分类、分割、人脸识别、图像自动标注和人脸验证等问题中,其特点是类间距离的优化效果非常好,但类内距离的优化效果比较差。

softmax损失函数具有类间可分性,在多分类和图像标注问题中,常用它解决特征分离问题。在基于卷积神经网络的分类问题中,一般使用softmax损失函数作为损失函数,但是softmax损失函数学习到的特征不具有足够的区分性,因此它常与对比损失或中心损失组合使用,以增强区分能力。

3.2.4 Focal loss focal loss的引入主要是为了解决难易样本不均衡的问题,注意有区别于正负样本不均衡的问题。难易样本分为四个类型: image 易分样本虽然损失很低,但是数量太多,对模型的效果提升贡献很小,模型应该重点关注那些难分样本,因此需要把置信度高的损失再降低一些 image

4. 如何选择损失函数? 通常情况下,损失函数的选取应从以下方面考虑: (1) 选择最能表达数据的主要特征来构建基于距离或基于概率分布度量的特征空间。 (2)选择合理的特征归一化方法,使特征向量转换后仍能保持原来数据的核心内容。 (3)选取合理的损失函数,在实验的基础上,依据损失不断调整模型的参数,使其尽可能实现类别区分。 (4)合理组合不同的损失函数,发挥每个损失函数的优点,使它们能更好地度量样本间的相似性。 (5)将数据的主要特征嵌入损失函数,提升基于特定任务的模型预测精确度。

xingchenshanyao commented 1 year ago

博客二

一、什么是损失函数 简单的理解就是每一个样本经过模型后会得到一个预测值,然后得到的预测值和真实值的差值就成为损失(当然损失值越小证明模型越是成功),我们知道有许多不同种类的损失函数,这些函数本质上就是计算预测值和真实值的差距的一类型函数,然后经过库(如pytorch,tensorflow等)的封装形成了有具体名字的函数。

二、为什么需要损失函数 我们上文说到损失函数是计算预测值和真实值的一类函数,而在机器学习中,我们想让预测值无限接近于真实值,所以需要将差值降到最低(在这个过程中就需要引入损失函数)。而在此过程中损失函数的选择是十分关键的,在具体的项目中,有些损失函数计算的差值梯度下降的快,而有些下降的慢,所以选择合适的损失函数也是十分关键的。

三、损失函数通常使用的位置 在机器学习中,我们知道输入的feature(或称为x)需要通过模型(model)预测出y,此过程称为向前传播(forward pass),而要将预测与真实值的差值减小需要更新模型中的参数,这个过程称为向后传播(backward pass),其中我们损失函数(lossfunction)就基于这两种传播之间,起到一种有点像承上启下的作用,承上指:接収模型的预测值,启下指:计算预测值和真实值的差值,为下面反向传播提供输入数据。

四、常用的损失函数(基于pytorch) 1.L1Loss函数 1 例子: 我们首先先引用一下函数先计算一个结果:

import torch as th
import torch.nn as nn

loss=nn.L1Loss()

input=th.Tensor([2,3,4,5])
target=th.Tensor([4,5,6,7])
output=loss(input,target)

output

tensor(2.)

我们可以用手动计算来验证数学本质正不正确(数学本质中的m在文中具体数值为4): output=(|2-4|+|3-5|+|4-6|+|5-7|)/4=2 ps:因为我们函数的“reduction”(l1loss函数的参数)选择的是默认的"mean"(平均值),所以还会在除以一个"4",如果我们设置“loss=L1Loss(reduction='sum')则不用再除以4。

2. MSELoss函数 image 例子: 我们首先先引用一下函数先计算一个结果:

import torch as th
import torch.nn as nn

loss=nn.MSELoss()

input=th.Tensor([2,3,4,5])
target=th.Tensor([4,5,6,7])
output=loss(input,target)

output

tensor(4.)

我们可以用手动计算来验证数学本质正不正确: output=[(2-4)^2+(3-5)^2+(4-6)^2+(5-7)^2 ]/4=4

3.CrossEntropyLoss函数(交叉熵函数) (1):CrossEntropyLoss函数主要用于分类项目中运用 (2):one-hot(独热)编码: 2 ps:最左边的一列1,2,3代表样本属于猫,狗,兔中的某一种,最上面一行是分类(图中猫,狗,兔三类属于三分类问题,当然在编码过程中种类是用数字来代替的),如图,1这一行在猫下有1(表示属于猫),在狗和兔下为0(表示1样本不属于狗和兔)以此类推,分类数据这样编写让样本与样本的欧式距离一致(根据离散特征的某个取值对应欧式空间的某一点) (3):函数的理解: image 关于图中公式的理解,此变换是softmax函数变换具体表达方式如下:

假设输入的y_hat=[1,2,3,4]

则经过图中函数变换输出的值=[e^1/(e^1+e^2+e^3+e^4),e^2/(e^1+e^2+e^3+e^4),e^3/(e^1+e^2+e^3+e^4),e^4/(e^1+e^2+e^3+e^4)]

xingchenshanyao commented 1 year ago

博客三

1、常见的MSE、MAE损失函数

1.1、均方误差MSE 均方误差(Mean Square Error,MSE)是回归损失函数中最常用的误差,它是预测值f(x)与目标值y之间差值平方和的均值,其公式如下所示: image 下图是均方误差值的曲线分布,其中最小值为预测值为目标值的位置。我们可以看到随着误差的增加损失函数增加的更为迅猛。 image

如果样本中存在离群点,MSE会给离群点更高的权重,这就会牺牲其他正常点数据的预测效果,最终降低整体的模型性能。 如下图: image 可见,使用 MSE 损失函数,受离群点的影响较大,虽然样本中只有 5 个离群点,但是拟合的直线还是比较偏向于离群点。

1.2、平均绝对误差MAE 平均绝对误差(MAE)是另一种常用的回归损失函数,它是目标值与预测值之差绝对值和的均值,表示了预测值的平均误差幅度,而不需要考虑误差的方向(注:平均偏差误差MBE则是考虑的方向的误差,是残差的和),范围是0到∞,其公式如下所示: image

优点:相比于MSE,MAE有个优点就是,对于离群点不那么敏感。因为MAE计算的是误差(y-f(x))的绝对值,对于任意大小的差值,其惩罚都是固定的。无论对于什么样的输入值,都有着稳定的梯度,不会导致梯度爆炸问题,具有较为稳健性的解。 缺点:MAE曲线连续,但是在(y-f(x)=0)处不可导。而且 MAE 大部分情况下梯度都是相等的,这意味着即使对于小的损失值,其梯度也是大的。这不利于函数的收敛和模型的学习。

针对上面带有离群点的数据,MAE的效果要好于MSE。 image 显然,使用 MAE 损失函数,受离群点的影响较小,拟合直线能够较好地表征正常数据的分布情况。

1.3、MSE与MAE的选择

从梯度的求解以及收敛上,MSE是优于MAE的。MSE处处可导,而且梯度值也是动态变化的,能够快速的收敛;而MAE在0点处不可导,且其梯度保持不变。对于很小的损失值其梯度也很大,在深度学习中,就需要使用变化的学习率,在损失值很小时降低学习率。 对离群(异常)值得处理上,MAE要明显好于MSE。

如果离群点(异常值)需要被检测出来,则可以选择MSE作为损失函数;如果离群点只是当做受损的数据处理,则可以选择MAE作为损失函数。

总之,MAE作为损失函数更稳定,并且对离群值不敏感,但是其导数不连续,求解效率低。另外,在深度学习中,收敛较慢。MSE导数求解速度高,但是其对离群值敏感,不过可以将离群值的导数设为0(导数值大于某个阈值)来避免这种情况。

在某些情况下,上述两种损失函数都不能满足需求。例如,若数据中90%的样本对应的目标值为150,剩下10%在0到30之间。那么使用MAE作为损失函数的模型可能会忽视10%的异常点,而对所有样本的预测值都为150。这是因为模型会按中位数来预测。而使用MSE的模型则会给出很多介于0到30的预测值,因为模型会向异常点偏移。

这种情况下,MSE和MAE都是不可取的,简单的办法是对目标变量进行变换,或者使用别的损失函数,例如:Huber,Log-Cosh以及分位数损失等。

2、L1_Loss和L2_Loss

2.1、L1_Loss和L2_Loss

L1范数损失函数,也被称为最小绝对值偏差(LAD),最小绝对值误差(LAE)。总的说来,它是把目标值y与估计值f(xi)的绝对差值的总和S最小化: image L2范数损失函数,也被称为最小平方误差(LSE)。总的来说,它是把目标值y与估计值f(xi)的差值的平方和S最小化: image

L1范数与L2范数作为损失函数的区别总结如下: image

总结:实际上我们发现,其实所谓的L1_Loss与L2_Loss与前面说的MAE、MSE损失函数只是差一个1/n的区别,所以他们的优点和缺点是互通的。

2.2、几个关键的概念 1.鲁棒性 因为与最小平方相比,最小绝对值偏差方法的鲁棒性更好,因此,它在许多场合都有应用。最小绝对值偏差之所以是鲁棒的,是因为它能处理数据中的异常值。这或许在那些异常值可能被安全地和有效地忽略的研究中很有用。如果需要考虑任一或全部的异常值,那么最小平方误差是更好的选择。 从直观上说,因为L2范数将误差平方化(如果误差大于1,则误差会放大很多),模型的误差会比L1范数来得大,因此模型会对这个样本更加敏感,这就需要调整模型来最小化误差。如果这个样本是一个异常值,模型就需要调整以适应单个的异常值,这会牺牲许多其它正常的样本,因为这些正常样本的误差比这单个的异常值的误差小。 2.稳定性 最小绝对值偏差方法的不稳定性意味着,对于数据集的一个小的水平方向的波动,回归线也许会跳跃很大。在一些数据结构(data configurations)上,该方法有许多连续解;但是,对数据集的一个微小移动,就会跳过某个数据结构在一定区域内的许多连续解。(The method has continuous solutions for some data configurations; however, by moving a datum a small amount, one could “jump past” a configuration which has multiple solutions that span a region. )在跳过这个区域内的解后,最小绝对值偏差线可能会比之前的线有更大的倾斜。相反地,最小平方法的解是稳定的,因为对于一个数据点的任何微小波动,回归线总是只会发生轻微移动;也就说,回归参数是数据集的连续函数。

3、Smooth L1损失函数(也被称为 Huber 损失函数) 在Faster R-CNN以及SSD中对边框的回归使用的损失函数都是Smooth (L_1) 作为损失函数。其实顾名思义,smooth L1说的是光滑之后的L1,前面说过了L1损失的缺点就是有折点,不光滑,那如何让其变得光滑呢? smooth L1损失函数为: image 其中, image Smooth L1能从两个方面限制梯度:

  1. 当预测框与 ground truth 差别过大时,梯度值不至于过大;
  2. 当预测框与 ground truth 差别很小时,梯度值足够小。 image 从上面可以看出,该函数实际上就是一个分段函数,在[-1,1]之间实际上就是L2损失,这样解决了L1的不光滑问题,在[-1,1]区间外,实际上就是L1损失,这样就解决了离群点梯度爆炸的问题。

pytorch实现1

torch.nn.SmoothL1Loss(reduction='mean')

pytorch实现2

def _smooth_l1_loss(input, target, reduction='none'):
    # type: (Tensor, Tensor) -> Tensor
    t = torch.abs(input - target)
    ret = torch.where(t < 1, 0.5 * t ** 2, t - 0.5)
    if reduction != 'none':
        ret = torch.mean(ret) if reduction == 'mean' else torch.sum(ret)
    return ret

也可以添加个参数beta 这样就可以控制,什么范围的误差使用MSE,什么范围内的误差使用MAE了。

pytorch实现3

def smooth_l1_loss(input, target, beta=1. / 9, reduction = 'none'):
    """
    very similar to the smooth_l1_loss from pytorch, but with
    the extra beta parameter
    """
    n = torch.abs(input - target)
    cond = n < beta
    ret = torch.where(cond, 0.5 * n ** 2 / beta, n - 0.5 * beta)
    if reduction != 'none':
        ret = torch.mean(ret) if reduction == 'mean' else torch.sum(ret)
    return ret

4、总结 对于大多数CNN网络,我们一般是使用L2-loss而不是L1-loss,因为L2-loss的收敛速度要比L1-loss要快得多。 对于边框预测回归问题,通常也可以选择平方损失函数(L2损失),但L2范数的缺点是当存在离群点(outliers)的时候,这些点会占loss的主要组成部分。比如说真实值为1,预测10次,有一次预测值为1000,其余次的预测值为1左右,显然loss值主要由1000决定。所以FastRCNN采用稍微缓和一点绝对损失函数(smooth L1损失),它是随着误差线性增长,而不是平方增长。 Smooth L1 和 L1 Loss 函数的区别在于,L1 Loss 在0点处导数不唯一,可能影响收敛。Smooth L1的解决办法是在 0 点附近使用平方函数使得它更加平滑。

Smooth L1的优点

相比于L1损失函数,可以收敛得更快; 相比于L2损失函数,对离群点、异常值不敏感,梯度变化相对更小,训练时不容易跑飞。