多标签“Softmax+交叉熵”的软标签版本
By 苏剑林 | 2022-05-07 | 50049位读者 |(注:本文的相关内容已整理成论文《ZLPR: A Novel Loss for Multi-label Classification》,如需引用可以直接引用英文论文,谢谢。)
在《将“Softmax+交叉熵”推广到多标签分类问题》中,我们提出了一个用于多标签分类的损失函数:
\begin{equation}\log \left(1 + \sum\limits_{i\in\Omega_{neg}} e^{s_i}\right) + \log \left(1 + \sum\limits_{j\in\Omega_{pos}} e^{-s_j}\right)\label{eq:original}\end{equation}
这个损失函数有着单标签分类中“Softmax+交叉熵”的优点,即便在正负类不平衡的依然能够有效工作。但从这个损失函数的形式我们可以看到,它只适用于“硬标签”,这就意味着label smoothing、mixup等技巧就没法用了。本文则尝试解决这个问题,提出上述损失函数的一个软标签版本。
巧妙联系 #
多标签分类的经典方案就是转化为多个二分类问题,即每个类别用sigmoid函数$\sigma(x)=1/(1+e^{-x})$激活,然后各自用二分类交叉熵损失。当正负类别极其不平衡时,这种做法的表现通常会比较糟糕,而相比之下损失$\eqref{eq:original}$通常是一个更优的选择。
在之前文章的评论区中,读者 @wu.yan 揭示了多个“sigmoid+二分类交叉熵”与式$\eqref{eq:original}$的一个巧妙的联系:多个“sigmoid+二分类交叉熵”可以适当地改写成
\begin{equation}\begin{aligned}
&\,-\sum_{j\in\Omega_{pos}}\log\sigma(s_j)-\sum_{i\in\Omega_{neg}}\log(1-\sigma(s_i))\\
=&\,\log\prod_{j\in\Omega_{pos}}(1+e^{-s_j})+\log\prod_{i\in\Omega_{neg}}(1+e^{s_i})\\
=&\,\log\left(1+\sum_{j\in\Omega_{pos}}e^{-s_j}+\cdots\right)+\log\left(1+\sum_{i\in\Omega_{neg}}e^{s_i}+\cdots\right)
\end{aligned}\label{eq:link}\end{equation}
对比式$\eqref{eq:original}$,我们可以发现式$\eqref{eq:original}$正好是上述多个“sigmoid+二分类交叉熵”的损失去掉了$\cdots$所表示的高阶项!在正负类别不平衡时,这些高阶项占据了过高的权重,加剧了不平衡问题,从而效果不佳;相反,去掉这些高阶项后,并没有改变损失函数的作用(希望正类得分大于0、负类得分小于0),同时因为括号内的求和数跟类别数是线性关系,因此正负类各自的损失差距不会太大。
形式猜测 #
这个巧妙联系告诉我们,要寻找式$\eqref{eq:original}$的软标签版本,可以尝试从多个“sigmoid+二分类交叉熵”的软标签版本出发,然后尝试去掉高阶项。所谓软标签,指的是标签不再是0或1,而是0~1之间的任意实数都有可能,表示属于该类的可能性。而对于二分类交叉熵,它的软标签版本很简单:
\begin{equation}-t\log\sigma(s)-(1-t)\log(1-\sigma(s))\end{equation}
这里$t$就是软标签,而$s$就是对应的打分。模仿过程$\eqref{eq:link}$,我们可以得到
\begin{equation}\begin{aligned}
&\,-\sum_i t_i\log\sigma(s_i)-\sum_i (1-t_i)\log(1-\sigma(s_i))\\
=&\,\log\prod_i(1+e^{-s_i})^{t_i}+\log\prod_i (1+e^{s_i})^{1-t_i}\\
=&\,\log\prod_i(1+t_i e^{-s_i} + \cdots)+\log\prod_i (1+(1-t_i)e^{s_i}+\cdots)\\
=&\,\log\left(1+\sum_i t_i e^{-s_i}+\cdots\right)+\log\left(1+\sum_i(1-t_i)e^{s_i}+\cdots\right)
\end{aligned}\end{equation}
如果去掉高阶项,那么就得到
\begin{equation}\log\left(1+\sum_i t_i e^{-s_i}\right)+\log\left(1+\sum_i(1-t_i)e^{s_i}\right)\label{eq:soft}\end{equation}
它就是式$\eqref{eq:original}$的软标签版本的候选形式,可以发现当$t_i\in\{0,1\}$时,正好是退化为式$\eqref{eq:original}$的。
证明结果 #
就目前来说,式$\eqref{eq:soft}$顶多是一个“候选”形式,要将它“转正”,我们需要证明在$t_i$为0~1浮点数时,式$\eqref{eq:soft}$能学出有意义的结果。所谓有意义,指的是理论上能够通过$s_i$来重构$t_i$的信息($s_i$是模型预测结果,$t_i$是给定标签,所以$s_i$能重构$t_i$是机器学习的目标)。
为此,我们记式$\eqref{eq:soft}$为$l$,并求$s_i$的偏导数:
\begin{equation}\frac{\partial l}{\partial s_i} = \frac{-t_i e^{-s_i}}{1+\sum\limits_i t_i e^{-s_i}}+\frac{(1-t_i)e^{s_i}}{1+\sum\limits_i(1-t_i)e^{s_i}}\end{equation}
我们知道$l$的最小值出现在所有$\frac{\partial l}{\partial s_i}$都等于0时,直接去解方程组$\frac{\partial l}{\partial s_i}=0$并不容易,但笔者留意到一个神奇的“巧合”:当$t_i e^{-s_i}=(1-t_i)e^{s_i}$时,每个$\frac{\partial l}{\partial s_i}$自动地等于0!所以$t_i e^{-s_i}=(1-t_i)e^{s_i}$应该就是$l$的最优解了,解得
\begin{equation}t_i = \frac{1}{1+e^{-2s_i}}=\sigma(2s_i)\end{equation}
这是一个很漂亮的结果,它告诉我们几个信息:
1、式$\eqref{eq:soft}$确实是式$\eqref{eq:original}$合理的软标签推广,它能通过$s_i$完全重建$t_i$的信息,其形式也刚好与sigmoid相关;
2、如果我们要将结果输出为0~1的概率值,那么正确的做法应该是$\sigma(2s_i)$而不是直觉中的$\sigma(s_i)$;
3、既然最后的概率公式也具有sigmoid的形式,那么反过来想,也可以理解为我们依旧还是在学习多个sigmoid激活的二分类问题,只不过损失函数换成了式$\eqref{eq:soft}$。
实现技巧 #
式$\eqref{eq:soft}$的实现可以参考bert4keras的代码multilabel_categorical_crossentropy,其中有个小细节值得跟大家一起交流一下。
首先,我们将式$\eqref{eq:soft}$可以等价地改写成
\begin{equation}\log\left(1+\sum_i e^{-s_i + \log t_i}\right)+\log\left(1+\sum_i e^{s_i + \log (1-t_i)}\right)\label{eq:soft-log}\end{equation}
所以看上去,只需要将$\log t_i$加到$-s_i$、将$\log(1-t_i)$加到$s_i$上,补零后做常规的$\text{logsumexp}$即可。但实际上,$t_i$是有可能取到$0$或$1$的,对应的$\log t_i$或$\log(1-t_i)$就是负无穷,而框架无法直接处理负无穷,因此通常在$\log$之前需要clip一下,即选定$\epsilon > 0$后定义
\begin{equation}\text{clip}(t)=\left\{\begin{aligned}&\epsilon, &t < \epsilon \\
&t, &\epsilon\leq t\leq 1-\epsilon\\
&1-\epsilon, &t > 1-\epsilon\end{aligned}\right.\end{equation}
但这样一clip,问题就来了。由于$\epsilon$不是真的无穷小,比如$\epsilon=10^{-7}$,那么$\log\epsilon$大约是$-16$左右;而像GlobalPointer这样的场景中,我们会提前把不合理的$s_i$给mask掉,方式是将对应的$s_i$置为一个绝对值很大的负数,比如$-10^7$;然而我们再看式$\eqref{eq:soft-log}$,第一项的求和对象是$e^{-s_i + \log t_i}$,所以$-10^7$就会变成$10^7$,如果$t_i$没有clip,那么理论上$\log t_i$是$\log 0 = -\infty$,可以把$-s_i + \log t_i$重新变回负无穷,但刚才我们已经看到进行了clip之后的$\log t_i$顶多就是$-16$,远远比不上$-s_i$的$10^7$,所以$-s_i + \log t_i$依然是一个大正数。
为了解决这个问题,我们不止要对$t_i$进行clip,我们还要找出原本小于$\epsilon$的$t_i$,手动将对应的$-s_i$置为绝对值很大的负数,同样还要找出大于$1-\epsilon$的$t_i$,将对应的$s_i$置为绝对值很大的负数,这样做就是将小于$\epsilon$的按照绝对等于0额外处理,将大于$1-\epsilon$的按照绝对等于1处理。
文章小结 #
本文主要将笔者之前提出的多标签“Softmax+交叉熵”推广到软标签场景,有了对应的软标签版本后,我们就可以将它与label smoothing、mixup等技巧结合起来了,像GlobalPointer等又可以多一个炼丹方向。
转载到请包括本文地址:https://kexue.fm/archives/9064
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (May. 07, 2022). 《多标签“Softmax+交叉熵”的软标签版本 》[Blog post]. Retrieved from https://kexue.fm/archives/9064
@online{kexuefm-9064,
title={多标签“Softmax+交叉熵”的软标签版本},
author={苏剑林},
year={2022},
month={May},
url={\url{https://kexue.fm/archives/9064}},
}
May 15th, 2022
感谢分享,请问苏神这个时候 网络预测阈值该如何选择?因为真实标签是[0,1]区间的值这个时候正负例如何构建?
既然是软标签,就没有正负样本的说法。阈值是人为自己选的,反正最后输出的概率是$\sigma(2\sigma_i)$。
May 17th, 2022
感谢苏神分享,第3个公示的第一项前面是否应该有个负号呢
对的,感谢指出,已经修正。
May 19th, 2022
我推导了一下,(7)确实是(6)的唯一解。话说(6)中分母求和下标也用i稍微有点不严谨,不过问题不大。
我觉得从运算的先后顺利来看,分母求和下标也用$i$并不会造成理解上的混乱。换用一个下标只不过是主流的一种强迫症而已。
May 31st, 2022
感谢苏神分享,小白想问下是不是如果数据集只有硬标签,这个软标签版本就用不上呢?
硬标签也可能用到mixup、标签平滑等技巧,这时候就转化为软标签了。
June 14th, 2022
请问式5优化的目的是不是使sigmoid(2*y_pred)=y_true?
但是我随机生成20个y_pred(实数范围),20个y_true(0到1范围)实验了下,发现并不是满足上式时,式5值最小。
补充一下:
我发现用单对y_pred和y_true试验时,就满足越接近式7时式5就越小,但用一组数据去试验就不满足这个关系。
理论解是这样,不清楚你实验的具体设置。
July 13th, 2022
请教下onehot转化为软标签后,loss下降到一定程度就不变了,可能是什么原因呢
可能是显然成立的原因(谁说loss的最小值一定是0?)
July 13th, 2022
K.infinity() 苏神,这个值在keras 2.3.1中没有啊,请问你是在哪个版本上跑的,话说这个值有pytorch替代版本吗?
1、安装并导入最新版本bert4keras;
2、在我这里不会有任何模型的pytorch实现,pytorch请自便。
July 21st, 2022
苏神,多标签之间的数据量相差很大会有问题吗,比如三个类别分别为35万,7万,3千
May 2nd, 2024
苏神,想问一下为什么二分类的交叉熵的软标签损失版本可以仍然用式(3)来表示,感觉明显不合理呀,有更好的表示方式吗
为什么不合理?它本质上就是两个分布的KL散度。