卷积神经网络全面解析之代码详解.docx

上传人:b****3 文档编号:5705386 上传时间:2023-05-09 格式:DOCX 页数:21 大小:177.95KB
下载 相关 举报
卷积神经网络全面解析之代码详解.docx_第1页
第1页 / 共21页
卷积神经网络全面解析之代码详解.docx_第2页
第2页 / 共21页
卷积神经网络全面解析之代码详解.docx_第3页
第3页 / 共21页
卷积神经网络全面解析之代码详解.docx_第4页
第4页 / 共21页
卷积神经网络全面解析之代码详解.docx_第5页
第5页 / 共21页
卷积神经网络全面解析之代码详解.docx_第6页
第6页 / 共21页
卷积神经网络全面解析之代码详解.docx_第7页
第7页 / 共21页
卷积神经网络全面解析之代码详解.docx_第8页
第8页 / 共21页
卷积神经网络全面解析之代码详解.docx_第9页
第9页 / 共21页
卷积神经网络全面解析之代码详解.docx_第10页
第10页 / 共21页
卷积神经网络全面解析之代码详解.docx_第11页
第11页 / 共21页
卷积神经网络全面解析之代码详解.docx_第12页
第12页 / 共21页
卷积神经网络全面解析之代码详解.docx_第13页
第13页 / 共21页
卷积神经网络全面解析之代码详解.docx_第14页
第14页 / 共21页
卷积神经网络全面解析之代码详解.docx_第15页
第15页 / 共21页
卷积神经网络全面解析之代码详解.docx_第16页
第16页 / 共21页
卷积神经网络全面解析之代码详解.docx_第17页
第17页 / 共21页
卷积神经网络全面解析之代码详解.docx_第18页
第18页 / 共21页
卷积神经网络全面解析之代码详解.docx_第19页
第19页 / 共21页
卷积神经网络全面解析之代码详解.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

卷积神经网络全面解析之代码详解.docx

《卷积神经网络全面解析之代码详解.docx》由会员分享,可在线阅读,更多相关《卷积神经网络全面解析之代码详解.docx(21页珍藏版)》请在冰点文库上搜索。

卷积神经网络全面解析之代码详解.docx

卷积神经网络全面解析之代码详解

卷积神经网络全面解析之代码详解

卷积神经网络全面解析之代码详解

本文介绍多层感知机算法,特别是详细解读其代码实现,基于pythontheano,代码来自:

ConvolutionalNeuralNetworks(LeNet)。

一、CNN卷积神经网络原理简介

要讲明白卷积神经网络,估计得长篇大论,网上有很多博文已经写得很好了,所以本文就不重复了,如果你了解CNN,那可以往下看,本文主要是详细地解读CNN的实现代码。

CNN的最大特点就是稀疏连接(局部感受)和权值共享,如下面两图所示,左为稀疏连接,右为权值共享。

稀疏连接和权值共享可以减少所要训练的参数,减少计算复杂度。

    

至于CNN的结构,以经典的LeNet5来说明:

这个图真是无处不在,一谈CNN,必说LeNet5,这图来自于这篇论文:

Gradient-BasedLearningAppliedtoDocumentRecognition,论文很长,第7页那里开始讲LeNet5这个结构,建议看看那部分。

我这里简单说一下,LeNet5这张图从左到右,先是input,这是输入层,即输入的图片。

input-layer到C1这部分就是一个卷积层(convolution运算),C1到S2是一个子采样层(pooling运算),关于卷积和子采样的具体过程可以参考下图:

然后,S2到C3又是卷积,C3到S4又是子采样,可以发现,卷积和子采样都是成对出现的,卷积后面一般跟着子采样。

S4到C5之间是全连接的,这就相当于一个MLP的隐含层了(如果你不清楚MLP,参考《DeepLearningtutorial(3)MLP多层感知机原理简介+代码详解》)。

C5到F6同样是全连接,也是相当于一个MLP的隐含层。

最后从F6到输出output,其实就是一个分类器,这一层就叫分类层。

ok,CNN的基本结构大概就是这样,由输入、卷积层、子采样层、全连接层、分类层、输出这些基本“构件”组成,一般根据具体的应用或者问题,去确定要多少卷积层和子采样层、采用什么分类器。

当确定好了结构以后,如何求解层与层之间的连接参数?

一般采用向前传播(FP)+向后传播(BP)的方法来训练。

具体可参考上面给出的链接。

二、CNN卷积神经网络代码详细解读(基于python+theano)

代码来自于深度学习教程:

