深度学习模型训练小技巧

这篇文章主要介绍一些在深度学习模型训练时的一些小技巧。

一、warmup

warmup可以理解为预热、热身的意思,它的思想是一开始以较小的学习率去更新参数,然后逐步提高学习率。

这样的好处是:

  1. 有助于减缓模型在初始阶段对mini-batch的提前过拟合现象,保持分布的平稳;
  2. 有助于保持模型深层的稳定性。
# 线性warmup
# num_warmup_steps:warmup的步数
# init_lr:预设的学习率

global_step = tf.train.get_or_create_global_step()

global_steps_int = tf.cast(global_step, tf.int32)
warmup_steps_int = tf.constant(num_warmup_steps, dtype=tf.int32)

global_steps_float = tf.cast(global_steps_int, tf.float32)
warmup_steps_float = tf.cast(warmup_steps_int, tf.float32)

warmup_percent_done = global_steps_float / warmup_steps_float
warmup_learning_rate = init_lr * warmup_percent_done

is_warmup = tf.cast(global_steps_int < warmup_steps_int, tf.float32)
learning_rate = (
		(1.0 - is_warmup) * learning_rate + is_warmup * warmup_learning_rate)
		

二、学习率递减

为什么需要学习率递减呢?因为当我们的模型在接近最优点的时候,过大的学习率会导致一直在最优点附近动荡,难以找到最优点,甚至可能会逃离,这个时候就需要以较小的学习率才能找到最优点,换另一种说法:这个时候我们的网络已经趋于稳定了,过大的学习率会破坏网络的稳定性。

适用场景:通过上述的理解,当我们的模型在前期loss能够正常下降,但在后期难以收敛的情况下,就可以派上用场了。

global_step = tf.train.get_or_create_global_step()
# learning_rate:初设的学习率
# num_train_steps:总的训练次数
# end_learning_rate:学习率最终降为多少
# power:决定递减的幅度
# cycle:当学习率递减为end_learning_rate时,是否开始新的一轮递减
learning_rate = tf.train.polynomial_decay(
        learning_rate,
        global_step,
        num_train_steps,
        end_learning_rate=0.0,
        power=1.0,
        cycle=False)

根据官方API的解释,递减的公式为:

global_step = min(global_step, decay_steps)
decayed_learning_rate = (learning_rate - end_learning_rate) *
                          (1 - global_step / decay_steps) ^ (power) +
                          end_learning_rate

这里的decay_steps就是总的递减步数,一般是训练的总步数即num_train_steps。

warmup + lr_decay

看到这里, 相信有人就有疑问了:warmup和学习率递减,这不是自相矛盾吗?

确实,它们两者是完全相反的思路,但是它们有各自不同的适用场景。

并且,在实际情况中,两者是可以结合一起使用的,例如大名鼎鼎的Bert模型就是这么干的。但是,warmup一般在前10%-20%的训练过程中,所以在前期对学习率影响较大的还是warmup,即专注于warmup,后期则是专注于lr_decar。

这样即可以缓解初设阶段对局部数据的过拟合,也能缓解后期的动荡,提高网络的稳定性,增加模型收敛的可能性

三、梯度裁剪

适用场景:当你的梯度很容易出现爆炸的情况下,这个时候就可以考虑使用梯度裁剪了。

# 获取所有待更新参数
tvars = tf.trainable_variables()
# 计算所有参数的梯度
# loss:your loss
grads = tf.gradients(loss, tvars)
# 对梯度进行裁剪
(grads, _) = tf.clip_by_global_norm(grads, clip_norm=1.0)

optimizer = tf.train.GradientDescentOptimizer(0.1)
# 进行梯度下降
train_op = optimizer.apply_gradients(
        zip(grads, tvars))

根据官方API的解释,梯度裁剪的公式为:

grads[i] = grads[i] * clip_norm / max(global_norm, clip_norm)

global_norm = sqrt(sum([l2norm(t)**2 for t in grads]))

l2norm(t) = sqrt(sum(t ** 2))

你可能感兴趣的:(tensorflow,深度学习,深度学习,warmup,梯度裁剪,学习率递减,tensorflow)