一、卷积神经网络结构:
卷积层
conv作用:
卷积层是一个n*n*m的权重矩阵,下图一目了然:
channel:一个卷积层的核数,对rgb图像channel = 3
kernel size:卷积核的维度
步长(step size):卷积核每次移动的像素点个数
边距(padding size):图像边缘补齐的像素点个数,目的是增加卷积核扫描到原始图像边缘的几率,理论上padding size超过卷积核的dimension--n之后将失去意义(个人理解:不会再增加扫描到原始边缘像素的概率)
池化层
作用:1、减少参数 2、提取特征
卷积之后的结果代表了这个卷积窗口的特征,但是这些特征有冗余,pooling的目的就是去除冗余信息,同时pooling之后也丢失了局部信息。
MaxPooling Over Time
CNN模型中最常见的一种下采样操作。意思是对于某个Conv Filter抽取到若干特征值,只取其中得分最大的那个值作为Pooling层保留值,其它特征值全部抛弃,值最大代表只保留这些特征中最强的,而抛弃其它弱的此类特征。
K-Max Pooling
K-MaxPooling的意思是:原先的Max Pooling Over Time从Convolution层一系列特征值中只取最强的那个值,那么我们思路可以扩展一下,K-Max Pooling可以取所有特征值中得分在Top –K的值,并保留这些特征值原始的先后顺序(图3是2-max Pooling的示意图),就是说通过多保留一些特征信息供后续阶段使用。
Chunk-Max Pooling
Chunk-MaxPooling的思想是:把某个Filter对应的Convolution层的所有特征向量进行分段,切割成若干段后,在每个分段里面各自取得一个最大特征值,比如将某个Filter的特征向量切成3个Chunk,那么就在每个Chunk里面取一个最大值,于是获得3个特征值。(如图4所示,不同颜色代表不同分段)
Average pooling 和 Max-pooling
Average pooling在历史上用的更多, 但是由于max-pooling通常效果更好, 所以现在max-pooling更常使用. Max-pooling和average pooling都对数据进行下采样, 除此之外, max-pooling还提供了非线性, 这是max-pooling效果更好的一个重要原因.Average pooling并非一无是处, 现在average pooling更多的是用在global average pooling中. 这最早由Network in network提出, 目前在ResNet, GoogLeNet等主流网络中都有使用.
分类问题上max-pooling相当于特征选择,选出有利于分类辨识度高的特征去分类。
----来源 知乎
参考文章:如何理解卷积与pooling-----如何理解 卷积 和pooling - 白婷 - 博客园
卷积层和池化层的作用:
1、不变性:平移(translation)旋转(rotation)尺度(scale)
2、保留主要特征同时减少参数。减少计算量,防止过拟合
http://www.360doc.com/content/17/1127/11/42392246_707519156.shtml
二、Tensorflow中CNN的创建:
卷积层
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
# 除去name参数用以指定该操作的name,与方法有关的一共五个参数:
# # 第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有 [batch, in_height, in_width, in_channels] 这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
# # 第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有 [filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是 [卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
# # 第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4
# # 第四个参数padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式(后面会介绍)
# # 第五个参数:use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
# # 结果返回一个Tensor,这个输出,就是我们常说的feature map
参考博客:TF-卷积函数 tf.nn.conv2d 介绍 - .每天进步一点点 - 博客园
具体实现:
# [batch, in_height, in_width, in_channels]
input_arg = tf.Variable(tf.ones([4, 5, 5, 5]))
# [filter_height, filter_width, in_channels, out_channels]
filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,7]))
op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,2,2,1], use_cudnn_on_gpu=False, padding='SAME')
oplist.append([op2, "case 8"])
with tf.Session() as a_sess:
a_sess.run(tf.global_variables_initializer())
for aop in oplist:
print("----------{}---------".format(aop[1]))
print(a_sess.run(aop[0]))
print('---------------------\n\n')
输出结果为 7*5*5*4的一个张量。分别表示:
7:卷积核每运行一次输出的feature数量
5:卷积核在width方向移动的次数
5:卷积核在height方向移动的次数
4:训练时一个batch的图片数量
运行结果:
----------case 8---------
[[[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]
[[ 30. 30. 30. 30. 30. 30. 30.]
[ 45. 45. 45. 45. 45. 45. 45.]
[ 30. 30. 30. 30. 30. 30. 30.]]
[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]]
[[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]
[[ 30. 30. 30. 30. 30. 30. 30.]
[ 45. 45. 45. 45. 45. 45. 45.]
[ 30. 30. 30. 30. 30. 30. 30.]]
[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]]
[[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]
[[ 30. 30. 30. 30. 30. 30. 30.]
[ 45. 45. 45. 45. 45. 45. 45.]
[ 30. 30. 30. 30. 30. 30. 30.]]
[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]]
[[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]
[[ 30. 30. 30. 30. 30. 30. 30.]
[ 45. 45. 45. 45. 45. 45. 45.]
[ 30. 30. 30. 30. 30. 30. 30.]]
[[ 20. 20. 20. 20. 20. 20. 20.]
[ 30. 30. 30. 30. 30. 30. 30.]
[ 20. 20. 20. 20. 20. 20. 20.]]]]
---------------------
池化层
以最大池化方法为例:
tf.nn.max_pool(value, ksize, strides, padding, name=None)
参数是四个,和卷积很类似:
第一个参数value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape
第二个参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在
batch和
channels
上做池化,所以这两个维度设为了1
第三个参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,
stride
, 1]
第四个参数padding:和卷积类似,可以取'VALID' 或者'SAME'
返回一个Tensor,类型不变,shape仍然是[batch, height, width, channels]
这种形式
示例源码:
假设有这样一张图,双通道
第一个通道:
第二个通道:
用程序作最大池化:
import tensorflow as tf
a=tf.constant([
[[1.0,2.0,3.0,4.0],
[5.0,6.0,7.0,8.0],
[8.0,7.0,6.0,5.0],
[4.0,3.0,2.0,1.0]],
[[4.0,3.0,2.0,1.0],
[8.0,7.0,6.0,5.0],
[1.0,2.0,3.0,4.0],
[5.0,6.0,7.0,8.0]]
])
a=tf.reshape(a,[1,4,4,2])
pooling=tf.nn.max_pool(a,[1,2,2,1],[1,1,1,1],padding='VALID')
with tf.Session() as sess:
print("image:")
image=sess.run(a)
print (image)
print("reslut:")
result=sess.run(pooling)
print (result)
输出结果:
image: [[[[ 1. 2.] [ 3. 4.] [ 5. 6.] [ 7. 8.]] [[ 8. 7.] [ 6. 5.] [ 4. 3.] [ 2. 1.]] [[ 4. 3.] [ 2. 1.] [ 8. 7.] [ 6. 5.]] [[ 1. 2.] [ 3. 4.] [ 5. 6.] [ 7. 8.]]]] reslut: [[[[ 8. 7.] [ 6. 6.] [ 7. 8.]] [[ 8. 7.] [ 8. 7.] [ 8. 7.]] [[ 4. 4.] [ 8. 7.] [ 8. 8.]]]]
池化后的图片: