Skip to content

由于模型训练初期:

  • 梯度大
  • 模型需要快速学习
  • 高学习率有利于跳过糟糕的局部最小值

中后期:

  • 参数需要更精细调整
  • 大学习率会震荡
  • 小学习率更稳定

因此需要对学习率做调整,使其逐渐衰减,有助于模型更好收敛。


1. 等间隔学习率衰减 ​

1.1 公式定义 ​

等间隔学习率衰减(StepLR Step Learning Rate Decay)是一种简单有效的学习率调整策略

\[\text{lr}*{new} = \text{lr}*{old} \times \gamma \]

每隔固定的训练步数(或 epoch),就把当前学习率乘以一个衰减系数 \(\gamma\),衰减系数恒定。

lr
│
│   ──────────┐
│             └───────┐
│                     └───────┐
│                             └───────┐
└────────────────────────────────────────── epoch
      50       100      150      200

1.2 计算示例 ​

使用等间学习率衰减对比不衰减学习率的情况:

python
import numpy as np
import matplotlib.pyplot as plt

# Simple quadratic function
def loss(w):
    return (w - 3)**2

def grad(w):
    return 2*(w - 3)

def gd(w0, lr, steps):
    w = w0
    traj = []
    for t in range(steps):
        w = w - lr * grad(w)
        traj.append(loss(w))
    return np.array(traj)

def gd_step_decay(w0, lr, steps, step_size, gamma):
    w = w0
    traj = []
    current_lr = lr
    for t in range(steps):
        if t > 0 and t % step_size == 0:
            current_lr *= gamma
        w = w - current_lr * grad(w)
        traj.append(loss(w))
    return np.array(traj)

# parameters
w0 = 20.0
lr = 0.1
steps = 200
step_size = 50
gamma = 0.5

loss_no_decay = gd(w0, lr, steps)
loss_step_decay = gd_step_decay(w0, lr, steps, step_size, gamma)

plt.figure(figsize=(7,5))
plt.semilogy(loss_no_decay, label="No LR Decay")
plt.semilogy(loss_step_decay, label="Step LR Decay")
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.title("Comparison of Learning Rate Decay")
plt.legend()
plt.grid(True)
plt.show()

{
    "final_loss_no_decay": float(loss_no_decay[-1]),
    "final_loss_step_decay": float(loss_step_decay[-1])
}

2. 指定间隔学习率衰减 ​

2.1 公式定义 ​

指定间隔学习率衰减(MultiStep LR)可以在不同的区间轮次上指定学习率:

  • 每隔固定 step_size(例如每 50 epoch)衰减一次
  • 指定多个不等间隔的衰减点

调度方式:

\[lr_{t+1} = \begin{cases} lr_t \cdot \gamma, & t \in \text{milestones}, \\ lr_t, & \text{otherwise}. \end{cases} \]
  • 当训练步数 \(t\) 到达预设的值 \(\text{milestones}\) 时,学习率乘以一个衰减因子 \(\gamma\)。
  • 在其他步数,学习率保持不变
python
optim.lr_scheduler.MultiStepLR(
    optimizer,
    milestones = [50, 125, 160],
    gamma = 0.1
)

2.2 计算示例 ​

指定间隔,在 milestones=[50, 125, 160] 分别衰减,对比等间隔衰减:

python
import numpy as np
import matplotlib.pyplot as plt

def loss(w):
    return (w - 3)**2

def grad(w):
    return 2 * (w - 3)


def gd_step_lr(w0, lr, steps, step_size, gamma):
    w = w0
    traj_loss = []
    traj_lr = []
    current_lr = lr

    for t in range(steps):
        # 等间隔衰减
        if t > 0 and t % step_size == 0:
            current_lr *= gamma
        
        w = w - current_lr * grad(w)
        traj_loss.append(loss(w))
        traj_lr.append(current_lr)

    return np.array(traj_loss), np.array(traj_lr)


def gd_multi_step_lr(w0, lr, steps, milestones, gamma):
    w = w0
    traj_loss = []
    traj_lr = []
    current_lr = lr

    for t in range(steps):
        # 指定间隔衰减
        if t in milestones:
            current_lr *= gamma
        
        w = w - current_lr * grad(w)
        traj_loss.append(loss(w))
        traj_lr.append(current_lr)

    return np.array(traj_loss), np.array(traj_lr)


