7.5 参数更新方法

7.5.1 Momentum

图片[1]-7.5 参数更新方法-大赛人网
import torch
import numpy as np
import matplotlib.pyplot as plt

def gradient_descent(X, optimizer, n_iters):
    X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
    for epoch in range(n_iters):
        y = X**2 @ w
        y.backward()  # 反向传播
        optimizer.step()  # 更新参数
        optimizer.zero_grad()  # 清空梯度
        X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
    return X_arr

# 从(-7, 2)出发
X = torch.tensor([-7, 2], dtype=torch.float32, requires_grad=True)
w = torch.tensor([[0.05], [1.0]], requires_grad=True)
lr = 1e-2  # 学习率
n_iters = 500  # 迭代次数

# 普通梯度下降
X_clone = X.clone().detach().requires_grad_(True)
X_arr1 = gradient_descent(X_clone, torch.optim.SGD([X_clone], lr=lr), n_iters=n_iters)
plt.plot(X_arr1[:, 0], X_arr1[:, 1], "r")

# 动量法
X_clone = X.clone().detach().requires_grad_(True)
X_arr2 = gradient_descent(X_clone, torch.optim.SGD([X_clone], lr=lr, momentum=0.9), n_iters=n_iters)
plt.plot(X_arr2[:, 0], X_arr2[:, 1], "b")

# 绘制等高线图
x1_grid, x2_grid = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-2, 2, 100))
y_grid = w.detach().numpy()[0, 0] * x1_grid**2 + w.detach().numpy()[1, 0] * x2_grid**2
plt.contour(x1_grid, x2_grid, y_grid, levels=30, colors="gray")
plt.legend(["SGD", "Momentum"])
plt.show()

7.5.2 学习率衰减

  1. 等间隔衰减

可以通过torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma)来实现学习率的等间隔衰减。

  • optimizer:要实现学习率衰减的优化器
  • step_size:间隔
  • gamma:衰减的比例

例如,使学习率每隔20 epoch衰减为之前的0.7:

图片[2]-7.5 参数更新方法-大赛人网
import torch
import numpy as np
import matplotlib.pyplot as plt

# 从(-7, 2)出发
X = torch.tensor([-7, 2], dtype=torch.float32, requires_grad=True)
w = torch.tensor([[0.05], [1.0]], requires_grad=True)
lr = 0.9  # 初始学习率
n_iters = 1000  # 迭代次数

optimizer = torch.optim.SGD([X], lr=lr)
scheduler_lr = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.7)  # 学习率衰减
X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
lr_list = []  # 记录学习率变化
for epoch in range(n_iters):
    y = X**2 @ w
    y.backward()  # 反向传播
    optimizer.step()  # 更新参数
    optimizer.zero_grad()  # 清空梯度
    X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
    lr_list.append(optimizer.param_groups[0]["lr"])  # 记录学习率变化
    scheduler_lr.step()  # 学习率衰减

plt.rcParams["font.sans-serif"] = ["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False
fig, ax = plt.subplots(1, 2, figsize=(12, 4))
x1_grid, x2_grid = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-2, 2, 100))
y_grid = w.detach().numpy()[0, 0] * x1_grid**2 + w.detach().numpy()[1, 0] * x2_grid**2
ax[0].contour(x1_grid, x2_grid, y_grid, levels=30, colors="gray")
ax[0].plot(X_arr[:, 0], X_arr[:, 1], "r")
ax[0].set_title("梯度下降过程")

ax[1].plot(lr_list, "k")
ax[1].set_title("学习率衰减")
plt.show()

2.指定间隔衰减

可以通过torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma)来实现学习率的指定间隔衰减。

  • optimizer:要实现学习率衰减的优化器
  • milestones:指定衰减的间隔
  • gamma:衰减的比例

例如,使学习率在epoch达到[10,50,200]时衰减为之前的0.7:

图片[3]-7.5 参数更新方法-大赛人网
import torch
import numpy as np
import matplotlib.pyplot as plt

# 从(-7, 2)出发
X = torch.tensor([-7, 2], dtype=torch.float32, requires_grad=True)
w = torch.tensor([[0.05], [1.0]], requires_grad=True)
lr = 0.9  # 初始学习率
n_iters = 400  # 迭代次数

optimizer = torch.optim.SGD([X], lr=lr)
scheduler_lr = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[10, 50, 200], gamma=0.7)  # 学习率衰减
X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
lr_list = []  # 记录学习率变化
for epoch in range(n_iters):
    y = X**2 @ w
    y.backward()  # 反向传播
    optimizer.step()  # 更新参数
    optimizer.zero_grad()  # 清空梯度
    X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
    lr_list.append(optimizer.param_groups[0]["lr"])  # 记录学习率变化
    scheduler_lr.step()  # 学习率衰减

plt.rcParams["font.sans-serif"] = ["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False
fig, ax = plt.subplots(1, 2, figsize=(12, 4))
x1_grid, x2_grid = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-2, 2, 100))
y_grid = w.detach().numpy()[0, 0] * x1_grid**2 + w.detach().numpy()[1, 0] * x2_grid**2
ax[0].contour(x1_grid, x2_grid, y_grid, levels=30, colors="gray")
ax[0].plot(X_arr[:, 0], X_arr[:, 1], "r")
ax[0].set_title("梯度下降过程")

