1. 程式人生 > >卷積層運算例項

卷積層運算例項

 

昨天晚上為了區分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]]]]

5X5,也無需在做更多的解釋