ConvolutionalNeuralNetworks(LeNet),这个代码实现的是一个简化了的LeNet5,具体如下:

∙没有实现location-specificgainandbiasparameters

∙用的是maxpooling,而不是average_pooling

∙分类器用的是softmax,LeNet5用的是rbf

∙LeNet5第二层并不是全连接的,本程序实现的是全连接

另外,代码里将卷积层和子采用层合在一起,定义为“LeNetConvPoolLayer“(卷积采样层),这好理解,因为它们总是成对出现。

但是有个地方需要注意,代码中将卷积后的输出直接作为子采样层的输入,而没有加偏置b再通过sigmoid函数进行映射,即没有了下图中fx后面的bx以及sigmoid映射,也即直接由fx得到Cx。

最后,代码中第一个卷积层用的卷积核有20个,第二个卷积层用50个,而不是上面那张LeNet5图中所示的6个和16个。

了解了这些,下面看代码:

(1)导入必要的模块

importcPickle

importgzip

importos

importsys

importtime

importnumpy

importtheano

importtheano.tensorasT

fromtheano.tensor.signalimportdownsample

fromtheano.tensor.nnetimportconv

(2)定义CNN的基本"构件"

CNN的基本构件包括卷积采样层、隐含层、分类器,如下

∙定义LeNetConvPoolLayer(卷积+采样层)

见代码注释:

"""

卷积+下采样合成一个层LeNetConvPoolLayer

rng:

随机数生成器,用于初始化W

input:

4维的向量,theano.tensor.dtensor4

filter_shape:

(numberoffilters,numinputfeaturemaps,filterheight,filterwidth)

image_shape:

(batchsize,numinputfeaturemaps,imageheight,imagewidth)

poolsize:

(#rows,#cols)

"""

classLeNetConvPoolLayer(object):

def__init__(self,rng,input,filter_shape,image_shape,poolsize=(2,2)):

#assertcondition,condition为True,则继续往下执行,condition为False,中断程序

#image_shape[1]和filter_shape[1]都是numinputfeaturemaps,它们必须是一样的。

assertimage_shape[1]==filter_shape[1]

self.input=input

#每个隐层神经元(即像素)与上一层的连接数为numinputfeaturemaps*filterheight*filterwidth。

#可以用numpy.prod(filter_shape[1:

])来求得

fan_in=numpy.prod(filter_shape[1:

])

#lowerlayer上每个神经元获得的梯度来自于:

"numoutputfeaturemaps*filterheight*filterwidth"/poolingsize

fan_out=(filter_shape[0]*numpy.prod(filter_shape[2:

])/

numpy.prod(poolsize))

#以上求得fan_in、fan_out,将它们代入公式,以此来随机初始化W,W就是线性卷积核

W_bound=numpy.sqrt(6./(fan_in+fan_out))

