【23-24 秋学期】NNDL 作业12 优化算法2D可视化

目录

简要介绍图中的优化算法,编程实现并2D可视化

1. 被优化函数 ​x^{2}

2. 被优化函数 ​x^{2}/20+y^{2}

3. 解释不同轨迹的形成原因 

分析各个算法的优缺点

总结 及心得体会


简要介绍图中的优化算法,编程实现并2D可视化

1. 被优化函数 x^{2}

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第1张图片

(1)SGD

       SGD优化算法,即随机梯度下降法,是一种经典的优化算法,广泛应用于机器学习和深度学习领域。该算法通过随机选取小批量样本的梯度均值来更新模型参数,每次迭代使用的是随机梯度,即从全局最优解开始,以一定概率向最近梯度方向传播的梯度。这种算法的优点在于计算速度快,可以处理大规模数据集。

from nndl.op import Op
import torch
import numpy as np
from matplotlib import pyplot as plt
 
from nndl.opitimizer import SimpleBatchGD
 
# 被优化函数
class OptimizedFunction(Op):
    def __init__(self, w):
        super(OptimizedFunction, self).__init__()
        self.w = w
        self.params = {'x': 0}
        self.grads = {'x': 0}
 
    def forward(self, x):
        self.params['x'] = x
        return torch.matmul(self.w.T, torch.tensor(torch.square(self.params['x']), dtype=torch.float32))
 
    def backward(self):
        self.grads['x'] = 2 * torch.multiply(self.w.T, self.params['x'])
 
 
# SGD梯度更新
import copy
 
def train_f(model, optimizer, x_init, epoch):
    x = x_init
    all_x = []
    losses = []
    for i in range(epoch):
        all_x.append(copy.copy(x.numpy()))
        loss = model(x)
        losses.append(loss)
        model.backward()
        optimizer.step()
        x = model.params['x']
        print(all_x)
    return torch.tensor(all_x), losses
 
 
# 可视化
class Visualization(object):
    def __init__(self):
        """
        初始化可视化类
        """
        # 只画出参数x1和x2在区间[-5, 5]的曲线部分
        x1 = np.arange(-5, 5, 0.1)
        x2 = np.arange(-5, 5, 0.1)
        x1, x2 = np.meshgrid(x1, x2)
        self.init_x = torch.tensor([x1, x2])
 
    def plot_2d(self, model, x, fig_name):
        """
        可视化参数更新轨迹
        """
        fig, ax = plt.subplots(figsize=(10, 6))
        cp = ax.contourf(self.init_x[0], self.init_x[1], model(self.init_x.transpose(0, 1)),
                         colors=['#e4007f', '#f19ec2', '#e86096', '#eb7aaa', '#f6c8dc', '#f5f5f5', '#000000'])
        c = ax.contour(self.init_x[0], self.init_x[1], model(self.init_x.transpose(0, 1)), colors='black')
        cbar = fig.colorbar(cp)
        ax.plot(x[:, 0], x[:, 1], '-o', color='#000000')
        ax.plot(0, 'r*', markersize=18, color='#fefefe')
 
        ax.set_xlabel('$x1$')
        ax.set_ylabel('$x2$')
 
        ax.set_xlim((-2, 5))
        ax.set_ylim((-2, 5))
        plt.savefig(fig_name)
        plt.show()
 
def train_and_plot_f(model, optimizer, epoch, fig_name):
    """
    训练模型并可视化参数更新轨迹
    """
    # 设置x的初始值
    x_init = torch.tensor([3, 4], dtype=torch.float32)
    print('x1 initiate: {}, x2 initiate: {}'.format(x_init[0].numpy(), x_init[1].numpy()))
    x, losses = train_f(model, optimizer, x_init, epoch)
    print(x)
    losses = np.array(losses)
 
    # 展示x1、x2的更新轨迹
    vis = Visualization()
    vis.plot_2d(model, x, fig_name)
 
 
