本文共 2989 字,大约阅读时间需要 9 分钟。
神经网络模型,我自己用一句话对其进行概括就是:通过不断的训练,学习出一个函数(即不断调整这个函数的各个参数),使得这个函数在训练集上可以很好的拟合训练样本的真实输出,因为理论上前馈神经网络,只需具备单隐含层和有限个神经单元,就能以任意精度拟合任意复杂度的函数,这是个已经被证明了的定理。比如来看下面这张图:
在这里蓝色的点表示我们的训练样本,行坐标表示的是样本的特征,为了简单起见这里假设输入的特征是一维的,纵坐标表示输出。光从这些蓝色的点我们可以看到这些样本大致呈显出以一定规律分布,即其分布可能与某个函数(红色曲线表示)的变化相一致,而为了预测后续输入(比如说x=5)的可能输出值,我们就需要学习出这样的一个函数。由于噪声的影响,这些样本不可能完全落在曲线上,而是会存在一定的偏差,因此我们学习的过程就是:首先初始化这条曲线的参数(系数),然后通过不断地对函数的各个参数进行调整使得训练样本距离曲线的总误差最小,这样得到的一个函数能够较好的对训练样本进行拟合,即能够较好的反应数据的分布规律。
这是一个神经元的结构,为神经元的输入,为各输入的权重,Σ执行操作,f为激活函数,将z输入到激活函数中的到神经元的输出,b成为神经元的偏置。神经网络即由众多神经元连接而构成,由下图所示:
这是一个四层的神经网络(严格来说为三层,即不包括输入层L0层在内),其中L0为输入层,L3为输出层,L1和L2为隐藏层(之所以称之为隐藏层,是因为我们在训练数据中无法直接观测到它们的值,而只能观测到输入层和输出层)。除了输入层外,每个神经元都有偏置b以及输入的权重,因为输入层只是作为神经网络的输入,不需要提供其他的功能。为了叙述方便,约定一下符号表示:表示第l-1层中的第i个神经元与第l层中的第j个神经元之间的连接权重;表示第l层中第j个神经元的偏置;作为第l层第j个神经元的加权输入;表示第l层第j个神经元的激活值;表示第l层第j个神经元的权重向量;表示第l层神经元的数量,表示第l层神经元的权重矩阵,其为形状为;表示第l层神经元的的偏置向量,其为一个行向量;表示第l层神经元的加权输入向量,也为行向量;表示第l层神经元的输出向量,为行向量。
神经网络模型的学习的目的是要让学习到的模型能够很好的对训练样本进行拟合,为了评估模型对样本的拟合程度,这里需要定义一个损失函数,用于计算单个样本的预测输出和真实输出的误差,那么对训练集上的所有样本的这样一个误差汇总后就得到模型在训练集上的整体误差,用代价函数(也叫目标函数)表示。其学习过程是一个前向传播和反向传播的过程,即将样本的特征作为输入,经由神经网络的层层计算最后得到样本的预测输出,此为前向传播的过程。反向过程为,由目标函数从后往前逐层计算出各层权重和偏置的偏导:和,然后使用梯度下降法更新权重和偏置:
(1)
(2)
在这里,η称为学习率,用于控制每次更新的“步伐”大小。因为梯度下降法是基于微分思想,即目标函数随着和的变化倾向是在一个很小的微元上成立的,因此η的值不宜设置过大,同时,η的值也不能够设置的过小,不然会使梯度下降算法收敛得特别慢。
前向传播和反向传播的过程可以用下面这个图来描述:
前向传播的过程比较简单,就是将样本的特征输入到网络并计算每一层的值,最终得到样本预测输出的一个过程。第l层第j个神经元的激活值的计算方式为:
(3)
对于激活函数的选取,最简单的是sigmoid,但是当神经网络的层数变大时有可能会导致的问题,梯度消失是指在层数较深的神经网络中,在进行反向传播链式求导时,由于连乘效应而导致前面隐藏层的梯度非常小使得前面隐藏层的权重和偏置更新非常缓慢几乎不变。因此可以考虑替代的使用ReLU、Leaky ReLU、ELU等激活函数。
公式(3)是计算第l层第j个神经元的激活值,通过矩阵乘法我们可以同时计算第l层所有神经元的激活值:
(4)
(5)
公式(4)中和均为维的行向量,为的矩阵。公式(5)是计算第l层的激活值,本层的激活值又作为下一层的输入。
公式(4)和(5)是计算一个样本的前向传播过程,因此进一步扩展为同时计算一批样本的前向传播过程:
(6)
(7)
与(4)和(5)不同,(6)和(7)中的和为m个样本按行堆叠构成的矩阵,其形状为,即矩阵的行表示不同的样本,列表示样本的特征。注意到(6)中为的矩阵,而为的行向量,两者的维度不一致,因此这里其实用到了python中的“广播”操作,即在进行矩阵的加法操作时,会在行的方向上复制m次扩展为的矩阵。
反向传播其实就是一个链式求导的过程,从输出层开始,从后往前逐层计算权重和偏置的偏导数。假设输出层为第L层,那么对于第L层来说,我们是希望得到和,根据链式求导的法则
(8)
(9)
因此为了求得对w和b的偏导,需要先求得对a和z的偏导。这里损失函数我们直接选取平方误差:
(10)
添上是为了求导方便。损失函数是计算单个样本的误差,代价函数(目标函数)是计算整个训练集中所有样本的整体误差,目标函数我们直接选取所有训练样本平方误差的均值:
(11)
(11)中m为训练集样本数量,A和Y均为的矩阵,行表示不用样本,列表示样本的特征;(k)表示第k个样本。首先来看对一个样本求导过程,即看损失函数对偏导很简单:
(12)
对求导为:
(13)
而对和求导为:
(14)
(15)
于是由(12)~(15)可得到:
(16)
(17)
(18)
(17)和(18)实现对L层的单个权重和偏置求导,使用矩阵运算可以实现对L层的所有权重和偏置同时求导。首先这里先引入hadamard积,hadamard积是指两个矩阵对应位置元素相乘,用表示。
(19)
(20)
在(19)中有广播操作,因为结果为的行向量,而为的列向量。进一步,将(19)和(20)扩展为目标函数对和求导:
(21)
(22)
(23)
(23)中求b的偏导时借用了python中的一句代码,功能是对矩阵的每一列求和后取平均值。
中间层的求导过程与输出层类似。损失函数对于第h层第i个神经元的偏导为:
(24)
(25)
(26)
(27)
因此由(24)~(27)可得到:
(28)
(29)
(30)
使用矩阵运算同时对h层的所有权重和偏置求导可得:
(31)
(32)
(33)
(34)
将(31)~(33)拓展为目标函数对和求导可得:
(35)
(36)
(37)
至此,反向传播推到结束。通过(21)~(23)以及(35)~(37)即可推到任意层权重和偏置的偏导,从而计算出目标函数的梯度,再使用上述提到的梯度下降法对所有的权重和偏置进行更新即完成一次迭代更新。通常我们的训练集非常的庞大,从而在进行反向传播计算偏导时运算量非常的大,非常耗时。因此在很多情况下我们并非直接采用标准的梯度下降法来更新权重和偏置,而是采用一种叫做mini-batch梯度下降的方法,即将整个训练集划分为规模更小的多个子集,每次只在这些规模较小训练集上使用梯度下降法来对权重和偏置进行一次迭代更新,当对所有的子集更新完一次后称为一轮(epoch)。在实际训练过程中,可以在每轮对训练集重新划分的条件下进行多轮训练以提高精度。
转载地址:http://yqhzb.baihongyu.com/