艺考网
全国站

超详细语义分割损失的全面盘点

xunaa
2024-10-03 20:17:43
编辑说
交叉熵Loss
其中,代表类别数,是一个one-hot向量。这些元素只有两个值: 和。如果类别与样本的类别相同,则取该类别。否则,就被采取。至于表达预测样本所属的概率。
当类别数量相等

交叉熵Loss

其中,代表类别数,是一个one-hot向量。这些元素只有两个值: 和。如果类别与样本的类别相同,则取该类别。否则,就被采取。至于表达预测样本所属的概率。

当类别数量相等时,这个损失是二元交叉熵,Pytorch中提供了单独的实现。

交叉熵损失可以用于大多数语义分割场景,但它有一个明显的缺点,就是当只分割前景和背景时,当前景像素数远小于背景像素数时,即如果数量远大于,则损失函数中的分量将占主导地位,导致模型严重偏向背景,导致结果不佳。

代码实现如下:

#二值交叉熵,这里的输入需要经过sigmoid处理import torchimport torch.nn as nnimport torch.nn.function as Fnn.BCELoss(F.sigmoid(input), target)#多分类交叉熵,使用这个损失是在添加Softmax 层nn.CrossEntropyLoss(input, target) 之前不需要

带权交叉熵Loss

加权交叉熵损失,公式为:

可以看到,根据交叉熵Loss,给每个类别添加了一个权重参数。计算公式为: 其中表示像素总数, 表示GT 类别的像素数。这样,与原始的交叉熵Loss相比,在样本数量不平衡的情况下可以获得更好的结果。

Focal Loss

何凯明团队在RetinaNet论文中引入Focal Loss,解决难易样本数量不平衡的问题。让我们回顾一下。我们知道One-Stage的物体检测器通常会产生10k量级的box,但只有少数是正样本,而且正负样本的数量很不平衡。我们计算分类时常用的损失——交叉熵的公式如下:

为了解决正负样本数量不平衡的问题,我们常常在二元交叉熵损失前面添加一个参数,即:

虽然正负样本数量均衡,但实际上目标检测中大量的候选目标都是容易分离的样本。这些样本的损失非常低,但由于数量极不平衡,容易划分的样本数量相对过多,最终主导了总损失。

因此,本文认为,容易区分的样本(即置信度高的样本)对模型的改进作用很小,模型应该主要关注那些难以区分的样本。于是Focal Loss诞生了。一个简单的想法就是,只要我们减少高置信度样本的损失就可以了,对吧?也就是下面的公式:

我们就拿它等于2来感受一下吧。如果,那么,损失就减少了1000倍。最后,Focal Loss还结合了公式(2),很容易理解。式(3)解决了难易样本的不平衡问题。式(2)解决了正负样本的不平衡问题。式(2)和(3))一起使用,同时解决正反难易题!所以Focal Loss的最终形式如下:

下图展示了Focal Loss设置为不同值时损失函数的下降情况。

实验结果表明,当

虽然它是RetinaNet中最好的,但这并不意味着这个参数在我们的分割任务和其他样本中是最好的。我们需要手动调整这个参数。另外,Focal Loss似乎只适合分割任务中的二元分类。情况。

Focal Loss的Pytorch代码实现如下:

类FocalLoss(nn.Module):

def __init__(self, gamma=0, alpha=None, size_average=True):

超级(FocalLoss,自我).__init__()

self.gamma=伽玛

self.alpha=alpha

if isinstance(alpha,(float,int,long)): self.alpha=torch.Tensor([alpha,1-alpha])

if isinstance(alpha,list): self.alpha=torch.Tensor(alpha)

self.平均尺寸=平均尺寸

def 前向(自身,输入,目标):

如果输入.dim()2:

输入=input.view(input.size(0),input.size(1),-1) # N,C,H,W=N,C,H*W

输入=input.transpose(1,2) # N,C,H*W=N,H*W,C

