【深度学习-pytorch篇】3. 优化器实现:momentum,NAG,AdaGrad,RMSProp,Adam

发布于:2025-05-29 ⋅ 阅读:(22) ⋅ 点赞:(0)

Optimization Algorithms Explained

1. Beale Function 与导数函数讲解

Beale 函数是一个著名的用于测试优化算法性能的函数,其具有多个局部极值点,适合评估不同优化器的表现:

def beale(x1, x2):
    """
    Beale 函数定义:
    f(x1, x2) = (1.5 - x1 + x1*x2)^2 + (2.25 - x1 + x1*x2^2)^2 + (2.625 - x1 + x1*x2^3)^2
    参数:
        x1 (float or array): 第一个变量
        x2 (float or array): 第二个变量
    返回:
        函数值(float or array)
    """
    return (1.5 - x1 + x1*x2)**2 + (2.25 - x1 + x1*x2**2)**2 + (2.625 - x1 + x1*x2**3)**2

def dbeale_dx(x1, x2):
    """
    Beale 函数的一阶偏导:返回 [df/dx1, df/dx2]。
    用于梯度下降算法中。
    参数:
        x1 (float): 当前 x1 位置
        x2 (float): 当前 x2 位置
    返回:
        dfdx1 (float): 对 x1 的偏导
        dfdx2 (float): 对 x2 的偏导
    """
    dfdx1 = 2*(1.5 - x1 + x1*x2)*(x2-1) + \
            2*(2.25 - x1 + x1*x2**2)*(x2**2-1) + \
            2*(2.625 - x1 + x1*x2**3)*(x2**3-1)

    dfdx2 = 2*(1.5 - x1 + x1*x2)*x1 + \
            2*(2.25 - x1 + x1*x2**2)*(2*x1*x2) + \
            2*(2.625 - x1 + x1*x2**3)*(3*x1*x2**2)

    return dfdx1, dfdx2

调用方式说明:

x = np.array([1.0, 1.5])
dfdx = dbeale_dx(*x)  # *x 解包为 x1, x2

这个解包调用方式是标准的 Python 用法,等价于 dbeale_dx(x[0], x[1])

2. Momentum 优化器逐行讲解

Momentum 方法在普通梯度下降基础上引入了动量项,公式如下:

  • 公式 (1): v t = γ v t − 1 − η ∇ f ( θ ) v_t = \gamma v_{t-1} - \eta \nabla f(\theta) vt=γvt1ηf(θ)
  • 公式 (2): θ = θ + v t \theta = \theta + v_t θ=θ+vt

代码实现:

def gd_momentum(df_dx, x0, conf_para=None):
    """
    Momentum 优化器
    参数:
        df_dx: 梯度函数,形式为 df_dx(x1, x2),返回 (df/dx1, df/dx2)
        x0: 初始参数位置 (array)
        conf_para: 字典,包含如下超参数:
            - n_iter: 迭代次数
            - learning_rate: 学习率 η
            - momentum: 动量参数 γ
    返回:
        x_traj: 参数更新轨迹
    """
    if conf_para is None:
        conf_para = {}

    conf_para.setdefault('n_iter', 1000)
    conf_para.setdefault('learning_rate', 0.001)
    conf_para.setdefault('momentum', 0.9)

    x_traj = [x0]  # 保存轨迹
    v = np.zeros_like(x0)  # 初始化速度向量 v0 = 0

    for _ in range(conf_para['n_iter']):
        dfdx = np.array(df_dx(*x_traj[-1]))
        v = conf_para['momentum'] * v - conf_para['learning_rate'] * dfdx  # 公式 (1)
        x_traj.append(x_traj[-1] + v)  # 公式 (2)

    return x_traj

3. Nesterov Accelerated Gradient 讲解

Nesterov 方法在计算梯度时先 “预判” 一步跳跃位置,公式如下:

  • 公式 (3): θ ^ = θ + v t − 1 \hat{\theta} = \theta + v_{t-1} θ^=θ+vt1
  • 公式 (4): v t = γ v t − 1 − η ∇ f ( θ ^ ) v_t = \gamma v_{t-1} - \eta \nabla f(\hat{\theta}) vt=γvt1ηf(θ^)
  • 公式 (5): θ = θ + v t \theta = \theta + v_t θ=θ+vt
def gd_nesterov(df_dx, x0, conf_para=None):
    """
    Nesterov 加速梯度方法
    参数:
        df_dx: 梯度函数
        x0: 初始参数位置
        conf_para: 参数字典(n_iter, learning_rate, momentum)
    返回:
        x_traj: 参数更新轨迹
    """
    if conf_para is None:
        conf_para = {}

    conf_para.setdefault('n_iter', 1000)
    conf_para.setdefault('learning_rate', 0.001)
    conf_para.setdefault('momentum', 0.9)

    x_traj = [x0]
    v = np.zeros_like(x0)

    for _ in range(conf_para['n_iter']):
        x_jump = x_traj[-1] + v  # 公式 (3)
        dfdx = np.array(df_dx(*x_jump))  # 在跳跃位置计算梯度 ∇f(θ + v)
        v = conf_para['momentum'] * v - conf_para['learning_rate'] * dfdx  # 公式 (4)
        x_traj.append(x_traj[-1] + v)  # 公式 (5)

    return x_traj

4. AdaGrad 讲解

