有效防止softmax計算時上溢出(overflow)和下溢出(underflow)的方法


Deep Learning》(Ian Goodfellow & Yoshua Bengio & Aaron Courville)第四章「數值計算」中,談到了上溢出(overflow)和下溢出(underflow)對數值計算的影響,並以softmax函數和log softmax函數為例進行了講解。這里我再詳細地把它總結一下。

『1』什么是下溢出(underflow)和上溢出(overflow)

  實數在計算機內用二進制表示,所以不是一個精確值,當數值過小的時候,被四舍五入為0,這就是下溢出。此時如果對這個數再做某些運算(例如除以它)就會出問題。反之,當數值過大的時候,情況就變成了上溢出。

『2』softmax函數是什么

softmax函數如下:

從公式上看含義不是特別清晰,所以借用知乎上的一幅圖來說明(感謝原作者):

 

這幅圖極其清晰地表明了softmax函數是什么,一圖勝千言。

『3』計算softmax函數值的問題

  通常情況下,計算softmax函數值不會出現什么問題,例如,當softmax函數表達式里的所有 xi 都是一個“一般大小”的數值 c 時——也就是上圖中, z1=z2=z3=c  時,那么,計算出來的函數值y1=y2=y3=1/3 。
但是,當某些情況發生時,計算函數值就出問題了:

  • c 極其大,導致分子計算 ec 時上溢出
  • c 為負數,且  |c| 很大,此時分母是一個極小的正數,有可能四舍五入為0,導致下溢出

『4』如何解決

所以怎樣規避這些問題呢?我們可以用同一個方法一口氣解決倆:
令  M=max(xi),i=1,2,,n ,即 M 為所有 xi 中最大的值,那么我們只需要把計算 f(xi)的值,改為計算  f(xiM) 的值,就可以解決上溢出、下溢出的問題了,並且,計算結果理論上仍然和 f(xi)保持一致。
舉個實例:還是以前面的圖為例,本來我們計算  f(z2) ,是用“常規”方法來算的:

現在我們改成:

其中, M=3 是  z1,z2,z3 中的最大值。可見計算結果並未改變。這是怎么做到的呢?通過簡單的代數運算就可以參透其中的“秘密”:

  通過這樣的變換,對任何一個 xi,減去M之后,e 的指數的最大值為0,所以不會發生上溢出;同時,分母中也至少會包含一個值為1的項,所以分母也不會下溢出(四舍五入為0)。所以這個技巧沒什么高級的技術含量。

『5』延伸問題

  看似已經結案了,但仍然有一個問題:如果softmax函數中的分子發生下溢出,也就是前面所說的 c 為負數,且 |c| 很大,此時分母是一個極小的正數,有可能四舍五入為0的情況,此時,如果我們把softmax函數的計算結果再拿去計算 log,即 log softmax,其實就相當於計算  log(0) ,所以會得到  ,但這實際上是錯誤的,因為它是由舍入誤差造成的計算錯誤。所以,有沒有一個方法,可以把這個問題也解決掉呢?
  答案還是采用和前面類似的策略來計算 log softmax 函數值:

  大家看到,在最后的表達式中,會產生下溢出的因素已經被消除掉了——求和項中,至少有一項的值為1,這使得log后面的值不會下溢出,也就不會發生計算 log(0) 的悲劇。在很多數值計算的library中,都采用了此類方法來保持數值穩定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM