【知识点】长文超详讲解深度学习中你总是掌握不牢的若干知识点

关注“深度学习自然语言处理”,一起学习一起冲鸭!

设为星标,第一时间获取更多干货

作者:云不见

链接:https://blog.csdn.net/Walk_OnTheRoad/article/details/108186355

编辑:王萌 澳门城市大学(深度学习冲鸭公众号)

此笔记是基于《深度学习入门》这本书的重点知识汇总。

连载目录(点击进链接):

豆瓣9.4!《深度学习入门》笔记总结,带你从感知机入门深度学习!(连载)

豆瓣9.4!《深度学习入门:基于Python的理论与实现》学习笔记(2)

手磕实现 CNN卷积神经网络!- 《深度学习入门:基于Python的理论与实现》系列之三

目录:

一、参数的更新

    SGD:

    1、Momentum

    2、AdaGrad

    3、Adam

    使用哪种更新方法呢?

    基于MNIST数据集的更新方法的比较

二、权重的初始值

    隐藏层的激活值的分布

    ReLU的权重初始值

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

三、Batch Normalization

    1、Batch Normalization的算法

    2、Batch Normalization的评估

四、正则化

五、超参数的验证

六、小结

总结

本文重点知识点:

  • 寻找最优权重参数的最优化方法、权重参数的初始值、超参数的设定方法等。

  • 应对过拟合,使用权值衰减、Dropout等正则化方法,并进行实现。

  • Batch Normalization方法

目的:

  • 高效地进行神经网络(深度学习)的学习,提高识别精度。

如有细节处没有写到的,请继续精读《深度学习入门:基于Python的理论与实现》,对小白来说真的是非常好的深度学习的入门书籍,通俗易懂。(书中的例子主要是基于CV的)

一、参数的更新

神经网络的学习的目的:

找到使Loss函数的值尽可能小的参数。

即最优化:寻找最优参数的问题

为了找到最优参数 ——> 梯度下降法

  SGD:

SGD:随机梯度下降法(stochastic gradient descent)

定义:

使用参数的梯度,沿梯度方向更新参数,并重复这个步骤多次,从而逐渐靠近最优参数。

式(6.1)为SGD更新公式:

SGD的策略:

朝着当前所在位置的坡度最大的方向前进。也就是每看一个example就更新,比GD更快。

SGD缺点:

  • 在解决某些问题时可能没有效率

  • SGD呈“之”字形移动。这是一个相当低效的路径。

  • 如果函数的形状非均向(anisotropic),比如呈延伸状,就会非常低效。

  • SGD低效的根本原因是,梯度的方向并没有指向最小值的方向。(所以李宏毅GD1中说要Feature Scaling特征缩放一下,就可以对着圆心更新,效率高)

其它更优于SGD的方法:

  • Momentum:参照小球在碗中滚动的物理规则进行移动

  • AdaGrad:为参数的每个元素适当地调整更新步伐。

  • Adam:将上述两个方法融合在一起

  1、Momentum

式(6.3/4)为Momentum更新公式:

新出现了一个变量v,对应物理上的速度。

式(6.3)表示了物体在梯度方向上受力;αv这一项:在物体不受任何力时,该项承担使物体逐渐减速的任务(α设定为0.9之类的值),对应物理上的地面摩擦或空气阻力。

Momentum方法就像是小球在碗中滚动。

优点:

  • 和SGD相比,“之”字形的“程度”减轻了。

  • 可以更快地朝x轴方向靠近,减弱“之”字形的变动程度。

Momentum的代码实现(源代码在 common/optimizer.py中)

class Momentum:
    def __init__(self, lr=0.01, momentum=0.9): # momentum = α,设定为0.9
        self.lr = lr
        self.momentum = momentum
        self.v = None  # 初始化时,v中什么都不保存


     # 第一次调用 update()时,v会以字典型变量的形式保存与参数结构相同的数据            
    def update(self, params, grads): 
        if self.v is None:
            self.v = {}  # 变量v 保存物体的速度
            for key, val in params.items():  # params.items()为参数权重W
                self.v[key] = np.zeros_like(val)  # v会以字典的形式保存与参数W结构相同的数据
        for key in params.keys():
            self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]  # 式(6.3)
            params[key] += self.v[key]  # 式(6.4) W = W + v


  2、AdaGrad

关于学习率的技巧:

学习率衰减(learning rate decay):