w0 = 20.0
lr = 0.1
steps = 200

step_size = 50
gamma = 0.5

milestones = [50, 125, 160]  # 指定衰减时刻


loss_step, lr_step = gd_step_lr(w0, lr, steps, step_size, gamma)
loss_multi, lr_multi = gd_multi_step_lr(w0, lr, steps, milestones, gamma)


plt.figure(figsize=(8,5))
plt.semilogy(loss_step, label="StepLR")
plt.semilogy(loss_multi, label="MultiStepLR")
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.title("Loss Curve: StepLR vs MultiStepLR")
plt.legend()
plt.grid(True)
plt.show()

plt.figure(figsize=(8,5))
plt.plot(lr_step, label="StepLR")
plt.plot(lr_multi, label="MultiStepLR")
plt.xlabel("Iteration")
plt.ylabel("Learning Rate")
plt.title("Learning Rate Schedule")
plt.legend()
plt.grid(True)
plt.show()

3. 指数学习率衰减 ​

3.1 公式定义 ​

指数学习率衰减(Exponential LR)是指对于每个训练周期(epoch)按照指数形式衰减,其特点为:

  • 学习率按指数函数平滑下降
  • 每个 epoch 都以相同比例衰减
  • 理论上学习率无限趋近于0但永不等于0

公式为:

\[lr_t = lr_0 \cdot \gamma^t \]

其中:

  • \(lr_t\) 是第 \(t\) 个 epoch 的学习率
  • \(lr_0\) 是初始学习率
  • \(\gamma\) 是衰减率(\(0 < \gamma < 1\))
  • \(t\) 是当前 epoch 数(从0开始)

3.2 计算示例 ​

对比等间衰减和指数学习率在函数 \(L(w) = (w - 3)^2\) 上的衰减:

python
import numpy as np
import matplotlib.pyplot as plt

def loss(w):
    return (w - 3)**2

def grad(w):
    return 2 * (w - 3)

def gd_step_lr(w0, lr, steps, step_size, gamma):
    w = w0
    traj_loss = []
    traj_lr = []
    current_lr = lr

    for t in range(steps):
        # StepLR:每 step_size 步衰减
        if t > 0 and t % step_size == 0:
            current_lr *= gamma
        
        w = w - current_lr * grad(w)
        traj_loss.append(loss(w))
        traj_lr.append(current_lr)

    return np.array(traj_loss), np.array(traj_lr)

def gd_exp_lr(w0, lr, steps, gamma):
    w = w0
    traj_loss = []
    traj_lr = []
    current_lr = lr

    for t in range(steps):
        # ExponentialLR:每一步都衰减 lr = lr * gamma
        if t > 0:
            current_lr *= gamma

        w = w - current_lr * grad(w)
        traj_loss.append(loss(w))
        traj_lr.append(current_lr)

    return np.array(traj_loss), np.array(traj_lr)

w0 = 20.0
lr = 0.1
steps = 200

step_size = 50
gamma_step = 0.5       # StepLR 的衰减系数
gamma_exp = 0.98       # ExponentialLR 的指数底

loss_step, lr_step = gd_step_lr(w0, lr, steps, step_size, gamma_step)
loss_exp, lr_exp = gd_exp_lr(w0, lr, steps, gamma_exp)

plt.figure(figsize=(8,5))
plt.semilogy(loss_step, label="StepLR (等间隔衰减)")
plt.semilogy(loss_exp, label="ExponentialLR (指数衰减)")
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.title("Loss Curve: StepLR vs ExponentialLR")
plt.legend()
plt.grid(True)
plt.show()

plt.figure(figsize=(8,5))
plt.plot(lr_step, label="StepLR")
plt.plot(lr_exp, label="ExponentialLR")
plt.xlabel("Iteration")
plt.ylabel("Learning Rate")
plt.title("Learning Rate Schedule Comparison")
plt.legend()
plt.grid(True)
plt.show()