输入=input.contigious().view(-1,input.size(2)) # N,H*W,C=N*H*W,C

目标=目标.view(-1,1)

logpt=F.log_softmax(输入)

logpt=logpt.gather(1,目标)

logpt=logpt.view(-1)

pt=变量(logpt.data.exp())

如果self.alpha 不是None:

如果self.alpha.type()!=input.data.type():

self.alpha=self.alpha.type_as(input.data)

at=self.alpha.gather(0,target.data.view(-1))

logpt=logpt * 变量(at)

损失=-1 * (1-pt)**self.gamma * logpt

如果self.size_average: 返回loss.mean()

else: 返回loss.sum()

Dice Loss

Dice系数:根据Lee Raymond Dice[1]命令,它是一个测量函数,用来衡量一个集合的相似度。它通常用于计算两个样本之间的像素。公式如下: 分子中之所以有系数2,是因为分母中存在重复计算和,最终的取值范围是。对于我们的分割任务,它代表Ground Truth 分割图像,Y 代表预测的分割图像。也许有必要再谈一下。其实除了上面的形式外,还可以写成: 其中, 分别代表真阳性、假阳性、假阴性的像素个数。 Dice Loss:公式定义为:当使用Dice Loss且样本极不平衡时,如果正常情况下使用Dice Loss,反向传播会产生不利影响,使训练不稳定。在训练分割网络(例如FCN或UNet)时,应该选择交叉熵损失(cross-entropy Loss)还是骰子损失(Dice Loss)?假设我们用它来表示预测值而不是真实标签值,那么交叉熵损失的梯度形式类似于(我会在文章后面给出推导),Dice Loss的值为或者,其梯度形式为Or,可以看出,在极端情况下,即sum 和都很小时,计算出的梯度值可能会很大,从而会导致训练非常不稳定。解决类别不平衡问题的另一种方法是简单地为每个类别分配不同的权重因子(例如为少数类别分配较大的权重因子),这样就可以缓解样本量不平衡的问题(上面已经介绍过) ) ,即加权交叉熵损失)。这两种加工方法哪种更好?建议您用自己的数据进行实验。代码实现: import torch.nn as nn

导入torch.nn.function 作为F

类SoftDiceLoss(nn.Module):

def __init__(self, 重量=无, size_average=True):

超级(SoftDiceLoss,自我).__init__()

def 前向(自我,logits,目标):

num=目标.size(0)

//防止被0除的情况发生

平滑=1

probs=F.sigmoid(logits)

m1=probs.view(num, -1)

m2=目标.view(num, -1)

交集=(m1 * m2)

分数=2. * (intersection.sum(1) + smooth)/(m1.sum(1) + m2.sum(1) + smooth)

分数=1 - 分数.sum()/num

返回分数

IOU Loss

IOU Loss 和Dice Loss 一样,是度量学习的一种衡量方法。公式定义如下:

与Dice Loss一样,它仍然存在训练过程不稳定的问题。 IOU Loss 在分割任务中不应该大量使用。如果你想尝试一下,代码实现非常简单。只需根据上面的骰子损失更改分母部分即可。但是,我不会详细说明。我们可以看一下VOC 2010上将IOU损失应用于FCN的实验结果:

可以看到,IOU Loss 提升了大部分类别的分割结果,但对于Person 类别,其性能有所下降。

Tversky Loss

论文地址为:https://arxiv.org/pdf/1706.05721.pdf。事实上,Dice Loss 只是Tversky 损失的一种特殊形式。我们先来看看特沃斯基系数的定义。它是Dice系数和Jaccard系数(即IOU系数,即)的广义系数。公式为: 这里A代表预测值。 B代表真实值。当和均为时,该式为Dice 系数,当和均为时,该式为Jaccard 系数。其中代表FP(假阳性),代表FN(假阴性)。通过调整这两个超参数,可以控制两者之间的权衡,从而影响召回率等指标。下表显示了使用Tversky Loss for FCN 进行病灶分割并采取不同求和参数得到的结果,其中Sensitivity 代表召回率Recall,Specificity 代表准确率Precision:

