nndl 作业12 优化算法2D可视化

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

优化算法:优化的目标是网络模型中的参数\theta(集合),损失函数L变量就是θ,其中L中的参数是整个训练集,换句话说,目标函数(损失函数)是通过整个训练集来确定的,训练集全集不同,则损失函数的图像也不同。

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

nndl 作业12 优化算法2D可视化_第1张图片

SGD算法

SGD又称为随机梯度下降算法 ,用于求解损失函数最小值,对于SGD而言,每次使用的损失函数只是通过这一个小批量的数据确定的,其函数图像与真实全集损失函数有所不同,所以其求解的梯度也含有一定的随机性,在鞍点或者局部最小值点的时候,震荡跳动,如果是mini-batch或者SGD,每次找到的梯度都是不同的,就会发生震荡,来回跳动。

SGD 一次只进行一次更新,就没有冗余,而且比较快,并且可以新增样本。

nndl 作业12 优化算法2D可视化_第2张图片

缺点:更新比较频繁,会造成 cost function 有严重的震荡。

Adagrad

可以对低频的参数做较大的更新,对高频的做较小的更新,也因此,对于稀疏的数据它的表现很好,很好地提高了 SGD 的鲁棒性

梯度更新

nndl 作业12 优化算法2D可视化_第3张图片

优点是减少了学习率的手动调节,超参数设定值:一般η选取0.01

缺点:

它的缺点是分母会不断积累,这样学习率就会收缩并最终会变得非常小。

RMSprop

RMSprop 为了解决 Adagrad 学习率急剧下降问题的,

梯度更新规则:

使用的是指数加权平均,旨在消除梯度下降中的摆动,与Momentum的效果一样,某一维度的导数比较大,则指数加权平均就大,某一维度的导数比较小,则其指数加权平均就小,这样就保证了各维度导数都在一个量级,进而减少了摆动。允许使用一个更大的学习率η)

Momentum

加速 SGD, 并且抑制震荡

当我们将一个小球从山上滚下来时,没有阻力的话,它的动量会越来越大,但是如果遇到了阻力,速度就会变小。 加入的这一项,可以使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新速度变慢,这样就可以加快收敛并减小震荡。

超参数设定值:  一般 γ 取值 0.9 左右。

缺点:

这种情况相当于小球从山上滚下来时是在盲目地沿着坡滚,如果它能具备一些先知,例如快要上坡时,就知道需要减速了的话,适应性会更好。

Adam

计算每个参数的自适应学习率的方法。相当于 RMSprop + Momentum

除了像 Adadelta 和 RMSprop 一样存储了过去梯度的平方 vt 的指数衰减平均值 ,也像 momentum 一样保持了过去梯度 mt 的指数衰减平均值

每个优化器实现代码

import torch
from abc import abstractmethod


class Op(object):
    def __init__(self):
        pass

    def __call__(self, inputs):
        return self.forward(inputs)

    # 输入:张量inputs
    # 输出:张量outputs
    def forward(self, inputs):
        # return outputs
        raise NotImplementedError

    # 输入:最终输出对outputs的梯度outputs_grads
    # 输出:最终输出对inputs的梯度inputs_grads
    def backward(self, outputs_grads):
        # return inputs_grads
        raise NotImplementedError


# 优化器基类
class Optimizer(object):
    def __init__(self, init_lr, model):
        """
        优化器类初始化
        """
        # 初始化学习率,用于参数更新的计算
        self.init_lr = init_lr
        # 指定优化器需要优化的模型
        self.model = model

    @abstractmethod
    def step(self):
        """
        定义每次迭代如何更新参数
        """
        pass


class SimpleBatchGD(Optimizer):  # SGD,实际是批量梯度下降
    # 初始化方法,接受初始学习率 init_lr 和模型 model 作为参数
    def __init__(self, init_lr, model):
        super(SimpleBatchGD, self).__init__(init_lr=init_lr, model=model)

    def step(self):
        # 参数更新
        # 首先检查模型的参数是否为字典类型
        if isinstance(self.model.params, dict):
            for key in self.model.params.keys():
                # 对每一个参数执行更新操作:原参数 - 学习率 * 对应参数的梯度
                # 这里假设 self.model.grads[key] 存储了对应参数的梯度信息
                self.model.params[key] = self.model.params[key] - self.init_lr * self.model.grads[key]


class Adagrad(Optimizer):
    # 初始化方法,接受初始学习率init_lr、模型model和一个小量epsilon作为参数
    def __init__(self, init_lr, model, epsilon):
        super(Adagrad, self).__init__(init_lr=init_lr, model=model)
        # 初始化一个字典G,用于存储每个参数的历史梯度平方
        self.G = {}
        for key in self.model.params.keys():
            self.G[key] = 0
        # 存储epsilon,用于防止除数为0的情况
        self.epsilon = epsilon

    # adagrad方法,用于计算参数更新和梯度平方的更新
    def adagrad(self, x, gradient_x, G, init_lr):
        # 更新梯度平方的历史记录,将新的梯度平方加到原来的值上
        G += gradient_x ** 2
        # 根据Adagrad算法计算参数的更新量
        x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
        return x, G

    def step(self):
        for key in self.model.params.keys():
            # 调用adagrad方法进行参数更新和梯度平方的更新,并将结果存储回model.params和G字典中
            self.model.params[key], self.G[key] = self.adagrad(self.model.params[key],
                                                               self.model.grads[key],
                                                               self.G[key],
                                                               self.init_lr)