# 固定随机种子
torch.manual_seed(0)
w = torch.tensor([0.2, 2])
model = OptimizedFunction(w)
opt = SimpleBatchGD(init_lr=0.2, model=model)
train_and_plot_f(model, opt, epoch=20, fig_name='opti-vis-para.pdf')
 

 【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第2张图片

 (2)Adagrad

        Adagrad优化算法是梯度下降法的改进算法,其优点是可以自适应学习率。该优化算法在较为平缓处学习速率大,有比较高的学习效率,在陡峭处学习率小,在一定程度上可以避免越过极小值点。Adagrad算法在每次使用一个batch size的数据进行参数更新时,会计算所有参数的梯度,并初始化一个变量s为0,然后将该参数的梯度平方求和累加到s上。在更新参数时,学习率就变Adagrad算法的公式中的值。由于不同的参数梯度不同,他们对应的s大小也不同,因此公式得到的学习率也不同,这实现了自适应的学习率。使用自适应的学习率可以帮助算法在梯度大的参数方向减缓学习速率,而在梯度小的参数方向加快学习速率,这导致了神经网络的训练速度的加快。

class Adagrad(Optimizer):
    def __init__(self, init_lr, model, epsilon):
        """
        Adagrad 优化器初始化
        输入:
            - init_lr: 初始学习率
            - model:模型,model.params存储模型参数值
            - epsilon:保持数值稳定性而设置的非常小的常数
        """
        super(Adagrad, self).__init__(init_lr=init_lr, model=model)
        self.G = {}
        for key in self.model.params.keys():
            self.G[key] = 0
        self.epsilon = epsilon
 
    def adagrad(self, x, gradient_x, G, init_lr):
        """
        adagrad算法更新参数,G为参数梯度平方的累计值。
        """
        G += gradient_x ** 2
        x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
        return x, G
 
    def step(self):
        """
        参数更新
        """
        for key in self.model.params.keys():
            self.model.params[key], self.G[key] = self.adagrad(self.model.params[key],
                                                               self.model.grads[key],
                                                               self.G[key],
                                                               self.init_lr)
 
torch.manual_seed(0)
w = torch.tensor([0.2, 2])
model = OptimizedFunction(w)
opt = Adagrad(init_lr=0.5, model=model, epsilon=1e-7)
train_and_plot_f(model, opt, epoch=50, fig_name='opti-vis-para2.pdf')
plt.show()

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第3张图片

(3)RMSprop

       RMSProp是一种自适应学习率的优化算法,由Geoffrey Hinton提出,主要用于解决梯度下降中的学习率调整问题。在梯度下降中,每个参数的学习率是固定的,但在实际应用中,每个参数的最优学习率可能是不同的。RMSProp算法通过自动调整每个参数的学习率来解决这个问题。它在每次迭代中维护一个指数加权平均值,用于调整每个参数的学习率。如果某个参数的梯度较大,则RMSProp算法会自动减小它的学习率;如果梯度较小,则会增加学习率。这样可以使得模型的收敛速度更快。

 
class RMSprop(Optimizer):
    def __init__(self, init_lr, model, beta, epsilon):
        """
        RMSprop优化器初始化
        输入:
            - init_lr:初始学习率
            - model:模型,model.params存储模型参数值
            - beta:衰减率
            - epsilon:保持数值稳定性而设置的常数
        """
        super(RMSprop, self).__init__(init_lr=init_lr, model=model)
        self.G = {}
        for key in self.model.params.keys():
            self.G[key] = 0
        self.beta = beta
        self.epsilon = epsilon
 
    def rmsprop(self, x, gradient_x, G, init_lr):
        """
        rmsprop算法更新参数,G为迭代梯度平方的加权移动平均
        """
        G = self.beta * G + (1 - self.beta) * gradient_x ** 2
        x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
        return x, G
 
    def step(self):
        """参数更新"""
        for key in self.model.params.keys():
            self.model.params[key], self.G[key] = self.rmsprop(self.model.params[key],
                                                               self.model.grads[key],
                                                               self.G[key],
                                                               self.init_lr)
 
 
# 固定随机种子
torch.manual_seed(0)
w = torch.tensor([0.2, 2])
model = OptimizedFunction(w)
opt = RMSprop(init_lr=0.1, model=model, beta=0.9, epsilon=1e-7)
train_and_plot_f(model, opt, epoch=50, fig_name='opti-vis-para3.pdf')

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第4张图片

