Класс CyclicLR
Класс CyclicLR позволяет изменять скорость обучения по циклическому закону в процессе тренировки нейронной сети. В отличие от монотонного уменьшения learning rate, циклический подход периодически повышает и понижает его значение в заданном диапазоне. Это помогает модели преодолевать локальные минимумы и плоские участки функции потерь. Политика была предложена в работе "Cyclical Learning Rates for Training Neural Networks". Класс принимает оптимизатор, базовую и максимальную скорости обучения, а также параметры управления циклом.
Синтаксис
torch.optim.lr_scheduler.CyclicLR(
optimizer,
base_lr,
max_lr,
step_size_up=2000,
step_size_down=None,
mode='triangular',
gamma=1.0,
scale_fn=None,
scale_mode='cycle',
cycle_momentum=True,
base_momentum=0.8,
max_momentum=0.9,
last_epoch=-1,
verbose=False
)
Основные параметры:
-
optimizer- оптимизатор, для которого изменяется скорость обучения -
base_lr- минимальная скорость обучения (нижняя граница цикла) -
max_lr- максимальная скорость обучения (верхняя граница цикла) -
step_size_up- количество итераций для увеличения learning rate отbase_lrдоmax_lr -
step_size_down- количество итераций для уменьшения learning rate (по умолчанию равноstep_size_up) -
mode- форма цикла:'triangular','triangular2'или'exp_range' -
gamma- коэффициент затухания для режима'exp_range' -
cycle_momentum- еслиTrue, то циклически изменяется и момент оптимизатора
Пример
Давайте создадим циклический планировщик с базовым learning rate 0.001 и максимальным 0.01:
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import CyclicLR
model = nn.Linear(10, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = CyclicLR(
optimizer,
base_lr=0.001,
max_lr=0.01,
step_size_up=100,
mode='triangular'
)
print(f"Initial learning rate: {scheduler.get_last_lr()}")
Результат выполнения кода:
"Initial learning rate: [0.001]"
Пример
В процессе обучения планировщик необходимо вызывать на каждой итерации. Давайте посмотрим, как изменяется learning rate в течение первых нескольких шагов:
import torch
from torch.optim.lr_scheduler import CyclicLR
model = torch.nn.Linear(10, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = CyclicLR(
optimizer,
base_lr=0.001,
max_lr=0.01,
step_size_up=5,
mode='triangular'
)
for step in range(12):
optimizer.step()
scheduler.step()
lr = scheduler.get_last_lr()[0]
print(f"Step {step}: lr = {lr:.4f}")
Результат выполнения кода:
Step 0: lr = 0.0028
Step 1: lr = 0.0046
Step 2: lr = 0.0064
Step 3: lr = 0.0082
Step 4: lr = 0.0100
Step 5: lr = 0.0082
Step 6: lr = 0.0064
Step 7: lr = 0.0046
Step 8: lr = 0.0028
Step 9: lr = 0.0010
Step 10: lr = 0.0028
Step 11: lr = 0.0046
Learning rate изменяется по треугольному закону, увеличиваясь от минимального до максимального значения, затем уменьшаясь обратно.
Пример
Рассмотрим использование режима 'triangular2', где амплитуда цикла уменьшается вдвое после каждого полного цикла:
import torch
from torch.optim.lr_scheduler import CyclicLR
model = torch.nn.Linear(10, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = CyclicLR(
optimizer,
base_lr=0.001,
max_lr=0.01,
step_size_up=5,
mode='triangular2'
)
for step in range(20):
optimizer.step()
scheduler.step()
lr = scheduler.get_last_lr()[0]
print(f"Step {step}: lr = {lr:.5f}")
Результат выполнения кода:
Step 0: lr = 0.00280
Step 1: lr = 0.00460
Step 2: lr = 0.00640
Step 3: lr = 0.00820
Step 4: lr = 0.01000
Step 5: lr = 0.00820
Step 6: lr = 0.00640
Step 7: lr = 0.00460
Step 8: lr = 0.00280
Step 9: lr = 0.00100
Step 10: lr = 0.00190
Step 11: lr = 0.00280
Step 12: lr = 0.00370
Step 13: lr = 0.00460
Step 14: lr = 0.00550
Step 15: lr = 0.00460
Step 16: lr = 0.00370
Step 17: lr = 0.00280
Step 18: lr = 0.00190
Step 19: lr = 0.00100
После каждого полного цикла амплитуда уменьшается вдвое, что обеспечивает более тонкую настройку модели к концу обучения.
Пример
Режим 'exp_range' применяет экспоненциальное затухание к амплитуде цикла. Параметр gamma контролирует скорость затухания:
import torch
from torch.optim.lr_scheduler import CyclicLR
model = torch.nn.Linear(10, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = CyclicLR(
optimizer,
base_lr=0.001,
max_lr=0.01,
step_size_up=5,
mode='exp_range',
gamma=0.9
)
for step in range(15):
optimizer.step()
scheduler.step()
lr = scheduler.get_last_lr()[0]
print(f"Step {step}: lr = {lr:.5f}")
Результат выполнения кода:
Step 0: lr = 0.00278
Step 1: lr = 0.00455
Step 2: lr = 0.00631
Step 3: lr = 0.00806
Step 4: lr = 0.00980
Step 5: lr = 0.00803
Step 6: lr = 0.00626
Step 7: lr = 0.00449
Step 8: lr = 0.00272
Step 9: lr = 0.00095
Step 10: lr = 0.00193
Step 11: lr = 0.00290
Step 12: lr = 0.00387
Step 13: lr = 0.00483
Step 14: lr = 0.00579
Learning rate изменяется по циклическому закону, но амплитуда постепенно затухает благодаря экспоненциальному множителю.
Пример
Планировщик поддерживает циклическое изменение момента оптимизатора при использовании оптимизаторов с моментом, таких как SGD. Для этого используется параметр cycle_momentum:
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import CyclicLR
model = nn.Linear(10, 1)
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.001,
momentum=0.8
)
scheduler = CyclicLR(
optimizer,
base_lr=0.001,
max_lr=0.01,
step_size_up=5,
cycle_momentum=True,
base_momentum=0.8,
max_momentum=0.95
)
for step in range(10):
optimizer.step()
scheduler.step()
momentum = optimizer.param_groups[0]['momentum']
lr = scheduler.get_last_lr()[0]
print(f"Step {step}: lr = {lr:.4f}, momentum = {momentum:.3f}")
Результат выполнения кода:
Step 0: lr = 0.0028, momentum = 0.830
Step 1: lr = 0.0046, momentum = 0.860
Step 2: lr = 0.0064, momentum = 0.890
Step 3: lr = 0.0082, momentum = 0.920
Step 4: lr = 0.0100, momentum = 0.950
Step 5: lr = 0.0082, momentum = 0.920
Step 6: lr = 0.0064, momentum = 0.890
Step 7: lr = 0.0046, momentum = 0.860
Step 8: lr = 0.0028, momentum = 0.830
Step 9: lr = 0.0010, momentum = 0.800
Когда learning rate достигает максимума, момент достигает минимума, и наоборот. Это сочетание часто даёт лучшие результаты.
Смотрите также
-
класс
OneCycleLR,
который реализует политику одного цикла изменения скорости обучения -
класс
CosineAnnealingWarmRestarts,
который использует косинусоидальное затухание с перезапусками -
класс
ReduceLROnPlateau,
который уменьшает learning rate при остановке прогресса на метрике -
класс
StepLR,
который уменьшает learning rate через равные интервалы эпох