即随着学习的进行,使学习率逐渐减小。一开始“多”学,然后逐渐“少”学的方法,在神经网络的学习中经常被使用。

AdaGrad进一步发展了这个想法,针对“一个一个”的参数,赋予其“定制”的值。

式(6.5/6)为Adagrad更新公式:

变量h ——> 保存以前的所有梯度值的平方和

在更新参数时,通过除以 <过去所有梯度的均方根>,就可以调整学习的尺度(lr)。

参数的元素中变动较大(被大幅更新)的元素的学习率将变小。

即可以按参数的元素进行学习率衰减,使变动大的参数的学习率逐渐减小。

AdaGrad优点:

  • 函数的取值高效地向着最小值移动

  • 刚开始变动较大,但是后面会根据这个较大的变动按比例进行调整,减小更新的步伐。

  • 因此,y轴方向上的更新程度被减弱,“之”字形的变动程度有所衰减。

学习越深入,更新的幅度就越小。如果无止境地学习,更新量就会变为 0,完全不再更新。为了改善这个问题,可以使用 RMSProp [7] 方法

  • 逐渐地遗忘过去的梯度,在做加法运算时将新梯度的信息更多地反映出来。

  • 即指数移动平均:呈指数函数式地减小过去的梯度的尺度。

用python实现 AdaGrad,(源 代 码 在common/optimizer.py中)

class AdaGrad:
    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None
        
    # 第一次调用 update()时,h会以字典的形式保存与参数结构相同的数据
    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)  # h会以字典的形式保存与参数结构相同的数据
        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) 
            # 防止除数为0


  3、Adam

Adam优点:

通过组合前面两个方法的优点:

  • 有望实现参数空间的高效搜索。

  • 进行超参数的“偏置校正”

也像Momentun一样,像小球在碗中滚动。但是,Adam的小球左右摇晃的程度有所减轻。因为学习的更新程度被适当地调整了(Adagrad)。

Adam会设置3个超参数。

  • 一个是学习率(论文中以α出现),

  • 另外两个是一次momentum系数β1和二次momentum系数β2。

  • 根据论文,标准的设定值是β1为0.9,β2 为0.999。设置了这些值后,大多数情况下都能顺利运行。

用python实现 Adam,(源 代 码 在common/optimizer.py中)

class Adam:


    """Adam (http://arxiv.org/abs/1412.6980v8)"""


    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):  # 一次momentum系数β1和二次momentum系数β2
        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)
            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)
            
            #unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
            #unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
            #params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)


  使用哪种更新方法呢?

比较一下这4种方法(源代码在 ch06/optimizer_compare_naive.py中)。

根据使用的方法不同,参数更新的路径也不同。

只看这个图的话,AdaGrad似乎是最好的,但

  • 其实结果会根据要解决的问题而变。

  • 超参数(学习率等)的设定值不同,结果也会发生变化。

这4种方法各有各的特点,各有擅长和不擅长(就像人一样,你能存粹的比较两个人谁好谁坏嘛)。

很多研究中至今仍在使用SGD。最近,很多研究人员都喜欢用Adam。本书将主要使用SGD或者Adam。

  基于MNIST数据集的更新方法的比较

以手写数字识 别为例,比较SGD、Momentum、AdaGrad、Adam这4种更新方法(源代码在 ch06/optimizer_compare_mnist.py中)。

这个实验以一个5层神经网络为对象,其中每层有100个神经元。激活函数使用的是ReLU。

结论:

  • 与SGD相比,其他3种方法学习得更快,AdaGrad的学习进行得稍微快一点。

  • 不过实验结果会随学习率lr等超参数、神经网络的结构(几层深等)的不同而发生变化。

  • 一般而言,与SGD相比,其他3种方法可以学习得更快,最终的识别精度也更高。

二、权重的初始值

接下来将介绍:

  • 设定什么样的权重初始值(关系到神经网络的学习能否成功)

  • 介绍权重初始值的推荐值:Xavier初始值

  • 通过实验确认神经网络的学习是否会快速进行

为什么要设置权重初始值?

这关系到神经网络的学习能否成功进行下去。

权值衰减(weight decay):

如果想减小权重的值,一开始就将初始值设为较小的值最好。

实际上,我们会 设置 标准差(weitght_int_std)为0.01的高斯分布作为权值W的随机初始值。如下:

W = 0.01 * np.random.randn(10, 100)
W = weitght_int_std * np.random.randn(10, 100)