(4)Momentum

       Momentum是一种在梯度下降法基础上添加动量的优化算法,其基本思想是从物理学的角度引入动量,使得在梯度下降的过程中,对于当前梯度方向上的参数更新有一定的惯性,即能够“加速”前进,而在相反的方向上则有一定的阻尼,即能够“刹车”。这样可以加速算法向最优解的收敛,同时也可以使得算法在遇到局部最优解时有一定的“逃逸”能力。Momentum优化算法的具体实现方式是,在每次更新参数时,除了考虑梯度外,还考虑上一个时刻的参数更新方向。具体来说,假设当前时刻的参数更新为Δθ,上一个时刻的参数更新为Δθ−1,那么当前时刻的参数更新方向可以由梯度和上一个时刻的更新方向共同决定。具体公式为:Δθ=βΔθ−1+(1−β)gradθ其中,β是动量系数,取值范围通常在0到1之间。如果β接近于1,那么当前的参数更新方向将主要由上一个时刻的更新方向决定;如果β接近于0,那么当前的参数更新方向将主要由梯度决定。Momentum优化算法的优点是可以加速算法向最优解的收敛,同时可以使得算法在遇到局部最优解时有一定的“逃逸”能力。但是,如果动量系数β取值不当,可能会导致算法震荡过大或者收敛速度过快而错过最优解。因此,在实际应用中,需要根据具体情况选择合适的动量系数β。

class Momentum(Optimizer):
    def __init__(self, init_lr, model, rho):
        """
        Momentum优化器初始化
        输入:
            - init_lr:初始学习率
            - model:模型,model.params存储模型参数值
            - rho:动量因子
        """
        super(Momentum, self).__init__(init_lr=init_lr, model=model)
        self.delta_x = {}
        for key in self.model.params.keys():
            self.delta_x[key] = 0
        self.rho = rho
 
    def momentum(self, x, gradient_x, delta_x, init_lr):
        """
        momentum算法更新参数,delta_x为梯度的加权移动平均
        """
        delta_x = self.rho * delta_x - init_lr * gradient_x
        x += delta_x
        return x, delta_x
 
    def step(self):
        """参数更新"""
        for key in self.model.params.keys():
            self.model.params[key], self.delta_x[key] = self.momentum(self.model.params[key],
                                                                      self.model.grads[key],
                                                                      self.delta_x[key],
                                                                      self.init_lr)
 
 
# 固定随机种子
torch.manual_seed(0)
w = torch.tensor([0.2, 2])
model = OptimizedFunction(w)
opt = Momentum(init_lr=0.01, model=model, rho=0.9)
train_and_plot_f(model, opt, epoch=50, fig_name='opti-vis-para4.pdf')

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第5张图片

 (5)Adam

        Adam是一种自适应学习率的优化算法,结合了AdaGrad和RMSProp两种算法的优点。Adam算法在权重更新时为不同的参数设计独立的自适应性学习率,通过计算梯度的一阶矩估计和二阶矩估计来实现。Adam算法在在线和非平稳问题上都表现出色,尤其在梯度变得稀疏时比RMSprop算法更快速和优秀。

class Adam(Optimizer):
    def __init__(self, init_lr, model, beta1, beta2, epsilon):
        """
        Adam优化器初始化
        输入:
            - init_lr:初始学习率
            - model:模型,model.params存储模型参数值
            - beta1, beta2:移动平均的衰减率
            - epsilon:保持数值稳定性而设置的常数
        """
        super(Adam, self).__init__(init_lr=init_lr, model=model)
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        self.M, self.G = {}, {}
        for key in self.model.params.keys():
            self.M[key] = 0
            self.G[key] = 0
        self.t = 1
 
    def adam(self, x, gradient_x, G, M, t, init_lr):
        """
        adam算法更新参数
        输入:
            - x:参数
            - G:梯度平方的加权移动平均
            - M:梯度的加权移动平均
            - t:迭代次数
            - init_lr:初始学习率
        """
        M = self.beta1 * M + (1 - self.beta1) * gradient_x
        G = self.beta2 * G + (1 - self.beta2) * gradient_x ** 2
        M_hat = M / (1 - self.beta1 ** t)
        G_hat = G / (1 - self.beta2 ** t)
        t += 1
        x -= init_lr / torch.sqrt(G_hat + self.epsilon) * M_hat
        return x, G, M, t
 
    def step(self):
        """参数更新"""
        for key in self.model.params.keys():
            self.model.params[key], self.G[key], self.M[key], self.t = self.adam(self.model.params[key],
                                                                                 self.model.grads[key],
                                                                                 self.G[key],
                                                                                 self.M[key],
                                                                                 self.t,
                                                                                 self.init_lr)
