函数光滑化杂谈:不可导函数的可导逼近
By 苏剑林 | 2019-05-20 | 126060位读者 |一般来说,神经网络处理的东西都是连续的浮点数,标准的输出也是连续型的数字。但实际问题中,我们很多时候都需要一个离散的结果,比如分类问题中我们希望输出正确的类别,“类别”是离散的,“类别的概率”才是连续的;又比如我们很多任务的评测指标实际上都是离散的,比如分类问题的正确率和F1、机器翻译中的BLEU,等等。
还是以分类问题为例,常见的评测指标是正确率,而常见的损失函数是交叉熵。交叉熵的降低与正确率的提升确实会有一定的关联,但它们不是绝对的单调相关关系。换句话说,交叉熵下降了,正确率不一定上升。显然,如果能用正确率的相反数做损失函数,那是最理想的,但正确率是不可导的(涉及到$\text{argmax}$等操作),所以没法直接用。
这时候一般有两种解决方案;一是动用强化学习,将正确率设为奖励函数,这是“用牛刀杀鸡”的方案;另外一种是试图给正确率找一个光滑可导的近似公式。本文就来探讨一下常见的不可导函数的光滑近似,有时候我们称之为“光滑化”,有时候我们也称之为“软化”。
max #
后面谈到的大部分内容,基础点就是$\max$操作的光滑近似,我们有:
\begin{equation}\max(x_1,x_2,\dots,x_n) = \lim_{K\to +\infty}\frac{1}{K}\log\left(\sum_{i=1}^n e^{K x_i}\right)\end{equation}
所以选定常数$K$,我们就有近似:
\begin{equation}\max(x_1,x_2,\dots,x_n) \approx \frac{1}{K}\log\left(\sum_{i=1}^n e^{K x_i}\right)\end{equation}
在模型中,很多时候可以设$K=1$,这等价于把$K$融合到模型自身之中,所以最简单地有:
\begin{equation}\begin{aligned}\max(x_1,x_2,\dots,x_n) \approx&\, \log\left(\sum_{i=1}^n e^{x_i}\right) \\
\triangleq&\, \text{logsumexp}(x_1, x_2, \dots, x_n)\end{aligned}\label{eq:max-approx}\end{equation}
这里出现了$\text{logsumexp}$,这是一个很常见的算子,在这里它是$\max$函数的光滑近似。没错,$\max$函数的光滑近似其实是$\text{logsumexp}$,而不是字面上很像的$\text{softmax}$。相关推导还可以参考我之前写的《寻求一个光滑的最大值函数》。
softmax #
刚才说$\text{softmax}$不是$\max$的光滑近似,那它是谁的光滑近似呢?它事实上是$\text{onehot}(\text{argmax}(\boldsymbol{x}))$的光滑近似,即先求出最大值所在的位置,然后生成一个等长的向量,最大值那一位置1,其它位置都置0,比如:
\begin{equation}[2, 1, 4, 5, 3]\quad \to \quad [0, 0, 0, 1, 0]\end{equation}
我们可以简单地给出一个从$\text{logsumexp}$到$\text{softmax}$的推导过程。考虑向量$\boldsymbol{x}=[x_1, x_2, \dots, x_n]$,然后考虑
\begin{equation}\boldsymbol{x}'=[x_1, x_2, \dots, x_n] - \max(x_1, x_2, \dots, x_n)\end{equation}
即每一位都减去整体的最大值,这样的新向量与原向量最大值所在的位置是一样的,即$\text{onehot}(\text{argmax}(\boldsymbol{x}))=\text{onehot}(\text{argmax}(\boldsymbol{x}'))$。不失一般性,考虑$x_1,x_2,\dots,x_n$两两不相等的情况,那么新向量的最大值显然为0,并且除去最大值外,其余各位都是负数。这样一来,我们可以考虑
\begin{equation}e^{\boldsymbol{x}'}=[e^{x_1 - \max(x_1, x_2, \dots, x_n)}, e^{x_2 - \max(x_1, x_2, \dots, x_n)}, \dots, e^{x_n - \max(x_1, x_2, \dots, x_n)}]\end{equation}
作为$\text{onehot}(\text{argmax}(\boldsymbol{x}'))$的近似,因为最大值为0,所以对应的位置是$e^0=1$,而其余为负,取指数后会比较接近于0。
最后将近似$\eqref{eq:max-approx}$代入上式,化简,就可以得到
\begin{equation}\begin{aligned}\text{onehot}(\text{argmax}(\boldsymbol{x}))=&\,\text{onehot}(\text{argmax}(\boldsymbol{x}'))\\
\approx&\, \left(\frac{e^{x_1}}{\sum\limits_{i=1}^n e^{x_i}}, \frac{e^{x_2}}{\sum\limits_{i=1}^n e^{x_i}}, \dots, \frac{e^{x_n}}{\sum\limits_{i=1}^n e^{x_i}}\right)\\
\triangleq&\,\text{softmax}(x_1, x_2, \dots, x_n)
\end{aligned}\end{equation}
argmax #
$\text{argmax}$是指直接给出向量最大值所在的下标(一个整数),比如
\begin{equation}[2, 1, 4, 5, 3]\quad \to \quad 4\end{equation}
这里我们遵循平时的使用习惯,下标是从1开始的,所以返回结果是4;但在编程语言中一般是从0开始的,所以在编程语言中返回结果一般是3。
如果是$\text{argmax}$的光滑近似,自然是希望输出一个接近4的浮点数。为了构造这样的近似,我们先观察到$\text{argmax}$实际上等于
\begin{equation}\text{sum}\Big(\underbrace{[1, 2, 3, 4, 5]}_{\text{序向量[1, 2, ..., n]}}\,\, \otimes\,\,\underbrace{[0, 0, 0, 1, 0]}_{\text{onehot}(\text{argmax}(\boldsymbol{x}))}\Big)\end{equation}
即数组$[1, 2, \dots, n]$与$\text{onehot}(\text{argmax}(\boldsymbol{x}))$的内积。那构造$\text{argmax}$的软化版就简单了,将$\text{onehot}(\text{argmax}(\boldsymbol{x}))$换成$\text{softmax}(\boldsymbol{x})$就行了,即
\begin{equation}\text{argmax} (\boldsymbol{x}) \approx \sum_{i=1}^n i\times \text{softmax}(\boldsymbol{x})_i\end{equation}
正确率 #
上述讨论的若干个近似,基本都是在one hot向量的基础上推导出正确形式,然后用softmax近似one hot,从而得到光滑近似。用这种思想,还可以导出很多算子的光滑近似,比如正确率。
简单起见,引入记号$\boldsymbol{1}_k$,它表示第$k$位为1的one hot向量。假设在分类问题中,目标类别是$i$,预测类别是$j$,那么可以考虑one hot向量$\boldsymbol{1}_i$和$\boldsymbol{1}_j$,然后考虑内积
\begin{equation}\langle \boldsymbol{1}_i, \boldsymbol{1}_j\rangle = \left\{\begin{aligned}&1,\,\,(i=j)\\ &0,\,\,(i\neq j)\end{aligned}\right.\end{equation}
也就是说两个类别一样时,内积刚好为1,而两个类别不一样时,内积刚好为0,所以目标类别和预测类别对应的one hot向量的内积,刚好定义了一个“预测正确”的计数函数,而有了计数函数,就可以计算正确率:
\begin{equation}\text{正确率}=\frac{1}{|\mathcal{B}|}\sum_{\boldsymbol{x}\in\mathcal{B}}\langle \boldsymbol{1}_i(\boldsymbol{x}), \boldsymbol{1}_j(\boldsymbol{x})\rangle\end{equation}
其中$\mathcal{B}$表示当前batch,上式正是计算一个batch内正确率的函数。而在神经网络中,为了保证可导性,最后的输出只能是一个概率分布(softmax后的结果),所以正确率的光滑近似,就是将预测类别的one hot向量,换成概率分布:
\begin{equation}\text{正确率}\approx \frac{1}{|\mathcal{B}|}\sum_{\boldsymbol{x}\in\mathcal{B}}\langle \boldsymbol{1}_i(\boldsymbol{x}), p(\boldsymbol{x})\rangle\end{equation}
类似地,可以导出recall、f1等指标的光滑近似。以二分类为例,假设$p(\boldsymbol{x})$是正类的概率,$t(\boldsymbol{x})$是样本$\boldsymbol{x}$的标签(0或1),则正类的f1的光滑近似是:
\begin{equation}\text{正类F1}\approx\frac{2 \sum\limits_{\boldsymbol{x}\in\mathcal{B}}t(\boldsymbol{x}) p(\boldsymbol{x})}{\sum\limits_{\boldsymbol{x}\in\mathcal{B}}\big[t(\boldsymbol{x}) + p(\boldsymbol{x})\big]}\end{equation}
这样导出来的正确率近似公式是可导的,可以直接将它的相反数作为loss。但事实上在采样估计过程中,它是f1的有偏估计(分母也有对batch的求和),有时候会影响优化轨迹甚至导致发散,所以一般情况下最好不要直接用,而是先用普通的交叉熵训练到差不多了,然后再用f1的相反数作为loss来微调。
softkmax #
$\text{softmax}$是“最大值那一位置1、其余置0”的光滑近似,那如果是“最大的$k$个值的位置都置1、其余置0”的光滑近似呢?我们可以称之为$\text{soft-}k\text{-max}$。
我没有构造出$\text{soft-}k\text{-max}$的简单形式,但可以利用递归地构造出来:
输入为$\boldsymbol{x}$,初始化$\boldsymbol{p}^{(0)}$为全0向量;
执行$\boldsymbol{x} = \boldsymbol{x} - \min(\boldsymbol{x})$(保证所有元素非负)对于$i=1,2,\dots,k$,执行:
$\boldsymbol{y} = (1 - \boldsymbol{p}^{(i-1)})\otimes\boldsymbol{x}$;
$\boldsymbol{p}^{(i)} = \boldsymbol{p}^{(i-1)} + \text{softmax}(\boldsymbol{y})$返回$\boldsymbol{p}^{(k)}$。
至于原理,将$\text{softmax}(\boldsymbol{y})$换成$\text{onehot}(\text{argmax}(\boldsymbol{y}))$然后递归下去就明白了,其实就是先$\max$,然后把将$\max$那一位减掉,这样次最大值就变成了最大值,然后重新$\text{softmax}$,递归下去即可。
总结 #
函数光滑化是一个比较有意思的数学内容,在机器学习中也经常出现。一方面,它是处理将某些操作可导化的技巧,使得模型可以直接使用反向传播求解,而不需要“动用”强化学习;另一方面,在某些情况下它也能增强模型的解释性,因为往往对应的不可导函数解释性是比较好的,将光滑化版本代入训练完成后,也许可能恢复为不可导版本来解释模型的输出结果。
当然,作为纯粹的数学之美来欣赏,也是相当赏心悦目的~
转载到请包括本文地址:https://kexue.fm/archives/6620
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (May. 20, 2019). 《函数光滑化杂谈:不可导函数的可导逼近 》[Blog post]. Retrieved from https://kexue.fm/archives/6620
@online{kexuefm-6620,
title={函数光滑化杂谈:不可导函数的可导逼近},
author={苏剑林},
year={2019},
month={May},
url={\url{https://kexue.fm/archives/6620}},
}
May 20th, 2019
正确率的损失,能给一个实验demo吗
同名啊。。老哥
May 26th, 2019
有一个Gumbel-Softmax,也是这种效果。大神可以讲讲。
CATEGORICAL REPARAMETERIZATION WITH GUMBEL-SOFTMAX
确实对它有兴趣,待我认真读读再写~
May 28th, 2019
如果这样的话,用以下公式
\begin{equation}\begin{aligned}
\left(\frac{e^{2x_1}}{\sum\limits_{i=1}^n e^{2x_i}}, \frac{e^{2x_2}}{\sum\limits_{i=1}^n e^{2x_i}}, \dots, \frac{e^{2x_n}}{\sum\limits_{i=1}^n e^{2x_i}}\right)\\
\end{aligned}\end{equation}
代替$softmax$会不会效果更好,因为更接近$onehot(argmax)$的近似
不是说了吗,很多时候$x$也是学习而来的,直接设$K=1$,相当于让模型自己决定$K$的大小。
您好,可以给一些有关这篇文章引用吗?有一些数学概念没看明白。谢谢!
没有参考文献,不知道哪个概念不明白?本文的介绍已经很基础了啊~
November 21st, 2019
能不能分享下召回率的光滑化结果。。。我推导出来感觉和正确率的一样。。。
召回率、F1这些,都是相对于单个类来说的,$(14)$已经给出了F1的近似,所以可以很自然给出precision和recall的近似:
$$\text{正类precision}\approx\frac{\sum\limits_{\boldsymbol{x}\in\mathcal{B}}t(\boldsymbol{x}) p(\boldsymbol{x})}{\sum\limits_{\boldsymbol{x}\in\mathcal{B}}\big[p(\boldsymbol{x})\big]}\qquad
\text{正类recall}\approx\frac{\sum\limits_{\boldsymbol{x}\in\mathcal{B}}t(\boldsymbol{x}) p(\boldsymbol{x})}{\sum\limits_{\boldsymbol{x}\in\mathcal{B}}\big[t(\boldsymbol{x})\big]}$$
您好,这种平滑近似请问要如何实现呢?我理解代码实现涉及到要判断一个样本是否是正类,就需要argmax函数,是不是意味着实现它们需要用到argmax函数的光滑近似?有没有源码分享下,谢谢!
像$(14)$式本身就已经是实现,至于参考源码,没有~
多分类情况要将argmax用one hot代替,然后转化为softmax。
这是我尝试以负正确率作为损失函数的代码实现,不知道为何效果不好,是不是实现有问题,烦请指教一下。
def neg_accuracy_loss(y_true, y_pred):
mul=tf.multiply(y_true,y_pred)
sum=tf.reduce_sum(mul)
total=tf.shape(y_true)[0]
total=tf.cast(total,"float32")
return tf.math.divide(sum,total)*(-1.0)
实现倒是没什么问题,但是你要注意一点,直接优化指标只是一个途径,但它未必是最好的途径,通常来说只是用于后期微调,前期还是用交叉熵居多。
参考:https://kexue.fm/archives/7708
你好,式子(6)的精度不太够,感觉加个n次方更好一些。
你随意。
March 8th, 2020
我的理解,这里正确率的光滑化之后感觉只有正样例在起作用,因为负样例为的标签是0,与预测的概率相乘也是0,所以负样例的预测概率无论是多少感觉都是无所谓的,这里感觉可以将负样例的标签更换为-1,这样光滑出来的正确率更符合定义,否则的话感觉更像精确率光滑化之后的结果。求大神解答一下疑问。
理解不正确。公式$(13)$用于任意多分类问题,多分类里边没什么正样例的说法,每个类都是平等的,用独自的one hot表示,公式里的$\boldsymbol{1}_i(\boldsymbol{x})$是one hot向量,$p(\boldsymbol{x})$是预测的概率分布向量。
原来如此,明白了,感谢大神解惑
这样的话,和交叉熵有什么区别呢?
谁跟交叉熵有什么区别?
jianjiu17可能问的是公式(13)和CrossEntropy的区别。
差在交叉熵是用 log p(x) 而不是 p(x)吧?
March 14th, 2020
这是我看过最好的关于softmax和one hot由来的文章,知道正态分布的重参数技巧,但分类离散分布如何采样,理解为什么要Gumbel-max 再到Gumbel softmax,这篇文章说到了本质,非常感谢!作者其他博客也非常精彩!
客气了~谢谢捧场。
April 6th, 2020
请问公式(9),内积本身就是求和了,还要外层写Sum吗?谢谢!
一般来说$\otimes$并不是表示内积,它只表示逐位相乘,它的结果仍然是一个向量,比如$[a,b]\otimes[c,d]=[ac,bd]$
July 20th, 2020
总觉得公式$(10)$过于简单粗暴,因为这么算即使和实际标签接近(比如$(10)$算出来5.6,实际标签是5),那么也会造成严重错误(5.6->6,标签6和标签5或许是质的差别)。
在下愚见,公式(10)考虑的似乎是$\text{argmax}$的下标而非类标,用$\text{onehot(argmax}(x))$进行分类似乎更合适。
不是很理解你的焦点。$(10)$式本来就是用来回归位置的,并不是用来预测类别的。
September 3rd, 2020
我感觉F1那里不能理解啊。。∑x∈Bt(x)p(x)是否应该是TP+TN呢,不应该是TP啊
否。
April 12th, 2022
[...]softmax(τx),τ→0 如果需要具体解释,参考《函数光滑化杂谈:不可导函数的可导逼近》。[...]