一維卷積 以例子說明 tf.nn.conv1d 矩陣運算過程

這幾天在看代碼,然後看網上關於一維卷積介紹的文檔很多,但是對於tf.nn.conv1d 矩陣運算過程幾乎沒有介紹,這裏我就將剛弄懂的寫出來,希望能幫到大家理解這個函數,也爲了讓自己以後能更好的查閱~~


conv1d(value,  filters, stride, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

value: A 3D Tensor. Must be of type float16 or float32.
被卷積的矩陣:可以當成是[batch, sample, feature]

filters: A 3D Tensor. Must have the same type as input.
卷積核:形狀 [filter_width, in_channels, out_channels]

stride: An integer. The number of entries by which the filter is moved right at each step.
步長:卷積核滑動步長

padding: ‘SAME’ or ‘VALID’
same和valid可以參考這篇文檔:深度學習面試題09:一維卷積(Full卷積、Same卷積、Valid卷積、帶深度的一維卷積)

廢話不多說,咱們今天不講原理,只講其中矩陣運算過程~ 幫助大家理解~


卷積核filter 的形狀:[filter_width, in_channels, out_channels]

  • in_channels 必須等於被卷積的矩陣的第3維數,即列數
  • out_channels 表示卷積核數目,類似於圖像裏,一個卷積核得到一個輸出,這裏有|out_channels |個卷積核,則輸出必定有|out_channels|
  • filter_width 表示與 value 進行卷積的 個數/每次 (這裏不懂可以以往後看例子)

例一:filter_width=1時:

舉例,令被一維卷積的value維度是:(2,3,4)
在這裏插入圖片描述
令卷積核的filter維度是:(1,4,5)
即 [filter_width, in_channels, out_channels] = (1,4,5)
在這裏插入圖片描述
filter_width =1 說明每次對value裏的一行進行卷積:

以value第一個batch裏爲例:

第一個batch中第1行的計算過程是:
在這裏插入圖片描述
第一個batch中第2行的計算過程是:
在這裏插入圖片描述
tf.nn.conv1d 一次對一個batch進行卷積處理,batch之間互不影響。
以此類推,完成一個batch的計算後,第二個batch的計算過程也如此。
所以value整體卷積的結果是:
在這裏插入圖片描述
以上filter_width=1時的代碼如下:

sess= tf.Session()
    a = tf.Variable(np.random.randint(1,3,(2,3,4)))
    filt = tf.get_variable("weights", initializer=np.random.randint(1,3,(1,4,5)))

    sess.run(tf.global_variables_initializer())
    print(sess.run(a))
    print('\n')
    print(sess.run(filt))
    filt_input = tf.nn.conv1d(tf.to_float(a), tf.to_float(filt), 1, "VALID", name="embedded_input")
    print(sess.run(filt_input))

由於filter_width=1時,valid和same的計算沒啥區別,這裏不講,在filter_width>1時介紹。


例二:filter_width>1時:

舉例,令被一維卷積的value維度是:(2,3,4)
在這裏插入圖片描述
令卷積核的filter維度是:(2,4,5)
即 [filter_width, in_channels, out_channels] = (2,4,5)
在這裏插入圖片描述
filter_width =2 說明每次對value裏的2行進行卷積:

1. VALID 時:

tf.nn.conv1d 一次對一個batch進行卷積處理,batch之間互不影響 ,所以這裏以第一個batch中的計算進行說明:
咱們這裏設置的filter_width =2, 說明每次對value裏的2行進行卷積。
則:

  • 第一次計算取1,2行進行卷積,第1行和卷積核的第一大塊,也就是(0,:,:)進行矩陣乘法,第2行和卷積核的第二大塊,也就是(1,:,:)進行矩陣乘法,結果相加得到第一次卷積結果:

在這裏插入圖片描述

  • 第二次計算取2,3行進行卷積,第2行和卷積核的第一大塊,也就是(0,:,:)進行矩陣乘法,第3行和卷積核的第二大塊,也就是(1,:,:)進行矩陣乘法,結果相加得到第二次卷積結果:
    在這裏插入圖片描述

以此類推,完成一個batch的計算後,第二個batch的計算過程也如此。

所以value整體VALID卷積的結果是:
在這裏插入圖片描述


2. SAME 時:

剛纔在VALID中,第一次計算取value的1,2行進行卷積,第二次取value的2,3行進行卷積。
也就是說VALID中,filter_width =2時每次取兩行來卷積,然後只要value的1,2,3行全部都處理完了就OK。也就是一共進行了兩次卷積,得到的卷積的結果,每個batch的行數爲兩行
而這裏的 “SAME”,爲了保證卷積後的結果每個batch的行數和原先VALUE行數相等(原先Value中每個batch有3行),所以還需要再在VALID基礎上做一次卷積!

以第一個batch爲例,整體運算過程是:

  • 第一次計算取1,2行進行卷積,第1行和卷積核的第一大塊,也就是(0,:,:)進行矩陣乘法,第2行和卷積核的第二大塊,也就是(1,:,:)進行矩陣乘法,相加得到第一次卷積結果:
    在這裏插入圖片描述
  • 第二次計算取2,3行進行卷積,第2行和卷積核的第一大塊,也就是(0,:,:)進行矩陣乘法,第3行和卷積核的第二大塊,也就是(1,:,:)進行矩陣乘法,相加得到第二次卷積結果:
    在這裏插入圖片描述
  • 第三次計算按理來說,每次取兩行來卷積,這裏就要取3,4行進行卷積,但是這裏VALUE中沒有第4行,所以只需要第3行和卷積核的第一大塊,也就是(0,:,:)進行矩陣乘法,得到第三次卷積結果:
    在這裏插入圖片描述
    這樣就保證了計算結果是3行。

以此類推,完成一個batch的計算後,第二個batch的計算過程也如此。

所以value整體SAME卷積的結果是:
在這裏插入圖片描述

這裏VALID和SAME代碼如下:

sess= tf.Session()
    a = tf.Variable(np.random.randint(1,3,(2,3,4)))
    filt = tf.get_variable("weights", initializer=np.random.randint(1,3,(2,4,5)))

    sess.run(tf.global_variables_initializer())
    print(sess.run(a))
    print('\n')
    print(sess.run(filt))
    filt_input = tf.nn.conv1d(tf.to_float(a), tf.to_float(filt), 1, "VALID", name="embedded_input")
    filt_input2 = tf.nn.conv1d(tf.to_float(a), tf.to_float(filt), 1, "SAME", name="embedded_input")
    print(sess.run(filt_input))
    print(sess.run(filt_input2))

個人覺得filter_width=1的時候更適合做embedding~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章