AdaGrad 通过累积历史梯度的平方来自适应地缩小学习率,公式如下:

  • r t = r t − 1 + ∇ f ( θ ) 2 r_t = r_{t-1} + \nabla f(\theta)^2 rt=rt1+f(θ)2
  • θ = θ − η r t + ϵ ∇ f ( θ ) \theta = \theta - \frac{\eta}{\sqrt{r_t} + \epsilon} \nabla f(\theta) θ=θrt +ϵηf(θ)
def gd_adagrad(df_dx, x0, conf_para=None):
    """
    AdaGrad 自适应梯度优化器
    参数:
        df_dx: 梯度函数
        x0: 初始参数位置
        conf_para: 参数字典,包含 learning_rate, epsilon, n_iter
    返回:
        x_traj: 参数轨迹
    """
    if conf_para is None:
        conf_para = {}

    conf_para.setdefault('n_iter', 1000)
    conf_para.setdefault('learning_rate', 0.001)
    conf_para.setdefault('epsilon', 1e-7)

    x_traj = [x0]
    r = np.zeros_like(x0)

    for _ in range(conf_para['n_iter']):
        dfdx = np.array(df_dx(*x_traj[-1]))
        r += dfdx**2  # 累积平方梯度
        x_traj.append(x_traj[-1] - conf_para['learning_rate'] * dfdx / (np.sqrt(r) + conf_para['epsilon']))

    return x_traj

5. RMSProp 讲解

RMSProp 是 AdaGrad 的改进,引入滑动平均:

  • r t = γ r t − 1 + ( 1 − γ ) ∇ f ( θ ) 2 r_t = \gamma r_{t-1} + (1-\gamma) \nabla f(\theta)^2 rt=γrt1+(1γ)f(θ)2
  • θ = θ − η r t + ϵ ∇ f ( θ ) \theta = \theta - \frac{\eta}{\sqrt{r_t} + \epsilon} \nabla f(\theta) θ=θrt +ϵηf(θ)
def gd_rmsprop(df_dx, x0, conf_para=None):
    """
    RMSProp 优化器
    参数:
        df_dx: 梯度函数
        x0: 初始值
        conf_para: 参数字典,包括 gamma, learning_rate, epsilon
    """
    if conf_para is None:
        conf_para = {}

    conf_para.setdefault('n_iter', 1000)
    conf_para.setdefault('learning_rate', 0.001)
    conf_para.setdefault('epsilon', 1e-7)
    conf_para.setdefault('gamma', 0.9)

    x_traj = [x0]
    r = np.zeros_like(x0)

    for _ in range(conf_para['n_iter']):
        dfdx = np.array(df_dx(*x_traj[-1]))
        r = conf_para['gamma'] * r + (1 - conf_para['gamma']) * dfdx**2
        x_traj.append(x_traj[-1] - conf_para['learning_rate'] * dfdx / (np.sqrt(r) + conf_para['epsilon']))

    return x_traj

6. Adam 讲解

Adam 同时融合了 Momentum 和 RMSProp 的优点:

  • 一阶动量: s t = β 1 s t − 1 + ( 1 − β 1 ) ∇ f ( θ ) s_t = \beta_1 s_{t-1} + (1-\beta_1) \nabla f(\theta) st=β1st1+(1β1)f(θ)
  • 二阶动量: r t = β 2 r t − 1 + ( 1 − β 2 ) ∇ f ( θ ) 2 r_t = \beta_2 r_{t-1} + (1-\beta_2) \nabla f(\theta)^2 rt=β2rt1+(1β2)f(θ)2
  • 偏差修正: s ^ t = s t 1 − β 1 t , r ^ t = r t 1 − β 2 t \hat{s}_t = \frac{s_t}{1 - \beta_1^t}, \hat{r}_t = \frac{r_t}{1 - \beta_2^t} s^t=1β1tst,r^t=1β2trt
  • 参数更新: θ = θ − η s ^ t r ^ t + ϵ \theta = \theta - \eta \frac{\hat{s}_t}{\sqrt{\hat{r}_t} + \epsilon} θ=θηr^t +ϵs^t
def gd_adam(df_dx, x0, conf_para=None):
    """
    Adam 优化器
    参数:
        df_dx: 梯度函数
        x0: 初始位置
        conf_para: 包含 rho1, rho2, epsilon, learning_rate
    """
    if conf_para is None:
        conf_para = {}

    conf_para.setdefault('n_iter', 1000)
    conf_para.setdefault('learning_rate', 0.001)
    conf_para.setdefault('rho1', 0.9)
    conf_para.setdefault('rho2', 0.999)
    conf_para.setdefault('epsilon', 1e-8)

    x_traj = [x0]
    t = 0
    s = np.zeros_like(x0)
    r = np.zeros_like(x0)

    for _ in range(conf_para['n_iter']):
        dfdx = np.array(df_dx(*x_traj[-1]))
        t += 1
        s = conf_para['rho1'] * s + (1 - conf_para['rho1']) * dfdx
        r = conf_para['rho2'] * r + (1 - conf_para['rho2']) * (dfdx**2)
        st = s / (1 - conf_para['rho1']**t)
        rt = r / (1 - conf_para['rho2']**t)
        x_traj.append(x_traj[-1] - conf_para['learning_rate'] * st / (np.sqrt(rt) + conf_para['epsilon']))

    return x_traj

网站公告

今日签到

点亮在社区的每一天
去签到