1. 程式人生 > >數學小記之卷積

數學小記之卷積

本文簡述了1維卷積和2維卷積的實現

一維卷積

描述卷積的方式很多,譬如這個:

  • 一個函式在另一個函式上的加權疊加

雖然各個解釋都有助於我們對卷積的理解,但是個人感覺還是直接通過公式來了解卷積更為直觀(簡單起見,這裡我們僅討論卷積的離散定義):

f ( x )

g ( x ) = n =
f ( n ) g (
x n ) f(x)*g(x) = \sum_{n=-\infty}^{\infty}f(n)g(x - n)

注意一下這個公式,其所表達的意思是: fg 這兩個函式在 x 處的卷積值,而這個在 x 處的卷積值是通過取遍自變數 n 的"所有值(從負無窮到正無窮)"而計算出來的

當然,對於實際給出的 f 函式(序列) 和 g 函式(序列) 都不會是無窮的,所以計算過程中自變數 n 的取值自然也不會是無窮的,舉個簡單的例子,假設我們有以下的函式(序列):

f ( 0 ) = 1 , f ( 1 ) = 2 , f ( 2 ) = 3 g ( 0 ) = 4 , g ( 1 ) = 5 , g ( 2 ) = 6 f(0) = 1, f(1) = 2, f(2) = 3\\ g(0) = 4, g(1) = 5, g(2) = 6

並設 fg 的卷積結果為 h, 那麼 h(1) 等於多少呢?

f ( 1 ) g ( 1 ) = h ( 1 ) = ? f(1)*g(1) = h(1) = ?

我們來套用一下之前的公式:

f ( 1 ) g ( 1 ) = h ( 1 ) = n = f ( n ) g ( 1 n ) f(1)*g(1) = h(1) = \sum_{n=-\infty}^{\infty}f(n)g(1 - n)

考慮到 n1 - n 的合法範圍(n 需為 f 的合法索引,1 - n 需為 g 的合法索引),我們有:

0 = m i n _ i n d e x ( f ) < = n < = m a x _ i n d e x ( f ) = 2 0 = m i n _ i n d e x ( g ) < = 1 n < = m a x _ i n d e x ( g ) = 2       0 < = n < = 1 0 = min\_index(f) <= n <= max\_index(f) = 2\\0 = min\_index(g) <= 1 - n <= max\_index(g) = 2\\\implies0 <= n <= 1

所以對於 h(1) 來說 自變數 n 有兩個合法取值: 01, 於是我們有:

f ( 1 ) g ( 1 ) = h ( 1 ) = f ( 0 ) g ( 1 0 ) + f ( 1 ) g ( 1 1 ) = f ( 0 ) g ( 1 ) + f ( 1 ) g ( 0 ) = 1 5 + 2 4 = 13 f(1)*g(1) = h(1) = f(0)g(1 - 0) + f(1)g(1 - 1) = f(0)g(1) + f(1)g(0) = 1 * 5 + 2 * 4 = 13

其餘的卷積數值也可以依樣進行計算,有興趣的朋友可以自行試下~

下面是使用 Lua 實現的一維卷積示例:

local function dimension(f)
    if type(f) == "table" then
        local dim = #f
        if dim > 0 then
            return dim, dimension(f[1])
        else
            return 0
        end
    end
end

local function value(f, ...)
    if f then
        local dim_index = { ... }
        for i = 1, #dim_index do
            local index = dim_index[i]
            f = f[index]
            if not f then
                return 0
            end
        end
    end
    
    return f
end

-- 1d convolution, sample f(array with 3 elements) and g(array with 3 elements), h is convolution result(array index is from 0)
-- h(0) = f(0) * g(0)
-- h(1) = f(0) * g(1) + f(1) * g(0)
-- h(2) = f(0) * g(2) + f(1) * g(1) + f(2) * g(0)
-- h(3) = f(1) * g(2) + f(2) * g(1)
-- h(4) = f(2) * g(2)