极小病灶的分割效果如下:

较大病灶的分割效果如下:

Keras代码实现如下:

def tversky(y_true, y_pred):

y_true_pos=K.flatten(y_true)

y_pred_pos=K.flatten(y_pred)

true_pos=K.sum(y_true_pos * y_pred_pos)

false_neg=K.sum(y_true_pos * (1-y_pred_pos))

false_pos=K.sum((1-y_true_pos)*y_pred_pos)

阿尔法=0.7

返回(true_pos + 平滑)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + 平滑)

def tversky_loss(y_true, y_pred):

返回1 - tversky(y_true,y_pred)

Generalized Dice loss

论文原文为:Generalized Overlap Measures for Assessment and Validation in Medical Image Analysis。刚才我们分析了,通过Dice Loss对小目标的预测是非常不利的,因为一旦小目标出现一些像素预测误差,可能会导致Dice系数大幅波动,导致梯度变化较大的训练不稳定。另外,从上面的代码实现可以发现,Dice Loss针对的是特定类别的分割损失。当存在多个类似病灶分割的场景时,一般会使用多个Dice Loss,因此Generalized Dice loss就是将多个类别的Dice Loss整合起来,用一个指标作为分割结果的量化指标。类别数为2时的GDL Loss公式如下: 其中表示第位置类别的真实像素类别, 表示对应的预测概率值, 表示每个类别的权重。的公式为:

Keras代码实现:

def Generalized_dice_coeff(y_true, y_pred):

Ncl=y_pred.shape[-1]

w=K.zeros(形状=(Ncl,))

w=K.sum(y_true, 轴=(0,1,2))

w=1/(w**2+0.000001)

#计算生成骰子coef:

分子=y_true*y_pred

分子=w*K.sum(分子,(0,1,2,3))

分子=K.sum(分子)

分母=y_true+y_pred

分母=w*K.sum(分母,(0,1,2,3))

分母=K.sum(分母)

gen_dice_coef=2*分子/分母

超详细语义分割损失的全面盘点

返回gen_dice_coef

def Generalized_dice_loss(y_true, y_pred):

返回1 - Generalized_dice_coeff(y_true, y_pred)

BCE + Dice Loss

即将把BCE Loss和Dice Loss结合起来,在数据比较平衡的时候会有改善,但是当数据极度不平衡的时候,迭代几个Epoch后,交叉熵Loss会比Dice Loss小很多。这种组合Loss会退化为Dice Loss。

Focal Loss + Dice Loss

这种Loss的组合应该首先看到腾讯医疗AI实验室2018年在《Medical Physics》上发表的这篇论文:https://arxiv.org/pdf/1808.05238.pdf。论文提出使用Focal Loss和Dice Loss来处理小器官的分割问题。公式如下:

其中, 分别代表类别c的真阳性、假阴性和假阳性。可以看到,这里使用Focal Loss时,两个参数直接替换为类别c的正样本像素数。具体实验细节和结果请参见原论文。

Exponential Logarithmic loss

这种损失是在MICCAI 2018 论文3D Segmentation with Exponential LogarithmicLoss for Height Unbalanced Object Sizes 中提出的。论文地址为:https://arxiv.org/abs/1809.00076。该损失结合了焦点损失和骰子损失。公式如下:

这里添加了两个参数权重,分别是和和指数对数Dice损失,以及指数交叉熵损失。公式如下:

其中,表示像素位置,表示类别标签,表示该位置处的groundtruth类别,表示经过softmax运算后的概率值。其中:其中表示标签出现的频率。该参数可以降低出现频率较高的类别的权重。并且可以改善函数的非线性,如图2所示:

