随机梯度下降法 SGD

stochastic gradient descent

假设红色部分为一个下凹空间,现在要前往空间的最低点。随机梯度下降法 SGD 低效的根本问题在于,每一步虽然都是立足于当前点的梯度方向(蓝线),但梯度的方向并不一定指向最小值的方向(黑线)。

深度学习之优化算法_优化器

深度学习之优化算法_人工智能_02

基于SGD的最优化的更新路径:呈“之”字形朝最小值(0, 0)移动,效率低

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]

Momentum

数学式表示

深度学习之优化算法_优化器_03

深度学习之优化算法_优化算法_04 为要更新的权重参数, 深度学习之优化算法_优化器_05 表示损失函数关于 深度学习之优化算法_优化算法_04 的梯度, 深度学习之优化算法_深度学习_07 表示学习率, 深度学习之优化算法_人工智能_08 对应物理上的速度。

深度学习之优化算法_深度学习_09

当从 A 点沿梯度方向走到 B 点时,将 B 的梯度方向与动量项合并,作为新的更新方向

  1. 如果 B 点梯度方向不变,由于加上了动量项,可以使 SGD 加快更新
  2. 如果 B 点梯度方向改变,动量项可以减弱更新幅度,防止发生较大改变导致更新不稳定

深度学习之优化算法_优化算法_10

基于 Momentum 的最优化的更新路径

和 SGD 相比,我们发现“之”字形的“程度”减轻了。这是因为虽然 x 轴方向上受到的力非常小,但是一直在同一方向上受力,所以朝同一个方向会有一定的加速。

反过来,虽然 y 轴方向上受到的力很大,但是因为交互地受到正方向和反方向的力,它们会互相抵消,所以 y 轴方向上的速度不稳定。因此,和 SGD 时的情形相比,可以更快地朝 x 轴方向靠近,减弱“之”字形的变动程度。

代码

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]

AdaGrad

自适应地为各个维度的参数分配不同的学习率

在神经网络的学习中,学习率过小,会导致学习花费过多时间;反过来,学习率过大,则会导致学习发散而不能正确进行。

在关于学习率的有效技巧中,有一种被称为学习率衰减(learning rate decay)的方法,即随着学习的进行,使学习率逐渐减小。AdaGrad(Ada 意为 Adaptive)会为参数的每个元素适当地调整学习率,与此同时进行学习。

深度学习之优化算法_优化算法_11

深度学习之优化算法_优化算法_12 保存了以前的所有梯度值的平方和, 深度学习之优化算法_人工智能_13 表示 element-wise 矩阵乘法(对应位置元素相乘), 深度学习之优化算法_优化算法_14 是一个极小值,防止出现分母为 0 的情况。

  • 优点:h 较小时,可以放大梯度;较大时,可以约束梯度(奖励+惩罚)
  • 缺点:
  • 梯度累积导致学习率单调递减,后期学习率极小
  • 仍然需要设置一个合适的全局初始学习率

代码

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]
            # 分母不得为0,加1e-7极小值
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

深度学习之优化算法_优化器_15

基于 AdaGrad 的最优化的更新路径

RMSProp

在 AdaGrad 基础上产生的改进版

深度学习之优化算法_人工智能_16

其中, 深度学习之优化算法_人工智能_17 默认为 0.9。

可以看见,RMSProp 与 AdaGrad 不同,它通过增加一个衰减系数,只关注最近某一时间窗口内的下降梯度,来控制历史梯度信息的获取。

深度学习之优化算法_优化器_18 是由历史平方梯度和当前平方梯度加权得到的平均数,而 深度学习之优化算法_人工智能_17 控制了历史平方梯度的权重:

  • 深度学习之优化算法_人工智能_17 较小时,平均数会对历史梯度进行平滑,从而减少历史梯度对参数更新的影响;
  • 深度学习之优化算法_人工智能_17 较大时,平均数会对历史梯度进行加权平均,从而增加历史梯度对参数更新的影响。

因此可以在一定程度上缓解 AdaGrad 在后期学习率太小这个问题。

代码

class 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)

Adam

Momentum + RMSProp = Adam

深度学习之优化算法_优化器_22

Adam 采用两个不同的超参数 β1 和 β2 来控制动量以及 RMSProp 中指数加权移动平均 深度学习之优化算法_人工智能_23 的更新。

