昨天晚上为了区分TensorFlow的tf.nn.conv2d 函数的中的参数取值问题,(padding='VALID’和 padding='SAME' ) 自己编写了一个非常简单的卷积层,但是出现了一些小问题,在这里做一下汇总。
import tensorflow as tf
x0 = tf.constant([[1., 2., 3., 4., 5.],
[6., 7., 8., 9., 10.],
[11., 12., 13., 14., 15.],
[16., 17., 18., 19., 20.]])
print(x0.shape)
x = tf.reshape(x0,[-1,4,5,1])
print(x)
fil0 = tf.constant([[2.,2.],
[3.,3.]])
print(fil0)
fil1 = tf.reshape(fil0,[2,2,1,1])
print(fil1)
这个是我自己定义的输入矩阵了卷积核矩阵,我将输入矩阵reshape为了[-1,4,5,1] 这样的维度,卷积核矩阵reshape为了[2,2,1,1] 这样的维度。
下面这里,我们简要的看一下输出:
(4, 5)
Tensor("Reshape_38:0", shape=(1, 4, 5, 1), dtype=float32)
Tensor("Const_42:0", shape=(2, 2), dtype=float32)
Tensor("Reshape_39:0", shape=(2, 2, 1, 1), dtype=float32)
---------------------------------------------------
好的,现在我们开始卷积运算,
# 计算过程
res1 = tf.nn.conv2d(input=x, filter=fil1, strides=[1,1,1,1],padding='VALID')
res2 = tf.nn.conv2d(input=x, filter=fil1, strides=[1,1,1,1],padding='SAME')
print('------# 计算过程 #--------')
print(res1)
print(res2)
print('------# 计算过程 #--------')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(res1))
print('- - - - - - - - - - -- - -- ')
print(sess.run(res2))
我们观察一下输出的结果
------# 计算过程 #--------
Tensor("Conv2D_34:0", shape=(1, 3, 4, 1), dtype=float32)
Tensor("Conv2D_35:0", shape=(1, 4, 5, 1), dtype=float32)
------# 计算过程 #--------
[[[[ 45.]
[ 55.]
[ 65.]
[ 75.]]
[[ 95.]
[105.]
[115.]
[125.]]
[[145.]
[155.]
[165.]
[175.]]]]
- - - - - - - - - - -- - --
[[[[ 45.]
[ 55.]
[ 65.]
[ 75.]
[ 40.]]
[[ 95.]
[105.]
[115.]
[125.]
[ 65.]]
[[145.]
[155.]
[165.]
[175.]
[ 90.]]
[[ 66.]
[ 70.]
[ 74.]
[ 78.]
[ 40.]]]]
想必大家之前对padding取值的不同对结果的影响都有了一个普遍的认识了,这里这是做一个小小的验证。
然而,我在这里发现了一个小小的意外
我们定义的卷积核的大小是2x2的,而且使用constant来定义的 ,这也就意味着我们在reshape这个卷积核矩阵的时候有着很大的局限,具体的来说就是[ [2., 2., ],[ 3., 3.] ] 这样的矩阵可以reshape为我们例子中的[2,2,1,1], 这种卷积核矩阵的意思就是单输入,单输出,然而这样并没有什么天大的意义;如果我们将其reshape为[2,2,1,15]这样的维度,那么编译器就会给你报错 。相信大家都看过MNIST的例子,在MNIST中打一层卷积的输入为1,输出为32。
其实解决这个问题并不困难,我们只需要更改定义的方式即可;譬如:::::
filter1 = tf.Variable(tf.random_normal([1,1,5,5]))
print(filter1)
或者说也可以:
fil1 = tf.truncated_normal(shape, stddev = 0.1)
# 正态分布
方法很多,但是我在网上看到用的最多的也就是这两种,这样更改完之后,我们就可以任意改变我们卷积层的输出维度了,这样也才能达到我们使用卷积层的真正目的了。。。。
# conv2d case 1
import tensorflow as tf
input1 = tf.Variable(tf.random_normal([1,3,3,5]))
print(input1)
filter1 = tf.Variable(tf.random_normal([1,1,5,5]))
print(filter1)
op1 = tf.nn.conv2d(input=input1,filter=filter1,strides=[1,1,1,1],padding='SAME')
print(op1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(input1))
print('- - - - - - - - - - - - - - - - - - - - - ')
print(sess.run(filter1))
print('- - - - - - - - - - - - - - - - - - - - - ')
print(sess.run(op1))
结果:
<tf.Variable 'Variable_24:0' shape=(1, 3, 3, 5) dtype=float32_ref>
<tf.Variable 'Variable_25:0' shape=(1, 1, 5, 5) dtype=float32_ref>
Tensor("Conv2D_23:0", shape=(1, 3, 3, 5), dtype=float32)
[[[[ 1.0076689 -1.0429513 0.19840461 -1.4179145 0.21241538]
[ 1.5745131 0.9061459 -0.8719591 0.9945474 -1.1337398 ]
[ 0.03464183 -1.5947934 0.64049923 -0.07008466 1.6137193 ]]
[[ 0.7869904 -0.6835375 0.69408005 -2.0935128 0.0372552 ]
[ 0.1736713 -1.221272 0.665623 0.7544438 -0.36622164]
[-0.31765813 0.9946766 -0.93498504 -0.20999084 1.073885 ]]
[[-0.4125433 -0.5018808 0.5720211 1.429884 0.16586587]
[ 0.5928908 -1.1014961 0.5609521 1.3232079 0.46690243]
[ 3.1215336 1.450255 -0.94082916 0.8863312 -0.7052749 ]]]]
- - - - - - - - - - - - - - - - - - - - -
[[[[-2.4539537 -0.5954268 0.6421796 -0.40367666 1.9257879 ]
[-0.77819943 -1.9217943 -0.5275012 0.04040896 -0.4035784 ]
[ 1.4318761 0.966928 -0.90433323 -0.520099 -1.5638638 ]
[ 0.59773684 -0.6318572 -0.05836076 -0.84807736 0.32493162]
[-1.8983399 -0.5072093 -0.1815751 0.988288 0.23245037]]]]
- - - - - - - - - - - - - - - - - - - - -
[[[[-2.6278341e+00 2.3843687e+00 1.0620198e+00 8.6032176e-01
1.6398423e+00]
[-3.0707808e+00 -3.5754230e+00 1.4694850e+00 -2.1093874e+00
4.0897241e+00]
[-1.0321066e+00 2.8893447e+00 -4.6440363e-03 1.2427056e+00
6.1020404e-02]]
[[-1.7275658e+00 2.8200538e+00 3.5369077e-01 1.1059786e+00
3.4402516e-02]
[ 2.6234736e+00 2.5962846e+00 1.7627250e-01 -1.4674065e+00
-5.3596362e-02]
[-3.4974389e+00 -3.0384851e+00 -6.5884218e-02 1.8941059e+00
6.3040936e-01]]
[[ 2.7618134e+00 7.7564323e-01 -6.3104808e-01 -1.1999829e+00
-9.8331565e-01]
[ 1.1006153e-01 1.2333306e+00 2.9249403e-01 -1.2363458e+00
1.2475530e+00]
[-8.2671928e+00 -5.7577639e+00 2.1667304e+00 -2.1608548e+00
7.0215044e+00]]]]
关于卷积的输出结果,可以参考https://blog.csdn.net/zuolixiangfisher/article/details/80528989 这位朋友的博客
到这里,其实我还有一个疑问。
那就是当padding的模式为SAME的时候,我们假设有一个5x5的矩阵,我们用3x3的核去做卷积,结果会是(4x4)还是(5x5)呢??????
我们来看代码
import tensorflow as tf
demo_input = tf.Variable(tf.truncated_normal([1,5,5,1],stddev=0.1))
filter_input = tf.Variable(tf.truncated_normal([3,3,1,1],stddev=0.1))
que_op = tf.nn.conv2d(input=demo_input, filter=filter_input,strides=[1,1,1,1], padding='SAME')
print(que_op.shape)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(que_op))
(1, 5, 5, 1)
[[[[-8.3898138e-03]
[-2.1066532e-02]
[-1.4402784e-03]
[ 8.5802004e-03]
[-1.4919336e-02]]
[[ 1.6910087e-02]
[ 3.8107365e-02]
[-4.9511576e-03]
[-8.5974624e-03]
[ 1.6875543e-02]]
[[-2.0971554e-03]
[-1.3970275e-02]
[-1.8095970e-02]
[ 1.7300552e-02]
[-4.7517763e-03]]
[[ 2.8687459e-03]
[ 2.7101874e-02]
[-2.2895761e-02]
[-1.7852791e-02]
[-8.9415582e-05]]
[[-2.4188370e-02]
[-1.0250438e-02]
[-1.1976613e-02]
[ 2.2352396e-02]
[ 4.6136477e-03]]]]