在訓練深度學習模型時,一個非常重要的超參數就是學習率,學習率設置的合理與否,非常影響模型的收斂速度和最終性能。本篇文章為大家總結了科學設置學習率的方法,建議大家閱讀收藏~
本文來自:https://zhuanlan.zhihu.com/p/332766013 已獲得授權轉載 。深度神經網絡的參數學習主要是通過梯度下降方法來尋找一組可以最小化結構風險的參數。而學習率在深度學習的訓練過程中是一個很重要的超參數,指導我們該如何通過損失函數的梯度調整網絡權重的超參數。學習率越低損失函數的變化速度就越慢。雖然使用低學習率可以確保我們不會錯過任何局部極小值,但也意味著我們將花費更長的時間來進行收斂,特別是在被困在高原區域的情況下。下面就是梯度下降法的公式:,其中 表示學習率。目前的各種優化算法本質上還是對梯度下降法的各種變形,所以我們還是以典型的梯度下降法來說明。借用下圖:
當學習率設置的較小,訓練收斂較慢,需要更多的epoch才能到達一個較好的局部最小值;
當學習率設置的較大,訓練可能會在接近局部最優的附件震蕩,無法更新到局部最優處;
當學習率設置的非常大,正如上一篇文章提到可能直接飛掉,權重變為NaN;
那麼如何去設置學習率這個超參數呢?總體上可以分為兩種:人工調整或策略調整。人工調整學習率一般是根據我們的經驗值進行嘗試,首先在整個訓練過程中學習率肯定不會設為一個固定的值,原因如上圖描述的設置大了得不到局部最優值,設置小了收斂太慢也容易過擬合。通常我們會嘗試性的將初始學習率設為:0.1,0.01,0.001,0.0001等來觀察網絡初始階段epoch的loss情況:如果訓練初期loss出現梯度爆炸或NaN這樣的情況(暫時排除其他原因引起的loss異常),說明初始學習率偏大,可以將初始學習率降低10倍再次嘗試;
如果訓練初期loss下降緩慢,說明初始學習率偏小,可以將初始學習率增加5倍或10倍再次嘗試;
如果訓練一段時間後loss下降緩慢或者出現震蕩現象,可能訓練進入到一個局部最小值或者鞍點附近。如果在局部最小值附近,需要降低學習率使訓練朝更精細的位置移動;如果處於鞍點附件,需要適當增加學習率使步長更大跳出鞍點。
如果網絡權重採用隨機初始化方式從頭學習,有時會因為任務複雜,初始學習率需要設置的比較小,否則很容易梯度飛掉帶來模型的不穩定(振蕩)。這種思想也叫做Warmup,在預熱的小學習率下,模型可以慢慢趨於穩定,等模型相對穩定後再選擇預先設置的學習率進行訓練,使得模型收斂速度變得更快,模型效果更佳。形狀如下:
這裡只說了如果設置學習率,至於學習率降低到什麼程序可以停止訓練,理論上訓練loss和驗證loss都達到最小的時候就可以了。這裡再說下去就是過擬合等內容,會再寫一篇詳細描述。策略調整學習率包括固定策略的學習率衰減和自適應學習率衰減,由於學習率如果連續衰減,不同的訓練數據就會有不同的學習率。當學習率衰減時,在相似的訓練數據下參數更新的速度也會放慢,就相當於減小了訓練數據對模型訓練結果的影響。為了使訓練數據集中的所有數據對模型訓練有相等的作用,通常是以epoch為單位衰減學習率。固定學習率衰減包括:
分段減緩:每N輪學習率減半或者在訓練過程中不同階段設置不同的學習率,便於更精細的調參。TF的接口函數為:global_step_op = tf.train.get_or_create_global_step()
base_learning_rate = 0.01
decay_boundaries = [2000, 4000] # 學習率衰減邊界;
learning_rate_value = [base_learning_rate, base_learning_rate/10., base_learning_rate/100.] # 不同階段對應學習率。
learning_rate = tf.train.piecewise_constant_decay(global_step_op, boundaries=decay_boundaries,values=learning_rate_value)
指數減緩:與分數減緩類似,只是採用指數形式做了表達, ,其中gamma表示指數的底(通常會設置為接近於1的數值,如0.95),隨著訓練批次epoch的增加,學習率呈指數下降。TF的接口函數為:
global_step_op = tf.train.get_or_create_global_step()
base_learning_rate = 0.01
decay_rate = 0.98
decay_steps = 2000
learning_rate_no_stair = tf.train.exponential_decay(learning_rate=base_learning_rate,
decay_rate=decay_rate,
decay_steps=decay_steps,
staircase=True,
global_step=global_step_op,
name="exponential_decay_use_stair")
# total_decay_step = 15000 總的學習率衰減步數
# base_learning_rate = 0.01 基學習率
# warmup_learning_rate = 0.0001 warm-up 學習率
# warmup_steps = 2000 warm-up 迭代次數
# hold_base_rate_steps_2000 = 2000 保持基學習率的步數
# hold_base_rate_steps_0 = 0
# alpha = 0.00001 最小學習率
global_step_op = tf.train.get_or_create_global_step()
learning_rate = cosine_decay_with_warmup(learning_rate_base=base_learning_rate,
total_decay_steps=total_decay_step,
alpha = alpha,
warmup_learning_rate=warmup_learning_rate,
warmup_steps=warmup_steps,
hold_base_rate_steps=hold_base_rate_steps_2000,
global_step=global_step_op)
def cosine_decay_with_warmup(global_step,
learning_rate_base,
total_decay_steps,
alpha = 0.0,
warmup_learning_rate=0.0,
warmup_steps=0,
hold_base_rate_steps=0):
"""Cosine decay schedule with warm up period.
In this schedule, the learning rate grows linearly from warmup_learning_rate
to learning_rate_base for warmup_steps, then transitions to a cosine decay
schedule."""
def eager_decay_rate():
"""Callable to compute the learning rate."""
learning_rate = tf.train.cosine_decay(learning_rate=learning_rate_base,
decay_steps=total_decay_steps - warmup_steps - hold_base_rate_steps,
global_step= global_step - warmup_steps - hold_base_rate_steps,
alpha=alpha)
if hold_base_rate_steps > 0:
learning_rate = tf.where(
global_step > warmup_steps + hold_base_rate_steps,
learning_rate, learning_rate_base)
if warmup_steps > 0:
if learning_rate_base < warmup_learning_rate:
raise ValueError('learning_rate_base must be larger or equal to '
'warmup_learning_rate.')
slope = (learning_rate_base - warmup_learning_rate) / warmup_steps
warmup_rate = slope * tf.cast(global_step,
tf.float32) + warmup_learning_rate
learning_rate = tf.where(global_step < warmup_steps, warmup_rate,
learning_rate)
return tf.where(global_step > total_decay_steps, alpha, learning_rate,
name='learning_rate')
if tf.executing_eagerly():
return eager_decay_rate
else:
return eager_decay_rate()
自適應學習率衰減包括:
AdaGrad、 RMSprop、 AdaDelta等。此處更偏向於優化算法,暫時不在該篇介紹。備註:推薦這篇文章「Cyclical Learning Rates for Training Neural Networks」介紹如何找到適合當前網絡的初始學習率。
歡迎掃描下方的二維碼添加小助手微信,邀請您加入我們的微信交流群。群裡有多位清北復交、BAT、AI獨角獸大牛和眾多深度學習er在一起愉快的交流技術,有任何問題,都可以諮詢大家,歡迎你的加入哦。