深度学习三人行-卷积神经网络实战进阶

上一期,我们一起学习了深度学习中卷积神经网络的通俗原理,

接下来我们一起学习下关于CNN的代码实现,内存计算和池化层等相关知识,我们多多交流,共同进步。本期主要内容如下:

CNN实现(TensorFlow)

CNN之内存计算

CNN之池化层

小结

一. CNN实现(TensorFlow)

在TensorFlow中,每一个图像都有一个3D的tensor,shape为[height, width, channels]。每一个mini-batch是以一个shape为[min-batch size, height, width, channels]的4Dtensor来表示的。卷积层的权重是以shape为[f_h, f_w, f_n, f_n'],其中偏置项是以1D tensor[f_n]表示。接下来,我们一起看下,在TensorFlow中是怎么实现的:首先,代码中用sklearn中的load_sample_images()来加载图片。然后手工创建了两个7x7的卷积核,一个为水平直线,一个为竖直直线。接着让图像通过一个卷积层conv2d()(边界扩充0,stride = 2),最后画出一个特征图。如下:

其中X是一个mini-batch(4D的tensor),filters也是一个4D的tensor,stride是一个有4个元素的1D tensor其中中间连个值为竖直和水平的stride,第一个元素和第四个元素必须是1,这个是备用的,以后可能会用在batch和channel上。padding必须设置为“VALID”或“SAME”,当设为“VALID”的时候,卷积层不进行边界扩充,但是可能会根据stride来忽略图像下面的某些行或右侧的某些列。如果设置为“SAME”,卷积层会进行对边界扩充0.这种情况下,输出神经元个数等于输入神经元个数除以stride,在下面的例子中输出层神经元为3,其中stride为5.如下:

所以,卷积层有一些参数要设置,比如:卷积核的个数,卷积核的高,卷积核的宽,以及stride,padding的类型。有时候,可以通过交叉验证来找最优的参数组合,但是这样往往是比较耗时的。后面我们会介绍一些通用的网络结构,可能会给我们一些启发,在实践中什么样的参数组合通常会得出最优的性能。

二. CNN之内存计算

卷积神经网络的一个问题就是需要大量的内存来处理数据,特别是在training阶段,因为反向传输需要保留前向传输的数据。举个例子,比方一个卷积层,其中卷积核为5x5,输出200个特征图,每一个特征图大小为150x100, stride为1,padding为"SAME",如果输入为一个150x100的RGB(3通道)图像的话,那么权重参数的个数为:

(5x5x3+1)x200 = 15200

其中+1为考虑到偏置项,相对来说,参数比全连接层要少。然而,每一个特征图包括150x100个神经元,每一个神经元需要计算5x5x3=75个权重,那么总共就有225million个浮点型数据相乘,虽然没有比全连接更糟,但是仍然是一个巨大的计算。如果特征图用32位float表示的话,那么一个卷积层将会占用:

200x150x100x32 = 96million bits

约11.4M内存,然而这只是一个样本,如果每个batch有100张图的话,那么单单这一层卷积层就要耗费超过一个G的内存。

在预测的时候,当一个卷积层计算的时候,就会将上一层所占用的内存释放掉,所以仅仅需要两个连续卷积层所占的内存即可。但是在计算的时候,每一次向前传输的数据都要为向后传输而保留,所以所需要的内存至少为全部层所占用的内存总和。

如果在training的时候,由于内存的问题导致crash,那么可以通过减少mini-batch的size来进行降低内存占有。当然也可以通过stride降维,或者减少一些层,甚至可以用16bit的float代替32bit的float或者多个设备来跑。

接下来,我们一起看一下CNN的另一个重要的构成:池化层。

三. CNN之池化层

一旦我们理解了卷积层的工作原理之后,池化层就相对来说比较简单了,池化层的目标就是为了降低计算负载,内存使用,参数数量,也可以降低过拟合的风险,而对输入进行的下采样。原理和卷积层一样,池化层的每一个神经元和上一层中有限区域(一个矩形的感受野)的神经元相连接。我们也必须定义感受野的size, stride,以及padding类型。然而不同的是,池化层的神经元没有权重,它的输出仅仅是输入区域的最大值或均值,下图显示了一个最大值的池化层,也是最常用的池化层,这个例子中用了一个2x2的池化核,stride=2,没有padding,也就是说,仅仅输出上一层中池化核位置的最大值到下一层。其他的输入都丢掉。

一般池化层在每一个输入通道上单独工作,所以经过池化层后,输入输出通道数不变。

在TensorFlow中实现池化还是蛮简单的,下面的代码创建一个2x2的池化核的池化层,stride为2,没有padding,然后应用到所有图像上。

上面参数ksize包括了池化核的4D参数[batch size, height, width, channels].TensorFlow目前暂时不支持跨样本池化,所以第一个数据必须是1,由于目前也不支持跨通道池化,所以最后一个参数也得是1.当然,想创建一个均值的池化层的话,仅仅将上面的max_pool替换为avg_pool即可。

四. 小结

今天,我们从TensorFlow上实现卷积层,以及卷积层的内存计算和池化层的相关原理知识等方面,更进一步的了解了CNN的知识。在学习的路上,我们共同进步,多谢有你。

(如需更好的了解相关知识,欢迎加入智能算法社区,在“智能算法”公众号发送“社区”,即可加入算法微信群和QQ群)

本文代码公众号回复关键字:CNN9

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181122B0B32X00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券