Lovasz-Softmax Loss

这是今天要介绍的最后一个Loss,Kaggle神器。本文来自CVPR 2018,原文地址为:https://arxiv.org/pdf/1705.08790.pdf。如果对原理感兴趣,可以阅读论文。该损失是Jaccard (IOU) Loss 的Lovaze 扩展,性能更好。因为本文的目的只是简单盘点,所以我不会详细介绍这个损失。这个Loss可能稍后会单独介绍。论文的官方源代码可以在附录中找到。使用起来并不太困难。

补充(Softmax梯度计算)

在介绍Dice Loss时,留下了一个问题,交叉熵的梯度形式的推导。这是推导。

(1) Softmax函数首先我们来明确一下softmax函数。一般来说,softmax函数是用于分类任务的输出层。 softmax的形式为:代表第i个神经元的输出。接下来,我们定义一个具有多个输入和一个输出的神经元。神经元的输出为其中是第th 个神经元的权重,b 是偏移值。它代表网络的第th 个输出。在这个输出上添加一个softmax函数可以写成:它代表softmax函数的第i个输出值。这个过程可以用下图:来表示

(2)损失函数softmax的损失函数一般是交叉熵损失函数。交叉熵函数的形式为: 其中y_i表示真实标签值(3) 需要用到的高数求导公式

c'=0(c是常数)

(x^a)'=ax^(a-1),a是常数且a0

(a^x)'=a^xlna

(e^x)'=e^x

(logax)'=1/(xlna),a0 且a1

(lnx)'=1/x

(sinx)'=cosx

(cosx)'=-sinx

(tanx)'=(secx)^2

(secx)'=secxtanx

(cotx)'=-(cscx)^2

(cscx)'=-csxcotx

(arcsinx)'=1/(1-x^2)

(arccosx)'=-1/(1-x^2)

(arctanx)'=1/(1+x^2)

(arccotx)'=-1/(1+x^2)

(shx)'=chx

(chx)'=shx

(uv)'=uv'+u'v

(u+v)'=u'+v'

(u/)'=(u'v-uv')/^2

(3) 推导时,我们需要求的是损失对神经元输出的梯度。求出梯度后才能反向传播,即求:根据链式法则(即复合函数的求导法则),我们刚学的时候就明白这个公式很久了,为什么会在这里而不是这里?这里我们回顾一下softmax的公告。分母部分包含了所有神经元的输出,因此除了i之外的所有输出的输出也包含在内,所以所有的a都必须参与计算。稍后我们会看到,计算需要分为和计算两种情况下的导数。首先,我们求前半部分: 接下来,求第二部分的导数:

如果,如果,接下来,结合以上,我们得到:推导完毕! (4) 对于分类问题,我们给出的结果只有一类为1,其他都是0。因此,对于分类问题,梯度等于:

最后,这里给出一个CS231N的代码实现,帮助进一步理解:

#编码=utf-8

将numpy 导入为np

def softmax_loss_native(W, X, y, reg):

'''

Softmax_loss的暴力实现使用了for循环

输入维度为D,有C个分类类别,我们对一批N个样本进行操作

输入:

- W: 一个numpy数组,形状为(D,C),代表权重

- X: 形状(N, D) 的numpy 数组表示输入数据

- y: 形状为(N,) 的numpy 数组,表示类别标签

- reg:(浮点)正则化参数

f 返回:

- 浮点数代表Loss

- 与W形状相同的渐变

'''

损失=0.0

dW=np.zeros_like(W) #dW表示W反向传播的梯度

num_classes=W.shape[1]

num_train=X.shape[0]

对于我在xrange(num_train):

分数=X[i].dot(W)

shift_scores=Scores - max(scores) #防止数值不稳定

loss_i=-shift_scores[y[i]] + np.log(sum(np.exp(shift_scores)))

损失+=损失_i

对于xrange 中的j(num_classes):

