【学习笔记】深度学习基础----DNN

系列文章目录

【第一章原理】【学习笔记】机器学习基础--线性回归_一无是处le的博客-CSDN博客

【第一章代码解释】 【线性回归】原生numpy实现波士顿房价预测_一无是处le的博客-CSDN博客

【第二章】 【学习笔记】机器学习基础--逻辑回归_一无是处le的博客-CSDN博客

【第三章】传统机器学习【先不写 

【第四章】聚类算法【先不写

【第五章代码实现】【学习笔记】手写神经网络之word2vec_一无是处le的博客-CSDN博客


目录

系列文章目录

前言

一、引入深度学习

二、DNN介绍

1.初识DNN

2.前向传播

3. 反向传播【重点】

三、补充/注意事项

1.梯度消失问题

2.权重初始化

3.神经网络的集成学习

4.优化梯度下降算法

总结


前言

【学习笔记】深度学习--DNN学习笔记,由浅入深理解DNN以及深度学习,以下都是我自己个人的理解,如有错误欢迎指出啦!(●ˇ∀ˇ●)。


一、引入深度学习

        人工只能包括传统机器学习LR,SVM,GBDT等)和深度学习(统称NN,Neural Networks),其中深度学习主要是使用网络模型,由于其结构形似我们人的神经网络系统,因此其算法模型被称为神经网络。而之之所以叫深度学习,是因为目前来看我们的神经网络大都是向着深度的方向去学习的(因此这种模型也叫DNN,Deep Neural Network),而不是宽度(这个为什么下面会讲到),一般来说,目前的网络深度越深其能力越强。

        除此之外深度学习和传统机器学习还有一个很重要的区别,那就是数据变换上的区别。我们之前无论是LR(逻辑回归)还是SVM,其对于线性不可分问题的处理都是简单的的升维映射,在高维空间中分割,这一点尤其是SVM体现的好(其核函数的优势,这也是为什么SVM能称霸机器学习分类任务这么多年的原因),但是无论是LR也好还是SVM也好,其对于数据的处理都是简单的改变数据的几何位置(不影响特征的相对位置,对分类没有影响)来达到分类的目的,但是这样简单的变换都算是线性变换【  f(w_{LR_{1}}x)这里使用LR来说明,实际上SVM也是如此)数据经过变换之后得到  f(w_{LR_{2}}*wx)  这个 w 就是学习中学习到的可以将数据映射到高维度的 w 但是这样的变换之后 f(w_{LR_{2}}*wx) 依然可以表示成 f(wx) 其本质依然是线性的(多层线性相乘,等价于1层)】,因此对于线性不可分问题的解决实际上是有限的。而深度学习需要经过多层的非线性变换【这里多用sigmoid函数来说明,实际情况中很少使用了】,例如w_{LR}*sigmoid(wx) ≠ wx ,这样就能很好的解决线性不可分问题了。

二、DNN介绍

1.初识DNN

DNN模型基础架构如下所示:

                  

        如果单看一根线(两个神经元相连)的话,基本可以看作是一个逻辑回归模型(先拟合得到 w 再进行非线性变换(sigmoid函数或其他非线性函数))。实际上DNN中的隐藏层往往是不止一层的,而这些隐藏层,可以总体上看作不停的对数据进行空间变换只变换数据的空间位置,对于有效特征上的相对位置不会改变,不会影响分类)。

        因此如果再形象点来描述的话,单个神经元可以看作单细胞生物(例如逻辑回归等传统机器学习),而整个神经网络就可以看作是多个单细胞(传统机器学习)的集成学习的效果,因此深度学习可以看作是集之前传统机器学习之大成者,这也能解释为什么深度学习的效果总是好于传统机器学习。

        虽然这里我们都使用sigmoid函数来说明,但是实际上我们在开发过充中一般不会使用sigmoid函数而是使用relu函数,为什么下面会讲。

 ​​​​​​

2.前向传播

