Learning Rate Scheduler
之前在cifar-10数据集上训练了MiniVGGNet网络,为了缓和过拟合,我们在应用SGD时引入了学习率decay的概念。
本片文章将讨论学习率调度器的概念,有时也称为适应性学习率,通过在不同epoch上调整学习率,我们可以降低loss,提高精确度,在某种情况写甚至可以减少训练网络的时间。
我们可以将调整学习率的过程看作:
- 用较高的learning rate在早期的训练过程中找到一组合理的权重。
- 之后用较小的learning rate慢慢的调整权重,直到找到最优的权重
你可能会遇到的两种学习率调度器的基本类型:
-
根据epoch数逐渐减小学习率,比如线性、多项式或指数方程
-
根据特定的epoch下降,比如分段函数。
1. Keras中标准的衰减调度器
回看我们之前初始化SGD的代码:
print("[INFO] compiling model...") opt = SGD(learning_rate=0.01, decay=0.01/40, momentum=0.9, nesterov=True) model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10) model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
这里我们以learning_rate α \alpha α=0.01,momentum γ \gamma γ=0.9,并指出我门使用了Nesterov accelerated gradient。然后我们将 decay等于学习率除以总epoch数,结果是0.01/40 = 0.00025
在底层,Keras调用如下的学习率调度器来调整每个epoch的学习率:
α e + 1 = α e × 1 / ( 1 + γ ∗ e ) \alpha_{e+1}=\alpha_e \times 1/(1+\gamma*e) αe+1=αe×1/(1+γ∗e)
当 γ \gamma γ=0时,lr不变
当 γ \gamma γ=0.01/40时,lr每个周期结束后会开始下降
2. 基于阶段的衰减
这种调度器在特定的epoch之后会自动降下learning rate,我们可以将其看成是一个分段函数,这种情况下学习率会在几个epoch内保持一个常数,然后突然下降,然后继续保持常数几个epoch,然后再突然下降,如此往复。
当我们的学习率调度器使用这种阶段衰减时,我们有两个选择:
-
定义这种关于learning rate的分段函数
-
在训练神经网络的时候,注意到验证时的表现不好,用ctrl+c停止脚本,然后调整学习率,再接着训练。
本文主要关注第一种方法,第二种方法更加高级一些,常用于在大型数据集上训练深度神经网络时,此时我们具体要在什么地方调整学习率是无法预测的,所以采用第二种方法。
3. 自定义keras的学习率调度器
Keras 库为我们提供了LearningRateScheduler类,让我们可以定义一个个性化的学习率函数,然后在训练时自动将其应用。
这个自定义的函数需要epoch作为参数,然后基于我们定义的函数算出对应的学习率。
我们定义了一个每D个epoch按照特定因子F降低学习率的分段函数,我们的函数如下:
α E + 1 = α 1 × F ( 1 + E ) / D \alpha_{E+1}=\alpha_1\times F^{(1+E)/D} αE+1=α1×F(1+E)/D
其中 α 1 \alpha_1 α1是初始学习率,F是控制学习率减少的因子,D是epoch的数量。实现代码如下:
alpha = initAlpha * (factor ** np.floor((1 + epoch) / dropEvery))
打开一个python文件,命名为cifar10_lr_decay.py
,写入以下代码:
import matplotlib matplotlib.use("Agg") from sklearn.preprocessing import LabelBinarizer from sklearn.metrics import classification_report from nn.conv.minivggnet import MiniVGGNet from tensorflow.keras.callbacks import LearningRateScheduler from tensorflow.keras.optimizers import SGD from tensorflow.keras.datasets import cifar10 import matplotlib.pyplot as plt import numpy as np def step_decay(epoch): # 初始化基础学习率,drop factor和多少个周期drop一次 initAlpha = 0.01 factor = 0.25 dropEvery = 5 # 计算当前epoch的学习率 alpha = initAlpha * (factor ** np.floor((1 + epoch) / dropEvery)) return float(alpha) # 定义输出 loss/acc图的路径 output = "/Users/liushanlin/PycharmProjects/DLstudy/result" # 加载训练数据和测试数据,并缩放至[0, 1]的范围内 print("[INFO] loading cifar_10 data...") ((trainX, trainY), (testX, testY)) = cifar10.load_data() trainX = trainX.astype("float") / 255.0 testX = testX.astype("float") / 255.0 # 将标签从整数转化为向量 lb = LabelBinarizer() trainY = lb.fit_transform(trainY) testY = lb.transform(testY) # 初始化CIFAR-10数据集的标签名 labelNames = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"] # 定义训练时传递模型给callbacks集合 callbacks = [LearningRateScheduler(step_decay)] # 初始化模型和优化器 opt = SGD(learning_rate=0.01, momentum=0.9, nesterov=True) model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10) model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"]) # 训练网络 H = model.fit(trainX, trainY, validation_data=(testX, testY), batch_size=64, epochs=40, callbacks=callbacks, verbose=1) # 评估网络 print("[INFO] evaluating network...") predictions = model.predict(testX, batch_size=64) print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1), target_names=labelNames)) #画图 plt.style.use("ggplot") plt.figure() plt.plot(np.arange(0, 40), H.history["loss"], label="train_loss") plt.plot(np.arange(0, 40), H.history["val_loss"], label="val_loss") plt.plot(np.arange(0, 40), H.history["accuracy"], label="train_acc") plt.plot(np.arange(0, 40), H.history["val_accuracy"], label="val_acc") plt.title("Training Loss and Accuracy on CIFAR-10") plt.xlabel("Epoch#") plt.ylabel("Loss/Accuracy") plt.legend() plt.savefig(output)
运行结果:
precision recall f1-score support airplane 0.83 0.72 0.77 1000 automobile 0.92 0.80 0.86 1000 bird 0.72 0.56 0.63 1000 cat 0.59 0.54 0.56 1000 deer 0.64 0.80 0.71 1000 dog 0.65 0.68 0.67 1000 frog 0.73 0.88 0.80 1000 horse 0.85 0.77 0.81 1000 ship 0.82 0.89 0.85 1000 truck 0.79 0.88 0.83 1000 accuracy 0.75 10000 macro avg 0.76 0.75 0.75 10000 weighted avg 0.76 0.75 0.75 10000
能看出,我们的网络准确率只有76%,学习率下降的非常之快,15epoch之后学习率就只有0.00125了,意味着我们的网络前进的步伐非常之小。
如果我们设置factor=0.5,结果会是什么样呢?
更改如下:
def step_decay(epoch): # 初始化基础学习率,drop factor和多少个周期drop一次 initAlpha = 0.01 factor = 0.5 dropEvery = 5 # 计算当前epoch的学习率 alpha = initAlpha * (factor ** np.floor((1 + epoch) / dropEvery)) return float(alpha)
再次运行程序,结果如下:
precision recall f1-score support airplane 0.81 0.81 0.81 1000 automobile 0.90 0.88 0.89 1000 bird 0.71 0.61 0.66 1000 cat 0.65 0.55 0.60 1000 deer 0.69 0.78 0.74 1000 dog 0.67 0.69 0.68 1000 frog 0.79 0.86 0.82 1000 horse 0.82 0.83 0.83 1000 ship 0.87 0.90 0.88 1000 truck 0.83 0.89 0.86 1000 accuracy 0.78 10000 macro avg 0.78 0.78 0.78 10000 weighted avg 0.78 0.78 0.78 10000 进程已结束,退出代码为 0
今天的文章
计算机视觉2.16:学习率调节器分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/61471.html