softmax_output=np.exp(shift_scores[j])/sum(np.exp(shift_scores))

如果j==y[i]:

dW[: j] +=(-1 + softmax_output) * X[i]

否则:

dW[: j] +=softmax_output * X[i]

损失/=num_train

损失+=0.5 * reg * np.sum(W * W)

dW=dW/num_train + reg * W

回波损耗,dW

def softmax_loss_vectorized(W, X, y, reg):

损失=0.0

dW=np.zeros_like(W)

num_class=W.shape[1]

num_train=X.shape[0]

分数=X.dot(W)

shift_scores=分数- np.max(scores, axis=1).reshape(-1, 1)

softmax_output=np.exp(shift_scores)/np.sum(np.exp(shift_scores), axis=1).reshape(-1, 1)

损失=-np.sum(np.log(softmax_output[范围(num_train), list(y)]))

损失/=num_train

损失+=0.5 * reg * np.sum(W * W)

dS=softmax_output.copy()

dS[范围(num_train), 列表(y)] +=-1

dW=(x.T).dot(dS)

dW=dW/num_train + reg*W

回波损耗,dW

总结

本文介绍了语义分割中近年来非常常用的一些损失函数。希望能够作为一个起点,引发大家进一步思考分割中的损失函数。当然,对于工程和竞赛类型来说,掌握一个新的Loss并将其应用到自己的项目或竞赛中也是有好处的。

附录

1. https://www.aiuai.cn/aifarm1159.html

2. 广义Dice 损失代码实现:多类分割的广义骰子损失· Issue #9395 · keras-team/keras

用户评论

疯人疯语疯人愿

终于来了解一下各个loss函数的特点了!太需要这篇详细梳理了

    有10位网友表示赞同!

不要冷战i

语义分割一直是比较费解的地方,希望这篇博客能帮我更深入地理解

    有12位网友表示赞同!

心贝

做深度学习模型,选用合适的Loss Function真是关键啊!多亏有了这篇文章详细讲解。

    有8位网友表示赞同!

绳情

这个title太吸引人了!期待学习到更多关于语义分割和Loss函数的知识。

    有6位网友表示赞同!

君临臣

我一直不太清楚不同loss函数怎么适用于不同的语义分割任务,看来要好好研究这篇博客了

    有14位网友表示赞同!

单身i

感觉对语义分割有了一些基础了解了,这次可以好好看看Loss函数的各种实现方式

    有14位网友表示赞同!

暖瞳

这篇博文的标题太棒了!我正在学习语义分割,这篇文章刚好可以作为我的参考资料。

    有11位网友表示赞同!

人心叵测i

终于找到一份关于loss函数的大盘点啦!太感谢作者了!

    有10位网友表示赞同!

花菲

我要分享一下这篇文章给学长学姐们!

    有13位网友表示赞同!

寻鱼水之欢

赶紧收藏起来,以后再学习语义分割时回顾

    有11位网友表示赞同!

景忧丶枫涩帘淞幕雨

不同类型的数据集需要使用不同类型的loss函数? 这点非常重要! 应该多关注一下这篇博客的细节

    有12位网友表示赞同!

有阳光还感觉冷

感觉损失函数真是绕啊!希望这篇博客能让我对它们更清晰地理解

    有12位网友表示赞同!

墨染年华

语义分割确实是一个比较细分的领域,需要深入学习各种Loss函数的设计原理

    有11位网友表示赞同!

有一种中毒叫上瘾成咆哮i

这篇文章应该能帮我解决很多关于loss函数的选择和应用的问题

    有17位网友表示赞同!

南初

终于有一个可以参考的汇总啦!希望包含比较详细的一些案例分析

    有12位网友表示赞同!

滴在键盘上的泪

期待深入了解到每个Loss Function 的优缺点,以及它在语义分割中的具体应用场景

    有5位网友表示赞同!

失心疯i

学习到了!

    有8位网友表示赞同!