①.流程    

        目前来说深度学习主要分为两个核心部分,前向传播和反向传播。前向传播就是从输入层到输出层的正向推导。

        前向传播的本质其实就是顺着每个神经元之间对应的公式进行正向的推导计算,无论是LR还是其他方式,经过隐藏层数据变换之后得到的数据最后进行非线性变换得到输出结果,这就是深度学习相比于传统机器学习的另一个优势:便于直接进行多分类。如上图的output层,输出得到四个结果,每个结果都是一个(0, 1)之间的概率,相加总和等于1,但是这里就不能使用sigmoid函数了,因为sigmoid函数是用于二分类问题的,其相加总和不等于1(经过简化,计算简单,只需要计算一类的概率就可以)。 因此我们需要用到softmax函数,其实sigmoid就是在二分类情况下的softmax函数,如下图所示:

        从上图可知,softmax的计算量很大,因此我们不能频繁使用,我们一般只在最后一层需要多分类的情况下使用,其他隐藏层中的非线性变换不会使用这个函数。

②.激活函数(建议先看三.1.梯度消失问题

        前面大致说了一下神经网络前向传播的基本流程,而现在这里的激活函数就是我们的重点----隐藏层,中重要的非线性函数,正是因为使用了这种函数,才能使深度学习与传统机器学习拉开差距。 本质上讲,激活函数有点类似于我们数学上讲的缩放,同时使数据非线性化。

        目前来说工程上用的最多的就是relu函数,因为他能很好的解决sigmoid等函数带来的梯度消失的问题(补充中会讲到),这是深度学习发展的转折点(因为它能帮助我们不断的让神经网络做深)。并且在神经网络当中激活函数可以落实到个体神经元,这样的话我们的网络就会更加灵活,但是实际工程上我们一般最后落实到层,因为这样的过高的灵活性会带来更加高的计算负载。

        下面我们讲讲relu函数和sigmoid函数的区别:

         这两个函数最主要的区别就是梯度问题:ReLu函数的梯度,要么为0要么为1(更激进,神经元要么死要么不死,大多数情况下不存在梯度消失问题);而Sigmoid函数大部分在(0, 0.25)之间游走(太柔和且值太小导致容易出现梯度消失)。而这也是决定了relu能解决sigmoid解决不了的问题。

        Relu函数如果通过归一化将所有数据缩放到大于0,这样就不存在神经元死亡的问题,但是这样真的好吗?答案当然是否定的,因为如果所有数据都是正数,那么这个函数就变成了线性函数,不存在非线性关系,并且随着层数的增加数据会很大,容易溢出,这样也就失去了作为激活函数的作用,因此我们在大多时候都是会让部分神经元死亡【这也是一个特征筛选的过程】。这样的性质也就意味着我们的每层的神经元不能太少,不然容易出现神经元死亡过多导致网络的效果不好或者一层神经元全都死亡导致网络报废。因此就有很多的人对Relu函数进行改良例如让负数部分从0改成 \alpha (e^{x}-1) ,人为的控制负数部分的变换;又如将负数部分从0改成 αx 等。

        但是无论怎么改都存在与之相对的缺点,好的激活函数只需要在特定的领域发挥出其特点即可,而我们需要的完美激活函数需要以下特点:

        1.零均值输出(关于原点对称,出现负数和正数的概率相等)【这一点很关键,因为这十分影响训练的速度】,如下图:

那看似目前来说tanh函数最能满足这个条件,但是我们下面会说到我们工程上依旧不会使用这个函数,这是因为我们能使用别的方式平替这种性质,例如在逻辑回归中我们会在特征工程上使用数据0均值化,直接让数据满足0均值条件,但是在深度学习中我们这样做起不到效果,因为我们只能改变第一个神经元的输入,而第二个神经元的输入是第一个神经元的输出,因此我们需要使用另一种方式:因为在神经网络中存在大量的神经元和层,每一个神经元的计算需要大量前面数的相加计算,因此当我们使用大量样本批量计算,就能使其达到类似于0均值的效果。

        2.激活函数的导数不能太小或太大。容易发生梯度消失(补充中会讲到)和梯度爆炸。

        3.单调性。目的:减小振荡。若非单调,单个神经元都会存在振荡(无法随意控制x于w之间的关系--x大w大?x大w小?),那么整个神经网络会存在更大的振荡,这样会严重影响性能。

        4.输入范围有限。激活函数最好要存在上下界,防止神经元饱和,溢出。

        5.没有超参数。存在超参数会人为的增加训练难度。

        6.运算速度快。这是公认的评判指标。

现实中不可能存在完美的激活函数,因此 ,我们只需要在找出在某些方面/领域有自己的独特的特点/优势的函数使用在特定的位置即可。

3. 反向传播【重点】

①.引入

        反向传播,顾名思义,就是与前向传播相反的推导方式:从输出层反向推导到输入层,这部分就是不是简单的按照公式来推导了,如果说前向传播是根据系数来直接计算结果,那么反向传播就是根据计算的结果来求解真正合适的系数----也就是我们传统机器学习中常常提到的w。一般来说,反向传播的重点在于梯度下降,通过前向传播给出的计算结果反过来求解其系数。而之所以使用梯度下降的主要原因在于深度学习的数据太过于复杂,往往具有成千上百万的上百维的数据,这样大的数据如果需要求解正规方程或者使用svm直接求解系数w根本就是不现实的,因此目前来说,深度学习中基本上都是通过梯度下降来进行简化计算。下面我将讲述一下梯度下降在深度学习中的用法。

②. 梯度下降【重点】

        深度学习中的梯度下降总体来说跟逻辑回归中使用的梯度下降是一样的。由于是分类问题,因此损失函数一般也用的都是一样的,都是用KL距离或者说是交叉熵。其具体用法可以看本系列的第二章【学习笔记】机器学习基础--逻辑回归_一无是处le的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_61737381/article/details/131652394?spm=1001.2014.3001.5501这里就不多赘述。但是深度学习还有一个点是和逻辑回归不一样的就是结构不同,逻辑回归可以只看做是神经网络中的一对连接的神经元,而在神经网络中,这个神经元的输出就是下一个神经元的输入,因此在神经网络中我们可以使用微分链式法则进行简化运算:

损失函数微分: \frac{\partial cost}{\partial w_{m}}=\frac{\partial cost}{\partial f_{m}(z_{m})}*\frac{\partial f_{m}(z_{m})}{\partial w_{m}}  

sigmoid函数:f_{m} =\frac{1}{1 + e^-{x}}

线性函数:z_{m}=w^{ T}x

梯度下降:w_{m}=w_{m-1}-\alpha \frac{\partial cost}{\partial w_{m-1}}

 那么我们更新参数后:\frac{\partial cost}{\partial w_{m-1}}=(\frac{\partial cost}{\partial f_{m}(z_{m})}*\frac{\partial f_{m}(z_{m})}{\partial f_{m-1}(z_{m-1})}) * \frac{\partial f_{m-1}(z_{m-1})}{\partial w_{m-1}}

                                                 =(\frac{\partial cost}{\partial f_{m}(z_{m})}*\frac{\partial f_{m}(z_{m})}{\partial x_{m}}) * \frac{\partial f_{m-1}(z_{m-1})}{\partial w_{m-1}}      

                                                 = \frac{\partial cost}{\partial f_{m}(z_{m})}* (\frac{\partial f_{m}(z_{m})}{\partial z_{m}}*\frac{\partial z_{m}}{\partial x_{m}})*\frac{\partial f_{m-1}(z_{m-1})}{\partial w_{m-1}}

                                                 = \frac{\partial cost}{\partial f_{m}(z_{m})}* (f_{m}{}'(z_{m})*w_{m})*\frac{\partial f_{m-1}}{\partial w_{m-1}}

最后的结果中我们需要算的仅仅只有  \frac{\partial f_{m-1}}{\partial w_{m-1}}  这个微分,而这个微分其实跟m层的时候是一样的【 f_{m}{}'(z_{m})*x_{m} 】,只不过替换了自变量,其他的都是前面的神经元已经计算过的,看图说话:

         这样的头尾相接其实就是类似于递归操作,这就是为什么我们需要反向传播,我们只需要计算出最后一项,那么前面的项都可以通过递归从后往前迭代来计算。一次计算完所有参数,之后一次全部更新。当有多层多个神经元的时候我们只需要进行一样的操作最后相加即可(一个神经元受到多个神经元的影响)【这样做的原因其实就是使用泰勒公式进行拟合函数,因为如果不使用深度的网络,单层或者层数过低会让函数的次数太低(很多时候我们使用的激活函数很多都不足以进行高阶求导),以至于不足以支撑泰勒公式,最终达不到多项式拟合的效果】这也能证明为什么神经网络一般来说要做深要优于做宽,同时也能说明为什么激活函数一定要使用非线性的,因为只要是线性函数,无论神经网络做的多深都无法把函数项的次数提高,也就无法使用泰勒函数进行拟合

参考:

神经网络误差回传或梯度下降法迭代更新原理推导_神经网络 泰勒展开_NgaPutunga的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lx101071/article/details/124321668?ops_request_misc=&request_id=&biz_id=102&utm_term=%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E4%B8%AD%E7%9A%84%E6%B3%B0%E5%8B%92%E5%85%AC%E5%BC%8F&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-124321668.142%5Ev93%5EchatgptT3_2&spm=1018.2226.3001.4187

但是这样也就意味着越靠前的位置的数的参数量越大,这样的结构也会带来一定的问题(例如梯度消失),下面补充中会说到。

三、补充/注意事项

1.梯度消失问题

        这里解释一下sigmoid会带来的问题,由于深度学习的隐藏层的目的是为了将特征提取分离,因此我们在深度学习,尤其是DNN类型的神经网络当中,我们往往会不停的加深网络的深度,这样带来的结果也就是不断的增加参数,不断的分离特征,但是这么多的参数如果非线性化的函数都使用sigmoid函数的话,一旦当我们训练的数据结果很小的时候,从上面二.3.②可知前面的神经元的参数量会非常的大并且 f_{m}{}'(z_{m}) 这个函数的结果为(0, 0.25),这样就可能会出现数据经过非线性变换(使用sigmoid函数)之后数据越来越小直到近乎于0,这种情况下的w几乎不会改变/更新,这个时候我们就可以认为是梯度消失了,因为这个时候的数据可能已经小到计算机无法求微分的地步。这也就是为什么我们现在工程上基本不使用sigmoid函数。

        有人可能会说,如果梯度值变小我们就可以让学习因子α变大不就可以抵消这种影响吗?事实上如果α变大,不说会出现梯度振荡的无法选取最小值的问题,再说我们无法实时调控学习因子无法达到让每层网络都能找到合适的α,因此,梯度消失的本质是因为各个层的梯度值不在一个量级(sigmoid函数导致),导致无法选取合适的学习因子α。

        要解决这个问题,我们就需要找一个导数相对较大的激活函数,这时候科学家找到了tanh函数,这个函数导数取值为(0,1),能在一定程度上减轻梯度消失的问题,但是并不能完全解决这个问题,因此之后科学家为了完全解决这个问题就找到了relu函数

y=max(0, x)】。当数据大于0的时候,这个函数的导数永远为1,也就是说完全解决了梯度消失的问题,但是这个激活函数也有可能让神经元死亡数据中有小于0的数】。但是真实场景中我们的网络结构往往都是多层多神经元网络,往往只会存在10%左右的神经元死亡,这并不会对总体结果有太大的影响。另外可以通过批量归一化等方法来减小这些影响。

        这里不详细展开,了解参考:

常用激活函数:Sigmoid、Tanh、Relu、Leaky Relu、ELU优缺点总结_leakyrelu函数_Joejwu的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Joejwu/article/details/118029884?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169077579316800225573048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169077579316800225573048&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-5-118029884-null-null.142%5Ev91%5Econtrol_2,239%5Ev12%5Econtrol2&utm_term=%E5%A6%82%E4%BD%95%E5%87%8F%E5%B0%8Frelu%E5%87%BD%E6%95%B0%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%BD%B1%E5%93%8D&spm=1018.2226.3001.4187

2.权重初始化

        权重的问题是神经网络中的一个很重要的问题,很多时候神经网络无法达到理想的效果就是因为权重初始化不达标导致的。例如神经元浪费的问题(两个神经元的初始化权重完全一致,那么采样就没有意义,两个神经元相当于一个神经元)。因此我们:

        ①.第一个要做的就是需要打破w初始化对称性。一般我们使用随机初始化【因方便而用的多,但小概率重复且信息大概率存在部分冗余(只要不正交就存在冗余,例如x1=z,x2=3z,存在信息冗余损失特征维度)】,除此之外还有一种正交初始化【完全不会重复,且信息完全不冗余】。坐标彼此点乘结果为0即为正交。但是适当的冗余是有好处的:提高稳定性。就像是老师讲课需要口头讲一遍同时还要再ppt放一遍,这样就存在信息冗余但是能提高学生理解内容的稳定性。因此我们在工程上可以考虑正交初始化(速度慢),且对于0均值输出的函数来说随机取正交的可能性大,因此我们在实际工程上依然大多使用随机初始化权重。

        ②.在逻辑回归中,初始w应该往小的方向取,可以防止过拟合,逻辑回归中的正则化的目的就是这个。但是在深度学习中,在前向传播中我们希望w尽可能的小(防止过拟合),但是在反向传播中我们希望w尽可能的大(防止梯度消失,二.3.②中公式可看到连乘中也存在w,w小了也会造成梯度消失)。因此在深度学习中我们初始化w应当折中取解决矛盾,满足:0均值,小方差,随机取。以正态分布为例,我们很清楚的知道这样取值w \propto σ,而我们从前向传播中可以知道 x_{j}=f(\sum_{i=1}^{m}w_{i}x_{i}) (这里xj表示xi的下一层输入值),可知\sigma \propto \frac{1}{m} 以此抵消n过大带来的影响。而在反向传播中我们从二.3.②中公式可得\frac{\partial L}{\partial y_{i}}=\sum_{i=1}^{n}\frac{\partial L}{\partial y_{j}}*{f}'w_{ij}  此时的关系和前向传播一致---- \sigma \propto \frac{1}{n},但是我们希望w尽可能接近于1(便于控制)。沿着这个思路有人之后就想到使用0均值的均匀分布来初始化w,此时min = -max,因此此时d \propto σ ,d\propto \frac{1}{m} ,d\propto \frac{1}{n} 。由此数学家研究发现 d=\pm \frac{\sqrt{6}}{\sqrt{m+n}} 时是一个非常好的w初始化(glorot或者Xavier初始化方法)。当然在后来还出现了一个kaiming初始化方法,详细可参考

Pytorch权重初始化方法——Kaiming、Xavier_权重初始化的意义及xavier法与何恺明法详解_劳塔罗爆射破门的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qhaaha/article/details/116141633?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169128877816800188552935%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169128877816800188552935&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-116141633-null-null.142%5Ev92%5EchatgptT3_1&utm_term=pytorch%E9%BB%98%E8%AE%A4%E5%88%9D%E5%A7%8B%E5%8C%96%E6%9D%83%E9%87%8D&spm=1018.2226.3001.4187

3.神经网络的集成学习

        集成学习的思想就是多个分类器同时作用于一个数据集然后结果取平均,效果要优于单个分类器:对于强分类器来说,集成主要是降低方差,对于弱分类器来说,集成主要是提升分类能力,且分类器之间越独立,其集成效果越明显。同样的,不管深度学习再怎么复杂,也同样可以适用于集成学习,但是在实际工程上我们不会这样使用,因为一般来说目前的深度学习都是十分之复杂且耗时的,一个网络的训练往往需要耗费很长的时间,或是几个小时或是几天,这样的情况下再去进行集成就需要更长的时间或者更强大的计算机性能,因此我们一般不会在深度学习中使用这种高独立性的集成。学者们在神经网络中对集成学习进行了改良,就是通过共享神经元(牺牲独立性)来模拟多个分类器的效果,其得到的多个结果可看作多个分类器的结果,再进行一层softmax进行分类处理【可以看作是多个小神经网络组成一个大神经网络】,如下图:

对于大神经网络来说,去掉某些神经元就对应一个子神经网络,这些子神经网络通过集成就组成了大神经网络。

        这样组成的神经网络虽然性能上比不过直接使用多个分类器进行集成学习,但是也不会相差太大,并且虽然牺牲了子神经网络之间的独立性,但是通过子神经网络的数量弥补了这部分缺口。省时省力这个最大的优势就不必多说,还增强了泛化能力(防止过拟合)。这个集成方式被称为Dropout-【每次训练的时候,随机的忽略一定数量的神经元(往往以概率的方法),可以产生集成学习的效果,剩下的神经元类比于一个子分类器,子分类器的数量可以看作是海量(因为神经网络中存在大量的神经元)】。我们设定一个抛弃神经元的概率P,每层神经网络的训练,我们都对该层神经元个数M抛弃概率为P的数量,这样的每轮训练下来几乎不会有子神经网络被训练多次,也就是说网络没有被训练到,曾经有人想要解决这个问题,但事实上,这个问题其实根本没有取解决的必要,因为对于dropout来说子网络的训练根本不重要,因为他们的数据是共享的,哪怕所有的子网络都没有被训练到,他们的数据依然是被大神经网络训练了无数次。下面再来说说dropout如何增强泛化能力:

        ①.特征筛选。对于dropout来说,随机的抛弃神经元其实就是一个特征筛选的过程,丢掉某些特征也能让分类器正常发挥作用,这样的结果不仅能防止过拟合,增强泛化能力,还能在一些方面起到独特的作用,例如在人脸识别中,我们随机筛选掉一些特征例如嘴巴鼻子,最终依旧能正确地进行识别,就类似于iPhone上的口罩人脸解锁。对某些特征的依赖性会减弱。

        ②.随机正则化。在神经网络前向传播的过程中,后面的神经元是由前面的神经元得到的,那么这时候我们如果在后面的层中筛选掉神经元,其实就是直接将一部分前面的神经元的w直接变为0,即L1正则,或者说是随机L1正则。这样的正则对神经网络做深起到了很大的作用。

详细可参考:

深度学习-Dropout详解_深度学习 dropout_Tc.小浩的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_48167570/article/details/121559922?ops_request_misc=&request_id=&biz_id=102&utm_term=dropout&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-121559922.142%5Ev92%5EchatgptT3_1&spm=1018.2226.3001.4187

Dropout原理及作用_dropout原理和作用_CV技术指南的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Mike_honor/article/details/125892375?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169137200116800225515666%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169137200116800225515666&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-125892375-null-null.142%5Ev92%5EchatgptT3_1&utm_term=dropout&spm=1018.2226.3001.4187

4.优化梯度下降算法

       ①.鞍点问题

       事实上,我们如果仅用逻辑回归的方式来对深度学习进行梯度下降其实效果是不好的,因为深度学习往往是具有很高维度,大量数据组成,这样的数据集组成往往会造成高维非凸问题,而造成难以优化问题的根本原因就是因为这样的数据分布往往会存在很多的鞍点而不是大量局部极小值点鞍点:一个维度向上倾斜且另一维度向下倾斜的点。这些鞍点通常被相同误差值的平面所包围,这使得算法陷入其中很难脱离出来,因为梯度在所有维度上接近于零。】这样的话如果优化点困于鞍点则无法继续进行梯度下降继续优化。 

在人们发现这个问题之后最先找到的解决方法就是使用SGD(随机梯度下降法)解决这个问题,因为是随机采样进行梯度下降,因此哪怕遇到鞍点该部分不能正常梯度下降也不会影响下一个批次,而只要脱离一次鞍点,梯度下降就能正常进行而避开鞍点并且不会影响极小值点(在深度学习中很难碰到极小值点,一般来说损失函数下降到能接受的范围即可,不需要找到极小值点才算优化完成。但是鞍点的损失函数往往较大,因此我们才需要逃离鞍点)【SGD-小扰动,逃离鞍点】。

        ②.悬崖问题

        多层神经网络通常存在像悬崖一样的斜率比较大的区域。当参数接近斜率极大的悬崖结构时,梯度下降更新会很大程度的改变参数值,使得参数弹射的非常远,可能会使大量已经完成的优化工作成为无用功。如下图所示:

 出现悬崖问题的原因往往都是由于梯度爆炸,而解决这个问题一般我们会使用梯度截断的方式一旦梯度突然大于某个阈值就直接调整系数,不让他产生梯度悬崖。

        ③.峡谷问题

        峡谷问题其实我们在逻辑回归中就有讲到过(前面的激活函数中的0均值输出也是类似的问题),其实就是等高线不均匀问题。

可参考:【学习笔记】机器学习基础--逻辑回归_一无是处le的博客-CSDN博客  中的4.②

如下图所示:

出现这种问题,梯度会来回的振荡, 优化的速度就会很慢,这个问题在逻辑回归中我们是使用批量归一化直接让数据集分布变得均匀,但在深度学习中我们并不能这样做(前面0均值输出中讲到过)。我们需要的就是想让振荡方向变化小,不振荡方向速度快(即一步到位),简单的改变学习率显然是并不能完全解决我们的问题的。之后就有人提出了动量法:梯度g,动量v,公式为:v_{t}=\alpha v_{t-1}-\varepsilon g    w_{t} = w_{t-1}+v_{t}  (可以自己带值进去验证以下,比较简单) 这样就能满足我们的需求。【动量法+SGD=改良的梯度下降

        其实深度学习的本质难点在于:各个方向导数数值的量级不一致,且难以动态调整。而之后又有人提出了一个记录各个维度数值量级的方法来使各个维度数值量级处于同一水平(归一化)【Ada Grad】,r记录梯度各维度量级  r_{t+1}=r_{t}+g\cdot g (梯度与自己内积/平方)  之后的梯度为:\frac{g}{\sqrt{r}}  (也可带入验证)以此来消除量级不一致的影响。但是这个方法存在一个严重的问题:就是当 r 累加到很大的时候,最终 g 得到的结果会无限接近于0,如果这时候还没有训练到想要的结果的时候,那么就会存在 w 学不动的问题,无法达到我们想要的结果。之后有人有对AdaGrad进行改进:r_{t+1}=\rho r_{t}+(1-\rho )g\cdot g  【RMSProp】这种方法能一定程度上解决AdaGrad的问题(一定程度上减小 r,防止r过大)。因此这个技术成熟之后又有人想用RMSProp来代替SGD做成 动量法+RMSProp 方法解决深度学习中的多个问题:动量法减小振荡,加速学习,RMSProp解决数值量级不一致问题。之后出现了集大成者 Adam 这个方法跟上一个方法类似,做了一定的改进,具体推导如下:

                 

参考: Adam优化器(通俗理解)_Longer2048的博客-CSDN博客

总结

        从本章开始正式进入我们学习的重点--深度学习。本篇是开章,可能也是入门深度学习的终章,本章我认为讲了深度学习或者说是机器学习70%以上的思想,后面要讲的可能更多是不同模型不同算法的改进,因此我认为本章是重中之重。如有错误欢迎指出(●'◡'●)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值