朋友们,如需转载请标明出处公众号:jack床长
新手请点击公众号里的“历史文章”从序言看起,否则你可能看不懂本篇文章
在讲人工智能之前,第一段我先讲讲其它的,讲一些我想讲的,讲一些大家需要知道的,讲一些对大家的人生有帮助的。说一下买家具吧。家具的水太深,对于这么深的行业,我还是建议买品牌产品,因为只有有品牌在,他们不管太乱搞。如果买无牌的家具,可能甲醛等超标,引发白血病等疾病。最近在选购家具,也正好看了国产精品电影《我不是药神》,所以越发觉得要买好点的家具。
我们知道神经网络的训练由前向传播和反向传播两部分构成,上一篇文章已经介绍了如何计算浅层神经网络的前向传播,本篇文章我们来说说反向传播的计算。
我们先计算出第二层的相关偏导数,然后再反向往前推,计算第一层的。第二层的计算其实和我们之前介绍的单神经元神经网络是一样的。因为如果我们不看输入层,而把第一层(隐藏层)看作输入层时,那么它就是一个我们之前学过的单神经元网络。
第二层的偏导数计算公式如下,和单神经元网络是一样的。(下面公式计算的是单训练样本时的情况,后面我们再说多训练样本时的情况),因为我们这里可以把第一层看作是输入层,所以在计算dW[2]的a[1]也可以看作是x(这样一来公式就和之前学过的单神经元网络一样一样了)。
dz[2]= a[2]– y
dW[2]= dz[2]a[1]T
db[2]= dz[2]
第二层的偏导数计算出来后,我们就可以往前传播,去计算第一层的偏导数了。第一层的偏导数的计算就与第二层的不同了。这也是我们需要重点讲解和学习的地方。首先我们先弄明白为什么第一层和第二层的计算会不同呢。我们结合下面的图来讲解。
神经网络的偏导数是相对于损失函数L来计算的。第二层是直接与损失函数相邻的,所以我们就可以直接计算它的偏导数。而第一层与损失函数没有直接的联系,所以我们只能通过链式法则来计算(不懂链式法则的请复习我前面的文章《1.2.5 计算图》)。
由链式法则可知,如果我们想要计算损失函数L关于z[1]的偏导数,可以通过L关于a[1]的偏导数与a[1]关于z[1]的偏导数的乘积来得到,而L关于a[1]的偏导数我们可以通过L关于z[2]的偏导数与z[2]关于a[1]的偏导数的乘积来得到。有点绕,但是慢慢地捋一捋就会顺了,小朋友要有耐心哦!其中L关于z[2]的偏导数dz[2]我们在前面已经计算出来了。
通过各种数学运算,最后得出L关于a[1]的偏导数公式为W[2]Tdz[2]。(详细的数学计算变换过程我就不说了,如果你数学很好,你可以自己慢慢地从损失函数开始推导出来,如果你数学不好,完全可以不用在意推导过程,很多时候我们并不需要知道推导过程,例如你知道1+1=2的论证过程吗?)
L关于a[1]的偏导数我们知道了,那么a[1]关于z[1]的偏导数呢?a[1]是一个激活函数,激活函数我们用g来表示,之前我们的激活函数一直用的是sigmoid,其实我们还可以用其他的激活函数,而不同的激活函数关于z[1]的偏导数计算公式都不同,所以这里我们就不给出具体的计算公式了,以后根据具体的激活函数再给出相应的计算公式。当前我们只用g[1]'(z[1])来表示激活函数\a[1]关于z[1]的偏导数。综上所述,损失函数L关于z[1]的偏导数(L关于a[1]的偏导数与a[1]关于z[1]的偏导数的乘积)的公式如下。
dz[1]= W[2]Tdz[2]* g[1]'(z[1])
上面公式中的星号表示矩阵元素间的一一相乘,而不是矩阵相乘。
得出dz[1]后,dW[1]以及db[1]就可以通过dz[1]求出来了。公式与单神经元网络是一样的,如下所示。
dW[1]= dz[1]xT
db[1]= dz[1]
上面是针对于单个训练样本时的计算公式,下面我们讲解一下多训练样本时的公式。
dZ[2]= A[2]–Y
dW[2]=dZ[2]A[1]T/m
db[2]= np.sum(dZ[2]) / m
dZ[1]= W[2]TdZ[2]* g[1]'(Z[1])
dW[1]=dZ[1]XT/m
db[1]=np.sum(dZ[1],axis=1,keepdims=True) / m
可以看到主要的变化是很多小写字母变成了大写。我们知道这是因为进行了向量化,将小写的向量组合成了大写的矩阵,从而达到可以一次性同时对所有样本进行运算的目的,极大地提升了运算效率。
另外一个变化是不少公式都要除以一个m。这是因为对于每一个样本来说,训练得出的参数都是不同的,所以将所有样本得出的参数累加起来,然后除以一个样本总数m来得到一个平均值。这样一来,这个参数(平均值)将会对绝大部分样本都适用,适应了最广大样本。
大家可能还发现了另外一个变化,那就是sum函数的参数不同了。因为第一层不再是只有一个神经元了,所以dZ[1]的维度是(n[1],m),n[1]在这本例中是4,表示有4个神经元,m表示有m个训练样本。也就是说,每一个神经元都对应m个训练样本,所以有4个m。而我们只需要将每一个神经元本身对应的训练样本的结果参数累加起来,即只需要将每一行中的所有元素累加起来,不需要累加每一列中的元素。如下图所示,只累加同色的。asix=1的作用就是让sum只累加每一行中的所有元素。
而keepdims是为了防止sum的输出结果变成(n[1], )这样的形式,我们需要的形式是(n[1],1)
通过上一篇文章和本篇文章你已经知道了如何计算浅层神经网络的前向传播和反向传播。本篇文章中还提到了我们可以用不同的激活函数,其实选对了激活函数可以让你的神经网络更强大,后面的文章将给大家详细介绍下激活函数。
请大家加我的微信,之后会用微信向大家公布测试题答案和一些通知,以及统一回答大家遇到的常见问题,有项目也可以招集大家一起做。加我时请注明“人工智能”。
领取专属 10元无门槛券
私享最新 技术干货