卷積是怎麼【卷】的

  • 2019 年 12 月 10 日
  • 筆記

前言:

現在人工智慧很火,但是它的數學門檻讓很多人都望而卻步,今天這篇文章就以很通俗的語言來講解了卷積,希望對大家有所幫助。

卷積,這個詞大家應該都不陌生,數學中傅立葉變換的時候,物理中訊號處理的時候,影像處理中濾波的時候、提取邊緣的時候,還有深度學習中卷積神經網路的時候,處處可見卷積的影子。卷積在影像處理中的應用非常廣泛,可以說理解了卷積,就可以理解影像處理演算法的半壁江山,也不知道這個說法是否誇張了。

但是都說卷積卷積,那捲積到底是怎麼個卷法呢?本文嘗試解答這一問題。

理解的卷積計算過程

想要理解卷積,一些必要的數學公式是少不了的,放心吧,就下面這一個公式了,所有討論圍繞這一個公式展開。

我們從維基百科中對於卷積的解釋引入:

設:, 是 上的兩個可積函數,作積分: 可以證明,關於幾乎所有的 ,上述積分是存在的。這樣,隨著 的不同取值,這個積分就定義了一個新函數 ,稱為函數 與 的卷積,記為 。

我們提取下重點公式寫在下面,記為公式1:

以上公式1最令人迷惑也是最需要注意的部分在於,在等式的左邊,自變數是,然而等式的右邊自變數卻變成了,更令人疑惑的是——右邊自變數不是是也就算了,竟然還出現了一個。

那麼問題來了,和,到底哪個在變?還是兩個都在變?如果是都在變,那到底是怎麼個變法?

這些問題還是需要慢慢道來。我們先看一個卷積稍微通俗一點的解釋。

卷積

(1)即是通過兩個函數和生成第三個函數的一種數學運算元。

(2)表徵函數f與經過翻轉和平移的g的乘積函數所圍成的的曲邊梯形的面積。

上面兩句話都非常重要,我們從第二句話開始看,第二句話中包含了以下四個重點資訊:

  • 翻轉
  • 平移
  • 乘積
  • 積分(函數圍成的面積不就是積分么?)

我們一個一個來看。先看右邊,我們不妨先令, 也就是不變而變的情況。於是公式1就變成了公式2:

1. 翻轉

先看翻轉,怎麼翻轉一個函數呢,想一下最簡單的,不難發現,翻轉之後即為。我用Python畫出了這倆函數的影像,看起來更為直觀。

f(x)-f(-x)

2. 平移

然後看一下一個函數如何平移,仍然以為例,回一下我們中學學過的數學知識,也許還能記起來,就是由向右平移得到的。我們仍然以圖說話,用Python作圖如下,分別取值為。

f(t-x)

3. 乘積

現在我們只看公式的右邊部分:

現在我們可以知道就是翻轉之後又向右平移了個單位。這時候需要考慮另一個函數了。這裡 我們繼續舉個例子,不妨令。

我們繼續用Python畫出如下圖所示:

fg

4. 積分

現在是較為完整的公式3的樣子了,這裡為了能夠更好地表達,我們把區間從改為,即畫出

int

注意了,在上面的所有過程中,一直是不變的,變的是。即我們上面一直是在做的是公式2右邊的計算,公式2如下:

不論怎麼變化,最後一旦積分,等式右邊就成了一個確定的數字,一個常量。

趣談編程註:積分確定了上下限,面積也就隨之確定了。

一個對應一個嘛。此時我們可以繼續看公式左邊了,我們直接看公式1:

左邊換下位置我們也許會更好理解,即。也即之前提到的一句話:卷積即是通過兩個函數和生成第三個函數的一種數學運算元。

總結一下,卷積計算過程可以分解為四步:翻轉、平移、乘積、積分

卷積為什麼叫「卷積」?

1. 卷積之【卷】

那麼問題來了?卷積為什麼要叫「卷積」呢?換言之,卷積之「卷」和卷積之「積」分別是什麼含義?

這裡想像一下如果我們要捲起一張A4紙,需要怎麼做?

(1)首先我們需要提起對著自己一條邊,向上翻轉使之對著自己身體前方——翻轉!

捲紙0

(2)然後繼續向下打個圈之後,就可以向前推了——平移!

捲紙1

看到沒?翻轉!平移!

你肯定還記得上面說的卷積計算的四個過程:翻轉、平移、乘積、積分。卷積之「卷」,你明白了嗎?

本文完

什麼?還不能走?你想要畫圖的源碼?

# coding:utf-8  """  Author:  CVPy-冰不語  Date:    2019/11/26  """    import numpy as np  import matplotlib.pyplot as plt      # 定義函數f(x)  def f(x):      """$f (\tau)$"""      return x      # 定義函數g(x)  def g(x):      """$f(x)=sin(x)$"""      return np.sin(x/10)      # 設置坐標系  def set_ax(ax):      ax.spines['top'].set_color('none')      ax.spines['right'].set_color('none')      ax.spines['bottom'].set_color('deepskyblue')      ax.spines['left'].set_color('deepskyblue')        ax.xaxis.set_ticks_position('bottom')      ax.spines['bottom'].set_position(('data', 0))      ax.yaxis.set_ticks_position('left')      ax.spines['left'].set_position(('data', 0))        ax.set_xticks(np.arange(-100,101, 50))      # ax.set_yticks(np.arange(-100,101, 50))        return ax      if __name__ == "__main__":      # x的取值範圍      x = np.arange(-100, 100, 0.1)        # ---------第一幅圖:f(x)和f(-x)----------      fig = plt.figure(figsize=(6, 6))        # 左邊畫f(x)      ax1 = fig.add_subplot(121)      ax1 = set_ax(ax1)      ax1.plot(x, f(x), 'orange', label=f.__doc__)      plt.legend(loc="upper left", bbox_to_anchor=[0, 1],                 ncol=1, fancybox=True)        # 右邊畫f(-x)      ax2 = fig.add_subplot(122)      ax2 = set_ax(ax2)      plt.plot(x, f(-x), 'orange', label="$f (-\tau)$")      plt.legend(loc="upper right", bbox_to_anchor=[1, 1],                 ncol=1, fancybox=True)      plt.show()        # ---------第二幅圖:f(t-x)----------      fig2 = plt.figure(figsize=(6, 6))      ax3 = fig2.add_subplot(111)        ax3 = set_ax(ax3)      ax3.set_xticks(np.arange(-100, 101, 20))      ax3.set_yticks(np.arange(-100, 181, 20))        for t in [20, 40, 60, 80]:          plt.plot(x, f(t-x), label="$f (x_0 - \tau)   x_0={0}$".format(t))      plt.legend(loc="upper right", bbox_to_anchor=[1, 1], ncol=1, fancybox=True)        plt.show()        # ---------第三幅圖:g(x) * f(t-x)----------      t = 80          def f_mul_g(x, t):          """$f(\tau-x)*g(\tau)$"""          return f(t-x)*g(x)        fig3, ax4 = plt.subplots()        ax4 = set_ax(ax4)      ax4.set_xticks(np.arange(-100,101, 20))      # ax4.set_yticks(np.arange(-100,181, 20))        plt.plot(x, f_mul_g(x, t), label=f_mul_g.__doc__)      plt.legend(loc="upper right", bbox_to_anchor=[1, 1], ncol=1, fancybox=True)        plt.show()        # ---------第四幅圖:g(x) * f(t-x)的積分----------      import matplotlib.patches as mPatches          def int_fg(x, t, ax5):          ax5 = set_ax(ax5)            plt.plot(x,f_mul_g(x, t), 'orange', label="$f (\tau)*g(x_0-\tau)    x_0={0}$".format(t))          plt.legend(loc="upper right", bbox_to_anchor=[1, 1],                     ncol=1, fancybox=True)            a = -50          b = 50          ix = np.linspace(a,b)          iy = f_mul_g(ix,t)            verts = [(a,0)] + list(zip(ix, iy)) + [(b,0)]          poly = mPatches.Polygon(verts,color='deepskyblue')          ax5.add_patch(poly)          # plt.plot(x,g(x),label=g.__doc__)            plt.text(30, 50, '$int_a^b f (\tau)*g(x_0-\tau)    x_0={0}$'.format(t), style='oblique',                   bbox={'facecolor': 'orange', 'alpha': 0.5, 'pad': 5}, fontsize=15)        fig4, ax5 = plt.subplots()      int_fg(x, t, ax5)      plt.legend(loc="upper right", bbox_to_anchor=[1, 1], ncol=1, fancybox=True)        plt.ion()        # for i in range(100):        #     y = np.random.random()        #     plt.autoscale()        #     plt.scatter(i, y)        #     plt.pause(0.01)        fig4, ax5 = plt.subplots()      tn = np.arange(-100,100,5)      for t in tn:          plt.cla()          plt.grid(True)          plt.autoscale()          int_fg(x, t, ax5)          plt.pause(0.01)            plt.legend(loc="upper right", bbox_to_anchor=[1, 1], ncol=1, fancybox=True)        plt.show()    

以上文章來源於CVPy,作者CVPy冰不語