一、Optimizer

深度神经网络通过反向传播来逼近全局最优解。反向传播使用梯度来更新权重,我们不仅要避免梯度消失或爆炸,同时也希望梯度能稳定且尽可能迅速地下降,从而减少让人抓狂的等待时间。
在避免梯度消失或爆炸的问题中,可以使用更好的权重初始化、更好的激活函数、batch normalization等;在使梯度稳定迅速下降的问题中,考虑使用更好的优化器。
当前已知的优化算法有一些:
Momentum, Nesterov accelerated gradient;
AdaGrad, RMSProp;
Adam and its variants。

二、常见Optimizer

0. SGD

基本优化器,就是随机梯度优化。使用损失函数当前关于权重的梯度来更新权重,使损失函数尽量向低处移动。

1. 通过历史梯度来优化SGD

在迭代更新的过程中,权重的更新不仅由当前的梯度决定,还需要考虑历史梯度的影响。类似运动惯性,通过加入之前梯度的加权和,来帮助模型更快收敛并减少震荡。

① SGD with Momentum

在这里插入图片描述
⭐ 历史衰减率 β 的经验值为0.9

def build_models(seed=42):
    tf.random.set_seed(seed)
    return keras.Sequential([
        keras.layers.Flatten(input_shape=[28, 28]),
        keras.layers.Dense(100, activation="relu", kernel_initializer="he_normal"),
        keras.layers.Dense(100, activation="relu", kernel_initializer="he_normal"),
        keras.layers.Dense(100, activation="relu", kernel_initializer="he_normal"),
        keras.layers.Dense(10, activation="softmax")
    ])

def build_and_train_models(optimizer):
    model = build_models()
    model.compile(optimizer=optimizer, loss="sparse_categorical_crossentropy",
                  metrics=["accuracy"])
    return model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid))

""" Momentum """
optimizer_momentum = keras.optimizers.SGD(learning_rate=0.001, momentum=0.9)
history_sgd_momentum = build_and_train_models(optimizer_momentum)

② SGD with Nesterov Acceleration

Nesterov accelerated gradient (NAG) 是对momentum的一个改进,like little trick。在momentum中,权重的更新由历史梯度和当前梯度决定,在NAG中,权重的更新由历史梯度和下一步梯度决定。类似前瞻性更新。
在这里插入图片描述

""" Nesterov Accelerated Gradient """
optimizer_nag = keras.optimizers.SGD(learning_rate=0.001, momentum=0.9, nesterov=True)
history_nesterov = build_and_train_models(optimizer_nag)

下图显示了momentum和nesterov acceleration的区别:
在这里插入图片描述

2. 通过历史梯度的平方来优化SGD

动量考虑了历史梯度的影响,但仅考虑历史梯度,并不能区分每个参数的学习速率。比如,对于更新多次的参数,我们已经学到了大量关于它的知识,因此可以让新样本对该参数造成的影响小一些;对于偶尔更新的参数,我们了解的信息太少,希望能从新样本身上多学一些,即可以使学习速率大一些。
通过考虑过去梯度的平方来调整每个参数的学习率(加入之前梯度的平方和),在加速训练的同时,还能够达到自适应学习速率的效果。

① AdaGrad

AdaGrad 即“自适应的梯度下降”。AdaGrad algorithm achieves this correction by scaling down the gradient vector along the steepest dimensions。
在这里插入图片描述

""" AdaGrad """
optimizer_ada = keras.optimizers.Adagrad(learning_rate=0.001)
history_adagrad = build_and_train_models(optimizer_ada)

② RMSProp

RMSProp 是针对AdaGrade速度降低过快以至于无法收敛这个缺点的改进版本。AdaGrade考虑从训练初始以来的所有梯度,而在RMSProp中,通过使用衰减率,降低历史梯度的影响,使梯度主要受最近迭代的影响。
在这里插入图片描述
⭐ 历史衰减率 ρ 的经验值为0.9

""" RMSProp """
optimizer_rmsprop = keras.optimizers.RMSprop(learning_rate=0.001, rho=0.9)
history_rmsprop = build_and_train_models(optimizer_rmsprop)

下图显示了Adagrad和原始SGD的区别:
在这里插入图片描述

3. 用一阶二阶共同优化SGD

考虑上述结合吖!Here comes Adam!
是的,Adam, which stands for adaptive moment estimation,是上述一阶动量momentum optimization 和二阶动量RMSProp 的结合优化版SGD。
like momentum optimization, it keeps track of an exponentially decaying average of past gradients; like RMSProp, it keeps track of an exponentially decaying average of past squared gradients.

① Adam

在这里插入图片描述
⭐衰减率 β1 的经验值是 0.9, 衰减率 β2 的经验值是 0.999。

""" Adam Optimization """
optimizer_adam = keras.optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999)
history_adam = build_and_train_models(optimizer_adam)

② 基于Adam的三个变形体:

  1. AdaMax
  2. Nadam:Nadam optimization is Adam optimization plus the Nesterov trick, so it will often converge slightly faster than Adam.
  3. AdamW: AdamW is a variant of Adam that integrates a regularization technique called weight decay.
""" Adamax Optimization """
optimizer_adamax = keras.optimizers.Adamax(learning_rate=0.001, beta_1=0.9, beta_2=0.999)
history_adamax = build_and_train_models(optimizer_adamax)

""" Nadam Optimization"""
optimizer_nadam = keras.optimizers.Nadam(learning_rate=0.001, beta_1=0.9, beta_2=0.999)
history_nadam = build_and_train_models(optimizer_nadam)

""" AdamW Optimization """
optimizer_adamw = keras.optimizers.AdamW(weight_decay=1e-5, learning_rate=0.001, beta_1=0.9, beta_2=0.999)
history_adamw = build_and_train_models(optimizer_adamw)

⭐ Table 11-2 优化器的比较 (* is bad, ** is average,** and *** is good).
在这里插入图片描述


**⭐ **
可以看到上述所有优化都只依赖于一阶偏导数(Jacobians矩阵)。
为什么不继续考虑二阶偏导数(Hessians,雅可比矩阵的偏导数)呢?
实际上技术大佬有试验过,只不过这些算法很难应用于深度神经网络。因为每个输出对应有n的平方个 Hessian 矩阵(其中 n 是参数的数量),而不是n个雅可比矩阵。巨海量的参数以及巨海量的运算使得二阶偏导不太实用。


总结

optimizers的学习记录。图源自于《Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow》chapter11

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