ax[1].plot(lr_list, "k")
ax[1].set_title("学习率衰减")
plt.show()

3.指数衰减

    图片[4]-7.5 参数更新方法-大赛人网
    图片[5]-7.5 参数更新方法-大赛人网
    import torch
    import numpy as np
    import matplotlib.pyplot as plt
    
    # 从(-7, 2)出发
    X = torch.tensor([-7, 2], dtype=torch.float32, requires_grad=True)
    w = torch.tensor([[0.05], [1.0]], requires_grad=True)
    lr = 0.9  # 初始学习率
    n_iters = 400  # 迭代次数
    
    optimizer = torch.optim.SGD([X], lr=lr)
    scheduler_lr = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.99)  # 学习率衰减
    X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
    lr_list = []  # 记录学习率变化
    for epoch in range(n_iters):
        y = X**2 @ w
        y.backward()  # 反向传播
        optimizer.step()  # 更新参数
        optimizer.zero_grad()  # 清空梯度
        X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
        lr_list.append(optimizer.param_groups[0]["lr"])  # 记录学习率变化
        scheduler_lr.step()  # 学习率衰减
    
    plt.rcParams["font.sans-serif"] = ["KaiTi"]
    plt.rcParams["axes.unicode_minus"] = False
    fig, ax = plt.subplots(1, 2, figsize=(12, 4))
    x1_grid, x2_grid = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-2, 2, 100))
    y_grid = w.detach().numpy()[0, 0] * x1_grid**2 + w.detach().numpy()[1, 0] * x2_grid**2
    ax[0].contour(x1_grid, x2_grid, y_grid, levels=30, colors="gray")
    ax[0].plot(X_arr[:, 0], X_arr[:, 1], "r")
    ax[0].set_title("梯度下降过程")
    
    ax[1].plot(lr_list, "k")
    ax[1].set_title("学习率衰减")
    plt.show()

    7.5.3 AdaGrad

    图片[6]-7.5 参数更新方法-大赛人网
    import torch
    import numpy as np
    import matplotlib.pyplot as plt
    
    def adagrad(X, lr, n_iters):
        """AdaGrad手动实现"""
        X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
        H = torch.zeros_like(X)  # 存放历史梯度信息
        for epoch in range(n_iters):
            grad = 2 * X * w.T  # 当前梯度
            grad.squeeze_()  # 降维
            H += grad**2  # 平方和
            X.data -= lr / (torch.sqrt(H) + 1e-8) * grad  # 更新参数,这里H后面加1e-8防止分母为0
            X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
        return X_arr
    
    def gradient_descent(X, optimizer, n_iters):
        X_arr = X.detach().numpy().copy()  # 拷贝,用于记录优化过程
        for epoch in range(n_iters):
            y = X**2 @ w
            y.backward()  # 反向传播
            optimizer.step()  # 更新参数
            optimizer.zero_grad()  # 清空梯度
            X_arr = np.vstack([X_arr, X.detach().numpy()])  # 记录优化过程
        return X_arr
    
    # 从(-7, 2)出发
    X = torch.tensor([-7, 2], dtype=torch.float32, requires_grad=True)
    w = torch.tensor([[0.05], [1.0]], requires_grad=True)
    lr = 0.9  # 学习率
    n_iters = 500  # 迭代次数
    
    # 普通梯度下降
    X_clone = X.clone().detach().requires_grad_(True)
    X_arr1 = gradient_descent(X_clone, torch.optim.SGD([X_clone], lr=lr), n_iters=n_iters)
    plt.plot(X_arr1[:, 0], X_arr1[:, 1], "r")
    
    # AdaGrad
    X_clone = X.clone().detach().requires_grad_(True)
    X_arr2 = gradient_descent(X_clone, torch.optim.Adagrad([X_clone], lr=lr), n_iters=n_iters)
    plt.plot(X_arr2[:, 0], X_arr2[:, 1], "b")
    
    # AdaGrad手动实现
    X_clone = X.clone().detach().requires_grad_(True)
    X_arr1 = adagrad(X_clone, lr=lr, n_iters=n_iters)
    plt.plot(X_arr1[:, 0], X_arr1[:, 1], c="orange", linestyle="--", linewidth=3)
    
    # 绘制等高线图
    x1_grid, x2_grid = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-2, 2, 100))
    y_grid = w.detach().numpy()[0, 0] * x1_grid**2 + w.detach().numpy()[1, 0] * x2_grid**2
    plt.contour(x1_grid, x2_grid, y_grid, levels=30, colors="gray")
    plt.legend(["SGD", "AdaGrad", "Manual AdaGrad"])
    © 版权声明
    THE END
    喜欢就支持一下吧
    点赞14 分享
    评论 抢沙发
    头像-大赛人网
    欢迎您留下宝贵的见解!
    提交
    头像-大赛人网

    昵称

    取消
    昵称

      请登录后查看评论内容