【深度学习系列】卷积神经网络详解(二)――自己手写一个卷积神经网络

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

【深度学习系列】卷积神经网络详解(二)——自己手写一个卷积神经网络作者:Charlotte77数学系的数据挖掘民工博客专栏:个人公众号:Charlotte数据挖掘(ID:CharlotteDataMining)精彩回顾:【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理【深度学习系列】PaddlePaddle之数据预处理??上篇文章中我们讲解了卷积神经网络的基本原理,包括几个基本层的定义、运算规则等。本文主要写卷积神经网络如何进行一次完整的训练,包括前向传播和反向传播,并自己手写一个卷积神经网络。如果不了解基本原理的,可以先看看上篇文章:????【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理卷积神经网络的前向传播首先我们来看一个最简单的卷积神经网络:1.输入层----卷积层以上一节的例子为例,输入是一个4*4的image,经过两个2*2的卷积核进行卷积运算后,变成两个3*3的feature_map以卷积核filter1为例(stride=1):计算第一个卷积层神经元o11的输入:神经元o11的输出:(此处使用Relu激活函数)其他神经元计算方式相同2.卷积层----池化层计算池化层m11的输入(取窗口为2*2),池化层没有激活函数3.池化层----全连接层池化层的输出到flatten层把所有元素“拍平”,然后到全连接层。4.全连接层----输出层全连接层到输出层就是正常的神经元与神经元之间的邻接相连,通过softmax函数计算后输出到output,得到不同类别的概率值,输出概率值最大的即为该图片的类别。卷积神经网络的反向传播传统的神经网络是全连接形式的,如果进行反向传播,只需要由下一层对前一层不断的求偏导,即求链式偏导就可以求出每一层的误差敏感项,然后求出权重和偏置项的梯度,即可更新权重。而卷积神经网络有两个特殊的层:卷积层和池化层。池化层输出时不需要经过激活函数,是一个滑动窗口的最大值,一个常数,那么它的偏导是1。池化层相当于对上层图片做了一个压缩,这个反向求误差敏感项时与传统的反向传播方式不同。从卷积后的feature_map反向传播到前一层时,由于前向传播时是通过卷积核做卷积运算得到的feature_map,所以反向传播与传统的也不一样,需要更新卷积核的参数。下面我们介绍一下池化层和卷积层是如何做反向传播的。在介绍之前,首先回顾一下传统的反向传播方法:1.通过前向传播计算每一层的输入值neti,jneti,j(如卷积后的feature_map的第一个神经元的输入:neti11neti11)2.反向传播计算每个神经元的误差项δi,jδi,j,δi,j=?E?neti,jδi,j=?E?neti,j,其中E为损失函数计算得到的总体误差,可以用平方差,交叉熵等表示。3.计算每个神经元权重wi,jwi,j的梯度,ηi,j=?E?neti,j??neti,j?wi,j=δi,j?outi,jηi,j=?E?neti,j??neti,j?wi,j=δi,j?outi,j4.更新权重wi,j=wi,j?λ?ηi,jwi,j=wi,j?λ?ηi,j(其中λλ为学习率)卷积层的反向传播由前向传播可得:所以上一层的输出也就是这一层的输入,即:outi11=activators(neti11)=i11outi11=activators(neti11)=i11首先计算输入层的误差项δ11δ11:(注意这里是neti11neti11,代表的是上一层的输入,不是neto11neto11)先计算?E?i11?E?i11此处我们并不清楚?E?i11?E?i11怎么算,那可以先把input层通过卷积核做完卷积运算后的输出feature_map写出来:然后依次对输入元素ii,jii,j求偏导i11i11的偏导:观察一下上面几个式子的规律,归纳一下,可以得到如下表达式:图中的卷积核进行了180°翻转,与这一层的误差敏感项矩阵deltai,j)deltai,j)周围补零后的矩阵做卷积运算后,就可以得到?E?i11?E?i11,即?E?ii,j=∑m?∑nhm,nδi+m,j+n?E?ii,j=∑m?∑nhm,nδi+m,j+n第一项求完后,我们来求第二项?i11?neti11此时我们的误差敏感矩阵就求完了,得到误差敏感矩阵后,即可求权重的梯度。由于上面已经写出了卷积层的输入neto11neto11与权重hi,jhi,j之间的表达式,所以可以直接求出:推论出权重的梯度:偏置项的梯度:可以看出,偏置项的偏导等于这一层所有误差敏感项之和。得到了权重和偏置项的梯度后,就可以根据梯度下降法更新权重和梯度了。池化层的反向传播池化层的反向传播就比较好求了,看着下面的图,左边是上一层的输出,也就是卷积层的输出feature_map,右边是池化层的输入,还是先根据前向传播,把式子都写出来,方便计算:假设上一层这个滑动窗口的最大值是outo11这样就求出了池化层的误差敏感项矩阵。同理可以求出每个神经元的梯度并更新权重。手写一个卷积神经网络1.定义一个卷积层首先我们通过ConvLayer来实现一个卷积层,定义卷积层的超参数classConvLayer(object):'''参数含义:input_width:输入图片尺寸——宽度input_height:输入图片尺寸——长度channel_number:通道数,彩色为3,灰色为1filter_width:卷积核的宽filter_height:卷积核的长filter_number:卷积核数量zero_padding:补零长度stride:步长activator:激活函数learning_rate:学习率'''def__init__(self,input_width,input_height,channel_number,filter_width,filter_height,filter_number,zero_padding,stride,activator,learning_rate):self.input_width=input_widthself.input_height=input_heightself.channel_number=channel_numberself.filter_width=filter_widthself.filter_height=filter_heightself.filter_number=filter_numberself.zero_padding=zero_paddingself.stride=strideself.output_width=\ConvLayer.calculate_output_size(self.input_width,filter_width,zero_padding,stride)self.output_height=\ConvLayer.calculate_output_size(self.input_height,filter_height,zero_padding,stride)self.output_array=np.zeros((self.filter_number,self.output_height,self.output_width))self.filters=[]foriinrange(filter_number):self.filters.append(Filter(filter_width,filter_height,self.channel_number))self.activator=activatorself.learning_rate=learning_rate其中calculate_output_size用来计算通过卷积运算后输出的feature_map大小@staticmethoddefcalculate_output_size(input_size,filter_size,zero_padding,stride):return(input_size-filter_size+52*zero_padding)/stride+12.构造一个激活函数此处用的是RELU激活函数,因此我们在activators.py里定义,forward是前向计算,backforward是计算公式的导数:classReluActivator(object):defforward(self,weighted_input):#returnweighted_inputreturnmax(0,weighted_input)defbackward(self,output):return1ifoutput0else0其他常见的激活函数我们也可以放到activators里,如sigmoid函数,我们可以做如下定义:classSigmoidActivator(object):defforward(self,weighted_input):return1.0/(1.0+np.exp(-weighted_input))#thepartialofsigmoiddefbackward(self,output):returnoutput*(1-output)如果我们需要自动以其他的激活函数,都可以在activator.py定义一个类即可。3.定义一个类,保存卷积层的参数和梯度classFilter(object):def__init__(self,width,height,depth):#初始权重self.weights=np.random.uniform(-1e-4,1e-4,(depth,height,width))#初始偏置self.bias=0self.weights_grad=np.zeros(self.weights.shape)self.bias_grad=0def__repr__(self):return'filterweights:\n%s\nbias:\n%s'%(repr(self.weights),repr(self.bias))defget_weights(self):returnself.weightsdefget_bias(self):returnself.biasdefupdate(self,learning_rate):self.weights-=learning_rate*self.weights_gradself.bias-=learning_rate*self.bias_grad4.卷积层的前向传播1).获取卷积区域#获取卷积区域defget_patch(input_array,i,j,filter_width,filter_height,stride):'''从输入数组中获取本次卷积的区域,自动适配输入为2D和3D的情况'''start_i=i*stridestart_j=j*strideifinput_array.ndim==2:input_array_conv=input_array[start_i:start_i+filter_height,start_j:start_j+filter_width]print'input_array_conv:',input_array_convreturninput_array_convelifinput_array.ndim==3:input_array_conv=input_array[:,start_i:start_i+filter_height,start_j:start_j+filter_width]print'input_array_conv:',input_array_convreturninput_array_conv2).进行卷积运算defconv(input_array,kernel_array,output_array,stride,bias):'''计算卷积,自动

1 / 28
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功