softmax函数比较简单,可以用如下公式表示
其中 C C 表示共有 C C 个类,即有 C C 个输出。并且一般将softmax的输出当做概率置信度结果,即
交叉熵的公式也很简单,对于两个向量 y,x y , x (其中 y y 表示真实的概率分布),他们的交叉熵可表示如下:
其中 p(xi) p ( x i ) 表示softmax的输出,认为是预测的概率分布。
在深度学习中,这二者常被联合使用,softmax常被用来将输出映射到0~1的概率值,而cross entropy则常被用来作为分类模型的损失函数,构成常见的softmax loss。
在softmax loss中需要注意的是数值稳定的问题。softmax loss存在数值下溢和上溢的问题,如果 ∀j,xj=c ∀ j , x j = c ,那么softmax的输出都一样 ∀j,softmax(xj)=1/n ∀ j , s o f t m a x ( x j ) = 1 / n 。但如果c很小,比如c=- 999999999999, 那么就可能因为计算机的舍入误差导致 ec=0 e c = 0 ,那么softmax函数的分母就等于0,就产生溢出,输出为nan,这就是下溢。同样,如果c特别大,比如 c=999999999999999 c = 999999999999999 ,那么 ec e c 就有可能等于无穷大,输出还是nan,那么就会上溢。不管是上溢还是下溢,都会出现Nan的情况,导致无法计算。那么怎么解决这个问题呢?
令 r=maxixi,zj=xj−r r = max i x i , z j = x j − r ,那么 zj≤0 z j ≤ 0 ,而且有 softmax(xj)=softmax(zj) s o f t m a x ( x j ) = s o f t m a x ( z j ) 。因为 ezj≤e0≤1 e z j ≤ e 0 ≤ 1 ,故不会出现上溢。而在分母中,至少包含一项 ezj=e0=1 e z j = e 0 = 1 ,故分母不会等于0,因此也就不会产生下溢。
那么就可以通过softmax的结果,计算cross entropy。但计算交叉熵的时候,会涉及到log算子,那么又有可能出现溢出的问题。如果softmax的输出结果 =0 = 0 ,那么就会导致需要计算 log(0) l o g ( 0 ) ,其等于负无穷,导致溢出。对于该溢出风险,只需在计算log时做一个等式变化,不要先计算出softmax,再计算log,而是将公式融在一起,并做相关变化,如下:
可以发现,做上述等式变换后,没有了除法,故前面谈到的softmax的分母下溢问题没有了,指数运算最大值为1,不存在上溢风险,log算子中的求和式子最小值为1,也不会出现溢出。
在tensorflow和caffe中,针对softmax的数值不稳定,也有相应的处理机制。单独的softmax层是数值不稳定的,会发生溢出,而在tensorflow中,tf.nn.softmax_cross_entropy_with_logits是数值稳定的,caffe中softmaxwithloss是数值稳定的。
另外一个需要提醒的问题是,在用softmax loss做分类时,真实的概率分布一般都是one-hot的编码,即只有一个值等于1,而其他值全都等于0,比如 [0,0,0,0,1,0,0] [ 0 , 0 , 0 , 0 , 1 , 0 , 0 ] ,那么cross entropy的多个求和项,只有一项是非0的,即one hot编码中非0项对应的输出概率。