.# input_image的结构:[batch, in_height, in_width, in_channels]
[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数]
input = tf.Variable(tf.constant(1.0,shape = [1, 5, 5, 1]))
input2 = tf.Variable(tf.constant(1.0,shape = [1, 5, 5, 2]))
input3 = tf.Variable(tf.constant(1.0,shape = [1, 4, 4, 1]))
##################
#fillter的结构: [filter_height, filter_width, in_channels, out_channels]
[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数]
filter1 = tf.Variable(tf.constant([-1.0,0,0,-1],shape = [2, 2, 1, 1]))
filter2 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 1, 2]))
filter3 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 1, 3]))
filter4 = tf.Variable(tf.constant([-1.0,0,0,-1,
-1.0,0,0,-1,
-1.0,0,0,-1,
-1.0,0,0,-1],shape = [2, 2, 2, 2]))
filter5 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 2, 1]))
Ps:TensorFlow中的矩阵数组啥的默认类型为tf.float32
再ps:如果数组中第一个数是float类型,那么这个数组就是float类型,如果是int,那这个数组就是int型。
#################################
tf.nn.conv2d(input,filter, strides, padding, use_cudnn_on_gpu=None, name=None)
对一个四维的输入数据input和四维的卷积核filter进行操作,然后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果
input:为一个Tensor,数据类型必须是float32或者float64;
filter:为一个tensor,数据类型必须是与input输入的数据类型相同;
strides:一个长度是4的一维整数类型数组,每一维度对应的是input中每一维的对应移动步数;如strides[1]对应input[1]的移动步数;
padding:一个字符串,取值为SAME或者VALID;‘SAME'适用于全尺寸操作,即输入数据维度和输出数据维度相同;'VALID'适用于部分窗口;
use_cudnn_on_gpu:一个可选布尔值,默认情况下是True;
name:为这个操作取一个名字;
################################
op1 = tf.nn.conv2d(input, filter1, strides=[1, 2, 2, 1], padding='SAME') #1个通道输入,生成1个feature ma
op2 = tf.nn.conv2d(input, filter2, strides=[1, 2, 2, 1], padding='SAME') #1个通道输入,生成2个feature map
op3 = tf.nn.conv2d(input, filter3, strides=[1, 2, 2, 1], padding='SAME') #1个通道输入,生成3个feature map
op4 = tf.nn.conv2d(input2, filter4, strides=[1, 2, 2, 1], padding='SAME') # 2个通道输入,生成2个feature
op5 = tf.nn.conv2d(input2, filter5, strides=[1, 2, 2, 1], padding='SAME') # 2个通道输入,生成一个feature map
vop1 = tf.nn.conv2d(input, filter1, strides=[1, 2, 2, 1], padding='VALID') # 5*5 对于pading不同而不同
op6 = tf.nn.conv2d(input3, filter1, strides=[1, 2, 2, 1], padding='SAME')
vop6 = tf.nn.conv2d(input3, filter1, strides=[1, 2, 2, 1], padding='VALID') #4*4与pading无关
op1:
[array([[[[-2.], [[-2.], [[-1.],
[-2.],[-2.], [-1.],
[-1.]],[-1.]],[-1.]]]], dtype=float32),
array([[[[-1.]],[[[ 0.]],
[[ 0.]]],[[-1.]]]], dtype=float32)]
------------------
op2:
[array([[[[-2., -2.],[-2., -2.],[-2., 0.]],
[[-2., -2.],[-2., -2.],[-2., 0.]],
[[-1., -1.], [-1., -1.],[-1., 0.]]]], dtype=float32),
array([[[[-1., 0.]], [[ 0., -1.]]],
[[[-1., 0.]],[[ 0., -1.]]]], dtype=float32)]
op3:
[array([[[[-2., -2., -2.],[-2., -2., -2.],[-1., -1., -1.]],
[[-2., -2., -2.],[-2., -2., -2.],[-1., -1., -1.]],
[[-2., -1., 0.],[-2., -1., 0.],[-1., 0., 0.]]]], dtype=float32),
array([[[[-1., 0., 0.]],[[-1., -1., 0.]]],
[[[ 0., -1., -1.]],[[ 0., 0., -1.]]]], dtype=float32)]
这个fillter怎么来的呢?
首先输入权重向量的是[-1.0,0,0,-1,-1.0,0,0,-1,-1.0,0,0,-1],然后根据要求分为3个fillter,每个fillter为2X2共4个权重。分配规则为:权重向量按照顺序每3为一组,[-1., 0., 0.][-1., -1., 0.][ 0., -1., -1.][ 0., 0., -1.],为什么是三个一组呢?因为要分成3个fillter。
然后后两个换到第二行:
A1 A2 A3 B1 B2 B3
[-1., 0., 0.][-1., -1., 0.]
[ 0., -1., -1.][ 0., 0., -1.]
然后AB两个矩阵两两组合形如[A,B],就得到了:
[-1.,-1 [0.,-1. [0.,0.
0.,0] -1.,0.] -1.,-1.] 三个fillter...手算一遍,和答案一致
------------------------------------------------
op4: 双通道输入
[array([[[[-4., -4.], [[-4., -4.],[[-2., -2.],
[-4., -4.],[-4., -4.],[-2., -2.],
[-2., -2.]],[-2., -2.]],[-1., -1.]]]], dtype=float32),
array([[[[-1., 0.],[[-1., 0.],[[[-1., 0.],[ 0., -1.]],
[ 0., -1.]],[ 0., -1.]]],[[-1., 0.],[ 0., -1.]]]], dtype=float32)]
op5:
[array([[[[-4.],[[-4.],[[-2.],
[-4.],[-4.],[-2.],
[-2.]],[-2.]],[-1.]]]], dtype=float32),
array([[[[-1.],[[ 0.],[[[-1.],[ 0.]],
[ 0.]],[-1.]]],[[ 0.],[-1.]]]], dtype=float32)]
总结:
- 两个单层核,一个通道:
两个核分别对此通道进行卷积,然后两个featuremap以[mapA,mapB]来表示
- 一个双层核,两个通道:
这个卷积核的两层对应着两个通道卷一次,然后每层卷出来的featuremap相加(因为是一个核,所以得相加)成一个总的featuremap。
- 两个双层核,两个通道
综合上述1、2的方法,两个卷积核分别卷出来两个featuremap,然后以[mapA,mapB]来表示
---------------------------
op1:
[array([[[[-2.],[[-2.],[[-1.],
[-2.],[-2.],[-1.],
[-1.]],[-1.]],[-1.]]]], dtype=float32),
array([[[[-1.]],[[[ 0.]],
[[ 0.]]],[[-1.]]]], dtype=float32)]
vop1:
[array([[[[-2.],[[-2.],
[-2.]],[-2.]]]], dtype=float32),
array([[[[-1.]],[[[ 0.]],
[[ 0.]]],[[-1.]]]], dtype=float32)]
op6:
[array([[[[-2.],[[-2.],
[-2.]],[-2.]]]], dtype=float32),
array([[[[-1.]],[[[ 0.]],
[[ 0.]]],[[-1.]]]], dtype=float32)]
vop6:
[array([[[[-2.], [[-2.],
[-2.]],[-2.]]]], dtype=float32),
array([[[[-1.]],[[[ 0.]],
[[ 0.]]],[[-1.]]]], dtype=float32)]