NLP(四十三)模型調(diào)參技巧之Warmup and Decay
??Warmup and Decay是深度學習中模型調(diào)參的常用trick。本文將簡單介紹Warmup and Decay以及如何在keras_bert中使用它們。
什么是warmup and decay?
??Warmup and Decay是模型訓練過程中,一種學習率(learning rate)的調(diào)整策略。
??Warmup是在ResNet論文中提到的一種學習率預熱的方法,它在訓練開始的時候先選擇使用一個較小的學習率,訓練了一些epoches或者steps(比如4個epoches,10000steps),再修改為預先設(shè)置的學習來進行訓練。
??同理,Decay是學習率衰減方法,它指定在訓練到一定epoches或者steps后,按照線性或者余弦函數(shù)等方式,將學習率降低至指定值。一般,使用Warmup and Decay,學習率會遵循從小到大,再減小的規(guī)律。
??由于剛開始訓練時,模型的權(quán)重(weights)是隨機初始化的,此時若選擇一個較大的學習率,可能帶來模型的不穩(wěn)定(振蕩),選擇Warmup預熱學習率的方式,可以使得開始訓練的幾個epoches或者一些steps內(nèi)學習率較小,在預熱的小學習率下,模型可以慢慢趨于穩(wěn)定,等模型相對穩(wěn)定后再選擇預先設(shè)置的學習率進行訓練,使得模型收斂速度變得更快,模型效果更佳。而當模型訓到一定階段后(比如10個epoch),模型的分布就已經(jīng)比較固定了,或者說能學到的新東西就比較少了。如果還沿用較大的學習率,就會破壞這種穩(wěn)定性,用我們通常的話說,就是已經(jīng)接近損失函數(shù)的局部最優(yōu)值點了,為了靠近這個局部最優(yōu)值點,我們就要慢慢來。
如何在keras_bert中使用Warmup and Decay?
??在keras_bert中,提供了優(yōu)化器AdamWarmup類,其參數(shù)定義如下:
class AdamWarmup(keras.optimizers.Optimizer):
"""Adam optimizer with warmup.
Default parameters follow those provided in the original paper.
# Arguments
decay_steps: Learning rate will decay linearly to zero in decay steps.
warmup_steps: Learning rate will increase linearly to lr in first warmup steps.
learning_rate: float >= 0. Learning rate.
beta_1: float, 0 < beta < 1. Generally close to 1.
beta_2: float, 0 < beta < 1. Generally close to 1.
epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
weight_decay: float >= 0. Weight decay.
weight_decay_pattern: A list of strings. The substring of weight names to be decayed.
All weights will be decayed if it is None.
amsgrad: boolean. Whether to apply the AMSGrad variant of this
algorithm from the paper "On the Convergence of Adam and
Beyond".
"""
def __init__(self, decay_steps, warmup_steps, min_lr=0.0,
learning_rate=0.001, beta_1=0.9, beta_2=0.999,
epsilon=None, weight_decay=0., weight_decay_pattern=None,
amsgrad=False, **kwargs):
在這個類中,我們需要指定decay_steps,warmup_steps,learning_rate,min_lr,其含義為模型在訓練warmup_steps后,將學習率逐漸增加至learning_rate,在訓練decay_steps后,將學習率逐漸線性地降低至min_lr。
??以下為Warmup預熱學習率以及學習率預熱完成后衰減(sin or exp decay)的曲線圖:

??在keras_bert的官方文檔中,給出了使用Warmup and Decay的代碼例子,如下:
import numpy as np
from keras_bert import AdamWarmup, calc_train_steps
train_x = np.random.standard_normal((1024, 100))
total_steps, warmup_steps = calc_train_steps(
num_example=train_x.shape[0],
batch_size=32,
epochs=10,
warmup_proportion=0.1,
)
optimizer = AdamWarmup(total_steps, warmup_steps, lr=1e-3, min_lr=1e-5)
Warmup and Decay實戰(zhàn)
??筆者在文章NLP(三十四)使用keras-bert實現(xiàn)序列標注任務(wù)中,在使用keras-bert訓練 序列標注模型時,學習率調(diào)整策略使用了ReduceLROnPlateau,代碼如下:
reduce_lr = ReduceLROnPlateau(monitor='val_loss', min_delta=0.0004, patience=2, factor=0.1, min_lr=1e-6,
mode='auto',
verbose=1)
在三個數(shù)據(jù)集上的評估結(jié)果如下:
人民日報命名實體識別數(shù)據(jù)集:micro avg F1=0.9182
時間識別數(shù)據(jù)集:micro avg F1=0.8587
CLUENER細粒度實體識別數(shù)據(jù)集:micro avg F1=0.7603
??我們將學習率調(diào)整策略修改為Warmup and Decay(模型其他參數(shù)不變,數(shù)據(jù)集不變),代碼如下:
# add warmup
total_steps, warmup_steps = calc_train_steps(
num_example=len(input_train),
batch_size=BATCH_SIZE,
epochs=EPOCH,
warmup_proportion=0.2,
)
optimizer = AdamWarmup(total_steps, warmup_steps, lr=1e-4, min_lr=1e-7)
model = BertBilstmCRF(max_seq_length=MAX_SEQ_LEN, lstm_dim=64).create_model()
model.compile(
optimizer=optimizer,
loss=crf_loss,
metrics=[crf_accuracy]
)
使用該trick,在三個數(shù)據(jù)集上的評估結(jié)果如下:
人民日報命名實體識別數(shù)據(jù)集
| 學習率調(diào)整 | 預測1 | 預測2 | 預測3 | avg |
|---|---|---|---|---|
| Warmup | 0.9276 | 0.9217 | 0.9252 | 0.9248 |
時間識別數(shù)據(jù)集
| 學習率調(diào)整 | 預測1 | 預測2 | 預測3 | avg |
|---|---|---|---|---|
| Warmup | 0.8926 | 0.8934 | 0.8820 | 0.8893 |
CLUENER細粒度實體識別數(shù)據(jù)集
| 學習率調(diào)整 | 預測1 | 預測2 | 預測3 | avg |
|---|---|---|---|---|
| Warmup | 0.7612 | 0.7629 | 0.7607 | 0.7616 |
可以看到,使用了Warmup and Decay,模型在不同的數(shù)據(jù)集上均有不同程度的效果提升。
??本項目已經(jīng)開源,代碼地址為:https://github.com/percent4/keras_bert_sequence_labeling 。
??本文到此結(jié)束,感謝大家的閱讀~
??2021年3月27日于上海浦東~