# 固定随机种子
torch.manual_seed(0)
w = torch.tensor([0.2, 2])
model = OptimizedFunction(w)
opt = Adam(init_lr=0.2, model=model, beta1=0.9, beta2=0.99, epsilon=1e-7)
train_and_plot_f(model, opt, epoch=20, fig_name='opti-vis-para5.pdf')

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第6张图片

2. 被优化函数 x^{2}/20+y^{2}  

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第7张图片

 
# coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
from collections import OrderedDict
 
 
class SGD:
    """随机梯度下降法(Stochastic Gradient Descent)"""
 
    def __init__(self, lr=0.01):
        self.lr = lr
 
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]
 
class Momentum:
    """Momentum SGD"""
 
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None
 
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)
 
        for key in params.keys():
            self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]
            params[key] += self.v[key]
 
class Nesterov:
    """Nesterov's Accelerated Gradient (http://arxiv.org/abs/1212.0901)"""
 
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None
 
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)
 
        for key in params.keys():
            self.v[key] *= self.momentum
            self.v[key] -= self.lr * grads[key]
            params[key] += self.momentum * self.momentum * self.v[key]
            params[key] -= (1 + self.momentum) * self.lr * grads[key]
 
class AdaGrad:
    """AdaGrad"""
 
    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None
 
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)
 
        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
 
class RMSprop:
    """RMSprop"""
 
    def __init__(self, lr=0.01, decay_rate=0.99):
        self.lr = lr
        self.decay_rate = decay_rate
        self.h = None
 
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)
 
        for key in params.keys():
            self.h[key] *= self.decay_rate
            self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
 
class Adam:
    """Adam (http://arxiv.org/abs/1412.6980v8)"""
 
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None
 
    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)
 
        self.iter += 1
        lr_t = self.lr * np.sqrt(1.0 - self.beta2 ** self.iter) / (1.0 - self.beta1 ** self.iter)
 
        for key in params.keys():
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key] ** 2 - self.v[key])
 
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
 
 
def f(x, y):
    return x ** 2 / 20.0 + y ** 2
   
 
def df(x, y):
    return x / 10.0, 2.0 * y
 
 
init_pos = (-7.0, 2.0)
params = {}
params['x'], params['y'] = init_pos[0], init_pos[1]
grads = {}
grads['x'], grads['y'] = 0, 0
 
learningrate = [0.9, 0.3, 0.3, 0.6, 0.6, 0.6, 0.6]
optimizers = OrderedDict()
optimizers["SGD"] = SGD(lr=learningrate[0])
optimizers["Momentum"] = Momentum(lr=learningrate[1])
optimizers["Nesterov"] = Nesterov(lr=learningrate[2])
optimizers["AdaGrad"] = AdaGrad(lr=learningrate[3])
optimizers["RMSprop"] = RMSprop(lr=learningrate[4])
optimizers["Adam"] = Adam(lr=learningrate[5])
 
idx = 1
id_lr = 0
 
for key in optimizers:
    optimizer = optimizers[key]
    lr = learningrate[id_lr]
    id_lr = id_lr + 1
    x_history = []
    y_history = []
    params['x'], params['y'] = init_pos[0], init_pos[1]
 
    for i in range(30):
        x_history.append(params['x'])
        y_history.append(params['y'])
 
        grads['x'], grads['y'] = df(params['x'], params['y'])
        optimizer.update(params, grads)
 
    x = np.arange(-10, 10, 0.01)
    y = np.arange(-5, 5, 0.01)
 
    X, Y = np.meshgrid(x, y)
    Z = f(X, Y)
    # for simple contour line
    mask = Z > 7
    Z[mask] = 0
 
    # plot
    plt.subplot(2, 3, idx)
    idx += 1
    plt.plot(x_history, y_history, 'o-', color="r")
    # plt.contour(X, Y, Z)  # 绘制等高线
    plt.contour(X, Y, Z, cmap='gray')  # 颜色填充
    plt.ylim(-10, 10)
    plt.xlim(-10, 10)
    plt.plot(0, 0, '+')
    # plt.axis('off')
    # plt.title(key+'\nlr='+str(lr), fontstyle='italic')
    plt.text(0, 10, key + '\nlr=' + str(lr), fontsize=20, color="b",
             verticalalignment='top', horizontalalignment='center', fontstyle='italic')
    plt.xlabel("x")
    plt.ylabel("y")
 
