本文介紹在tensorflow
庫中,用於動態調整神經網路的學習率的一種方法——指數衰減ExponentialDecay()
策略的引數含義及其具體用法。
在進行神經網路訓練時,我們經常需要用到動態變化的學習率,其中指數衰減ExponentialDecay()
策略是我們常用的一種策略。在tensorflow
庫中,其完整的用法是tf.keras.optimizers.schedules.ExponentialDecay()
,其中的具體引數如下所示。
tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate, decay_steps, decay_rate, staircase=False, name=None
)
首先,我們需要知道,在用了ExponentialDecay()
策略後,程式將動態調整神經網路訓練過程中的學習率,且這一調整是與我們當前訓練的step
有關的。具體關於step
的解釋,大家可以參考文章神經網路常見引數解釋:epoch、batch、batch size、step、iteration,本文就不再贅述。
如以下程式碼所示,使用ExponentialDecay()
策略後,程式將依據如下的規律,基於當前訓練的step
,以及我們自行設定的幾個引數,從而計算得到當前的學習率。其中,函式的返回值就是當前的學習率。
def decayed_learning_rate(step):
return initial_learning_rate * decay_rate ^ (step / decay_steps)
其中,initial_learning_rate * decay_rate ^ (step / decay_steps)
就是當前學習率的計算公式。這裡的initial_learning_rate
、decay_rate
以及decay_steps
,就是我們前面提到的ExponentialDecay()
函式的前3
個引數。其中,initial_learning_rate
是我們的初始學習率,decay_rate
是學習率下降的速率,而decay_steps
則是學習率下降的位置(具體含義我們稍後介紹)。此外,ExponentialDecay()
策略還有兩個引數,staircase
表示我們在計算(step / decay_steps)
時,是對結果向下取整還是取小數,預設為False
,即取小數結果(具體含義我們稍後介紹);最後一個name
引數,只是對當前這一學習率下降的策略加以命名,一般用不上這個引數,我們就不再介紹了。
由此,我們可以初步知道,ExponentialDecay()
函式的前4
個引數都是用來計算當前的學習率的;且結合我們前面的公式initial_learning_rate * decay_rate ^ (step / decay_steps)
,我們可以知道,隨著當前的step
不斷增加,decay_rate ^ (step / decay_steps)
是降低的。
接下來,我們直接帶入具體的資料,來看一下這幾個引數的具體作用。
如下圖所示,我們這裡有一個訓練資料集,其中共有193608
個樣本。
同時,我設定了神經網路的batch size
為2048
,那麼基於前述提及的文章神經網路常見引數解釋:epoch、batch、batch size、step、iteration,可知在1
個epoch
中,我們對這193608
個樣本加以訓練,共需要的batch
數目為193608 / 2048
,也就是94.54
,向上取整為95
,相當於需要95
個step
。此外,我設定initial_learning_rate
、decay_rate
以及decay_steps
分別為0.1
、0.95
以及95
,且設定staircase
為True
。如下圖所示。
此時,我們就可以對每一個引數的具體含義與作用加以介紹了。首先,我們開始訓練神經網路模型,即step
開始從0
逐步增加;但是由於我的staircase
為True
,因此只要指數(step / decay_steps)
是小於1
的,那麼都視作0
(因為當前引數設定是對結果向下取整);而由於除了0
以外任何數的0
次方都是1
,因此此時的公式initial_learning_rate * decay_rate ^ (step / decay_steps)
始終等於initial_learning_rate
,也就是一直保持0.1
;只有當step
到達我們設定的decay_steps
之後,指數(step / decay_steps)
才可以成為1
,使得decay_rate
終於產生了效果。而在這裡,由於我故意設定decay_steps
為95
,因此按道理只要經過1
個epoch
之後,學習率就會下降——因為前面我們計算過了,在1
個epoch
中需要95
個step
。那麼此時,學習率就變為了0.1 * 0.95
。
接下來,我們執行上述程式碼,訓練6
個epoch
,來驗證一下學習率的變化是否如同我們的設想。
下圖為TensorBoard
中,學習率隨著epoch
的變化。這裡需要注意,我這裡截圖的時候開了曲線圖的平滑選項,因此應該以淺色的線為準。
上面的圖因為不太全,所以或許看不出什麼;我們直接將學習率變化情況匯出,如下圖所示。
其中,圖中的step
實際上表示的是epoch
,大家這裡理解即可。可以看到,在epoch
為0
時(也就是進行第一個epoch
時),學習率一直為0.1
;而進行到第二個epoch
時——此時我們訓練過程的step
就應該是從95
開始,但還不到190
,因此(step / decay_steps)
始終為1
,學習率就是0.1 * 0.95 = 0.095
了(因為資料格式問題,精度稍有差距);隨後,進行到第三個epoch
時——此時我們訓練過程的step
就應該是從190
開始,但還不到285
,因此(step / decay_steps)
始終為2
,學習率就已經是0.1 * 0.95 * 0.95 = 0.09025
了。
由此可知,假如我將decay_steps
擴大10
倍,使得其為950
,那麼在前10
個epoch
時,學習率都不會發生改變,而從第11
個epoch
開始,學習率才會開始衰減。
這裡我的引數staircase
設定為True
,因此會出現上述結果;相反的,如果設定為False
,那麼計算(step / decay_steps)
時,是對結果取小數,換句話說只要step
發生變化,那麼當前對應的學習率也會發生變化,只不過變化的幅度會稍小一些。
由此看到,上述學習率的變化,是符合我們的預期的。當然,上圖中最後兩個epoch
對應的學習率沒有發生變化,這個具體原因我暫時也沒搞清楚;不過學習率下降作為一種策略,我們透過上述程式碼,還是達到了動態調整學習率的需求的。
至此,大功告成。