从loss的硬截断、软化到focal loss
By 苏剑林 | 2017-12-25 | 219271位读者 |前言 #
今天在QQ群里的讨论中看到了focal loss,经搜索它是Kaiming大神团队在他们的论文《Focal Loss for Dense Object Detection》提出来的损失函数,利用它改善了图像物体检测的效果。不过我很少做图像任务,不怎么关心图像方面的应用。本质上讲,focal loss就是一个解决分类问题中类别不平衡、分类难度差异的一个loss,总之这个工作一片好评就是了。大家还可以看知乎的讨论:
《如何评价kaiming的Focal Loss for Dense Object Detection?》
看到这个loss,开始感觉很神奇,感觉大有用途。因为在NLP中,也存在大量的类别不平衡的任务。最经典的就是序列标注任务中类别是严重不平衡的,比如在命名实体识别中,显然一句话里边实体是比非实体要少得多,这就是一个类别严重不平衡的情况。我尝试把它用在我的基于序列标注的问答模型中,也有微小提升。嗯,这的确是一个好loss。
接着我再仔细对比了一下,我发现这个loss跟我昨晚构思的一个loss具有异曲同工之理!这就促使我写这篇博文了。我将从我自己的思考角度出发,来分析这个问题,最后得到focal loss,也给出我昨晚得到的类似的loss。
硬截断 #
整篇文章都是从二分类问题出发,同样的思想可以用于多分类问题。二分类问题的标准loss是交叉熵
Lce=−ylogˆy−(1−y)log(1−ˆy)={−log(ˆy),当y=1−log(1−ˆy),当y=0
其中y∈{0,1}是真实标签,ˆy是预测值。当然,对于二分类我们几乎都是用sigmoid函数激活ˆy=σ(x),所以相当于
Lce=−ylogσ(x)−(1−y)logσ(−x)={−logσ(x),当y=1−logσ(−x),当y=0
(我们有1−σ(x)=σ(−x)。)
我在上半年的博文《文本情感分类(四):更好的损失函数》中,曾经针对“集中精力关注难分样本”这个想法提出了一个“硬截断”的loss,形式为
L⋅=λ(y,ˆy)⋅Lce
其中
λ(y,ˆy)={0,(y=1且ˆy>0.5)或(y=0且ˆy<0.5)1,其他情形
这样的做法就是:正样本的预测值大于0.5的,或者负样本的预测值小于0.5的,我都不更新了,把注意力集中在预测不准的那些样本,当然这个阈值可以调整。这样做能部分地达到目的,但是所需要的迭代次数会大大增加。
原因是这样的:以正样本为例,我只告诉模型正样本的预测值大于0.5就不更新了,却没有告诉它要“保持”大于0.5,所以下一阶段,它的预测值就很有可能变回小于0.5了,当然,如果是这样的话,下一回合它又被更新了,这样反复迭代,理论上也能达到目的,但是迭代次数会大大增加。所以,要想改进的话,重点就是“不只是要告诉模型正样本的预测值大于0.5就不更新了,而是要告诉模型当其大于0.5后就只需要保持就好了”。(好比老师看到一个学生及格了就不管了,这显然是不行的。如果学生已经及格,那么应该要想办法要他保持目前这个状态甚至变得更好,而不是不管。)
软化loss #
硬截断会出现不足,关键地方在于因子λ(y,ˆy)是不可导的,或者说我们认为它导数为0,因此这一项不会对梯度有任何帮助,从而我们不能从它这里得到合理的反馈(也就是模型不知道“保持”意味着什么)。
解决这个问题的一个方法就是“软化”这个loss,“软化”就是把一些本来不可导的函数用一些可导函数来近似,数学角度应该叫“光滑化”。这样处理之后本来不可导的东西就可导了,类似的算例还有《梯度下降和EM算法:系出同源,一脉相承》中的kmeans部分。我们首先改写一下L∗。
L⋅={−θ(0.5−ˆy)log(ˆy),当y=1−θ(ˆy−0.5)log(1−ˆy),当y=0
这里的θ就是单位阶跃函数
θ(x)={1,x>012,x=00,x<0
这样的L∗跟原来的是完全等价的,它也等价于(因为σ(0)=0.5)
L⋅={−θ(−x)logσ(x),当y=1−θ(x)logσ(−x),当y=0
这时候思路就很明显了,要想“软化”这个loss,就得“软化”θ(x),而软化它就再容易不过,它就是sigmoid函数!我们有
θ(x)=lim
所以很显然,我们将\theta(x)替换为\sigma(Kx)即可:
L^{\cdot \cdot }=\left\{\begin{aligned}&-\sigma(-Kx)\log \sigma(x),\,\text{当}y=1\\ &-\sigma(Kx)\log\sigma(-x),\,\text{当}y=0\end{aligned}\right.
这就是我昨晚思考得到的loss了,显然实现上也是很容易的。
现在跟focal loss做个比较。
Focal Loss #
Kaiming大神的focal loss形式是
L_{fl}=\left\{\begin{aligned}&-(1-\hat{y})^{\gamma}\log \hat{y},\,\text{当}y=1\\ &-\hat{y}^{\gamma}\log (1-\hat{y}),\,\text{当}y=0\end{aligned}\right.
如果落实到\hat{y}=\sigma(x)这个预测,那么就有
L_{fl}=\left\{\begin{aligned}&-\sigma^{\gamma}(-x)\log \sigma(x),\,\text{当}y=1\\ &-\sigma^{\gamma}(x)\log\sigma(-x),\,\text{当}y=0\end{aligned}\right.
特别地,如果K和\gamma都取1,那么L^{**}=L_{fl}!
事实上K和\gamma的作用都是一样的,都是调节权重曲线的陡度,只是调节的方式不一样~注意L^{**}或L_{fl}实际上都已经包含了对不均衡样本的解决方法,或者说,类别不均衡本质上就是分类难度差异的体现。比如负样本远比正样本多的话,模型肯定会倾向于数目多的负类(可以想象全部样本都判为负类),这时候,负类的\hat{y}^{\gamma}或\sigma(Kx)都很小,而正类的(1-\hat{y})^{\gamma}或\sigma(-Kx)就很大,这时候模型就会开始集中精力关注正样本。
当然,Kaiming大神还发现对L_{fl}做个权重调整,结果会有微小提升
L_{fl}=\left\{\begin{aligned}&-\alpha(1-\hat{y})^{\gamma}\log \hat{y},\,\text{当}y=1\\ &-(1-\alpha)\hat{y}^{\gamma}\log (1-\hat{y}),\,\text{当}y=0\end{aligned}\right.
通过一系列调参,得到\alpha=0.25,\gamma=2(在他的模型上)的效果最好。注意在他的任务中,正样本是属于少数样本,也就是说,本来正样本难以“匹敌”负样本,但经过(1-\hat{y})^{\gamma}和\hat{y}^{\gamma}的“操控”后,也许形势还逆转了,还要对正样本降权。不过我认为这样调整只是经验结果,理论上很难有一个指导方案来决定\alpha的值,如果没有大算力调参,倒不如直接让\alpha=0.5(均等)。
多分类 #
focal loss在多分类中的形式也很容易得到,其实就是
L_{fl}=-(1-\hat{y}_t)^{\gamma}\log \hat{y}_t
\hat{y}_t是目标的预测值,一般就是经过softmax后的结果。那我自己构思的L^{**}怎么推广到多分类?也很简单:
L^{\cdot \cdot }=-\text{softmax}(-Kx_t)\log \text{softmax}(x_t)
这里x_t也是目标的预测值,但它是softmax前的结果。
结语 #
什么?你得到了跟Kaiming大神一样想法的东西?不不不,本文只是对Kaiming大神的focal loss的一个介绍而已,更准确地说,是应对分类不平衡、分类难度差异的一些方案的介绍,并尽可能给出自己的看法而已。当然,本文这样的写法难免有附庸风雅、东施效颦之嫌,请读者海涵。
转载到请包括本文地址:https://spaces.ac.cn/archives/4733
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Dec. 25, 2017). 《从loss的硬截断、软化到focal loss 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/4733
@online{kexuefm-4733,
title={从loss的硬截断、软化到focal loss},
author={苏剑林},
year={2017},
month={Dec},
url={\url{https://spaces.ac.cn/archives/4733}},
}
December 26th, 2017
最后一个公式出了点问题,只能看到LaTeX源码,是我浏览器的问题吗?
经测试并没有问题哦,尝试清除一下浏览器缓存?
December 27th, 2017
博主你好,请问软化loss小节中,公式第一个L*里0.5-y^为何等于第二个L*里-x?
不是0.5-\hat{y}等于-x,而是\theta(0.5-\hat{y})=\theta(-x)。\theta(0.5-\hat{y})就是说\hat{y} > 0.5时取0,小于0.5时取1;而\theta(-x)就是说x > 0时取0,小于0时取1。\hat{y} > 0.5和\hat{y} < 0.5分别刚好对应x > 0和x < 0。
博主,如果把sigmoid换成softmax会不会有提升?
多分类就是softmax的呀。focal loss在多分类也是可以用的,难度在于前面的参数\alpha的选择了。也可以用我的那个L^{**}=-\text{softmax}(-Kx_t)\log \text{softmax}(x_t)。
我看他论文里面只用了sigmoid没用softmax,而且别人复现的code也只用了sigmoid,所以我刚刚突发奇想了一下。。
January 2nd, 2018
博主,你好。请问你在训练Focal loss的时候,有没有发现效果有退化的现象(就是效果不升反降)。另外,训练有没有发现难以训练的现象,收敛较慢。我是做图像检测任务的,发现有以上两个问题,不知道是不是因为我编码哪里出了错误还是训练方法不对。
我觉得使用者需要清楚两件事情:
1、focal loss是一个解决分类难度差异的一个很简单直接的方案,但它不一定就是最好的,如果你之前使用了各种策略(过采样、人工调权重等等)已经解决了这个问题,那么换用focal loss不一定能取得更好的效果;
2、focal loss的使用本身也需要调参的,一般可以取\gamma=2,但是\alpha的选取还是需要好好测的。而且要注意的是,\alpha=0.25是乘在类别数少的样本,而不是类别多的样本。至于\alpha等于多少最好,可能还是要根据你的实际情况来调。
January 14th, 2018
请问一下博主,您在QA上使用focal loss的代码可以分享一下吗?使用这个focal loss 就是把损失函数改成这个,其他部分进行相应调整吗?
你想要QA代码还是focal loss代码?focal loss不就是一行的事情么?
March 19th, 2018
你好,有个小问题啊,如果二分类交叉熵表示成最开始出现的公式,则 \hat y 应该为y=1的概率,
所以 y=1 且 \hat y > 0.5 的情况下不更新,但是 1-\hat y 为对应负样本的预测值,因此, 1-\hat y < 0.5 即
同样 \hat y > 0.5 不更新
“\hat{y} 应该为y=1的概率”,这句话没错。
对于正样本,我们希望\hat{y} > 0.5,等价的希望是1 - \hat{y} < 0.5;
对于负样本,我们希望\hat{y} < 0.5,等价的希望是1 - \hat{y} > 0.5。
也就是说,不管什么情况下,我们都是算\hat{y},不是说正样本就算\hat{y},负样本就算1-\hat{y}
嗷嗷嗷,恍然大悟,厉害厉害!!!!
May 30th, 2018
你好,有一个问题想请教。focal loss 多分类的公式也就是倒数第二个公式中为什么没有alpha,如果有的话对于多分类问题是不是应该从标量变为向量呢
可以有,你说的没错,是一个向量,要为每个类分别一个alpha并且alpha之和为1。
但是这个alpha向量的确定就比较艰难了~
基于focal loss 的多分类的代码您方便提供一下吗,有些地方还是不知道怎么修改,谢谢
就是-K.sum(alpha * y_true * (1 - y_pred) * K.log(y_pred + 1e-6), -1)类似的~
y_true表示实际标签的热编码,y_pred表示softmax输出吗
是的
还是有一些细节需要处理的,独热码[[0,0,1][0,1,0],[1,0,0]]和数字码[1,2,3]在计算上还是有差的。
苏神,请教一下,如果独热码[[0,0,1][0,1,0],[1,0,0]]改为数字码[0,1,2],那么是不是应为-(alpha*(1-ypred)*K.log(ypred+1e-6))[y_true] ?
伪代码可以这样写,但实际上这个代码会报错。
May 31st, 2018
您好,论文中在交叉上前面乘了一个alpha,是用来解决样本严重不平衡问题的吗?那么在常规的多分类问题(不是目标检测)是不是不用乘以1-p的gamma次方呢,谢谢
解决样本不平衡的最重要的一项就是你说的那个(1-p)^{\gamma}
在多分类中,我把alpha设置为一个向量,乘在train_y(标签)前面,实验表明准确率还是和之前一样的,这是为什么呀,似乎没有效果
没有什么东西是绝对能提升效果的,都是需要慢慢调试的。而且就算调试了也未必提升,也许这个loss就不适合你的数据。
说的好 ,赞
June 1st, 2018
对于多分类alpha的设置是需要实验得到最佳还是根据类别比例设定,alpha向量需要和为1吗
估计也只能靠实验了。为了方便比较,alpha向量最好和为1。
July 9th, 2018
最后一个多分类的公式是不是有问题? Xt是预测之前的结果?不是应该Xt越大,softmax就越大吗?反之Xt越小,softmax也越小。如果预测的结果是小概率的,那么前面再乘softmax(-KXt)不就更小了吗?
如果x_t越大,那么\text{softmax}(x_t)也越大,说明分类越成功了,那么这一项的权重可以相对小一些,可以权重可以取为\text{softmax}(-Kx_t),跟二分类的原理是一样的呀。
可是如果Xt小的话,softmax(Xt)也小啊,那么softmax(-KXt)不是更小了吗?分类不成功的权重更小?
softmax是整体归一化的呀。Xt小,softmax(Xt)也小,相对而言softmax(-Xt)就大了(指的是将整个向量的所有元素取相反数,然后再softmax一次)。
比如原来是softmax([1,2,3]),权重就是softmax([-1, -2, -3])。
非常感谢您的解释,我自己再琢磨琢磨
May 16th, 2019
大神,请问下这里focal loss是根据损失函数-交叉熵定义的,最后一层是softmax或者sigmoid;那如果我尝试用crf进行命名实体识别,但crf的损失函数是整个序列的对数似然,还能用focal loss吗?
能是能,但是没有必要了。
focal loss是-(1-p)^{\gamma}\log p的形式,CRF直接给出L=-\log p,所以p = e^{-L},所以直接将loss改为\left(1 - e^{-L}\right)^{\gamma}L就相当于用了focal loss。
只不过crf直接以路径为单位,事实上不存在困难类的问题。
了解了,谢谢大神。
实体识别中可能存在大量无实体的序列, 降低简单句的权重应该还是有意义的