plt.subplots_adjust(wspace=0, hspace=0)  # 调整子图间距
plt.show()

【23-24 秋学期】NNDL 作业12 优化算法2D可视化_第8张图片

3. 解释不同轨迹的形成原因 

分析各个算法的优缺点

(1)SGD

轨迹形成原因:SGD收敛轨迹呈“之”字形,是因为y方向变化很大,x方向变化很小,随机收敛只能迂回往复地寻找,效率很低。单纯的朝着梯度方向,使得在函数的形状非均向时,只能反复的寻找。

优点:

  1. 训练速度快:SGD每次只需要计算一个样本的梯度,因此训练速度非常快。
  2. 可适用于大规模数据集:由于SGD的训练速度很快,因此它对于大规模数据集也很适用。
  3. 可以跳出局部最优:由于SGD每次只考虑一个样本,因此更容易跳出局部最优点,从而找到全局最优解。

然而,SGD优化算法也存在一些缺点:

  1. 更新不稳定:由于SGD只考虑一个样本,因此每次更新都有一定的随机性,导致更新不稳定。
  2. 容易陷入局部最优:虽然SGD容易跳出局部最优,但是由于随机性的影响,也容易陷入局部最优点。
  3. 需要调整学习率:SGD的收敛速度很快,但是需要调整学习率,否则可能导致模型无法收敛或收敛速度过慢。

(2)Adagrad 

轨迹形成原因:函数的取值高效地向着最小值移动。 由于y轴方向上的梯度较大,因此刚开始变动较大,但是后面会根据前面较大的变动进行调整,减小更新的步伐,导致y轴方向上的更新程度被减弱,“之”字形的变动程度衰减,呈现稳定的向最优点收敛。

优点:

  1. 自适应学习率:Adagrad算法能够根据每个参数的梯度大小自动调整学习率,使得算法更加灵活和自适应。
  2. 稀疏数据集效果好:对于稀疏数据集,Adagrad算法能够更好地处理稀疏特征,因为其能够自动调整每个特征的学习率。
  3. 收敛速度快:Adagrad算法在某些情况下比其他优化算法具有更快的收敛速度。

缺点:

  1. 学习率衰减过快:Adagrad算法在每次迭代中都会减小学习率,导致在训练过程的后期学习率变得非常小,这可能会导致模型在训练过程的后期出现收敛速度缓慢的问题。
  2. 不能处理不同特征的尺度问题:Adagrad算法对所有特征的学习率都进行了相同的缩放,不能处理不同特征的尺度问题,这可能导致模型在训练过程中出现一些问题。
  3. 对初始值敏感:Adagrad算法对初始值比较敏感,如果初始值设置不当,可能会导致算法收敛到局部最优解或者无法收敛。

(3)RMSprop

轨迹形成原因:RMSprop算法的轨迹图与AdaGrad相比,RMSprop的轨迹到后期表现出更加平缓和稳定的学习率变化,从而更有效地收敛到损失函数的最小值。但是由于该算法会逐渐遗忘过去的梯度,只被近期的梯度所影响,在最初的时候会收敛的更快,变化幅度大。

优点:

  1. 自适应学习率:RMSprop算法能够根据每个参数的梯度大小自动调整学习率,使得算法更加灵活和自适应。
  2. 避免学习率选择问题:由于RMSprop算法能够自动调整学习率,因此避免了手动选择学习率的问题,减少了人工干预和调参的难度。
  3. 适用于非平稳目标:RMSprop算法适用于非平稳目标,能够更好地处理复杂和动态的数据分布。

缺点:

  1. 依赖于全局学习率:RMSprop算法虽然能够自适应调整每个参数的学习率,但仍然依赖于一个全局的学习率。如果全局学习率设置不当,可能会影响算法的性能。
  2. 对初始值敏感:RMSprop算法对初始值比较敏感,如果初始值设置不当,可能会导致算法收敛到局部最优解或者无法收敛。
  3. 对异常值敏感:RMSprop算法对异常值比较敏感,如果数据集中存在异常值,可能会影响算法的性能。

 (4)Monmentum

轨迹形成原因:该算法的收敛路径以一种有所抑制的振荡模式接近最小值。动量法是梯度估计修正算法,引入了动量的概念,当梯度方向不一致时,会起到减速作用,增加稳定性。