为什么不能直接设置初始值为0,这不是最小嘛?

不能设置为0,如果设置为0,直接把输入杀掉了不是吗。

为什么设置为随机初始值呢?

实际上,权重初始值不能设置为一样的值。

因为如果设置成一样的权重值,在误差反向传播法中,所有的权重值都会进行相同的更新。并拥有了许多重复的值,这使得神经网络拥有许多不同的权重的意义丧失了。为了防止“权重均一化”,必须随机生成初始值,且不能为0

  隐藏层的激活值的分布

使用Xavier初始值:如果前一层的节点数为n,则初始值使用标准差为 1/√n 的高斯分布进行初始化。

为什么使用Xavier初始值?

为了使各层的激活值呈现出具有相同广度的分布。

因为通过在各层间传递多样性(具有广度)的数据,神经网络可以进行高效的学习。

反过来,如果传递的是有所偏向的数据,就会出现梯度消失或者“广度受限”的问题,导致学习可能无法顺利进行。

权重标准差为1的高斯分布,各层的激活值呈偏向0和1的分布。 sigmoid函数是S型函数,靠近0和靠近1的地方,它的导数逐渐接近0。导致梯度消失。如下图所示:(该实验的源代码在 ch06/weight_init_activation_histogram.py中)

权重初始值:标准差为0.01的高斯分布,各层的激活值的分布集中在0.5附近,不会发生梯度消失,但是广度不够。因为如果有多个神经元都输出几乎相同的值,那它们就没有存在的意义了。如下图所示:

所以使用Xavier初始值, 各层的激活值呈现出具有广度的分布。

如下图所示,权重初始值为:Xavier初始值;激活函数为Sigmoid:

改善稍微歪斜的分布:

激活函数用tanh函数(双曲线函数)代替 sigmoid函数。 如下图所示:

众所周知,用作激活函数的函数最好具有关于原点对称的性质。

而tanh函数就是关于原点对称的S型函数。

  ReLU的权重初始值

He 初始值使用标准差为 √(2/n) 的高斯分布。

(直观上)可以解释为,因为ReLU的负值区域为0,为了使它更有广度,所以需要2倍的系数。

总结:

激活函数/权重初始值sigmoid
tanh
ReLU
Xavier初始值

He初始值

  • 当激活函数使用ReLU时,权重初始值使用He初始值;

  • 当激活函数为 sigmoid或 tanh等S型曲线函数时,初始值使用Xavier初始值。

  • 这是目前的最佳实践。

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

采用不同的权重初始值:std = 0.01、Xavier初始值、He初始值进行实验(源代码在 ch06/weight_init_compare.py中)。得到的结果如下图所示:

这个实验神经网络有5层,每层有100个神经元,激活函数使用的是ReLU。

结论:

  • std = 0.01时完全无法进行学习

  • 权重初始值为Xavier初始值和He初始值时,学习进行得都很顺利。

  • 并且He初始值学习进度更快一些。

综上,在神经网络的学习中,权重初始值非常重要。关系到能否成功得进行学习。

三、Batch Normalization

  1、Batch Normalization的算法

是什么?

批归一化的算法。以进行学习时的mini-batch为单位,按mini-batch进行正规化。就是进行使数据分布的均值为0、方差为1的正规化。

干什么?方法的思路

为了使各层拥有适当的广度,“强制性”地调整激活值的分布。

即调整各层的激活值分布使其拥有适当的广度。

有什么优点?

  • 可以使学习快速进行(可以增大学习率),训练得时候不用等那么久

  • 不那么依赖初始值(对于初始值不那么神经质)

  • 抑制过拟合(降低Dropout等的必要性)

Batch Norm层放在哪里?

通过将这个处理插入到激活函数的前面(或后面),可以减小数据分布的偏向。使数据分布更广。(近几年主要放激活函数后面多一点)

前面说了,Batch Norm,顾名思义,以进行学习时的mini-batch为单位,按mini-batch进行正规化。就是进行使数据分布的均值为0、方差为1的正规化。

用数学式表示的话,如下所示。

数学公式


接着,Batch Norm层会对正规化后的数据进行缩放和平移的变换,公式如下所示:

这个算法是神经网络上的正向传播,下图所示为Batch Norm正向传播的计算图:

