本文所要介绍的一本书《Neural Networks and Deep Learning》,该书作者Michael Nielsen,Y Combinator Research的研究员,是多年之前自己看的一本基础书籍,很适合入门了解一些关于深度学习的概念知识,当然也包含了一些小的案例。刚好有篇当年存档的小笔记,做一下分享。
该书以识别手写数字为切入点,以不断引入新的优化手段提升识别准确度为线索贯穿始终。
一开始介绍了感知器,再引出多层感知器。仅仅三层MLP(输入层&隐藏层&输出层),代价函数采用MSE(均方误差),由于学习率直接影响到算法的迭代,对于学习率进行了一定的探讨,学习率不能太大也不能太小,一般来说还是一个经验值。同时对GD(梯度下降法),SGD(随机梯度下降法)。GD由于要使用全量的样本,因此速度较慢,不太适合真实场景;SGD随机选取mini-batch(小批量数据)的训练输入样本来计算梯度,通过对少量样本的平均值进行计算来对实际梯度进行快速近似。通过反向传播算法(BP)快速计算代价函数的梯度,训练得到合适的MLP模型,经过几十轮(epoch)迭代,模型可以达到约95%的准确度。通过增加隐藏层神经元,增加模型的复杂性,可以进一步提升到约96.5%。这也就引出了调整参数,是可以影响最终的学习效果。同时,插了一小段svm等统计机器学习算法的表现,通过增加好的训练样本数据,使用简单的机器学习算法,也是可以取得比较好的效果的。
进而逐步引出稍复杂的神经网络,也就是多层结构(更多隐藏层)的网络(深度神经网络)。首先介绍了反向传播算法(四个基本方程),该算法同样是应用于深度神经网络的学习,反向传播其实是对权重和偏置变化如何影响代价函数过程的理解。同时使用权重矩阵,偏置向量的方式来表征相关学习参数。引入输出层误差概念。
针对前述神经网络,提出了一系列的优化改进思路。首先是调整代价函数,由均方误差函数调整为交叉熵代价函数。把交叉熵看成代价函数,有两点原因:第一它是非负的;第二对于所有的输入x,神经元实际输出接近目标值,交叉熵接近0,这也是代价函数需要具备的性质。引入交叉熵取代二次代价函数,能够避免学习速度下降。交叉熵求导得到的结果,可以看到权重学习的速度是受到sigma(z)-y的影响,也就是输出值与目标值的差距,差距越大,学习速度越快,参数更新幅度越大。而二次代价函数求导的结果,权重学习的速度是与sigma(z)的导数有关,我们知道S函数,越到1 或 0,其导数越小,也就是饱和了,那参数基本就没法更新。交叉熵衡量我们学习到y的正确值的平均起来的不确定性。使用交叉熵训练的模型,可以提升到约96.8%。
其次,文中引入softmax输出(柔性最大值),取代之前使用的sigmoid函数。softmax可以被看作是一种概率分布。得到分类任务中正确分类为j的概率。同时,引入softmax,也能够缓解学习缓慢的问题。把⼀个具有对数似然代价的柔性最⼤值输出层,看作与一个具有交叉熵代价的 S 型输出层⾮常相似,这是很有⽤的。在实际中,我们通常会使用softmax+log-likelihood或者sigmoid+cross entropy。而柔性最⼤值加上对数似然的组合更加适⽤于那些需要将输出激活值解释为概率的场景。
介绍完权重学习速度之后,然后引入过拟合和规范化,过拟合是影响模型泛化能力的关键。如果仅仅看模型在训练集上的代价函数曲线变化,如果出现持续下降,但是测试集的误差在变大,这就可能发生了过度拟合。early-stop是一种策略,在测试集开始出现误差升高的时候,进行提前终止训练。提出使用validation data来学习超参数,然后使用得到的最佳的参数模型再进行test的预测。这种称为hold out的做法,可以避免模型仅使用train&test data时偏向于找到test数据集的超参数,影响其应用到其他新数据上的效果。另外,增加训练样本的数量也是一种减轻多度拟合的方法。文中着重讲到降低网络的规模(复杂度)也是一种有效方式。一种最常见的规范化手段为权重衰减(weight decay)或者L2规范化。L2规范化的想法是增加一个额外的项到代价函数上,称为规范化项。规范化的效果是让网络倾向于学习小一点的权重。⼩的权重在某种程度上,意味着更低的复杂性,也就对数据给出了⼀种更简单却更强⼤解释,规范化⽹络受限于根据训练数据中常⻅的模式来构造相对简单的模型,⽽能够抵抗训练数据中的噪声的特性影响。因此应该优先选择调整后的模型效果也提升到了约98%。
规范化的其他方式,还有L1规范化,dropout和人为增加训练样本。L1是在代价函数上加一个权重绝对值的和。在 L1 规范化中,权重通过⼀个常量向 0 进⾏缩⼩。在 L2 规范化中,权重通过⼀个和 w 成⽐例的量进⾏缩⼩的。所以,当⼀个特定的权重绝对值 w 很⼤时, L1 规范化的权重缩⼩得远⽐ L2 规范化要⼩得多。相反,当⼀个特定的权重绝对值 w很⼩时, L1 规范化的权重缩⼩得要⽐ L2 规范化⼤得多。最终的结果就是: L1 规范化倾向于聚集⽹络的权重在相对少量的⾼重要度连接上,⽽其他权重就会被驱使向 0 接近。dropout也是一种规划化的策略,在该策略中,不依赖于对代价函数的修改,而是改变网络结构。会从随机(临时)地删除网络中的半隐藏神经元,同时保持输入和输出层的神经元不变。每个epoch都会进行一次随机删除隐藏神经元,更新权重和偏置。所以看起来dropout很类似与random forest中的列抽样。本质上就是构建了很多不同结构的神经网络,起到投票的作用,这种平均的方式可以减轻过度拟合。另一种解释就是因为神经元不能依赖其他神经元特定的存在,可以减少复杂的互适应的神经元。权重和偏置的集合,是在一半隐藏神经元被弃权的情形下学到的,当我们运行整个网络时,是指两倍的隐藏神经元被激活。使用L2正则+弃权,模型可以提升到98.7%准确率。至于扩展数据集,通过旋转拉伸扭曲,加噪音,调整像素、颜色可以衍生出大量的新的数据,进行补充,可以进一步提升到99.3%的识别率。
说完了规范化,降低过拟合风险后,引出权重的初始化,可以提升学习速度。一般上,我们通过独立高斯随机变量来选择权重和偏置,被归一化为均值0,标准差1。独立高斯分布相加后的均值方差即为各均值之和,和方差之和。这导致z是一个非常宽的高斯分布。这就导致隐藏神经元的输出sigma(z)很容易接近1或者0。导致隐藏神经元趋于饱和。在权重中进⾏微⼩的调整仅仅会给隐藏神经元的激活值带来极其微弱的改变。导致进⾏梯度下降算法时会学习得⾮常缓慢。如果将原先的高斯分布的标准差改为1/开根号(Nin),Nin是输入层的神经元个数,用它来初始化权重参数。仔细想想,该方式使得每一个输入都有同样的方差,并且相加之后的方差为1。不过偏置的初始化依然采用均值为0,标准差为1的高斯分布。Glorot等人所写的文章Understanding the difficulty of training deep feedforward neural networks中有类似的分析。在这篇论文中,作者的结论是建议初始化的形式是2/(Nin+Nout),即是把输出的神经元数据也考虑进。
超参数选择,可以采用grid search,random search,以及hyperopt的贝叶斯观点超参优化。
关于随机梯度下降,文中介绍了两种变种,Hessian和momentum技术。GD是使用一阶导(Jacobian矩阵), 而Hessian使用二阶导。Hessian矩阵就是一个二阶偏导矩阵。Hessian方法比标准的梯度下降方法收敛速度更快,通过引入代价函数的二阶变化信息,可以让Hessian方法避免在梯度下降中常碰到的多路径问题。虽然Hessian有这方面优势,但是二阶导的矩阵实在太大了,在实际应用中限制很大。受Hessian优化启发,引出了基于momentum梯度下降的方法。momentum技术中,引入了称为速度(velocity),又引入参数miu(monentum efficient)来控制速度的大小。速度是由梯度控制,而速度有控制w的变化率,通过不断重复叠加梯度项来构造速度,获得较大的动量。
神经元激活函数,sigmoid(S函数),tanh(双曲正切),reLU(修正线性单元)。
深度神经网络训练的问题。主要是我们熟知的梯度消失和梯度爆炸。以一个实验作为切入,通过增加隐藏层的层数,发现识别率反而下降了,这个问题引出所要探讨的梯度计算问题。直观感觉应该是增加隐藏层的层数,提升了模型复杂度,在分类上应该更好吧,但事与愿违。问题大概率就出在没有学习到更好的权重和偏置。通过对每一隐藏层神经元的学习过程(神经元在⽹络进⾏学习时改变的速度)分析,发现越靠近输出层的隐藏层神经元学习速度更快,前面的层学习速度低于后面的层。也就是在BP中,梯度倾向于变小,也就意味着在前面的隐藏层中的神经元学习速度要慢于后面的隐藏层。这就是所谓的梯度消失问题(vanishing gradient problem)。在深度学习中,权重初始值较大会导致梯度爆炸,激增问题也同样会遇到。这类问题统称为梯度不稳定。导致梯度消失或者梯度爆炸的原因,就是链式求导法则中的导数问题,如果激活函数使用的是sigmoid,那么求导后,其表达式为sigmoid*(1-sigmoid),其值最大为1/4, 同时加入w的初始化使用的是(0,1)高斯分布,w都是小于1,那么可以看到连乘之后,且层数越多,乘积下降的越快,即前面的层,其梯度越小。如果w初始为100,w*sigmoid导数>1,容易遇到梯度爆炸的问题。不稳定的梯度问题:根本的问题其实并非是消失的梯度问题或者激增额梯度问题,而是在前面的层上的梯度是来自后面的层上项的乘积。唯一让所有层都接近相同的学习速度的方式,是所有项的乘积都能得到一种平衡。因此使用标准的基于梯度的学习算法,在网络中的不同层会出现按照不同学习速度学习的情况。因此要想消除梯度消失问题,需要保证w*s'(z)的绝对值大于1,而s'(z)又依赖于w*a+b,当w变大时,会使得wa+b变得很大,那么会导致sigmoid(z)的导数变得很小,很容易造成梯度消失。因此在深度神经网络中,就需要考虑其他的激活函数,如reLU。
此外,介绍下语言模型解码中的Beam Search(集束搜索)。解码是seq2seq模型的常见问题,常用方法有贪心搜索(Greedy Search)集束搜索(Beam Search)。
以下是一个简单的贪心搜索例子。Decoder根据Encoder的中间语义编码向量和标签得到第一个输出的概率分布,选择概率最大的0.4,即moi。根据隐向量和moi得到第二个输出的概率分布[0.1, 0.1, 0.1, 0.1, 0.6],选择概率最大的0.6,即suis。以此类推,直到遇到<\s>标签,得到最终的序列moi suis étudiant。
上面的贪心搜索只选择了概率最大的一个,而集束搜索则选择了概率最大的前k个。这个k值也叫做集束宽度(Beam Width)。
还是以上面的例子作为说明,k值等于2,则集束搜索的过程如下图所示。得到第一个输出的概率分布[0.1,0.1,0.3,0.4,0.1],选择概率最大的前两个,0.3和0.4,即Je和moi。然后Je和moi分别作为Decoder的输入,得到两个概率分布,然后再选择概率和最大的前两个序列,0.3+0.8和0.4+0.6,即Je suis和moi suis。以此类推,最终可以得到两个序列,即Je suis étudiant和moi suis étudiant,很明显前者的概率和最大,为2.2,所以这个序列是最终得到的结果。
集束搜索本质上也是贪心的思想,只不过它考虑了更多的候选搜索空间,因此可以得到更多的翻译结果。
附参考材料pdf链接:
链接: 书籍《Neural Networks and Deep Learning》 提取码: 7kf3