self.W=theano.shared(

numpy.asarray(

rng.uniform(low=-W_bound,high=W_bound,size=filter_shape),

dtype=theano.config.floatX

),

borrow=True

#thebiasisa1Dtensor--onebiasperoutputfeaturemap

#偏置b是一维向量,每个输出图的特征图都对应一个偏置,

#而输出的特征图的个数由filter个数决定,因此用filter_shape[0]即numberoffilters来初始化

b_values=numpy.zeros((filter_shape[0],),dtype=theano.config.floatX)

self.b=theano.shared(value=b_values,borrow=True)

#将输入图像与filter卷积,conv.conv2d函数

#卷积完没有加b再通过sigmoid,这里是一处简化。

conv_out=conv.conv2d(

input=input,

filters=self.W,

filter_shape=filter_shape,

image_shape=image_shape

#maxpooling,最大子采样过程

pooled_out=downsample.max_pool_2d(

input=conv_out,

ds=poolsize,

ignore_border=True

#加偏置,再通过tanh映射,得到卷积+子采样层的最终输出

#因为b是一维向量,这里用维度转换函数dimshuffle将其reshape。

比如b是(10,),

#则b.dimshuffle('x',0,'x','x'))将其reshape为(1,10,1,1)

self.output=T.tanh(pooled_out+self.b.dimshuffle('x',0,'x','x'))

#卷积+采样层的参数

self.params=[self.W,self.b]

∙定义隐含层HiddenLayer

这个跟上一篇文章《 DeepLearningtutorial(3)MLP多层感知机原理简介+代码详解》中的HiddenLayer是一致的,直接拿过来:

"""

注释:

这是定义隐藏层的类,首先明确:

隐藏层的输入即input,输出即隐藏层的神经元个数。

输入层与隐藏层是全连接的。

假设输入是n_in维的向量(也可以说时n_in个神经元),隐藏层有n_out个神经元,则因为是全连接,

一共有n_in*n_out个权重,故W大小时(n_in,n_out),n_in行n_out列,每一列对应隐藏层的每一个神经元的连接权重。

b是偏置,隐藏层有n_out个神经元,故b时n_out维向量。

rng即随机数生成器,numpy.random.RandomState,用于初始化W。

input训练模型所用到的所有输入,并不是MLP的输入层,MLP的输入层的神经元个数时n_in,而这里的参数input大小是(n_example,n_in),每一行一个样本,即每一行作为MLP的输入层。

activation:

激活函数,这里定义为函数tanh

"""

classHiddenLayer(object):

def__init__(self,rng,input,n_in,n_out,W=None,b=None,

activation=T.tanh):

self.input=input#类HiddenLayer的input即所传递进来的input

"""

注释:

代码要兼容GPU,则必须使用dtype=theano.config.floatX,并且定义为theano.shared

另外,W的初始化有个规则:

如果使用tanh函数,则在-sqrt(6./(n_in+n_hidden))到sqrt(6./(n_in+n_hidden))之间均匀

抽取数值来初始化W,若时sigmoid函数,则以上再乘4倍。

"""

#如果W未初始化,则根据上述方法初始化。

#加入这个判断的原因是:

有时候我们可以用训练好的参数来初始化W,见我的上一篇文章。

ifWisNone:

W_values=numpy.asarray(

rng.uniform(

low=-numpy.sqrt(6./(n_in+n_out)),

high=numpy.sqrt(6./(n_in+n_out)),

size=(n_in,n_out)

),

dtype=theano.config.floatX

ifactivation==theano.tensor.nnet.sigmoid:

W_values*=4

W=theano.shared(value=W_values,name='W',borrow=True)

ifbisNone:

b_values=numpy.zeros((n_out,),dtype=theano.config.floatX)

b=theano.shared(value=b_values,name='b',borrow=True)

#用上面定义的W、b来初始化类HiddenLayer的W、b

self.W=W

self.b=b

#隐含层的输出

lin_output=T.dot(input,self.W)+self.b

self.output=(

lin_outputifactivationisNone

elseactivation(lin_output)

#隐含层的参数

self.params=[self.W,self.b]

∙定义分类器(Softmax回归)

采用Softmax,这跟《DeepLearningtutorial

(1)Softmax回归原理简介+代码详解》中的LogisticRegression是一样的,直接拿过来:

"""

定义分类层LogisticRegression,也即Softmax回归

在deeplearningtutorial中,直接将LogisticRegression视为Softmax,

而我们所认识的二类别的逻辑回归就是当n_out=2时的LogisticRegression

"""

#参数说明:

#input,大小就是(n_example,n_in),其中n_example是一个batch的大小,

#因为我们训练时用的是MinibatchSGD,因此input这样定义

#n_in,即上一层(隐含层)的输出

#n_out,输出的类别数

classLogisticRegression(object):

def__init__(self,input,n_in,n_out):

#W大小是n_in行n_out列,b为n_out维向量。

即:

每个输出对应W的一列以及b的一个元素。

self.W=theano.shared(

value=numpy.zeros(

(n_in,n_out),

dtype=theano.config.floatX

),

name='W',

borrow=True

self.b=theano.shared(

value=numpy.zeros(

(n_out,),

dtype=theano.config.floatX

),

name='b',

borrow=True

#input是(n_example,n_in),W是(n_in,n_out),点乘得到(n_example,n_out),加上偏置b,

#再作为T.nnet.softmax的输入,得到p_y_given_x

#故p_y_given_x每一行代表每一个样本被估计为各类别的概率

#PS:

b是n_out维向量,与(n_example,n_out)矩阵相加,内部其实是先复制n_example个b,

#然后(n_example,n_out)矩阵的每一行都加b

self.p_y_given_x=T.nnet.softmax(T.dot(input,self.W)+self.b)

#argmax返回最大值下标,因为本例数据集是MNIST,下标刚好就是类别。

axis=1表示按行操作。

self.y_pred=T.argmax(self.p_y_given_x,axis=1)

#params,LogisticRegression的参数

self.params=[self.W,self.b]

 

到这里,CNN的基本”构件“都有了,下面要用这些”构件“组装成LeNet5(当然,是简化的,上面已经说了),具体来说,就是组装成:

LeNet5=input+LeNetConvPoolLayer_1+LeNetConvPoolLayer_2+HiddenLayer+LogisticRegression+output。

然后将其应用于MNIST数据集,用BP算法去解这个模型,得到最优的参数。

 

(3)加载MNIST数据集(mnist.pkl.gz)

"""

加载MNIST数据集load_data()

"""

defload_data(dataset):

#dataset是数据集的路径,程序首先检测该路径下有没有MNIST数据集,没有的话就下载MNIST数据集

#这一部分就不解释了,与softmax回归算法无关。

data_dir,data_file=os.path.split(dataset)

ifdata_dir==""andnotos.path.isfile(dataset):

#Checkifdatasetisinthedatadirectory.

new_path=os.path.join(

os.path.split(__file__)[0],

"..",

"data",

dataset

ifos.path.isfile(new_path)ordata_file=='mnist.pkl.gz':

dataset=new_path

if(notos.path.isfile(dataset))anddata_file=='mnist.pkl.gz':

importurllib

origin=(

'http:

//www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz'

print'Downloadingdatafrom%s'%origin

urllib.urlretrieve(origin,dataset)

print'...loadingdata'

#以上是检测并下载数据集mnist.pkl.gz,不是本文重点。

下面才是load_data的开始

#从"mnist.pkl.gz"里加载train_set,valid_set,test_set,它们都是包括label的

#主要用到python里的gzip.open()函数,以及cPickle.load()。

#‘rb’表示以二进制可读的方式打开文件

f=gzip.open(dataset,'rb')

train_set,valid_set,test_set=cPickle.load(f)

f.close()

#将数据设置成sharedvariables,主要时为了GPU加速,只有sharedvariables才能存到GPUmemory中

#GPU里数据类型只能是float。

而data_y是类别,所以最后又转换为int返回

defshared_dataset(data_xy,borrow=True):

data_x,data_y=data_xy

shared_x=theano.shared(numpy.asarray(data_x,

dtype=theano.config.floatX),

borrow=borrow)

shared_y=theano.shared(numpy.asarray(data_y,

dtype=theano.config.floatX),

borrow=borrow)

returnshared_x,T.cast(shared_y,'int32')

 

test_set_x,test_set_y=shared_dataset(test_set)

valid_set_x,valid_set_y=shared_dataset(valid_set)

train_set_x,train_set_y=shared_dataset(train_set)

rval=[(train_set_x,train_set_y),(valid_set_x,valid_set_y),

(test_set_x,test_set_y)]

returnrval

(4)实现LeNet5并测试

"""

实现LeNet5

LeNet5有两个卷积层,第一个卷积层有20个卷积核,第二个卷积层有50个卷积核

"""

defevaluate_lenet5(learning_rate=0.1,n_epochs=200,

dataset='mnist.pkl.gz',

nkerns=[20,50],batch_size=500):

"""

learning_rate:

学习速率,随机梯度前的系数。

n_epochs训练步数,每一步都会遍历所有batch,即所有样本

batch_size,这里设置为500,即每遍历完500个样本,才计算梯度并更新参数

nkerns=[20,50],每一个LeNetConvPoolLayer卷积核的个数,第一个LeNetConvPoolLayer有

20个卷积核,第二个有50个

"""

rng=numpy.random.RandomState(23455)

#加载数据

datasets=load_data(dataset)

train_set_x,train_set_y=datasets[0]

valid_set_x,valid_set_y=datasets[1]

test_set_x,test_set_y=datasets[2]

#计算batch的个数

n_train_batches=train_set_x.get_value(borrow=True).shape[0]

n_valid_batches=valid_set_x.get_value(borrow=True).shape[0]

n_test_batches=test_set_x.get_value(borrow=True).shape[0]

n_train_batches/=batch_size

n_valid_batches/=batch_size

n_test_batches/=batch_size

#定义几个变量,index表示batch下标,x表示输入的训练数据,y对应其标签

index=T.lscalar()

x=T.matrix('x')

y=T.ivector('y')

######################

#BUILDACTUALMODEL#

######################

print'...buildingthemodel'

 

#我们加载进来的batch大小的数据是(batch_size,28*28),但是LeNetConvPoolLayer的输入是四维的,所以要reshape

layer0_input=x.reshape((batch_size,1,28,28))

#layer0即第一个LeNetConvPoolLayer层

#输入的单张图片(28,28),经过conv得到(28-5+1,28-5+1)=(24,24),

#经过maxpooling得到(24/2,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2