深度学习之优化算法_优化算法_24

通常,β1=0.9,β2=0.999,ϵ=1e−7

初始化偏差修正

Adam 的一个改进点是 Adam 对一阶矩估计和二阶矩估计进行了修正,使其近似为对期望的无偏估计。修正方式为:

深度学习之优化算法_优化算法_25

下面对偏差修正进行解释。

通过下列推导得到在前面所有时间步上只包含梯度和衰减率的函数,即消去 v:

深度学习之优化算法_人工智能_26

深度学习之优化算法_人工智能_27

E (aX) = aE (X),好像是有这么个期望公式?概率论忘干净了 hhhh

深度学习之优化算法_人工智能_28

可以发现,当 t 取的很小时,例如 t=1,此时 深度学习之优化算法_深度学习_29 。显然,在迭代初期,这个偏差很大,因此需要对其作出修正,即 深度学习之优化算法_优化器_30 。如此一来,当 t 取的很小时,可以起到放大的效果来修正偏差;当 t 足够大时, 深度学习之优化算法_深度学习_31 ,即偏差修正几乎没有作用。

对一阶动量的修正也是同理

代码

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] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
            self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
            
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)

深度学习之优化算法_深度学习_32

基于 Adam 的最优化的更新路径

虽然 Momentun 也有类似的移动,但是相比之下,Adam 的 y 轴震荡程度有所减轻,这得益于学习的更新程度被适当地调整了。

对比

import matplotlib.pyplot as plt
from d2l.mnist import load_mnist
from d2l.common.util import smooth_curve
from d2l.common.multi_layer_net import MultiLayerNet
from d2l.common.optimizer import *


# 0:读入MNIST数据==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000


# 1:进行实验的设置==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()

networks = {}
train_loss = {}
for key in optimizers.keys():
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100, 100, 100],
        output_size=10)
    train_loss[key] = []    


# 2:开始训练==========
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    for key in optimizers.keys():
        grads = networks[key].gradient(x_batch, t_batch)
        optimizers[key].update(networks[key].params, grads)
    
        loss = networks[key].loss(x_batch, t_batch)
        train_loss[key].append(loss)
    
    if i % 100 == 0:
        print( "===========" + "iteration:" + str(i) + "===========")
        for key in optimizers.keys():
            loss = networks[key].loss(x_batch, t_batch)
            print(key + ":" + str(loss))


# 3.绘制图形==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.keys():
    plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()

深度学习之优化算法_人工智能_33

基于 MNIST 数据集的4种更新方法的比较:横轴表示学习的迭代次数(iteration),纵轴表示损失函数的值(loss)

权重的初始值

初始权重可以为 0 吗

将权重初始值设为 0 的话,将无法正确进行学习。严格地说,不能将权重初始值设成一样的值。因为在误差反向传播法中,所有的权重值都会进行相同的更新,因此,权重被更新为相同的值,并拥有了对称的值(重复的值)。

这使得神经网络拥有许多不同的权重的意义丧失了。为了防止“权重均一化”(严格地讲,是为了瓦解权重的对称结构),必须随机生成初始值。

隐藏层的激活值分布

import numpy as np
import matplotlib.pyplot as plt


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def ReLU(x):
    return np.maximum(0, x)


def tanh(x):
    return np.tanh(x)

# 随机生成一个元素符合标准正态分布(高斯分布)的数组作为输入层
input_data = np.random.randn(1000, 100)  # 1000个数据
node_num = 100  # 各隐藏层的节点(神经元)数
hidden_layer_size = 5  # 隐藏层有5层
activations = {}  # 激活值的结果保存在这里

x = input_data

for i in range(hidden_layer_size):
    # 如果不是第一层,将前一层输出作为本层输入
    if i != 0:
        x = activations[i-1]

    # 重新生成一个100x100的高斯分布数组作为本层权重
    w = np.random.randn(node_num, node_num) * 1
    
    a = np.dot(x, w)

    # 激活后获得本层输出
    z = sigmoid(a)

    # 保存本层输出,以便下一层使用
    activations[i] = z

# 绘制直方图
for i, a in activations.items():
    # 按层数划分子图
    plt.subplot(1, len(activations), i+1)
    plt.title(str(i+1) + "-layer")
    # 非输入层,隐藏y轴上的刻度标签和刻度线
    if i != 0:
        plt.yticks([], [])
    # plt.xlim(0.1, 1)
    # plt.ylim(0, 7000)
    # 绘制直方图:a扁平化,直方图30条,统计(0,1)间的数据
    plt.hist(a.flatten(), 30, range=(0,1))
