1982年的Hopfiled网络首次将统计物理学的能量观点引入到神经网络中,html
将神经网络的全局最小值求解,近似认为是求解热力学系统的能量最低点(最稳定点)。编程
为此,特意为神经网络定义了神经网络能量函数$E(x|Label)$,其中$x$为输入。网络
$E(x|Label)=-\frac{1}{2}Wx \Delta Y \quad where \quad \Delta Y=y-label$ (省略Bias项)app
值得注意的是,这套山寨牌能量函数只能求出局部最小值,SVM用二次规划函数替换掉以后才能求全局最小值。框架
惟一的败笔是,Hopfiled网络的输出仍然采用了阶跃函数Sign,走的仍是Rosenblatt的老路子。机器学习
这个能量函数很是有趣,它在阶跃函数状态下永远是递减的,即使是W永远是正的。(错误的随机初始化也是OK的)。ide
缘由以下:函数
I、当阶跃函数输出为1时,Wx为正,若产生Loss,$\Delta Y=1-(-1)=2$,显然$\Delta YE(x|y)$为负。学习
II、当阶跃函数输出为-1时,Wx为负,若产生Loss,$\Delta Y=-1-(1)=-2$,显然$\Delta YE(x|y)$仍是为负。优化
III、若无LOSS,$\Delta Y=1-1$或$(-1)-(-1)$都为0,$\Delta E(x|y)$也为0。
祖师爷Hinton在1985年创立了第一个随机神经网络,首次将几率引入神经网络这个大玄学中。
值得一提的是,在当时几率图模型也是被公认为玄学之一,不少研究者认为,信几率还不如信神经网络。(今天却是反过来了)
Boltzmann机延续了Hopfiled能量函数的传统,可是用一个奇葩的归一化函数来产生几率,以取代相对不精确的阶跃函数。
这个归一化函数描述以下:
$P(y)=\frac{1}{1+e^{\frac{-(Wx+b)}{T}}}$
其中T为温度系数,超参数之一,须要调参。
看起来怎么那么眼熟呢,扔掉T以后,这不就是Sigmoid函数么。
能够看到,Boltzmann机为了表达几率,选用了Sigmoid函数做为神经网络的几率平滑产生器。
1986年由Smolensky创立的限制Boltzmann机将Hopfiled网络的输出部折回,这样就产生了多变量的输出。
如何去表达此时多变量状况下的几率,能量模型—配分函数(Partition Function)解决了这一点:
$P(x)=\frac{e^{-E(x)}}{Z}=\frac{e^{-E(x)}}{\sum _{i}e^{-E(i)}}$
配分项Z是你们耳熟能详的恶心之物,它的求解让深度学习推迟了20年。
在深度学习被卡的20年间,配分项函数在多变量的判别模型中普遍推广,疑似是Softmax的雏形。
在LeCun的EBM教程Slides的介绍了配分判别函数,也就是今天的Softmax函数。
★The partition function ensures that undesired answers are given low probability
★For learning, we need to approximate the partition function (or its gradient with respect to the parameters)
顺便将其批判了一番:
★Max likelihood learning gives high probability to good answers
★Problem: there are too many bad answers!
这部分的观点能够参照PRML的序章关于贝叶斯拟合学习的讨论,采用配分判别的Loss、基于极大似然的频统方法
很是容易产生过拟合和弱泛化,贝叶斯学习和深度学习则引入先验Prior在极大似然的统计基础上作惩罚。
配分判别函数的定义以下:
$P(Y|X)=\frac{e^{-\beta}E(Y,X)}{\int_{y\in Y}e^{-\beta}E(y,X)}$
其中$\beta$为系数,扔掉以后就是Softmax函数。
$NLL = - \sum _{i}^{examples}\sum _{k}^{classes}l(y(i)=k)\cdot log[Softmax(X_{k}^{i})]$
不作过多介绍,见个人早期博文:Softmax回归
前向传播求Loss的时候只要记住一点区别:
I、在Logistic回归中,对每一个样本,Loss-=$\log(1-Sigmoid)$或者Loss-=$\log(Sigmoid)$
II、在Softmax回归中,对每一个样本,Loss只减去对应Label的$\log(Softmax)$
比较I、II也能够看出来,Logistic回归的二选一只是Softmax回归的N选一的特例。
尽管DeepLearning的基石是多样本与并行计算,可是在泛型章节中不考虑多样本状况。
求导描述将尽可能与Caffe框架中的命名方式同步,以便于理解代码。
同时假定Softmax Axis上,命中Label的下标为k。
上图是在当单样本状况下,直接取Softmax Axis而画的,如今咱们假设这是一个N=3的分类问题。(0,1,2)
同时取Class=2做为当前样本,命中的Label,即k=2。
因为Loss只和命中的分类有关,有:
$Softmax(X_{k})=\frac{e^{X_{k}}}{\sum _{i}e^{X_{i}}}$
则NLL (Negative-Log-Likelihood)为:
$NLL=-\log(Softmax(X_{k}))=-\log(\frac{e^{X_{K}}}{\sum _{i}e^{X_{i}}})\\ \quad \\ \qquad \qquad \qquad \qquad \qquad \qquad \; \; \,=\log(\sum _{i}e^{X_{i}})-log(e^{X_{k}}) \\ \quad \\ \qquad \qquad \qquad \qquad \qquad \qquad \; \; \, =\log(\sum _{i}e^{X_{i}})-X_{k}$
此时对于神经元$X_{k}$,有以下两种求导方案:
I、 $BottomDiff(k)=\frac{\partial NLL}{\partial Softmax(X_{k})}\frac{\partial Softmax(X_{k})}{\partial X_{k}}$
II、 $BottomDiff(k)=\frac{\partial NLL}{\partial X_{k}}$
其中,第一种是没有必要的,通常而言,Softmax的中间导数几乎不会用到。
除非咱们让Softmax后面不接Loss,接其它的层,下一节会讲这种特殊状况,求导至关复杂。
如今考虑更通常的神经元$X_{i}$,对NLL求导:
$\frac{\partial \log(\sum _{i}e^{X_{i}})-X_{k}}{\partial X_{i}}=\left\{\begin{matrix}\frac{e^{X_{K}}}{\sum _{i}e^{X_{i}}} - 1 \quad (i\neq k) \\ \\\frac{e^{X_{K}}}{\sum _{i}e^{X_{i}}} \quad (i=k)\\ \\0 \quad (if \;ignore\;i)\end{matrix}\right.$
编程时:
对于①条件:先Copy一下Softmax的结果(即prob_data)到bottom_diff,再对k位置的unit减去1
对于②条件:直接Copy一下Softmax的结果(即prob_data)到bottom_diff
对于③条件:找到ignore位置的unit,强行置为0。
图示以下:
在SoftmaxLayer中,咱们将会遇到最广泛的反向传播任务:已知top_diff,求bottom_diff。
为了表述方便,设已知的top_diff的偏导表达式为:$\frac{\partial l}{Softmax(X)}$,则:
$BottomDiff(i)=\sum _{j}\frac{\partial l}{\partial Softmax(X_{j})}\frac{\partial Softmax(X_{j})}{\partial X_{i}}$
这是单独对Softmax求导的最麻烦之处,因为全链接性,输入神经元$X_{i}$将被所有的输出神经元污染。
更通常的,咱们将其写成:
$BottomDiff(i)=\frac{\partial l}{\partial Softmax(X)}\frac{\partial Softmax(X)}{\partial X_{i}}$。
考虑$\frac{\partial Softmax(X_{j})}{\partial X_{i}}$,有:
$\frac{\partial Softmax(X_{j})}{\partial X_{i}}=\left\{\begin{matrix}-Softmax(X_{j})*Softmax(X_{i})+Softmax(X_{i}) \quad i=j\\ \\ -Softmax(X_{j})*Softmax(X_{i}) \quad i\neq j\end{matrix}\right.$
联合两部分后,有:
$\sum \left\{\begin{matrix}-Softmax(X_{j})*\frac{\partial l}{\partial Softmax(X_{j})}*Softmax(X_{i})+Softmax(X_{i})*\frac{\partial l}{\partial Softmax(X_{j})} \quad i=j\\ \\ -Softmax(X_{j})*\frac{\partial l}{\partial Softmax(X_{j})}*Softmax(X_{i}) \quad i\neq j\end{matrix}\right.$
提取公共项部分:
$BottomDiff(i)=Softmax(X_{i})\left \langle \sum {j}\left \{-Softmax(X_{j})*\frac{\partial l}{\partial Softmax(X_{j})}\right \}+\frac{\partial l}{\partial Softmax(X_{i}) })\right \rangle\\ \quad \\ \qquad \qquad \qquad \; \; \; =TopData(i)\left \langle - \sum {j}\left \{TopData(j)*TopDiff(j)\right \}+TopDiff(i) \right \rangle\\ \quad \\ \qquad \qquad \qquad \; \; \; =TopData(i)\left \langle - \left \{TopData \bullet TopDiff \right \} +TopDiff(i) \right \rangle$
Caffe中作了如下两点额外的优化:
I、因为对全部$X_{i}$,都要计算相同的点积项$\sum {j}\left \{TopData(j)*TopDiff(j)\right \}$,
一个简单优化是用GEMM作一次矩阵广播,这样,对每一个样本的Softmax Axis轴上的多个单元,只需点积一次。
II、因为top_data与bottom_diff的shape相同,最外层top_data可基于全样原本乘,这在CUDA环境中,能够有效提高瞬时并行度。
Caffe中将二轴Softmax(Batchsize/Softmax)扩展到了nD轴Softmax,用于全卷积网络。
这部分代码由此paper两位做者Jonathan Long&Evan Shelhamer加入,Github的History以下:
空间Soffmax是为了Dense Pixel Prediction(密集点预测)而生的,对于一张300x500的输入图像,
一次Softmax将产生300*500=15W个Loss,这属于神经网络——像素级理解,是目前最难的CV任务。
空间Softmax取消了Softmax前的InnerProduct作的Flatten,由于必须保证空间轴信息。
一个语义分割的图示以下:
传统机器学习中的样本单数值Label,在ComputerVision中扩展为多数值Label后,即变成GroundTruth。
Caffe中采用如下格式来规范存储与读取:
对于GroundTruth的$outer:inner=(i,j)$位置,即第$i$个样本,空间$j$位置的Label,对应的Softmax向量以下:
$PixelExample=\left\{\begin{matrix}BottomData/BottomDiff(i*dim+0*inner+j) \quad class=0 \\
\quad \\ BottomData/BottomDiff(i*dim+1*inner+j) \quad class=1\\ \\ BottomData/BottomDiff(i*dim+2*inner+j) \quad class=2\\ \\...... \\ \\ BottomData/BottomDiff(i*dim+c*inner+j) \quad class=c\end{matrix}\right.$
这样,对于outer_num数量的输入图像,就变成了outer_num*inner_num个像素样本。
值得注意的是,目前最新的研究代表,在像素级的理解中,batch_size大于1是没有意义的,会严重减慢收敛速度。
输入单张图像时,SGD作密集点预测,不会致使偏离最终的局部最值点,由于15W的Loss近似能够当作batch_size=15,0000
从上节可知,空间轴(e.g. Height/Width)的引入,可当作是倍化了batch_size轴。
故在SoftmaxLayer中,对单样本图像的输入,须要多引入一次循环模拟多样本,循环量即inner_num。
对于泛型Softmax中的点积运算,由计算单点积值,须要变化至求一组$TopData \bullet TopDiff$:
一样设$outer:inner=(i,j)$,那么$j$位置的两组点积向量分别以下:
$\bullet \left\{\begin{matrix}TopData/TopDiff(i*dim+0*inner+j) \quad class=0\\ \\ .........\\ \\ TopData/TopDiff(i*dim+c*inner+j) \quad class=c\\ \end{matrix}\right.$
因为点积的元素每次都要跳跃inner_num个位置,可利用BLAS库作StridedDot运算,点积增量设为inner_num便可。
I、在GEMM矩阵广播优化中,原来只须要将单点积值广播成[classes,1]的矩阵,顺次在Softmax-Axis轴上减去,即:
从$TopDiff(i*dim)$的一段减去,因为无空间轴时,dim=classes,TopDiff的shape为[batch_size,classes],
矩阵的值刚好填充到下同样本的开头。
扩展空间轴时,则须要减去[classes,inner_num]个值,注意因为此时的shape为[batch_size,classes,inner_num],
若是你要线性覆盖,则须要先覆盖class=0的inner_num个值,因此必定要保证广播矩阵的shape为[classes,inner_num]。
而后再作一次向量减法。因为BLAS的GEMM运算支持$C=\beta C+\alpha AB $,可一步完成。
II、在最外围的top_data乘算中,因为top_data与bottom_diff的shape相同,扩展空间轴无需调整代码。