在一些書籍和博客中所講的卷積(一個卷積核和輸入的對應位置相乘,而後累加)不是真正意義上的卷積。根據離散卷積的定義,卷積核是須要旋轉180的。html
按照定義來講,一個輸入和一個卷積核作卷積操做的流程是:ide
①卷積核旋轉180spa
②對應位置相乘,而後累加code
舉例htm |
下面這個圖是常見的卷積運算圖:blog
中間的卷積核,實際上是已經旋轉過180度的ip
即,作卷積的兩個矩陣實際上是ci
[[2, 1, 0, 2, 3],get
[9, 5, 2, 2, 0],input
[2, 3, 4, 5, 6],
[1, 2, 3, 1, 0],
[0, 4, 4, 2, 8]]
和
[[1, 0, -1],
[1, 0, -1],
[1, 0, -1]]
沒有旋轉只有乘積求和就不叫卷積運算。
可是,在tensorflow中以爲這樣很糾結,因此乾脆定義的卷積核直接就是旋轉後的卷積核,因此tensorflow能夠直接對應位置相乘,而後相加
import tensorflow as tf # [batch, in_height, in_width, in_channels] input = tf.constant([ [2, 1, 0, 2, 3], [9, 5, 4, 2, 0], [2, 3, 4, 5, 6], [1, 2, 3, 1, 0], [0, 4, 4, 2, 8], ], tf.float32) input = tf.reshape(input, [1, 5, 5, 1]) #定義旋轉180後的卷積核 # [filter_height, filter_width, in_channels, out_channels] kernel = tf.constant([ [-1, 0, 1], [-1, 0, 1], [-1, 0, 1] ], tf.float32) kernel = tf.reshape(kernel, [3, 3, 1, 1]) print(tf.Session().run(tf.nn.conv2d(input,kernel,[1,1,1,1],"VALID"))) [[[[-5.] [ 0.] [ 1.]] [[-1.] [-2.] [-5.]] [[ 8.] [-1.] [ 3.]]]]
而在scipy中,是按照嚴格的卷積定義來的,你定義了一個卷積核後,scipy要先將你的卷積核旋轉180度,而後纔對應位置相乘,再相加。
import numpy as np from scipy import signal input = np.array([ [2, 1, 0, 2, 3], [9, 5, 4, 2, 0], [2, 3, 4, 5, 6], [1, 2, 3, 1, 0], [0, 4, 4, 2, 8] ]) #定義未經旋轉的卷積核 kernel = np.array([ [1, 0, -1], [1, 0, -1], [1, 0, -1] ]) # kernel1 = np.flip(kernel1) print(signal.convolve(input, kernel, mode="valid")) [[-5 0 1] [-1 -2 -5] [ 8 -1 3]]
結論 |
若是你定義的是旋轉180度後的卷積核,那就直接對應位置相乘再相加
若是你定義的是未經旋轉的卷積核,那須要先旋轉180,再對應位置相乘再相加
市面上的參考書大部分描述的卷積核都是旋轉後的卷積核,個人博客中也是這樣,由於這樣更容易理解,否則作一次卷積,你是很難直觀看出來結果的。
參考資料 |
什麼!卷積要旋轉180度?!
https://www.jianshu.com/p/8dfe02b61686
二維卷積的計算原理