plt.show()

通过上述代码我们可以得到如下的数据分布图。其记载了一个 5 层神经网络,每层有 100 个神经元,激活函数使用 sigmoid,传入标准正态分布随机生成的数据后,用直方图绘制各层激活值的数据分布。

深度学习之优化算法_优化器_34

如上图,各层的激活值呈现偏向 0 和 1 的分布

深度学习之优化算法_优化器_35

这是 sigmoid 函数的图像,可见它是一个 S 型函数,随着输出不断地靠近0(或者靠近1),它的导数的值逐渐接近0。因此,偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题称为梯度消失(gradient vanishing)。层次加深的深度学习中,梯度消失的问题可能会更加严重。

那如果将高斯分布的标准差设为 0.01 呢?

w = np.random.randn(node_num, node_num) * 0.01

深度学习之优化算法_人工智能_36

这次呈集中在0.5附近的分布。因为不像刚才的例子那样偏向0和1,所以不会发生梯度消失的问题。但是,激活值的分布有所偏向,说明在表现力上会有很大问题。

因为如果有多个神经元都输出几乎相同的值,那它们就没有存在的意义了。比如,如果100 个神经元都输出几乎相同的值,那么也可以由1个神经元来表达基本相同的事情。因此,激活值在分布上有所偏向会出现“表现力受限”的问题

Xavier 初始值

Xavier Glorot 等人在论文中推荐了一种权重初始值,俗称“Xavier 初始值”。现在,在一般的深度学习框架中,Xavier 初始值已被作为标准使用。其推导出的结论是,如果前一层的节点数为 n,则初始值使用标准差为 深度学习之优化算法_优化器_37 的分布

显然,前一层节点数越多,n 越大,则方差越小,因此初始值的尺度就越小

[!warning] Xavier 初始值是以激活函数是线性函数为前提推导出的

将上文代码中的权重改为

w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)

深度学习之优化算法_深度学习_38

越是后面的层,图像变得越歪斜,但是呈现了比之前更有广度的分布。因为各层间传递的数据有适当的广度,所以 sigmoid 函数的表现力不受限制,有望进行高效的学习。

[!tip] 用作激活函数的函数最好具有关于原点对称的性质

ReLU 的权重初始值

当激活函数使用 ReLU 时,一般推荐使用 ReLU 专用的初始值,也就是 Kaiming He 等人推荐的初始值,也称为 “He 初始值”

当前一层的节点数为 n 时,He 初始值使用标准差为 深度学习之优化算法_人工智能_39 的高斯分布。

可以理解为,因为 ReLU 函数值域为非负数,因此为了使其具有更大的广度,需要使用 Xavier 初始值的 2 倍(更大的方差,更大的尺度)

深度学习之优化算法_优化器_40

权重初始值为标准差是 0.01 的高斯分布时

神经网络上传递的是非常小的值,说明逆向传播时权重的梯度也同样很小。这是很严重的问题,实际上学习基本上没有进展。

深度学习之优化算法_人工智能_41

权重初始值为 Xavier 初始值时

随着层的加深,偏向一点点变大。实际上,层加深后,激活值的偏向变大,学习时会出现梯即便层加深,数据的广度也能保持不变,因此逆向传播时,也会传递合适的值。度消失的问题。

深度学习之优化算法_优化器_42

权重初始值为 He 初始值时

即便层加深,数据的广度也能保持不变,因此逆向传播时,也会传递合适的值。

基于 mnist 数据集的权重初始值比较

深度学习之优化算法_人工智能_43

  • 标准差为 0.01 的正态分布压根没法学习,损失函数动都不动
  • Xavier 和 He 效果很好,且 He 学习进度更快(loss 下降的更快)

Batch Normalization

Batch Normalization(批量归一化) 的思路是调整各层的激活值分布使其拥有适当的广度, 因此在 affine 层与 ReLU 层之间添加一个 Batch Norm 层以对神经网络中的数据进行正规化。

深度学习之优化算法_人工智能_44

其具体操作如下

深度学习之优化算法_优化器_45

