在本教程中,我们将了解 timm 库中的 StepLRScheduler

该调度器看起来像这样

StepLR

from timm.scheduler.step_lr import StepLRScheduler
from nbdev.showdoc import show_doc

class StepLRScheduler[来源]

StepLRScheduler(optimizer:Optimizer, decay_t:float, decay_rate:float=1.0, warmup_t=0, warmup_lr_init=0, t_in_epochs=True, noise_range_t=None, noise_pct=0.67, noise_std=1.0, noise_seed=42, initialize=True) :: Scheduler

如上所示,StepLRScheduler 接受一个 optimizer 以及一些超参数,我们将在下面详细介绍。我们将首先了解如何使用 timm 训练文档训练模型时使用 StepLRScheduler,然后了解如何将此调度器用作自定义训练脚本的独立调度器。

使用 StepLRScheduler 调度器配合 timm 训练脚本

要使用 StepLRScheduler 训练模型,我们只需通过传入 --sched step 参数以及必要的超参数来更新训练脚本参数。在本节中,我们还将介绍每个超参数如何更新 cosine 调度器。

使用 cosine 调度器的训练命令看起来像这样

python train.py ../imagenette2-320/ --sched step

参数

这样我们就可以开始使用带有所有默认设置的 StepLRScheduler。现在让我们看看相关的超参数以及它们如何更新退火计划。

optimizer

这是将用于训练过程的 optimizer

from timm import create_model 
from timm.optim import create_optimizer
from types import SimpleNamespace
model = create_model('resnet34')

args = SimpleNamespace()
args.weight_decay = 0
args.lr = 1e-4
args.opt = 'adam' 
args.momentum = 0.9

optimizer = create_optimizer(args, model)

使用 create_optimizer 创建的这个 optimizer 对象就是传递给 optimizer 参数的对象。

decay_t

学习率衰减的周期数,衰减后的新学习率等于 lr * decay_rate

decay_rate

decay_rate > 0 且 < 1 时,在每个周期结束时,学习率按新学习率(等于 lr * decay_rate)进行衰减。因此,如果 decay_rate=0.5,那么在这种情况下,新的学习率将是初始 lr 的一半。

from matplotlib import pyplot as plt

def get_lr_per_epoch(scheduler, num_epoch):
    lr_per_epoch = []
    for epoch in range(num_epoch):
        lr_per_epoch.append(scheduler.get_epoch_values(epoch))
    return lr_per_epoch

decay_rate=1. 或无衰减

通过设置 decay_t = 5 和 decay_rate = 1.,我们告诉调度器每 5 个周期按 decay_rate 降低学习率,其中新学习率等于 lr * decay_rate

但是由于 decay_rate=1.,新的学习率等于旧的学习率,因此我们得到一条常数线。

num_epoch = 50
scheduler = StepLRScheduler(optimizer, decay_t = 5, decay_rate=1.)
lr_per_epoch = get_lr_per_epoch(scheduler, num_epoch)

plt.plot([i for i in range(num_epoch)], lr_per_epoch);

decay_rate=0.5

通过设置 decay_t = 5 和 decay_rate = 0.5,我们告诉调度器每 5 个周期按 decay_rate 降低学习率,其中新学习率等于 lr * decay_rate,即每 5 个周期将学习率减半。

num_epoch = 50
scheduler = StepLRScheduler(optimizer, decay_t = 5, decay_rate=.5)
lr_per_epoch = get_lr_per_epoch(scheduler, num_epoch)

plt.plot([i for i in range(num_epoch)], lr_per_epoch);

warmup_t

定义热身周期数。

warmup_lr_init

热身期间的初始学习率。

num_epoch = 50
scheduler = StepLRScheduler(optimizer, decay_t=5, warmup_t=2, warmup_lr_init=1e-5, decay_rate=0.8)
lr_per_epoch = get_lr_per_epoch(scheduler, num_epoch)
plt.plot([i for i in range(num_epoch)], lr_per_epoch, label="With warmup");

num_epoch = 50
scheduler = StepLRScheduler(optimizer, decay_t=5, decay_rate=0.8)
lr_per_epoch = get_lr_per_epoch(scheduler, num_epoch)
plt.plot([i for i in range(num_epoch)], lr_per_epoch, label="Without warmup", alpha=0.8);

plt.legend();

正如我们所见,通过设置 warmup_twarmup_lr_initcosine 调度器首先以 warmup_lr_init 的值开始,然后逐渐上升到优化器中设置的 initial_lr,即 1e-4。从 warmup_lr_initinitial_lr 需要 warmup_t 个周期。

noise_range_t

噪声的上下限。

noise_pct

要添加的噪声百分比。

noise_std

噪声标准差。

noise_seed

用于添加随机噪声的种子。

t_in_epochs

如果设置为 False,则为周期 t 返回的学习率为 None

num_epoch = 50
scheduler = StepLRScheduler(optimizer, decay_t=5, t_in_epochs=False)
lr_per_epoch = get_lr_per_epoch(scheduler, num_epoch)

lr_per_epoch[:5]
[None, None, None, None, None]

initialize

如果为 True,则在 optimizer 的每个参数组内设置一个新字段,称为 initial_{field_name},其中 field_name 指的是我们在参数组中进行调度的字段。通常 field_name='lr'