function convolution_1d(f, g)
    local row_1 = dimension(f)
    local row_2 = dimension(g)
    if row_1 > 0 and row_2 > 0 then
        local h = {}
        
        local n = row_1 + row_2 - 2
        for i = 0, n do
            local sum = 0
            for j = 0, i do
                sum = sum + value(f, j + 1) * value(g, i - j + 1)
            end
            table.insert(h, sum)
        end
        
        return h
    end
end

示例中的 dimension函式 和 value函式 對於不熟悉 Lua 的朋友可能會造成些閱讀障礙(對於示例來說確實有些過度技巧化了),在此我們可以簡單理解:

  • dimension(f) 獲取 f 的陣列個數(支援多維陣列)
  • value(f, …) 獲取 f 在 …(不定引數) 所給定的索引處的數值,數值不存在則返回 0 (支援多維陣列)

二維卷積

二維卷積可以使用一維卷積來進行類比,在此僅給出(離散定義)公式和相關示例實現(使用 Lua):

f ( x , y ) g ( x , y ) = m = n = f ( m , n ) g ( x m , y n ) f(x, y)*g(x, y) = \sum_{m=-\infty}^{\infty}\sum_{n=-\infty}^{\infty}f(m, n)g(x - m, y - n)

示例程式碼如下,其中的 dimension函式 和 value函式 即來自於之前的示例程式碼,在此不再重複列出:

-- 2d convolution, sample f(matrix 3 * 3) and g(matrix 2 * 2), h is convolution result(matrix index is from (0, 0))
-- h(0, 0) = f(0, 0) * g(0, 0)
-- h(0, 1) = f(0, 0) * g(0, 1) + f(0, 1) * g(0, 0)
-- h(0, 2) = f(0, 1) * g(0, 1) + f(0, 2) * g(0, 0)
-- h(0, 3) = f(0, 2) * g(0, 1)
-- h(1, 0) = f(0, 0) * g(1, 0) + f(1, 0) * g(0, 0)
-- h(1, 1) = f(0, 0) * g(1, 1) + f(0, 1) * g(1, 0) + f(1, 0) * g(0, 1) + f(1, 1) * g(0, 0)
-- h(1, 2) = f(0, 1) * g(1, 1) + f(0, 2) * g(1, 0) + f(1, 1) * g(0, 1) + f(1, 2) * g(0, 0)
-- h(1, 3) = f(0, 2) * g(1, 1) + f(1, 2) * g(0, 1)
-- h(2, 0) = f(1, 0) * g(1, 0) + f(2, 0) * g(0, 0)
-- h(2, 1) = f(1, 0) * g(1, 1) + f(1, 1) * g(1, 0) + f(2, 0) * g(0, 1) + f(2, 1) * g(0, 0)
-- h(2, 2) = f(1, 1) * g(1, 1) + f(1, 2) * g(1, 0) + f(2, 1) * g(0, 1) + f(2, 2) * g(0, 0)
-- h(2, 3) = f(1, 2) * g(1, 1) + f(2, 2) * g(0, 1)
-- h(3, 0) = f(2, 0) * g(1, 0)
-- h(3, 1) = f(2, 0) * g(1, 1) + f(2, 1) * g(1, 0)
-- h(3, 2) = f(2, 1) * g(1, 1) + f(2, 2) * g(1, 0)
-- h(3, 3) = f(2, 2) * g(1, 1)

function convolution_2d(f, g)
    local row_1, col_1 = dimension(f)
    local row_2, col_2 = dimension(g)
    if row_1 > 0 and col_1 > 0 and row_2 > 0 and col_2 > 0 then
        local h = {}
        
        local m = row_1 + row_2 - 2
        local n = col_1 + col_2 - 2
        for i = 0, m do
            for j = 0, n do
                local sum = 0
                for k1 = 0, i do
                    for k2 = 0, j do
                        sum = sum + value(f, k1 + 1, k2 + 1) * value(g, i - k1 + 1, j - k2 + 1)
                    end
                end
                h[i + 1] = h[i + 1] or {}
                h[i + 1][j + 1] = sum
            end
        end
        
        return h
    end
end

參考

  1. 如何通俗地理解卷積?(很好的介紹文章,推薦首先閱讀)
  2. 我對卷積的理解
  3. 最容易理解的對卷積(convolution)的解釋