优点:

  1. 加速收敛:Momentum算法能够加速参数的更新和优化算法的收敛速度。
  2. 避免局部最优解:Momentum算法能够通过引入动量项来克服局部最优解的问题,使算法更加稳定和可靠。
  3. 适用于大规模数据集:Momentum算法在大规模数据集上表现良好,能够有效地处理大量数据。

缺点:

  1. 对学习率敏感:Momentum算法对学习率的选择比较敏感,如果学习率设置不当,可能会导致算法无法收敛或者收敛速度过慢。
  2. 对参数设置敏感:Momentum算法对参数设置比较敏感,例如动量系数和衰减率等,如果设置不当,可能会影响算法的性能。
  3. 对初始值敏感:Momentum算法对初始值比较敏感,如果初始值设置不当,可能会导致算法收敛到局部最优解或者无法收敛。

(5)Nesterov 

轨迹形成原因:该算法是对动量法的改进,不仅仅根据当前梯度调整位置,而是根据当前动量在预期的未来位置计算梯度。所以,算法可以相应地调整更新,避免在使用梯度下降时可能出现的振荡,特别是当表面具有陡峭的峡谷时,可能会导致更快地收敛到最小值。图中的轨迹呈现出更加平滑、更有方向性的路径朝向最优点。

优点:

  1. 加速收敛:Nesterov算法能够加速参数的更新和优化算法的收敛速度,尤其在处理非凸优化问题时表现优秀。
  2. 减少局部最优解的可能性:Nesterov算法通过在每次迭代中引入预估的梯度信息,能够更好地探索参数空间,从而减少陷入局部最优解的可能性。
  3. 适用于大规模数据集:Nesterov算法在处理大规模数据集时表现良好,能够有效地处理大量数据。

缺点:

  1. 对学习率敏感:Nesterov算法对学习率的选择比较敏感,如果学习率设置不当,可能会导致算法无法收敛或者收敛速度过慢。
  2. 对参数设置敏感:Nesterov算法对参数设置比较敏感,例如动量系数和衰减率等,如果设置不当,可能会影响算法的性能。
  3. 需要计算预估的梯度信息:Nesterov算法需要计算预估的梯度信息,这会增加计算量和存储开销。

 (6)Adam

轨迹形成原因:Adam的收敛轨迹图和其他的相比,明显要稳定,基本上是呈直线,或者前期收敛幅度较大,后期逐渐平稳,朝着最优点不断移动。Adam算法由于可以结合了动量法和 RMSprop 算法,不仅何以自适应调整学习率,收敛速度快,并且参数更新更加平稳。

优点:

  1. 自适应学习率:Adam算法能够根据每个参数的梯度大小自动调整学习率,使得算法更加灵活和自适应。
  2. 避免梯度消失和梯度爆炸问题:Adam算法采用梯度的一阶矩估计和二阶矩估计来调整每个参数的学习率,从而避免了梯度消失和梯度爆炸问题。
  3. 适用于大规模数据集:Adam算法在大规模数据集上表现良好,能够有效地处理大量数据。
  4. 适用于深度学习模型:Adam算法适用于深度学习模型,尤其在训练初期可以更快地收敛。

缺点:

  1. 对初始值敏感:Adam算法对初始值比较敏感,如果初始值设置不当,可能会导致算法收敛到局部最优解或者无法收敛。
  2. 对参数设置敏感:Adam算法对参数设置比较敏感,例如beta1、beta2和epsilon等,如果设置不当,可能会影响算法的性能。
  3. 计算量大:Adam算法需要计算每个参数的梯度的一阶矩估计和二阶矩估计,计算量比较大,会增加训练时间和计算成本。
总结 及心得体会

   通过这次作业,让我对几种优化算法进行了比较,对SGD、Momentum、AdaGrad、Adam有了一定的了解,总结了它们的优缺点以及内在联系。尤其对SGD和Adam进行了深刻地学习。对参数更新优化算法有了一定了解,再加上上学期学的最优化方法,这次上课的内容就有了更加深刻的认识。

参考链接:

【NNDL 作业】优化算法比较 增加 RMSprop、Nesterov_随着优化的进展,需要调整γ吗?rmsprop算法习题-CSDN博客

【23-24 秋学期】NNDL 作业12 优化算法2D可视化-CSDN博客

你可能感兴趣的:(python,人工智能,深度学习)