利用Theano理解深度学习——Convolutional Neural Networks
来源:互联网 发布:mac应用程序根目录 编辑:程序博客网 时间:2024/06/05 20:15
注:本系列是基于参考文献中的内容,并对其进行整理,注释形成的一系列关于深度学习的基本理论与实践的材料,基本内容与参考文献保持一致,并对这个专题起名为“利用Theano理解深度学习”系列,若文中有任何问题欢迎咨询。本文提供PDF版本,欢迎索取。
“利用Theano理解深度学习”系列分为
- 利用Theano理解深度学习——Logistic Regression
- 利用Theano理解深度学习——Multilayer perceptron
- 利用Theano理解深度学习——Deep Convolutional Network
一、CNN概述
卷积神经网络(Convolutional Neural Networks, CNN)是多层感知机MLP模型的一个变种,主要是受到生物学的启发。从Hubel和Wiesel早期的有关猫的视觉皮层的工作中我们知道猫的视觉皮层包含了一个复杂的细胞排列。这些细胞对小范围的视觉区域敏感,这样的小范围的视觉区域称为一个感受野(receptive field)。这些小的区域平铺开来可以盖满整个视觉区域。这些细胞就像是一个个的局部过滤器,可以对输入空间的信息进行过滤,并且非常适合在自然图像中发觉在空间上存在极强的局部相关性。
两种基本类型的细胞已经被确认:1、简单的细胞。这些细胞在他们的感受野中最大化的响应特定的类似边缘的模式;2、复杂的细胞。这些细胞拥有较大的感受野,而且对于确切的位置模式是局部不变的。
在现实世界中,动物的视觉皮层是最强大的视觉处理系统,似乎模仿其行为也变得很自然。因此,许多受神经系统启发的模型被发现,如NeoCognitron,HMAX和LeNet-5。
二、CNN的特点
卷积神经网络CNN的特点主要有:1、稀疏连接(局部感受),2、共享权值,3、子采样。其中,稀疏连接主要是通过对数据中的局部区域进行建模以发现局部的一些特性;共享权值的目的为了简化计算的过程,使得需要优化的参数变少;子采样的目的是在解决图像中的平移不变性,即所要识别的内容与其在图像中的具体位置无关。
1、稀疏连接(Sparse Connectivity)
CNN通过在邻接层的神经元之间使用局部连接模式来发现输入特征在空间上存在的局部相关性。如下图所示,第
假设第
然而,正如上面所示,堆叠如此多的层导致这些非线性的“过滤器”变得急剧的“全局化”,例如,对更大的像素空间区域产生响应。在
2、共享权值(Shared Weights)
在CNN中,每一个过滤器
在上图中有
每一个单元重复这样的方法。此外,权值共享可以极大的缩减需要学习的参数的数量,这样就可以加速学习的速度。在模型上的这个约束可以使得CNN在视觉问题上可以获得更好的泛化能力。
3、池化(pooling)
在CNN中,另一个比较重要的概念是池化,在这里使用的是最大池化max-pooling,这是非线性下采样的一种形式。max-pooling将输入图像划分成为一系列的不重叠的正方形区域,然后对于每一个子区域,输出其中的最大值。
对于机器视觉而言,max-pooling的策略是非常有效的,主要有两个原因:
- 降低计算量。通过消除非最大值(选择最大值的操作),为上层降低了计算量。
- 解决了平移不变性。max-pooling提供了一种变换不变性的形式。假设在卷积层的后面串联一个max-pooling层,对于输入图像中的每一个像素点的位置,与其邻接的有
8 个方向可以变换,如果max-pooling采用的是2×2 大小的正方形区域,在这8 种可能的结构中,只要有3 种就能产生与卷积层的输出一样的结果,如果在max-pooling层使用3×3 大小的正方形区域,则只需要5 种就能产生于卷积层的输出一样的结果。因为在max-pooling层对位置信息提供了额外的鲁棒性,max-pooling的方法是在中间表示的过程中降低维度的一种极其有效的方法。
三、CNN的详细说明和符号描述
特征映射的过程是通过对整个图像的局部区域重复应用一个函数得到的,即对于一个输入图像进行卷积操作指的是利用一个线性过滤器,加上一个偏置项,之后再利用一个非线性函数。
假设
对于一维信号,有以下的卷积定义:
o[n]=f[n]∗g[n]=∑u=−∞∞f[u]g[n−u]=∑u=−∞∞f[n−u]g[u] 推广到二维的形式:
o[m,n]=f[m,n]∗g[m,n]=∑u=−∞∞∑v=−∞∞f[u,v]g[m−u,n−v]
为了能够对数据进行更丰富的表示,每一个隐含层都由多个特征映射组成,如
上图是一个卷积神经网络中的两层。第
将他们放在一起,
四、LeNet
稀疏连接,卷积操作和最大池化是LeNet型的卷积神经网络模型的关键,然而,对于模型的具体细节会差别很大。下图展示的是LeNet模型:
下层主要是由卷积层和最大池化层交替形成的。上层是全连接的,对应为传统的MLP(即隐含层+Logistic回归)。第一个全连接层的输入是所有特征平铺后组成的,这些特征有下层映射得到。
从实现的角度来看,这就意味着哎下层操作的是是
五、Tips和Tricks
1、超参数的选择
CNN的训练是比较棘手的问题,因为相比较于MLP来说,CNN比标准的MLP有更多的超参数。一个经验的法则是:对于学习率和正则化参数通常选择常数,这在优化CNN的过程中要记住。
2、卷积层的过滤器的个数
当需要确定每一层过滤器的个数的时候,记住计算单个卷积过滤器的激活函数时的代价要远比传统的MLP的代价要高。
假设
然而对于标准的MLP,计算量为:
特征映射的大小会随着深度减少,越靠近输入层,卷积层的过滤器个数越少。
3、卷积层的过滤器的大小
对于卷积层的过滤器的大小,一般取决于具体的数据集。对于数据集MNIST,其大小为
因此,对于卷积层的过滤器的大小的选择一般是根据给定的数据集中图像的大小而决定的。
4、池化层的最大池化的大小
在池化层,池化的目的是利用图像数据固有的特点,在计算的中间过程中降低数据的维度,一般比较常用的最大池化的大小为
六、Theano实现CNN的代码解析
1、导入数据集
导入数据集的过程与Logistic回归中使用的一致。前面已经比较细致的描述 。代码如下:
def load_data(dataset):'''导入数据:type dataset: string:param dataset: MNIST数据集''' #1、处理文件目录 data_dir, data_file = os.path.split(dataset)#把路径分割成dirname和basename,返回一个元组 if data_dir == "" and not os.path.isfile(dataset): new_path = os.path.join( os.path.split(__file__)[0],#__file__表示的是当前的路径 ".", "data", dataset ) if os.path.isfile(new_path) or data_file == 'mnist.pkl.gz': dataset = new_path#文件所在的目录 if (not os.path.isfile(dataset)) and data_file == 'mnist.pkl.gz': import urllib origin = ( 'http://www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz' ) print 'Downloading data from %s' % origin urllib.urlretrieve(origin, dataset) print '... loading data' #2、打开文件 f = gzip.open(dataset, 'rb')# 打开一个gzip已经压缩好的gzip格式的文件,并返回一个文件对象:file object. train_set, valid_set, test_set = cPickle.load(f)#载入本地的文件 f.close() '''训练集train_set,验证集valid_set和测试集test_set的格式:元组(input, target) 其中,input是一个矩阵(numpy.ndarray),每一行代表一个样本;target是一个向量(numpy.ndarray),大小与input的行数对应 ''' def shared_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) return shared_x, T.cast(shared_y, 'int32')#将shared_y转换成整型 #3、将数据处理成需要的形式 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) #4、返回数据集 rval = [(train_set_x, train_set_y), (valid_set_x, valid_set_y), (test_set_x, test_set_y)] return rval
2、建立模型
建立模型阶段主要是定义一个卷积+池化的过程,具体代码如下:
class LeNetConvPoolLayer(object): def __init__(self, rng, input, filter_shape, image_shape, poolsize=(2, 2)): """ :type rng: numpy.random.RandomState :param rng:用于随机数生成权重 :type input: theano.tensor.dtensor4 :param input:卷积+池化层的输入,是一个4维的张量 :type filter_shape: tuple or list of length 4 :param filter_shape: 卷积层过滤器的大小(number of filters, num input feature maps, filter height, filter width) :type image_shape: tuple or list of length 4 :param image_shape: 图像的大小(batch size, num input feature maps, image height, image width) :type poolsize: tuple or list of length 2 :param poolsize: 池化的参数(#rows, #cols) """ assert image_shape[1] == filter_shape[1] self.input = input #fan_in和fan_out主要用于初始化权重参数 #卷积层的输入的大小 "num input feature maps * filter height * filter width" fan_in = numpy.prod(filter_shape[1:]) #池化层的输出的大小 "num output feature maps * filter height * filter width" /pooling size fan_out = (filter_shape[0] * numpy.prod(filter_shape[2:]) / numpy.prod(poolsize)) #初始化权重 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 ) #初始化偏置 b_values = numpy.zeros((filter_shape[0],), dtype=theano.config.floatX) self.b = theano.shared(value=b_values, borrow=True) #定义卷积层 conv_out = conv.conv2d( input=input,#卷积层的输入 filters=self.W,#卷积层使用的权重 filter_shape=filter_shape,#每个过滤器的大小 image_shape=image_shape ) #定义下采样层 pooled_out = downsample.max_pool_2d( input=conv_out,#池化层的输出 ds=poolsize,#最大池化的大小 ignore_border=True ) #加上偏置的过程,最终计算非线性映射 self.output = T.tanh(pooled_out + self.b.dimshuffle('x', 0, 'x', 'x')) #模型中的参数,权重和偏置 self.params = [self.W, self.b] # keep track of model input self.input = input
在代码中,注意在卷积层的输出阶段只是将权重乘以输入,然后计算池化,在最终的结果上加上偏置,并进行非线性函数的映射,即利用tanh函数对其进行非线性的映射,这样的操作,主要是因为可以省去很多的计算。
3、训练模型
在模型的训练阶段,主要是将数据通过两个卷积+池化层,最终用过一个MLP计算其分类,并通过梯度下降法对其模型中的参数进行调整,具体的代码如下:
# 三、训练模型##############################################################################print '... training'# early-stopping参数patience = 10000patience_increase = 2improvement_threshold = 0.995validation_frequency = min(n_train_batches, patience / 2)best_validation_loss = numpy.infbest_iter = 0test_score = 0.start_time = timeit.default_timer()epoch = 0done_looping = False# 循环训练while (epoch < n_epochs) and (not done_looping): epoch = epoch + 1 # 针对每一批样本 for minibatch_index in xrange(n_train_batches): iter = (epoch - 1) * n_train_batches + minibatch_index if iter % 100 == 0: print 'training @ iter = ', iter # 计算训练的误差 cost_ij = train_model(minibatch_index) if (iter + 1) % validation_frequency == 0: # 在验证集上计算误差 validation_losses = [validate_model(i) for i in xrange(n_valid_batches)] this_validation_loss = numpy.mean(validation_losses) print('epoch %i, minibatch %i/%i, validation error %f %%' % (epoch, minibatch_index + 1, n_train_batches, this_validation_loss * 100.)) # 记录最优的模型 if this_validation_loss < best_validation_loss: #improve patience if loss improvement is good enough if this_validation_loss < best_validation_loss * \ improvement_threshold: patience = max(patience, iter * patience_increase) # save best validation score and iteration number best_validation_loss = this_validation_loss best_iter = iter test_losses = [ test_model(i) for i in xrange(n_test_batches) ] test_score = numpy.mean(test_losses) print((' epoch %i, minibatch %i/%i, test error of ' 'best model %f %%') % (epoch, minibatch_index + 1, n_train_batches, test_score * 100.)) if patience <= iter: done_looping = True breakend_time = timeit.default_timer()print('Optimization complete.')print('Best validation score of %f %% obtained at iteration %i, ' 'with test performance %f %%' % (best_validation_loss * 100., best_iter + 1, test_score * 100.))print >> sys.stderr, ('The code for file ' + os.path.split(__file__)[1] + ' ran for %.2fm' % ((end_time - start_time) / 60.))
七、实验的结果
部分实验的结果如下:
若需要PDF版本,请关注我的新浪博客@赵_志_勇,私信你的邮箱地址给我。
参考文献
Convolutional Neural Networks (LeNet)http://www.deeplearning.net/tutorial/lenet.html#tips-and-tricks
- 利用Theano理解深度学习——Convolutional Neural Networks
- theano学习-Convolutional Neural Networks (LeNet)
- 【深度学习】卷积神经网络(Convolutional Neural Networks)
- 深度学习(3):Convolutional Neural Networks
- 深度卷积神经网络——Deep Convolutional Neural Networks
- Convolutional Neural Networks学习
- 深度学习论文理解3:Flexible, high performance convolutional neural networks for image classification
- 深度学习研究理解9:Convolutional Neural Networks at Constrained Time Cost
- Deep Learning(深度学习)Convolutional Neural Networks卷积神经网络
- Deep Learning(深度学习)Convolutional Neural Networks卷积神经网络
- 【深度学习】卷积层提速Factorized Convolutional Neural Networks
- 利用Theano理解深度学习——Logistic Regression
- 利用Theano理解深度学习——Multilayer Perceptron
- 利用Theano理解深度学习——Auto Encoder
- 利用Theano理解深度学习——Logistic Regression
- 利用Theano理解深度学习——Multilayer Perceptron
- 利用Theano理解深度学习——Auto Encoder
- Convolutional Neural Networks—overview(二)
- RESB 0x7dfe-$ 报错
- VirtualBox+Centos6.3加载新的硬盘分区及其建立文件系统并挂载目录
- 解决:ScrollView中嵌套ListView无法正常显示
- 微信支付的使用(微信支付SDK)
- Blender快捷键
- 利用Theano理解深度学习——Convolutional Neural Networks
- 黑马程序员——Java基础---面向对象(二)
- Ubuntu设置用户与用户组
- exportfs命令
- HDU 2795 Billboard【线段树】单点查找更新
- 设计模式之模板模式和建造者模式
- ARC MRC混编
- JAVA_SE基础——54.异常
- 杂七杂八