这里对 mini-batch 的 m 歌输入数据的集合 深度学习之优化算法_人工智能_46 分别求均值 深度学习之优化算法_优化算法_47 和方差 深度学习之优化算法_深度学习_48 ,然后更新 深度学习之优化算法_优化器_49 ,将其正规化为均值为 0,方差为 1 的数据 深度学习之优化算法_深度学习_50 ,以此来减小数据分布的倾向深度学习之优化算法_优化算法_14 为极小值,防止出现除 0。

接着,Batch Norm 层会对正规化后的数据进行缩放和平移的变换,用数学式可以如下表示

深度学习之优化算法_深度学习_52

这里, 深度学习之优化算法_优化器_53深度学习之优化算法_人工智能_17 是参数。一开始 深度学习之优化算法_深度学习_55深度学习之优化算法_优化器_56 (因为这些值可以保持输出的原始分布)后经过学习调整为合适的值。

推导过程详解

  • 反向传播初始梯度为 深度学习之优化算法_优化算法_57
  • 需要计算 深度学习之优化算法_优化器_58深度学习之优化算法_深度学习_59深度学习之优化算法_人工智能_60

深度学习之优化算法_深度学习_61

深度学习之优化算法_深度学习_62

论文中,作者将 深度学习之优化算法_优化器_58 拆分为如下三个部分

深度学习之优化算法_优化算法_64

下面是它们的推导过程

深度学习之优化算法_优化器_65

深度学习之优化算法_人工智能_66

深度学习之优化算法_优化算法_67

这里漏写了一个, 深度学习之优化算法_人工智能_68

论文原文

深度学习之优化算法_优化算法_69

过拟合

发生过拟合的原因,主要有以下两个。

  • 模型拥有大量参数、表现力强
  • 训练数据少

例如从 MNIST 数据集原本的6w个训练数据中只选定300个

深度学习之优化算法_深度学习_70

不使用权值衰减

过了 100 个 epoch 左右后,用训练数据测量到的识别精度几乎都为 100%。但是,对于测试数据,离 100% 的识别精度还有较大的差距。如此大的识别精度差距,是只拟合了训练数据的结果。从图中可知,模型对训练时没有使用的一般数据(测试数据)拟合得不是很好。

权值衰减

权值衰减是一直以来经常被使用的一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚,来抑制过拟合。很多过拟合原本就是因为权重参数取值过大才发生的。

如果权值为 深度学习之优化算法_优化算法_04 ,则为损失函数加上权重的平方范数(L2范数),即 深度学习之优化算法_优化算法_72 。因此,在求权重梯度的计算中,要为之前的误差反向传播法的结果加上正则化项的导数 深度学习之优化算法_优化算法_73

  • 深度学习之优化算法_深度学习_74 是控制正则化强度的超参数,设置得越大,对大的权重施加的惩罚就越重。
  • 深度学习之优化算法_深度学习_75 是为了 深度学习之优化算法_优化算法_72 的求导结果变为 深度学习之优化算法_优化算法_73 而使用的调整常量
def loss(self, x, t):

    y = self.predict(x)

    weight_decay = 0
    for idx in range(1, self.hidden_layer_num + 2):
        W = self.params['W' + str(idx)]
        # 权重衰减项会在每次更新时被累加,以确保越来越多的权重被惩罚
        weight_decay += 0.5 * self.weight_decay_lambda * np.sum(W ** 2)

    return self.last_layer.forward(y, t) + weight_decay

深度学习之优化算法_深度学习_78

使用了权值衰减

虽然训练数据的识别精度和测试数据的识别精度之间有差距,但是与没有使用权值衰减的结果相比,差距变小了。这说明过拟合受到了抑制

Dropout

Dropout 是一种在学习的过程中随机删除神经元的方法。训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号的传递。训练时,每传递一次数据,就会随机选择要删除的神经元。然后,测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时的删除比例后再输出。

深度学习之优化算法_优化器_79

不听话?不听话就夹你!

class Dropout:

    def __init__(self, dropout_ratio=0.5):
        self.dropout_ratio = dropout_ratio
        self.mask = None

    def forward(self, x, train_flg=True):
        if train_flg:
            # 生成的同型数组中,大于ratio的置为True,否则为False
            self.mask = np.random.rand(*x.shape) > self.dropout_ratio
            # 与x相乘后,为True的保留,为False的被置为0,达到drop节点的作用
            return x * self.mask
        else:
            return x * (1.0 - self.dropout_ratio)

    def backward(self, dout):
        # 反向传播时,行为与ReLU相同,即  
        # 正向传播时传递了信号的神经元,反向传播时按原样传递信号  
        # 正向传播时没有传递信号的,反向传播时信号将停在那里
        return dout * self.mask

