反向傳播之一:softmax函數

反向傳播之一:softmax函數

來自專欄反向傳播6 人贊了文章

不知道知乎怎麼預覽草稿,就先發布,邊寫邊改吧,反正我也沒有任何影響力

我目前的理解是:反向傳播是神經網路的精要,沒搞明白反向傳播,神經網路就還沒入門。

我的學習計劃是:

(1)推導一遍公式;

(2)寫一遍純numpy代碼;

(3)看一遍源碼。

本系列所有文章都不是原創,只是收集網上前期那些認真的牛人的文章於一處,手擼一遍推導,以求入門。於大家也是方便,於自己是一遍學習。


本文來源

帳號登錄?

blog.csdn.net

  1. softmax函數

egin{align} &設X=[x_1,x_2,cdots,x_n],Y=softmax(X)=[y_1,y_2,cdots,y_n]\&則y_i=frac{e^{x_i}}{sumlimits_{j=1}^{n}e^{x_j}},顯然sumlimits_{i=1}^ny_i=1 end{align}

例如:X=[2,3],則Y=softmax(X)=[frac{e^2}{e^2+e^3},frac{e^3}{e^2+e^3}]

numpy代碼:

import numpy as npdef softmax(x): x = np.exp(x)/np.sum(np.exp(x)) return xprint(softmax([2,3]))

結果:[ 0.26894142 0.73105858]

2.softmax函數求導 frac{partial y_i}{partial x_j}

(1)當 i=j

egin{align} frac{partial y_i}{partial x_j}&=frac{partial y_i}{partial x_i} \ &=frac{partial}{partial x_i}(frac{e^{x_i}}{sum_ke^{x_k}}) \&=frac{(e^{x_i})^{}(sum_ke^{x_k})-e^{x_i}(sum_ke^{x_k})^{}}{(sum_ke^{x_k})^2} \ &=frac{e^{x_i}cdot(sum_ke^{x_k})-e^{x_i}cdot e^{x_i}}{(sum_ke^{x_k})^2} \ &=frac{e^{x_i}cdot(sum_ke^{x_k})}{(sum_ke^{x_k})^2}-frac {e^{x_i}cdot e^{x_i}}{(sum_ke^{x_k})^2} \ &=frac{e^{x_i}}{sum_ke^{x_k}}-frac{e^{x_i}}{sum_ke^{x_k}}cdot frac{e^{x_i}}{sum_ke^{x_k}}\&=y_i-y_icdot y_i\&=y_i(1-y_i) end{align}

(2)當 i
e j

egin{aligned} frac{partial y_i}{partial x_j}&=frac{partial}{partial x_j}(frac{e^{x_i}}{sum_ke^{x_k}}) \&=frac{(e^{x_i})^{}(sum_ke^{x_k})-e^{x_i}(sum_ke^{x_k})^{}}{(sum_ke^{x_k})^2} \&=frac{0cdot(sum_ke^{x_k})-e^{x_i}cdot e^{x_j}}{(sum_ke^{x_k})^2} \&=frac{-e^{x_i}cdot e^{x_j}}{(sum_ke^{x_k})^2} \&=-frac{e^{x_i}}{sum_ke^{x_k}}cdot frac{e^{x_j}}{sum_ke^{x_k}}\&=-y_icdot y_j end{aligned}

