softmax雜談
在多分類問題中,我們可以使用 softmax 函數,對輸出的值歸一化為機率值。下面舉個例子:
上圖轉換為表達式:
????(0)=(????(0)0,????(0)1,⋯,????(0)9)????????(1)=(????(1)0,????(1)1,⋯,????(1)6)????????(2)=(????(2)0,????(2)1,⋯,????(2)4)????a(0)=(a0(0),a1(0),⋯,a9(0))Ta(1)=(a0(1),a1(1),⋯,a6(1))Ta(2)=(a0(2),a1(2),⋯,a4(2))T
對于任意的 0≤????≤20≤i≤2, 有前向傳播的表達式:
????(????+1)=????(????)????(????)+????(????)????(????+1)=????(????+1)(????(????+1))z(i+1)=W(i)a(i)+b(i)a(i+1)=f(i+1)(z(i+1))
其中,????(????)f(j) 表示激活函數,除了輸出層外,一般使用 ReLU 函數;????(????),????(????)W(i),b(i) 為模型參數。
如若我們有 ????m 個樣本 {????(????)}????????=1{x(j)}j=1m 組成的資料集 ????D, 稱 ????=(????(1),????(2),⋯,????(????))????X=(x(1),x(2),⋯,x(m))T 為資料集 ????D 的設計矩陣。
這樣,前向傳播可以改寫為:
{????(1+????)=????(????)????(0)+(????(????))????????(1+????)=????(1+????)(????(1+????)){Z(1+i)=Z(i)W(0)+(b(i))TA(1+i)=f(1+i)(Z(1+i))
????(????)=(????(????)1,????(????)2,⋯,????(????)????)????Z(i)=(z1(i),z2(i),⋯,zm(i))T, 這裡對 ????(????)z(i) 添加下标以差別不同的樣本;
這裡對列向量 ????(????)b(i) 進行了 broadcast 操作;
且 ????(0)=????Z(0)=X.
對于多分類問題,一般輸出層對應的激活函數的 softmax 函數:
求解 ????(2)A(2):
計算 ????????????=exp(????(1))exp=exp(Z(1));
對 ????????????exp 按列做歸一化, 便可得到 softmax(????(1))softmax(A(1)).
但如果輸入值較大或較小時,會出現記憶體溢出的現象:
一種簡單有效避免該問題的方法就是讓 exp(????????)exp(zj) 中的 ????????zj 替換為 ????????−max????{????????}zj−maxi{zi}, 由于 max????maxi 是個固定的常數,是以 exp(????????)exp(zj)的值沒有改變。但是,此時避免了溢出現象的出現。
當然這種做法也不是最完美的,因為 softmax 函數不可能産生 <code>0</code> 值,但這總比出現 <code>nan</code> 的結果好,并且真實的結果也是非常接近 00 的。
除此之外,還有一個問題:如果我們計算 logsoftmax(????????)logsoftmax(zj) 時,先計算 softmaxsoftmax 再将其傳遞給 loglog,會錯誤的得到 −∞−∞
最簡單的處理方式是直接加一個很小的常數:
為了解決此數值計算的不穩定,MXNet 提供了:
解決計算交叉熵時出現的數值不穩定的問題。