美文网首页
卷积神经网络的数学推导及简单实现

卷积神经网络的数学推导及简单实现

作者: 迎风漂扬 | 来源:发表于2019-04-09 13:13 被阅读0次

    先来看一个网络:


    这是一个简单的CNN的前半部分,不包含全连接层,而且已有一个卷积层和一个池化层,卷积核大小是2X2,步长1,Padding为0,Pooling操作为Max Pooling,大小同样是2x2
    先来看正向的计算,卷积操作就没什么好说的了,不了解的可以随便百度一下,下面直接写公式:
    u_{i, j}=w_{0,0} a_{i, j}+w_{0,1} a_{i, j+1}+w_{1,0} a_{i+1, j}+w_{1,1} a_{i+1, j+1}=\sum_{m} \sum_{n} w_{m, n} a_{i+m, j+n}
    b_{i, j}=f^{\prime}\left(u_{i, j}\right)
    u_{i, j}是节点b_{i, j}的加权输入,f是激活函数ReLU

    self.activative = lambda x: np.maximum(0, x)        #激活函
    self.dirivative = lambda x: 1 if x > 0 else 0       #导数
    self.u_a = conv(self.input, self.filter, stride = 1, padding = 0)   #卷积函数,实现略
    self.b = self.activative(self.u_a)
    

    算出所有的b_{i, j}后,就是Max Pooling了:
    c_{i, j}=\max \left(b_{2 i, 2 j}, b_{2 i, 2 j+1}, b_{2 i+1,2 j}, b_{2 i+1,2 j+1}\right)

    self.c, position = maxpooling(self.b, size = 2)   #实现略,position为矩阵,记录位置,后面要用到
    

    卷积层和池化层的前向计算都说完了,虽然实际中一般不止一层,不过都是可以套用的,接下来就是全连接层了:


    如图所示,max pooling的结果‘拉平’后就是全连接层的输入向量了:

    input_vector = self.c.flatten()
    

    这是之前的一篇关于DNN的推导,就不赘述了:
    https://www.jianshu.com/p/bed8d5dac958
    关于全连接层的误差传播已经知道怎么算了,接下来的问题就是将误差传回池化层及卷积层了:

    上图中\delta_{1},\delta_{2},\delta_{3},\delta_{4}是FC(全连接)层中输入层的误差,也是池化层的下一层的误差,公式在上面一篇文章中已经讨论了:
    \delta_{j}=f^{\prime}\left(u_{j}\right) \sum_{k} w_{j k} \delta_{k}
    而输入层是没有激活函数的,所以f^{\prime}\left(u_{j}\right)=1,即:
    \delta_{j}=\sum_{k} w_{j k} \delta_{k}

    在得到误差项之后,进一步求Pooling操作之前的误差项,如果Max Pooling如下:


    则upsample操作则同样:


    self.delta_c = dnn.getInputDelta(input_vector, target).reshape(2, 2)    #获得FC输入层的误差
    self.delta_b = upsample(self.delta_c, position)
    

    推导过程如下:


    若x1为最大值,则不难求得下列偏导数:
    \frac{\partial u_{5}}{\partial u_{1}}=1
    \frac{\partial u_{5}}{\partial u_{2}}=0
    \frac{\partial u_{5}}{\partial u_{3}}=0
    \frac{\partial u_{5}}{\partial u_{4}}=0

    因为只有最大的那一项会队x5产生影响,所以其余项的偏导数都为0,又因为:
    \delta_{5}=-\frac{\partial E}{\partial u_{5}},所以:
    \delta_{1}=-\frac{\partial E}{\partial u_{1}}=-\frac{\partial E}{\partial u_{5}} \frac{\partial u_{5}}{\partial u_{1}}=\delta_{5}
    \delta_{2}=-\frac{\partial E}{\partial u_{2}}=-\frac{\partial E}{\partial u_{5}} \frac{\partial u_{5}}{\partial u_{2}}=0
    \delta_{3}=-\frac{\partial E}{\partial u_{3}}=-\frac{\partial E}{\partial u_{5}} \frac{\partial u_{5}}{\partial u_{3}}=0
    \delta_{4}=-\frac{\partial E}{\partial u_{4}}=-\frac{\partial E}{\partial u_{5}} \frac{\partial u_{5}}{\partial u_{4}}=0
    如下图所示:

    池化层没有参数需要更新,所以只要把误差传给上一层就可以了,接下的问题就是已知卷积层的上一层(也就是正向计算的下一层)误差,求卷积层的误差以及更新卷积核了。

    首先已知了上一层所有节点b_{i,j}的误差项\delta_{i,j},来看看如何更新卷积核的梯度。由于任一w都对所有b_{i,j}有影响,根据全导数公式:
    \frac{\partial E}{\partial w_{i, j}}=\sum_{m} \sum_{n} \frac{\partial E}{\partial u_{m, n}} \frac{\partial u_{m, n}}{\partial w_{i, j}}

    上面已经讨论过u_{m,n}是节点b_{m,n}的加权输入,所以:
    \frac{\partial E}{\partial u_{m, n}}=-\delta_{m, n}
    \frac{\partial u_{m, n}}{\partial w_{i, j}}=\frac{\partial \sum_{p} \sum_{q} w_{p, q} a_{m+p, n+q}}{\partial w_{i, j}}=a_{m+i, n+j}
    \frac{\partial E}{\partial w_{i, j}}=-\sum_{m} \sum_{n} \delta_{m, n} a_{m+i, n+j}

    for i in range(2):
        for j in range(2):
            self.filter[i,j] += self.learningrate * (self.delta_b * self.input[i:i+m, j:j+n]).sum()
    

    最后,就是把误差继续往上一层传递了,如图:


    先看几个例子:
    \delta_{0,0}^{a}=-\frac{\partial E}{\partial u_{0,0}^{a}}=-\frac{\partial E}{\partial u_{0,0}^{b}} \frac{\partial u_{0,0}^{b}}{\partial a_{0,0}} \frac{\partial a_{0,0}}{\partial u_{0,0}^{a}}=\delta_{0,0}^{b} w_{0,0} f^{\prime}\left(u_{0,0}^{a}\right)
    \delta_{0,1}^{a}=-\frac{\partial E}{\partial u_{0,1}^{a}}=-\left(\frac{\partial E}{\partial u_{0,0}^{b}} \frac{\partial u_{0,0}^{b}}{\partial a_{0,1}} \frac{\partial a_{0,1}}{\partial u_{0,1}^{a}}+\frac{\partial E}{\partial u_{0,1}^{b}} \frac{\partial u_{0,1}^{b}}{\partial a_{0,1}} \frac{\partial a_{0,1}}{\partial u_{0,1}^{a}}\right)=\left(\delta_{0,1}^{b} w_{0,1}+\delta_{0,1}^{b} w_{0,0}\right) f^{\prime}\left(u_{0,1}^{a}\right)
    \delta_{1,1}^{a}=-\frac{\partial E}{\partial u_{1,1}^{a}}=\left(\delta_{0,0}^{b} w_{1,1}+\delta_{0,1}^{b} w_{1,0}+\delta_{1,0}^{b} w_{0,1}+\delta_{1,1}^{b} w_{0,0}\right) f^{\prime}\left(u_{1,1}^{a}\right)

    归纳一下,可以发现如下图的规律:


    公式如下:
    \delta_{i, j}^{a}=f^{\prime}\left(u_{i, j}^{a}\right) \sum_{m} \sum_{n} \delta_{m+i, n+j}^{b} r o t 180\left(w_{m, n}\right)
    写成卷积形式:
    \delta^{a}=f^{\prime\left(u^{a}\right)} \cdot \delta^{b} * \operatorname{rot} 180(W)

    filterrot = np.rot90(np.rot90(self.filter))
    delta_bpadding = np.zeros((6, 6))
    deldelta_bpadding[1:-1, 1:-1] = self.delta_b
    self.delta_a = conv(deldelta_bpadding, filterrot) * getDirivative(self.input)
    

    总算写完了,只是后面的有些粗糙,以后有时间再完善吧

    相关文章

      网友评论

          本文标题:卷积神经网络的数学推导及简单实现

          本文链接:https://www.haomeiwen.com/subject/ljlbiqtx.html