卷積層運算例項
昨天晚上為了區分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]]]]