NLP(四十三)模型調(diào)參技巧之Warmup and Decay
??Warmup and Decay是深度學(xué)習(xí)中模型調(diào)參的常用trick。本文將簡單介紹Warmup and Decay以及如何在keras_bert中使用它們。
什么是warmup and decay?
??Warmup and Decay是模型訓(xùn)練過程中,一種學(xué)習(xí)率(learning rate)的調(diào)整策略。
??Warmup是在ResNet論文中提到的一種學(xué)習(xí)率預(yù)熱的方法,它在訓(xùn)練開始的時(shí)候先選擇使用一個(gè)較小的學(xué)習(xí)率,訓(xùn)練了一些epoches或者steps(比如4個(gè)epoches,10000steps),再修改為預(yù)先設(shè)置的學(xué)習(xí)來進(jìn)行訓(xùn)練。
??同理,Decay是學(xué)習(xí)率衰減方法,它指定在訓(xùn)練到一定epoches或者steps后,按照線性或者余弦函數(shù)等方式,將學(xué)習(xí)率降低至指定值。一般,使用Warmup and Decay,學(xué)習(xí)率會(huì)遵循從小到大,再減小的規(guī)律。
??由于剛開始訓(xùn)練時(shí),模型的權(quán)重(weights)是隨機(jī)初始化的,此時(shí)若選擇一個(gè)較大的學(xué)習(xí)率,可能帶來模型的不穩(wěn)定(振蕩),選擇Warmup預(yù)熱學(xué)習(xí)率的方式,可以使得開始訓(xùn)練的幾個(gè)epoches或者一些steps內(nèi)學(xué)習(xí)率較小,在預(yù)熱的小學(xué)習(xí)率下,模型可以慢慢趨于穩(wěn)定,等模型相對穩(wěn)定后再選擇預(yù)先設(shè)置的學(xué)習(xí)率進(jìn)行訓(xùn)練,使得模型收斂速度變得更快,模型效果更佳。而當(dāng)模型訓(xùn)到一定階段后(比如10個(gè)epoch),模型的分布就已經(jīng)比較固定了,或者說能學(xué)到的新東西就比較少了。如果還沿用較大的學(xué)習(xí)率,就會(huì)破壞這種穩(wěn)定性,用我們通常的話說,就是已經(jīng)接近損失函數(shù)的局部最優(yōu)值點(diǎn)了,為了靠近這個(gè)局部最優(yōu)值點(diǎn),我們就要慢慢來。
如何在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):
在這個(gè)類中,我們需要指定decay_steps,warmup_steps,learning_rate,min_lr,其含義為模型在訓(xùn)練warmup_steps后,將學(xué)習(xí)率逐漸增加至learning_rate,在訓(xùn)練decay_steps后,將學(xué)習(xí)率逐漸線性地降低至min_lr。
??以下為Warmup預(yù)熱學(xué)習(xí)率以及學(xué)習(xí)率預(yù)熱完成后衰減(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實(shí)戰(zhàn)
??筆者在文章NLP(三十四)使用keras-bert實(shí)現(xiàn)序列標(biāo)注任務(wù)中,在使用keras-bert訓(xùn)練 序列標(biāo)注模型時(shí),學(xué)習(xí)率調(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)
在三個(gè)數(shù)據(jù)集上的評估結(jié)果如下:
人民日報(bào)命名實(shí)體識別數(shù)據(jù)集:micro avg F1=0.9182
時(shí)間識別數(shù)據(jù)集:micro avg F1=0.8587
CLUENER細(xì)粒度實(shí)體識別數(shù)據(jù)集:micro avg F1=0.7603
??我們將學(xué)習(xí)率調(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,在三個(gè)數(shù)據(jù)集上的評估結(jié)果如下:
人民日報(bào)命名實(shí)體識別數(shù)據(jù)集
| 學(xué)習(xí)率調(diào)整 | 預(yù)測1 | 預(yù)測2 | 預(yù)測3 | avg |
|---|---|---|---|---|
| Warmup | 0.9276 | 0.9217 | 0.9252 | 0.9248 |
時(shí)間識別數(shù)據(jù)集
| 學(xué)習(xí)率調(diào)整 | 預(yù)測1 | 預(yù)測2 | 預(yù)測3 | avg |
|---|---|---|---|---|
| Warmup | 0.8926 | 0.8934 | 0.8820 | 0.8893 |
CLUENER細(xì)粒度實(shí)體識別數(shù)據(jù)集
| 學(xué)習(xí)率調(diào)整 | 預(yù)測1 | 預(yù)測2 | 預(yù)測3 | avg |
|---|---|---|---|---|
| Warmup | 0.7612 | 0.7629 | 0.7607 | 0.7616 |
可以看到,使用了Warmup and Decay,模型在不同的數(shù)據(jù)集上均有不同程度的效果提升。
??本項(xiàng)目已經(jīng)開源,代碼地址為:https://github.com/percent4/keras_bert_sequence_labeling 。
??本文到此結(jié)束,感謝大家的閱讀~
??2021年3月27日于上海浦東~
