先给出原文连接
还记得我们之前把mnist数据集的输入图片(28像素*28像素)压缩成了一个列表扔进了dnn当中,但我们写字的时候总不会按每行的像素点去写。因此我们之前的做法已经破坏了输入图片的一些特征,导致准确率并不算高(但是也不低了)。对图片的特征提取一直以来都是个难题,直到感受野的提出。
在CNN当中我们不再对图片直接进行简单粗暴的降维处理,CNN接收的输入端是三维的,第一维和第二维对应图片的长和宽。第三维为3对应色光三原色(红,绿,蓝)。我们的CNN包括了很多的模块,来执行3个操作:
1.卷积
卷积就是让我们从输入图片(特征),通过滤波器(filters)进行卷积操作来提取新的特征。这里红色的就是滤波器(fliters)。
图片来自谷歌官方教程:
在卷积操作中我们需要定义几个参数。
第一个则是滤波器的形状以及初始随机数我们在这里一般不会再用random_normal()来生成正态分布的随机变量,一般是使用tf.truncated_normal()来生成去除极值的正态分布变量。
第二个则是步长(strides) 这里的步长很明显就是 [1,1]也就是没进行一次卷积横向移动一个像素,当横向没法移动时初始横向的位置纵向移动一个像素。
第三个则是padding,也就是我们卷积的方式,有SAME和VALID两种方法,图中就是使用的valid方法,该方法不会在原图片上进行扩充(用0扩充). same则会用0扩充原图像,让输出的shape和输入的shape保持一致。这里valid方法显然计算量会小的多,然而对图片的边缘就没有充分的进行卷积,可能无法很好的处理边缘的特征。一般来说推荐same方法,因为边缘的信息可能原图片的边缘没有什么信息,但是多卷几次边缘可能就有丰富的特征了。
滤波器的大小一般为(3x3)或(5x5)。这里我们假设左边图片为输入的图片,右边的图片为滤波器
图片来自谷歌官方教程:
当滤波器对输入图片进行卷积的操作时,我们使用的并不是矩阵乘法,而是元素和元素之间相乘:
我们这里来自己写一下:
import tensorflow as tf
import numpy as np
input = np.array([3, 5, 2, 8, 1, 9, 7, 5, 4, 3, 2, 0, 6, 1, 6, 6, 3, 7, 9, 2, 1, 4, 9, 5, 1]).astype('float32')
input_ = tf.reshape(input, [-1, 5, 5, 1])
fliter = tf.Variable(tf.constant([1, 0, 0, 1, 1, 0, 0, 0, 1], shape=[3, 3, 1, 1], dtype=tf.float32))
conv1 = tf.nn.conv2d(input_, fliter, strides=[1, 1, 1, 1], padding='VALID')
sess = tf.Session()
sess.run(tf.global_variables_initializer())
print(sess.run(conv1))
[[[[25.]
[18.]
[17.]]
[[18.]
[22.]
[14.]]
[[20.]
[15.]
[23.]]]]
滤波器能够提取输入图片的特征,随着滤波器的数量增加,我们所提取的特征也会越来越多,但是消耗的资源(计算量和时间)也越来越多,并且每添加一个滤波器,其提取的特征就会比之前的滤波器少(提取的特征会逐渐衰减)。因此我们在选择滤波器的数量上时尽量越少越好。(当然conv2d后我们还会添加一个biases)
2RELU
我们同样也会在卷积后把特征非线性化,这里使用的就是relu至于为什么用relu,relu可以有效防止梯度爆炸和梯度消失。
如果我们的网络层数很多,卷积在反向传播是最靠后的位置,很容易就会出现梯度爆炸和梯度消失。
3.池化(pooling)
卷积会让我们的模型过于庞大,我们希望压缩模型,同时仍然可以保留关键的特征。我们常用的方法成为 最大池化(max pooling)
池化与卷积的过程类似,我们仍就需要定义 滤波器(fliter)和步长(strides)。
最大池化的滤波器我们一般定义的shape为2*2。
步长我们则不会对同一个特征用滤波器多次扫过。
这里给出官方教程的图片更清楚一些:
左边作为输入,右边是经过最大池化后的结果。这里同样padding有SAME 和VALID。和卷积类似。其实很好理解,但是语言表述起来有点困难。不妨自己动手试试。
在池化后,我们往往接入另一个卷积层或者将结果输出到全连接层,接到全连接层我们就可以通过softmax来进行图片分类了。
图片来自官方教程:
图上显示了 2个卷积模块(conv2d+relu+maxpool整体算1个),然后接入了2个全连接层(黄的和绿的)来进行图片分类。
卷积模块数和全连接层数并不是固定的,这个需要我们自己权衡。
最后请做一下,官方关于这节课的练习。
原文的意思就是,输入图片是4*4的,滤波器是3*3的, 步长为1,没有添加padding(padding='VALID')问输出的图片形状是几*几的?