綜上所述: frac{partial y_i}{partial x_j}=left{ egin{aligned} &=y_i-y_iy_i ,當i=j\ &= 0-y_icdot y_j , 當 i 
e j \ end{aligned} 
ight.

所以 frac{partial Y}{partial X}=diag(Y)-Y^Tcdot Y (當Y的shape為(1,n)時)

3.softmax 函數的一個性質

egin{align} & (1)softmax(X+c)=softmax(X)\ & end{align}

這裡X是向量,c是一個常數。下面證明左右兩邊的每一個分量相等。

egin{align} 證:softmax(X+c)_i&=frac{e^{x_i+c}}{sum_ke^{x_k+c}}\ &=frac{e^{x_i}cdot e^c}{sum_ke^{x_k}cdot e^c}\ &=frac{e^{x_i}}{sum_ke^{x_k}}\ &=softmax(X)_i end{align}

實際應用:為了防止溢出,事先把x減去最大值。最大值是有效數據,其他值溢不溢出可管不了,也不關心。

import numpy as npdef softmax(x): #減去最大值 x-=np.max(x) x = np.exp(x)/np.sum(np.exp(x)) return xprint(softmax([2,3]))

結果還是:[ 0.26894142 0.73105858]

4.作為中間層的激活函數

經過上面的討論,已經可以把softmax激活層的代碼寫出來:

class Softmax(object): def __init__(self): pass def forward(self, x): self.out = np.copy(x) self.out -= np.max(self.out) self.out = np.exp(self.out) s = np.sum(self.out) self.out= self.out / s return self.out def backward(self, eta): dout=np.diag(self.out)-np.dot(self.out,self.out.T) return np.dot(dout,eta)

結果怎樣呢?可以說是非常糟糕,開始表現還不錯,準確率可以衝到80%,但很快又回到原點。當然只要想想,一堆全部小於1的數不停的數乘來乘去,結果會怎樣!而且可以看出,它求導的計算量也非常大,所以softmax很特殊,沒有誰把它作為中間層的激活函數。都是放在最後一層,而且都是和交叉熵損失函數結合起來用。

5.softmax函數+交叉熵(log似然)代價函數

C=-sum_khat y_klog; y_k

這裡的 hat y_k 是真實值,是訓練的目標,取0或1.在求導的時候是常量。 y_k 是softmax函數的輸出值,是訓練結果,是變數。

egin{align} frac{partial C}{partial x_k} &=sum_ifrac{partial C}{partial y_i}cdot frac{partial y_i}{partial x_k} \ &=-sum_ifrac{partial}{partial y_i}(hat y_ilog;y_i) cdot frac{partial y_i}{partial x_k} \ &= -sum_ifrac{hat y_i}{y_i}cdot frac{partial y_i}{partial x_k} \ &=-frac{ hat y_k}{y_k}cdot frac{partial y_k}{partial x_k}-sum_{i
e k}frac{hat y_i}{y_i}cdot frac{partial y_i}{partial x_k} \ &=-frac{hat y_k}{y_k}cdot y_k(1-y_k)-sum_{i
e k}frac{hat y_i}{y_i}(-y_iy_k)\ &=-hat y_k+hat y_ky_k+sum_{i
e k}hat y_iy_k\ &=-hat y_k+sum_ihat y_iy_k\ &=-hat y_k+y_ksum_ihat y_i\ &=-hat y_k+y_k\ &=y_k-hat y_k end{align}

log似然代價函數C對每一個 x_i 求偏導,結果都是

frac{partial C}{partial x_i}=y_i-hat y_i

frac{partial C}{partial X}=Y-hat Y

當使用獨熱(onehot)編碼時, hat Y 只有一個位置為1,其他位置都是0。 hat Y也不需要用一個向量來存儲,只要 Y[i]=Y[i]-1 即可。

毫無疑問,這是一個無比優美的結果!!!

6.交叉熵是個什麼鬼?為什麼用交叉熵作為代價函數可以起到訓練作用?

簡單來說,訓練的目的是讓 Y=hat Y

但等於的可能性不大,至少 Y
ightarrowhat Y 趨近即可。

而交叉熵的最小值是信息熵,當 Y=hat Y 時,C就是信息熵。怎麼證明?後面有一篇專門談這個證明。

反過來講,當我們訓練使得C達到最小值的時候, Y 就逐步趨近於 hat Y 了。

就是說方法是求C的最小值,目的是Y 逐步趨近於 hat Y 。這個是個間接的關係。當然,其他損失函數也是這樣。

7.源碼:fmscole/backpropagation

推薦閱讀:

TAG:機器學習 | 深度學習DeepLearning | 神經網路 |