深度学习之优化算法_深度学习_80

没有使用 Dropout

深度学习之优化算法_优化器_81

使用了 Dropout

通过使用 Dropout,即便是表现力强的网络,也可以抑制过拟合。

机器学习中经常使用集成学习。所谓集成学习,就是让多个模型单独进行学习,推理时再取多个模型的输出的平均值。

用神经网络的语境来说,比如,准备 5个结构相同(或者类似)的网络,分别进行学习,测试时,以这 5个网络的输出的平均值作为答案。实验告诉我们,通过进行集成学习,神经网络的识别精度可以提高好几个百分点。

这个集成学习与 Dropout 有密切的关系。这是因为可以将 Dropout 理解为,通过在学习过程中随机删除神经元,从而每一次都让不同的模型进行学习。并且,推理时,通过对神经元的输出乘以删除比例(比如,0.5等),可以取得模型的平均值。也就是说,可以理解成,Dropout 将集成学习的效果(模拟地)通过一个网络实现了。

超参数

超参数是指,比如各层的神经元数量、batch 大小、参数更新时的学习率或权值衰减等。如果这些超参数没有设置合适的值,模型的性能就会很差。

调整超参数时,必须使用超参数专用的确认数据,一般称为验证数据(validation data)。我们使用这个验证数据来评估超参数的好坏。比较理想的是只用一次验证数据

[!warning] 不能使用测试数据评估超参数的性能,否则超参数的值会对测试数据发生过拟合

根据不同的数据集,有的会事先分成训练数据、验证数据、测试数据三部分,有的只分成训练数据和测试数据两部分,有的则不进行分割。在这种情况下,用户需要自行进行分割。例如用训练数据的20%作为验证数据。

def shuffle_dataset(x, t):
    """
    打乱数据集
    """
    # 随机排列一个数组或者一个整数范围内的数。它返回一个新的、随机排列的数组
    permutation = np.random.permutation(x.shape[0])
    x = x[permutation, :] if x.ndim == 2 else x[permutation, :, :, :]
    t = t[permutation]

    return x, t

超参数的范围只要 “大致地指定” 就可以了。所谓“大致地指定”,是指像0.001( 深度学习之优化算法_优化器_82 )到1000( 深度学习之优化算法_深度学习_83 )这样,以“10的阶乘”的尺度指定范围,也表述为“用对数尺度(log scale)指定”。

# 指定搜索的超参数的范围
# 生成一个在区间 [-8, -4) 内均匀分布的随机浮点数
weight_decay = 10 ** np.random.uniform(-8, -4)
lr = 10 ** np.random.uniform(-6, -2)

在超参数的最优化中,要注意的是深度学习需要很长时间(比如,几天或几周)。因此,在超参数的搜索中,需要尽早放弃那些不符合逻辑的超参数。于是,在超参数的最优化中,减少学习的 epoch,缩短一次评估所需的时间是一个不错的办法。

Best-1(val acc:0.79) | lr:0.008381149872316536, weight decay:1.2740132675595203e-07
Best-2(val acc:0.61) | lr:0.006798932859815733, weight decay:5.427724799985068e-05
Best-3(val acc:0.52) | lr:0.003081830866896804, weight decay:3.424534700612302e-06
Best-4(val acc:0.47) | lr:0.003997839005016555, weight decay:1.3090155201683637e-06
Best-5(val acc:0.33) | lr:0.001760154887955398, weight decay:6.227114725290454e-07
Best-6(val acc:0.32) | lr:0.002993807782496189, weight decay:7.564414060749376e-07
Best-7(val acc:0.25) | lr:0.0018178836880097615, weight decay:1.4716823735556433e-05

例如一次训练后,我们发现学习率在0.001到0.01,权值衰减系数在 深度学习之优化算法_优化器_84深度学习之优化算法_优化器_85 之间时,学习效果不错。因此,在这个缩小的范围中重复相同的操作,这样就能缩小到合适的超参数的存在范围,然后在某个阶段,选择一个最终的超参数的值。

深度学习之优化算法_人工智能_86