卷積是怎麼【卷】的
- 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冰不語