目录
对于一元分类问题,比如我们上节判断两个数是不是异或关系。
又如多元分类,我们正如上节说的,我们输出这是个鸡鸭鹅或者是什么,我们不能输出1,2,3。我们输出一个
" role="presentation" style="position: relative;">向量(0/1),比如第一维是1就是鸡......。 R 4 然后我们上次得到的
θ " role="presentation" style="position: relative;">值都不是经过训练过的,因此我们要训练θ " role="presentation" style="position: relative;">值,也要获得获得训练出θ " role="presentation" style="position: relative;">值的好坏因此我们要获得代价函数。那么就让我们看看都怎么做吧!
逻辑回归的代价函数如下:
ȷ ( θ ) = − 1 m [ ∑ i = 1 m ( y ( i ) l o g ( h θ ( x ( i ) ) ) + ( 1 − y ( i ) ) l o g ( 1 − h θ ( x ( i ) ) ) ] + λ 2 m ∑ j = 1 n " role="presentation" style="position: relative;"> θ j 2 仿照逻辑回归的代价函数,我们仿写出逻辑回归的代价函数:
ȷ ( Θ ) = − 1 m [ ∑ i = 1 m ∑ k = 1 K y k ( i ) l o g ( h Θ ( x ( i ) ) ) k + ( 1 − y k ( i ) ) l o g ( 1 − ( h Θ ( x ( i ) ) ) k ) ] + λ 2 m ∑ l = 1 L − 1 ∑ i = 1 s l ∑ j = 1 s l + 1 ( Θ j i ( l ) " role="presentation" style="position: relative;"> ) 2 其中:
h Θ ( x ) ⊂ R k ( h Θ ( x ) ) i = i t h O u t p u t " role="presentation" style="position: relative;">解释:
我们得到了神经网络的代价函数:(后文有解释这是怎么推出来的)
这里
K " role="presentation" style="position: relative;">是输出的分类结果,m " role="presentation" style="position: relative;">是样本个数,L " role="presentation" style="position: relative;">是神经网络层数," role="presentation" style="position: relative;">为在 s l l " role="presentation" style="position: relative;">层的单元。
ȷ ( Θ ) = − 1 m [ ∑ i = 1 m ∑ k = 1 K y k ( i ) l o g ( h Θ ( x ( i ) ) ) k + ( 1 − y k ( i ) ) l o g ( 1 − ( h Θ ( x ( i ) ) ) k ) ] + λ 2 m ∑ l = 1 L − 1 ∑ i = 1 s l ∑ j = 1 s l + 1 ( Θ j i ( l ) " role="presentation" style="position: relative;"> ) 2 我们要求的是
θ " role="presentation" style="position: relative;">使得m i n Θ ȷ ( Θ ) " role="presentation" style="position: relative;">。因此要编码去求
ȷ ( Θ ) " role="presentation" style="position: relative;">和" role="presentation" style="position: relative;">。 ∂ ∂ Θ i j ( l )
我们给定一个数据
( x , y ) " role="presentation" style="position: relative;">,神经网络系统在做如下的事情。
为了方便标记,我们把输入
x " role="presentation" style="position: relative;">作为第一层的激活项,即a ( 1 ) = x " role="presentation" style="position: relative;">,然后前向传播,计算第二层的激活项即a ( 2 ) = g ( z ( 2 ) ) , z ( 2 ) = Θ ( 1 ) a ( 1 ) = ( θ 0 , θ 1 ) ( 1 , x " role="presentation" style="position: relative;"> 。然后最终得到输出 ) T " role="presentation" style="position: relative;">也就是 a ( 4 ) y " role="presentation" style="position: relative;">。在这一步中,我们得到了每一层的输出值。
反向传播是用于计算代价函数的,如下图所示:
我们定义误差项
" role="presentation" style="position: relative;">为在 δ j ( l ) l " role="presentation" style="position: relative;">层第j " role="presentation" style="position: relative;">个节点的误差。对于第四层,我们假设只有一个输出节点
δ j ( 4 ) = a j ( 4 ) − " role="presentation" style="position: relative;">,误差为第四层的输出值-真值y。 y j 对于第三层的误差,我们只给出最终结果(推导较难)
δ j ( 3 ) = ( Θ ( 3 ) ) T δ ( 4 ) . ∗ g ′ ( z ( 3 ) ) " role="presentation" style="position: relative;">对于第二层的误差,我们只给出最终结果(推导较难)
δ j ( 2 ) = ( Θ ( 2 ) ) T δ ( 3 ) . ∗ g ′ ( z ( 2 ) ) " role="presentation" style="position: relative;">
" role="presentation" style="position: relative;">为第 δ j ( i ) i " role="presentation" style="position: relative;">层的所有节点的误差,即每一个节点的误差为该层下一层可学习参数的向量与反向穿播得到的误差进行点乘,再点乘激活函数的导数。
我们有
m " role="presentation" style="position: relative;">个训练集。先将可叠加误差项" role="presentation" style="position: relative;">初始化为0,它被用来计算偏导项 △ i j ( l ) ∂ ∂ Θ i j ( L ) ȷ ( Θ ) " role="presentation" style="position: relative;">,意思为对第L " role="presentation" style="position: relative;">层的第j " role="presentation" style="position: relative;">个参数Θ − − − − ( Θ i j ) " role="presentation" style="position: relative;">求偏导,如下图:
至此,我们来总结一下这个算法到底在做什么:对于每一个数据,我们先利用前向传播计算出每一个节点的激活项。我们用反向传播计算出最后一层的误差
δ " role="presentation" style="position: relative;">,我们用这个误差值乘以训练参数再计算出前一层的误差向量 ( L ) δ " role="presentation" style="position: relative;"> ,我们按照这样算出所有层的误差向量,将每一个样本的误差 ( L − 1 ) a j ( l ) " role="presentation" style="position: relative;">(第i个样本的第l层第j列节点的误差) 累计得到 δ i ( l + 1 ) " role="presentation" style="position: relative;">,最终除以样本数量得到对于每个节点的累计误差,我们也就得到了对每个学习参数的偏导。从而我们也就能通过梯度下降法来寻找最优解完成学习任务。 △ i j ( l )
正向传播:以
" role="presentation" style="position: relative;">的获得为例子: z 1 ( 3 ) z 1 ( 3 ) = + 1 ∗ Θ 02 ( 2 ) + a 1 ( 2 ) ∗ Θ 12 ( 2 ) + a 2 ( 2 ) ∗ " role="presentation" style="position: relative;">,再根据激活函数 Θ 22 ( 2 ) a 1 3 = g ( z 1 ( 3 ) ) " role="presentation" style="position: relative;">得到下一层的输入,经过这些步骤,我们前向计算得到了每一个节点的激活值和最终的分类输出结果。我们再前面得出:
" role="presentation" style="position: relative;">是 δ j ( l ) " role="presentation" style="position: relative;">的误差项(第 a j ( l ) l " role="presentation" style="position: relative;">层的第j " role="presentation" style="position: relative;">个节点),学过高等数学的同学可能指导,我们所算的" role="presentation" style="position: relative;">其实就是代价函数关于 δ j ( l ) " role="presentation" style="position: relative;">的偏导数 z j ( l ) 反向传播:以
δ 1 ( 4 ) , " role="presentation" style="position: relative;">的获得为例子: δ 2 ( 2 ) δ 1 ( 4 ) = y ( i ) − " role="presentation" style="position: relative;">这个很好理解,最终节点的误差就是我们的神经网络输出值与实际值的插值。 a 1 ( 4 ) δ 2 ( 2 ) = Θ 12 ( 2 ) δ 1 ( 3 ) + Θ 22 ( 2 ) " role="presentation" style="position: relative;">,这个也很好理解,我们把误差反向传播,和前向传播相似。 δ 2 ( 3 )
在神经网络或其他复杂的模型下使用前向传播,反向传播时,如果使用梯度下降来寻找参数,那么使用梯度检测会100%地消除梯度下降过程中产生的bug。
有一个代价函数
J ( Θ ) " role="presentation" style="position: relative;">,在横轴上取一点θ ( θ ∈ R ) " role="presentation" style="position: relative;">,则这一点的导数对应于图像上在该点的切线斜率,如下图:计算该点切线的斜率,可以做一个近似,即:
在
θ " role="presentation" style="position: relative;">附近分别取点θ + ε " role="presentation" style="position: relative;">和θ − ε " role="presentation" style="position: relative;">(易知ε " role="presentation" style="position: relative;">为很小的值),两点在曲线上表现为( θ + ε , J ( θ + ε ) ) " role="presentation" style="position: relative;">和( θ − ε , J ( θ − ε ) ) " role="presentation" style="position: relative;">,两点的割线斜率即可近似为θ " role="presentation" style="position: relative;">点在曲线上的切线斜率。即双侧差分:
" role="presentation" style="position: relative;"> J ( θ + ε ) − J ( θ − ε ) 2 ε 考虑更普遍的情况,参数
θ " role="presentation" style="position: relative;">为向量参数的时候也很好理解,如下图:
其实如果加上
" role="presentation" style="position: relative;">就是偏导数定义了。 l i m ε → 0
之后,检查这个得到的
θ " role="presentation" style="position: relative;">向量导数值(gradApprox)和通过反向传播计算出的偏导项进行比较,如果相等或在数值上近似等于,那么就可以确定反向传播的实现(或使用其他高级算法计算出来的偏导数)是正确的。(等于的阈值是多少,那就交给调参侠了啊哈哈哈)那么总的来说,梯度检测的步骤如下:
①反向传播得到各个节点的误差项
②利用梯度检测算出偏导数
③看看误差和偏导数差的大不大
④梯度检测消耗资源很大,记得确认在反向传播代码无问题的时候关闭接口。
对于一个模型来说,当执行梯度下降法或者高级算法时,我们需要对初始化参数
Θ " role="presentation" style="position: relative;">初始一个值,对于梯度下降法也是如此,给予梯度下降法初始参数后,就能一步步通过梯度下降来最小化代价函数J ( Θ ) " role="presentation" style="position: relative;">,但怎样初始化就成了一个难题。
我们先考虑一个问题:如果将参数都初始化设置为0会有什么问题呢?首先进行正向传播,第一层的激活项经过计算都是相同的且都是0,经过反向传播,误差项也相等,偏导数也相等.....因此经过每次更新以后,这两个隐藏单元的每个参数输入都相等的。即使利用梯度下降进行了一次迭代,这两个隐藏单元依然以相同的函数输入作为计算。他们会一直相等下去.....
解决方法是我们要进行随机初始化。如上图所示。
因此,为了训练神经网络,首先要将权重随机初始化为一个接近0的范围在
( − ε , + ε ) " role="presentation" style="position: relative;">中的数,然后进行反向传播、梯度检验,最后使用梯度下降来最小化我们的代价函数。
当训练一个神经网络时,我们第一步做的就是选择一种网络架构(神经元之间的连接方式):一般来说,我们只设置一个隐藏层,若设置多个隐藏层,每一层神经元的数量应该相等,如下图所示:
第二步:构建一个神经网络并初始化权重(随机法)
第三步:执行前向传播算法
第四步:计算出代价函数
" role="presentation" style="position: relative;"> J Θ 第五步:执行反向传播算法计算偏导数们
第六步:梯度检查
第七步:用梯度下降或是其他优化方法最小化代价函数