class RMSprop(Optimizer):
    def __init__(self, init_lr, model, beta, epsilon):
        super(RMSprop, self).__init__(init_lr=init_lr, model=model)
        # 初始化一个字典G,用于存储每个参数的历史梯度平方的加权移动平均
        self.G = {}
        for key in self.model.params.keys():
            self.G[key] = 0
        # 存储衰减率beta和epsilon,其中epsilon用于防止除数为0的情况
        self.beta = beta
        self.epsilon = epsilon

    # rmsprop方法,用于计算参数更新和梯度平方加权移动平均的更新
    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)



class Momentum(Optimizer):
    # 初始化方法,接受初始学习率init_lr、模型model和动量系数rho作为参数
    def __init__(self, init_lr, model, 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)


class Adam(Optimizer):
    def __init__(self, init_lr, model, 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  # 将每个参数的历史梯度的一阶矩初始化为0
            self.G[key] = 0  # 将每个参数的历史梯度的二阶矩初始化为0
        self.t = 1  # 初始化时间步t为1

    def adam(self, x, gradient_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)  # 对一阶矩进行正规化,使其除以(1 - beta1的t次方)
        G_hat = G / (1 - self.beta2 ** t)  # 对二阶矩进行正规化,使其除以(1 - 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)

调用优化器可视化

# coding=gbk
from Op import *
import torch
import numpy as np
from matplotlib import pyplot as plt
 
 
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'])
import copy
def train_f(model, optimizer, x_init, epoch):
    """
    训练函数
    输入:
        - model:被优化函数
        - optimizer:优化器
        - x_init:x初始值
        - 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'])
        '''
        这行代码使用contourf方法绘制了一个填充的等高线图。
        self.init_x[0]和self.init_x[1]是x1和x2的网格点。
        model(self.init_x.transpose([1, 0, 2]))表示将self.init_x转置后传递给模型函数,得到每个网格点的值。
        colors=['#e4007f', ...]定义了等高线填充的颜色。
        '''
        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')#不断更新的x,y绘制点,连成线
        ax.plot(0, 'r*', markersize=18, color='#fefefe')#标记0,0点
 
        ax.set_xlabel('$x1$')#标签名称
        ax.set_ylabel('$x2$')
 
        ax.set_xlim((-2, 5))#标签范围
        ax.set_ylim((-2, 5))
        plt.savefig(fig_name)
        plt.show()
 
 
import numpy as np
 
 
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.seed()
w = torch.as_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')
 
# 固定随机种子
torch.seed()
w = torch.as_tensor([0.2, 2])
model2 = OptimizedFunction(w)
opt2 = Adagrad(init_lr=0.5, model=model2, epsilon=1e-7)
train_and_plot_f(model2, opt2, epoch=50, fig_name='opti-vis-para2.pdf')
 
torch.seed()
w = torch.as_tensor([0.2, 2])
model3 = OptimizedFunction(w)
opt3 = RMSprop(init_lr=0.1, model=model3, beta=0.9, epsilon=1e-7)
train_and_plot_f(model3, opt3, epoch=50, fig_name='opti-vis-para3.pdf')
 
# 固定随机种子
torch.seed()
w = torch.as_tensor([0.2, 2])
model4 = OptimizedFunction(w)
opt4 = Momentum(init_lr=0.01, model=model4, rho=0.9)
train_and_plot_f(model4, opt4, epoch=50, fig_name='opti-vis-para4.pdf')
 
# 固定随机种子
torch.seed()
w = torch.as_tensor([0.2, 2])
model5 = OptimizedFunction(w)
opt5 = Adam(init_lr=0.2, model=model5, beta1=0.9, beta2=0.99, epsilon=1e-7)
train_and_plot_f(model5, opt5, epoch=20, fig_name='opti-vis-para5.pdf')

nndl 作业12 优化算法2D可视化_第4张图片 nndl 作业12 优化算法2D可视化_第5张图片

nndl 作业12 优化算法2D可视化_第6张图片 nndl 作业12 优化算法2D可视化_第7张图片

nndl 作业12 优化算法2D可视化_第8张图片

 2.被优化函数  :\frac{x^{2}}{20}+y^{2}

 nndl 作业12 优化算法2D可视化_第9张图片

# 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.m[key]也可使用(1 - self.beta1)
            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(50):
        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
    # 将数组Z中所有大于7的值都设置为0

    # plot
    plt.subplot(2, 3, idx)
    idx += 1
    plt.plot(x_history, y_history, 'o-', color="b")
    # plt.contour(X, Y, Z)  # 绘制等高线
    plt.contour(X, Y, Z, cmap='copper')  # 颜色填充
    # plt.contour()函数用于绘制等高线图
    # X 和 Y 是网格点的x和y坐标。
    # Z 是每个网格点上的值。
    # cmap 是一个可选参数,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=10, color="r",
             verticalalignment='top', horizontalalignment='center', fontstyle='normal')
    '''
    0, 10: 这是文本的坐标位置。0是x坐标,10是y坐标。
    key + '\nlr=' + str(lr): 这是要添加到图上的文本字符串。key是一个变量,'\n'是一个换行符,将文本分成两行。lr是另一个变量,使用str()函数将其转换为字符串类型,以便与key连接。
    fontsize=20: 设置文本的字体大小为10。
    color="b": 设置文本的颜色为红色(red)。
    verticalalignment='top': 设置文本的垂直对齐方式为顶部对齐。
    horizontalalignment='center': 设置文本的水平对齐方式为居中对齐。
    fontstyle='italic': 设置文本的字体样式为正常。
    '''
    plt.xlabel("x")
    plt.ylabel("y")

plt.subplots_adjust(wspace=0, hspace=0)  # 调整子图间距wspace: 水平间距,即子图之间的宽度间距。hspace: 垂直间距,即子图之间的高度间距。
plt.show()

nndl 作业12 优化算法2D可视化_第10张图片 

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

SGD轨迹形成原因:

1、因为是随机梯度下降,SGD在每一步仅仅使用一个样本的梯度信息,这使得它对函数局部特性的估计可能不够准确。当函数具有非均向性(如一个维度上的变化远大于另一个维度)时,SGD可能会在最优解附近来回震荡,呈现出“之”字形的轨迹,

2、学习率设置不合适:如果学习率设置得过大,SGD可能会跳过最优解;如果学习率设置得过小,SGD可能会在最优解附近徘徊不前。当学习率的调整不恰当时,SGD的收敛轨迹就可能呈现出“之”字形。

Adagrad

y轴梯度较大,后面会根据前面较大的变动进行调整,减小更新的步伐,呈现稳定的向最优点收敛。

RMSprop

RMSprop因为逐渐遗忘过去的梯度,只被近期的梯度影响,在最初的时候会收敛的更快,变化幅度大。

Momentum

对以前的梯度做了指数加权平均,不会像原始的那样直接折线那么厉害,因为有之前速度影响,所以瞬间就折,而是会再向原来那个方向前进一段距离,也可以理解为对原始梯度做了一个平滑,然后再用来做梯度下降

Adam

前期收敛幅度较大,后期逐渐平稳,朝着最优点不断移动。Adam算法由于可以结合了动量法和 RMSprop 。

动量法

动量相当于给梯度一个惯性,使其能够在相同方向上持续更新。这可以帮助算法跳过局部最小值并加速收敛。动量系数是一个介于0和1之间的值,通常设置为0.9。该值越高,算法越趋向于保持之前的方向。在每次迭代中,算法会计算梯度,并将其与之前的梯度相加,产生一个新的梯度。它可以跳过局部最小值并加速收敛。另外,由于动量系数的引入,该算法具有一定的平滑性,这可以帮助防止过度拟合。

缺点:

它需要更多的内存来存储之前的梯度。此外,由于动量系数的引入,该算法可能会导致权重更新过多。这可以通过调整动量系数和学习率来解决。

Adam中使用一阶矩和二阶矩,一阶矩就是期望值,换句话说就是平均数,二阶矩方差

当 一阶矩大,且二阶矩大,梯度大且稳定

当一阶矩小,二阶矩很大,振荡,考虑成可能是向下更新到一个局部的波谷,又进行一波反弹

当 一阶矩 趋近于 0,且 二阶矩也趋近于 0 :梯度趋于零,可能达到局部最低点,也可能走到一个极度平缓的平地

如何选择优化算法深度学习——优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)-腾讯云开发者社区-腾讯云 (tencent.com)

如果数据是稀疏的,就用自适用方法,即 Adagrad, Adadelta, RMSprop, Adam。

RMSprop, Adadelta, Adam 在很多情况下的效果是相似的。

Adam 就是在 RMSprop 的基础上加了 bias-correction 和 momentum,

随着梯度变的稀疏,Adam 比 RMSprop 效果会好。

整体来讲,Adam 是最好的选择。

很多论文里都会用 SGD,没有 momentum 等。SGD 虽然能达到极小值,但是比其它算法用的时间长,而且可能会被困在鞍点。

如果需要更快的收敛,或者是训练更深更复杂的神经网络,需要用一种自适应的算法。

 

REF:

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

深度学习——优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)-腾讯云开发者社区-腾讯云 (tencent.com)

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

NNDL 作业12-优化算法2D可视化 [HBU]-CSDN博客 

Adam Algorithm & First-order moment, Second moment_一阶矩估计-CSDN博客 

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