Batch Norm的反向传播的推导有些复杂。不过如果使用图6-17的计算图来思考的话,Batch Norm的反向传播或许也能比较轻松地推导出来。Frederik Kratzert 的博客“Understanding the backward pass through Batch Normalization Layer”[13]里有详细说明,感兴趣可以参考一下。

  2、Batch Normalization的评估

实验一:

使用 MNIST 数据集,观察使用Batch Norm层和不使用Batch Norm层时学习效果怎么样(源代码在 ch06/batch_norm_test.py中),结果如图6-18所示。

结论:

使用Batch Norm后,学习进行得更快了。

实验二:

给予不同的初始值,观察学习的效果。下图是权重初始值的标准差为各种不同的值时的学习过程图。

结论:

  • 几乎所有的情况下都是使用Batch Norm时学习进行得更快

  • 不使用Batch Norm的情况下,特别依赖权重初始值,如果选不好,学习将完全无法进行。

  • 综上,通过使用Batch Norm,可以推动学习的进行。

  • 并且,对权重初始值变得健壮(“对初始值健壮”表示不那么依赖初始值)。

四、正则化

什么是正则化?

为什么要正则化?

防止过拟合

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

  • 模型拥有大量参数、表现力强。

  • 训练数据少。

抑制过拟合的技巧:

  • 权值衰减:减小权重参数的值。(后续在 <怎么正则化?> 中会详细介绍)

  • Dropout:在学习的过程中随机删除神经元。(模型复杂,只用权值衰减效果没那么好)

正则化项:假设有权重W = (w1, w2, . . . , wn)

  • L1范数:各个元素的绝对值之和,相当于|w1| + |w2| + . . . + |wn|。

  • L2范数:各个元素的平方和,再开根号。

L∞范数:也叫Max范数,取各个元素的绝对值中最大的那一个。

怎么正则化?

1、使用权值衰减的方法:

利用正则化项L2范数,将权值衰减加上L2范数:½λW²。

  • 将这个权值衰减的值加到损失函数中,亦能减少损失函数的值(这是神经网络学习的主要目的呀:减少损失函数的值!)

  • λ是控制正则化强度的超参数。λ越大,对大的权重W抑制越多。

  • ½的目的是将½λW²的求导结果变成λW。

  • 在求权重梯度时,误差反向传播法的结果则要加上正则化项的导数λW。

做实验:故意造成过拟合

实验一:不使用权值衰减


训练数据的识别精度几乎是100%(可想而知,过拟合多严重啦!)

实验二:使用权值衰减,超参数 λ=0.1


2、使用Dropout的方法:

  • 在学习的过程中随机删除神经元的方法。

  • 即训练时,每传递一次数据,就会随机选择要删除的神经元。

  • 测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时的删除比例后再输出。(深度学习框架中不需要这一步,因为训练时进行了恰当的计算)

Dropout的简单实现:

class Dropout:
    def __init__(self, dropout_ratio=0.5):  # dropout_ratio:删除神经元的比例
        self.dropout_ratio = dropout_ratio
        self.mask = None
        
    def forward(self, x, train_flg=True):
        if train_flg:
            # 随机生成和x形状相同的数组,并和dropout_ratio相比较。>,mask=True;<,mask=False
            self.mask = np.random.rand(*x.shape) > self.dropout_ratio  
            return x * self.mask  # 返回Fasle的地方 x=0,即删除掉了神经元
        else:
            return x * (1.0 - self.dropout_ratio)
    
    # 反向传播时的行为和ReLU相同。正向传播传递了神经元,反向传播按原样传递信号;正向传播没有传递神经元,反向传播信号将停在那里。
    def backward(self, dout):
        return dout * self.mask


做实验:

使用MNIST数据集进行验证,以确认Dropout的效果

前提:使用7层网络(每层有100个神经元,激活函数为ReLU)(挺深的网络)

实验一:没有使用Dropout

实验二:使用Dropout

下图为使用Dropout的网络,虽然有效抑制了过拟合,但是识别精度不是很高,这还和别的超参数的设置有关;比如下图dropout_rate=0.2;我再把dropout_rate=0.15做了一次实验。可以看到识别精度有较大改善。(图二)

总结:

  • 通过使用Dropout,训练数据和测试数据的识别精度的差距变小了。

  • 训练数据也没有到达100%的识别精度。

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

  • 其实还可以通过改进其它超参数的值来抑制过拟合,而且能使网络的识别精度表现更好,继续看 <五、超参数的验证>

