使用Python的一維卷積

學習&轉載文章:使用Python的一維卷積

背景

在開發機器學習算法時,最重要的事情之一(如果不是最重要的話)是提取最相關的特徵,這是在項目的特徵工程部分中完成的。

在CNNs中,此過程由網絡自動完成。特別是在早期層中,網絡試圖提取圖像的最重要的特徵,例如邊緣和形狀

另一方面,在最後一層中,它將能夠組合各種特徵以提取更復雜的特徵,例如眼睛或嘴巴,這在例如我們想要創建人類圖像的分類器時可能很有用。

讓我們想象一隻狗的形象。我們想在這張圖片中找到一隻耳朵,以確保有一隻狗。我們可以創建一個濾波器或核,以查看它是否可以在圖像中的各個點找到耳朵。

圖片

在圖像中,我們有一組紫色的權重(內核),當乘以輸入圖像的像素值時,它會告訴我們是否存在耳朵或下巴。我們是如何創建這些權重參數的?嗯…隨機!網絡的訓練將慢慢學習正確的權重參數。

生成的輸出(橙色)稱爲特徵圖

通常在卷積之後,所以在獲得特徵圖之後,我們有彙集層來彙總更多信息,然後我們將進行另一個卷積等等,但我們在本文中不討論其他層。

一維卷積

我們直觀地理解了卷積如何從圖像中提取特徵。但卷積也經常與文本等其他類型的數據一起使用,這是因爲卷積只是一個公式,我們需要了解它是如何工作的。

一維卷積是在兩個向量之間定義的,而不是像圖像中的情況那樣在矩陣之間定義的。

所以我們將有一個向量\(x\)作爲我們的輸入,一個核\(w\)作爲第二個向量。

图片

符號\(*\)表示卷積(不是乘法)。\(Y[i]\)是合成向量\(Y\)的元素\(i\)

首先,如果你注意到求和的極端值從\(-inf\)\(+inf\),但這在機器學習中沒有太大意義。我們通常給某個大小加前綴。假設輸入向量的大小必須爲12。但是如果向量小於前綴大小會發生什麼?嗯,我們可以在向量的開頭和結尾添加零,以使其大小正確,這種技術稱爲填充

圖片

然後我們假設原始輸入\(x\)和濾波器\(w\)分別具有大小\(n\)\(m\),其中\(n≤ m\)、 然後,帶有填充的輸入將具有大小\(n+2p\),原始公式如下。

图片

從上面的公式中,我們可以注意到一件事:我們所做的是滾動\(x^p\)向量和\(w\)向量的單元格。然而,向量\(x^p\)從右向左滾動,\(w\)從左向右滾動。但是,我們可以簡單地反轉向量\(w\),並執行\(x^p\)\(w^{rotated}\)之間的向量積。

\(x^p\):表示\(x\)填充後的

\(w^{rotated}\):表示\(x\)旋轉後的

讓我們直觀地看看會發生什麼。首先,我們旋轉濾波器(旋轉\(w\))。

图片

初始公式告訴我們要做的是使兩個向量之間的向量積,只考慮初始向量的一部分。這部分被稱爲局部感受野。然後,我們將向量\(w^R\)每次滑動兩個位置,在這種情況下,我們將說我們使用的是步幅=2。後者也是我們需要優化的網絡的超參數。

图片

padding

你應該注意,根據我們使用的填充模式,我們或多或少地強調了一些輸入單元格。在前面的例子中,當我們計算輸出\(y[0]\)時,單元格\(x[0]\)只考慮了一次。相反,在\(y[1]\)\(y[2]\)的計算中都考慮了\(x[2]\)單元,因此它更重要。我們還可以通過使用填充來處理向量邊界處的單元格的這種重要性。

有3種不同類型的填充:

  • 全模式:填充參數\(p\)設置爲\(p=m-1\),其中\(m\)是核大小。這種填充導致輸出大於輸入,因此很少使用。
  • 相同模式:用於確保輸出與輸入大小相同。例如,在計算機視覺中,輸出圖像將與輸入圖像大小相同,因此通常是最常用的。
  • 有效模式:當\(p=0\)時,因此我們不使用填充。

如何確定卷積輸出大小?

許多人經常對CNN各個層的輸入和輸出大小感到困惑,並與不匹配的錯誤作鬥爭!實際上,計算卷積層的輸出大小非常簡單。

假設我們有一個輸入\(x\),一個核\(w\),並且想要計算卷積\(y=x*w\)

要考慮的參數是\(x\)的大小\(n\)\(w\)的大小\(m\)、填充\(p\)和步幅\(s\)。輸出的大小\(o\)將由以下公式給出:

圖片

符號$⌊⌋ \(指示向下取整操作。例如\)⌊2.4⌋ = 2$.

讓我們看看如何應用公式和示例:

图片

在第一個示例中,我們看到輸出大小與輸入大小相同,因此我們推斷使用了相同的模式填充

我們看到另一個例子,我們改變了核大小和步長。

图片

編碼

如果到目前爲止你仍然有點困惑,沒問題。讓我們開始着手編寫代碼,事情會變得更清楚。

import numpy as np


def conv1D(x,w, p=0 , s=1): 
  '''
  x : input vector
  w : filter
  p : padding size
  s : stride
  '''
  assert len(w) <= len(x), "x should be bigger than w"
  assert p >= 0, "padding cannot be negative"

  w_r = np.array(w[::-1]) #rotation of w 
  x_padded = np.array(x)

  if p > 0 :
    zeros = np.zeros(shape = p)
    x_padded = np.concatenate([zeros, x_padded, zeros]) #add zeros around original vector

  out = []
  #iterate through the original array s cells per step
  for i in range(0, int((len(x_padded) - len(w_r))) + 1 , s):
    out.append(np.sum(x_padded[i:i + w_r.shape[0]] * w_r)) #formula we have seen before
  return np.array(out)

讓我們嘗試在一些真實數據上運行此函數並查看結果。讓我們將結果與自動計算卷積結果的NumPy內置函數進行比較。

x = [3,6,8,2,1,4,7,9]
w = [4 ,0, 6, 3, 2]

conv1D(x,w,2,1)

'''
>>> array([50., 53., 76., 64., 56., 67., 56., 83.])
'''

np.convolve(x , w, mode = 'same')

'''
>>> array([50., 53., 76., 64., 56., 67., 56., 83.])
'''

最後

正如你所看到的,我們開發的函數和NumPy的卷積方法的結果是相同的。卷積是卷積神經網絡以及現代計算機視覺的基本元素。我們經常在不瞭解其組成的構建塊的情況下立即開始實現複雜的算法。

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