颜洛殇

super!

    有5位网友表示赞同!

夏日倾情

Good Job!

    有15位网友表示赞同!

免责声明
本站所有收录的学校、专业及发布的图片、内容,均收集整理自互联网,仅用于信息展示,不作为择校或选择专业的建议,若有侵权请联系删除!

大家都在看

超详细语义分割损失的全面盘点

超详细语义分割损失的全面盘点

交叉熵Loss 其中,代表类别数,是一个one-hot向量。这些元素只有两个值: 和。如果类别与样本的类别相同,则取该类别。否则,就被采取。至于表达预测样本所属的概率。 当类别数量相等
2024-10-03
积分这个特别烧脑的二次替换法怎么理解?

积分这个特别烧脑的二次替换法怎么理解?

代换积分法有两种类型。黄已经介绍了第一种代换积分法。这里我们继续用代入法来分析第二种积分方法。 无论是第一种代入法还是第二种代入法,都是基于以下定理: 定理:(代入积分法
2024-10-03
数学的“自洽”

数学的“自洽”

今天我们来谈谈数学的“自洽”。 数学世界的自洽性应该是令人震惊和惊讶的。我想知道我们是否有这个想法。当我们使用多个解来解决一个数学问题时,如何能够独立地维持各个解
2024-10-03
2018年成人高考数学考试大纲、复习要点

2018年成人高考数学考试大纲、复习要点

考试主要内容如下: 第一部分:代数 (1)集合和简单逻辑 1.解决集合的含义及其表示方法,了解空集、完备集、子集、交集、并集、补集的概念和表示方法,理解与集合有关的各种符号的含
2024-10-03
本科生高等数学知识点总结

本科生高等数学知识点总结

常用知识点: 1.常用函数的定义域总结如下: y,kx,b(1) 通用形式域:x?R 2y,ax,bx,c k(2)小数形式的定义域为:x?0 y,x (3) 根式表达式的形式域为:x?0 y,x (4) 对数形式的定义域为:x,
2024-10-03
数学学习:常微分方程、拉普拉斯变换和级数实验

数学学习:常微分方程、拉普拉斯变换和级数实验

常微分方程组的求解Solving Ordinary Differential Equations 通话功能 二维绘图原理 应用案例展示应用案例展示 答复: In[1]:=DSolve[{y'[x]==z[x],z'[x]==-y[x],y[0]==0,
2024-10-03
三数不定积分的相关求解方法

三数不定积分的相关求解方法

第一类:由基本微分公式推导出来的综合微分公式 定理1:假设f(u)有原函数且u=(x)可微,则有代入公式: f[(x)]’(x)dx=[f(u)du]u=(x)。 步: (1) 将被积函数中的简单因子组成复合函数
2024-10-03
你知道如何用英语表达日期吗?

你知道如何用英语表达日期吗?

中国: 2019 年6 月10 日 英国: 2019年6月10日月日年 美国:2019 年6 月10 日 一旦你了解了每个国家的语言规则,一切就变得容易了。 月份 一月n。一月,正月(简称Jan) 二月二月(简称二
2024-10-03
阅读澳大利亚产品标签指南

阅读澳大利亚产品标签指南

终于买到了心仪的澳洲直邮产品,但密集的英文说明和商标还是让很多人望而却步。产品体验不再是一开始的愉快…… 这是否意味着如果你英语说得不好,你就不配拥有愉快的澳洲直邮
2024-10-03
健师药师讲座|什么东西真正管用,教你如何轻松看懂国外保健品标签

健师药师讲座|什么东西真正管用,教你如何轻松看懂国外保健品标签

编辑|健康知识局冬雪大雪 王海莲,首都医科大学宣武医院副主任药师,从事专职用药咨询10年,北京市健康科普专家,中国首届药物治疗管理药师,2017年中国十大优秀药师之一, 2016年北京
2024-10-03