Dropout 类似于 集成学习

集成学习定义:让多个模型单独进行学习,推理时再取多个模型的输出的平均值。

即 有5个结构相同(或类似)的网络,分别进行学习;测试时,以这5个网络的输出的平均值作为答案。

通过集成学习,神经网络的识别精度可提高好几个百分点。

Dropout可以理解为,通过在学习过程中随机删除神经元,形成了不同的模型,从而每一次都让不同的模型进行学习。并且,推理时,通过对神经元的输出乘以删除比例(比如0.5等),可以取得模型的平均值。

所以Dropout相当于用一个网络随机删除神经元后变成了不同的几个网络,再进行学习。也就是集成学习的意思。

五、超参数的验证

  • 本节介绍高效寻找超参数的值的方法:通过实验不断缩小超参数的范围

什么是超参数?(Hyper-Parameter)

比如各层的神经元数量、batch大小、参数更新时的学习率lr或权值衰减weigh decay等。

为什么要设置合适的超参数?

如果超参数没有设置合适的值,模型的性能就会很差。

  • 训练数据用于参数(权重和偏置)的学习;

  • 测试数据用于评估泛化能力;(比较理想的是只用一次测试数据评估,多次的话会导致数据过拟合测试数据)

  • 还需要一笔验证数据(validation data):用于超参数的性能评估。

为什么不能用测试数据去评估超参数,从而选择合适的超参数?

会导致超参数的值被调整为只拟合测试数据。

验证数据哪里来?

如果数据集只有训练数据和测试数据,则需要自己事先从训练数据中抽一笔出来。比如从训练数据中事先分割出20%做验证数据。

而且,分割训练数据前,先打乱了输入数据和监督标签。这是因为数据集的数据可能存在偏向(比如,数据从“0”到“10”按顺序排列等)。

比如对于MNIST数据集,分割训练数据做验证数据的代码如下所示:

(x_train, t_train), (x_test, t_test) = load_mnist()  # 载入MNIST数据集


# 打乱训练数据
x_train, t_train = shuffle_dataset(x_train, t_train)


# 分割出验证数据
validation_rate = 0.20  # 从训练数据中事先分割出20%做验证数据
validation_num = int(x_train.shape[0] * validation_rate)  # x_train.shape[0]表示训练数据的数量(矩阵数据表示有几行)
# 比如有100笔训练数据,则validation_num=20
x_val = x_train[:validation_num]
t_val = t_train[:validation_num]  # x_val,t_val 表示验证数据 
x_train = x_train[validation_num:]
t_train = t_train[validation_num:]  # 其余数据还给训练数据


使用验证数据观察超参数的最优化方法:不断尝试,减小最优超参数的取值范围,最终确定一个值。

超参数的最优化方法的步骤:

  1. 设定超参数的大致范围。(以“10 的阶乘”的尺度指定范围)

  2. 从设定的超参数范围中随机采样,随机选择一个超参数。(随机采样的搜索方式效果更好)(尽早放弃那些不符合逻辑的超参数)

  3. 使用步骤2中随机选择的超参数的值进行学习,通过验证数据评估识别精度(但是要将epoch设置得很小,从而缩短一次评估所需的时间)。

  4. 重复步骤2和步骤3(约100次等),根据它们的识别精度的结果,缩小超参数的范围。

  5. 反复进行上述操作,不断缩小超参数的范围,在缩小到一定程度时,从该范围中选出一个超参数的值。

如需更精炼的方法,可以使用贝叶斯最优化(Bayesian
optimization)。贝叶斯最优化能够更加严密、高效地进行最优化。详细内容请参考论文“Practical Bayesian
Optimization of Machine Learning Algorithms”[16]等。

超参数最优化的具体实现案例

  • 使用MNIST数据集进行超参数的最优化。(源代码在 ch06/hyperparameter_optimization.py中。)

  • 这里我们将 对 学习率 lr 和控制权值衰减强度的系数(下文称为“权值衰减系数”)weight decay 这两个超参数 进行优化。

步骤如下:

1. 设定超参数的大致范围:权值衰减系数 weight decay 的初始范围为,学习率 lr 的初始范围为

2. 随机采样,随机选择一个超参数:超参数的随机采样的代码如下所示。

weight_decay = 10 ** np.random.uniform(-8, -4)
lr = 10 ** np.random.uniform(-6, -2)


3. 再使用那些值进行学习。之后,多次使用各种超参数的值重复进行学习。(约100次等)

4. 观察合乎逻辑的超参数在哪里。

学习结果图:


取出“Best-1”到“Best-5”中的超参数的值,缩小两个超参数的范围至 学习率lr = 0.001到0.01、权值衰减系数weight decay在10^−8到10^−6之间时,学习可以顺利进行。

Best-1(val acc:0.77) | lr:0.008991967621142708, weight decay:5.425501025852778e-07
Best-2(val acc:0.77) | lr:0.006609255709609137, weight decay:8.124543461085908e-06
Best-3(val acc:0.76) | lr:0.007539029001714733, weight decay:1.2510664720534263e-06
Best-4(val acc:0.74) | lr:0.006670405931523085, weight decay:2.915136844957729e-05
Best-5(val acc:0.66) | lr:0.005631468995380081, weight decay:2.049732949146344e-07


在这个缩小的范围中,继续上述步骤,再缩小范围。最终选择一个范围内的超参数的值。

六、小结

本章我们介绍了神经网络的学习中的几个重要技巧。

  • 参数的更新方法

  • 权重初始值的赋值方法

  • Batch Normalization

  • Dropout等。

  • 而且都在最先进的深度学习中被频繁使用。

总结

  • 参数的更新方法,除 了 SGD 之 外,还 有 Momentum、AdaGrad、Adam等方法。(而且后三者往往比SGD效果好)

  • 权重初始值的赋值方法对进行正确的学习非常重要。

  • 作为权重初始值,Xavier初始值(用于Sigmoid和tanh)、He初始值(用于ReLU)等比较有效。

  • 通过使用Batch Normalization,可以加速学习,并且对初始值变得健壮(不那么敏感)。

  • 抑制过拟合的正则化技术有权值衰减、Dropout等。

  • 通过验证数据,进行实验,来逐渐缩小超参数最优值的范围是最终选择超参数的一个有效方法。


注:如有细节处没有写到的,请继续精读《深度学习入门》,对小白来说真的是非常通俗易懂的深度学习入门书籍。(书中的例子主要是基于CV的)

说个正事哈

由于微信平台算法改版,公号内容将不再以时间排序展示,如果大家想第一时间看到我们的推送,强烈建议星标我们和给我们多点点【在看】。星标具体步骤为:

(1)点击页面最上方深度学习自然语言处理”,进入公众号主页。

(2)点击右上角的小点点,在弹出页面点击“设为星标”,就可以啦。

感谢支持,比心

投稿或交流学习,备注:昵称-学校(公司)-方向,进入DL&NLP交流群。

方向有很多:机器学习、深度学习,python,情感分析、意见挖掘、句法分析、机器翻译、人机对话、知识图谱、语音识别等。

记得备注呦

推荐两个专辑给大家:

专辑 | 李宏毅人类语言处理2020笔记

专辑 | NLP论文解读


整理不易,还望给个在看!
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,作为文本AI助手,我无法绘制思维导图。但是,我可以为您提供一个简要的java IO流知识点总结。 Java IO流是Java用于处理输入和输出的机制。它提供了一种有效的方式来读取和写入数据,以及与文件、网络和其他设备进行交互。 Java IO流包括字节流和字符流两种类型。字节流以字节为单位进行操作,适用于处理二进制数据。而字符流以字符为单位进行操作,适用于处理文本数据。 常用的字节流包括InputStream和OutputStream类,用于读取和写入字节数据。常用的字符流包括Reader和Writer类,用于读取和写入字符数据。可以通过使用字节流和字符流的组合来实现不同类型数据的读写操作。 在Java IO流,还有一些特殊的流,如缓冲流、转换流、对象流等。缓冲流提供了缓冲区来提高IO性能。转换流用于处理字符编码和解码。对象流用于对Java对象进行读写操作。 此外,Java IO流还包括一些常用的类和方法,如File类用于处理文件和目录,RandomAccessFile类用于对文件进行随机访问,FileInputStream和FileOutputStream类用于读写文件等。 通过组合和使用不同类型的流和类,您可以实现各种复杂的IO操作,如读写文件、网络通信、序列化对象等。 希望这个简要总结对您有所帮助。如果您有任何更具体的问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [万字长文+思维导图帮你梳理 Java IO 流,还学不会你来打我(值得收藏)](https://blog.csdn.net/a1405/article/details/116766237)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值