深層学習の畳み込み層の処理は「畳み込み」じゃなかった件

畳み込み層の処理は厳密には畳み込みではなかったのか・・・

畳み込み層

畳み込み層の処理

畳み込み層ではインプットの画像データに対して重みを掛けてアウトプットします。この重みをカーネルと呼びます。
実際の計算は図1のようになっています。

f:id:tdualdir:20180501211957p:plain
図1. 畳み込み層の処理
インプットデータの一部にカーネルを適応してその適応された部分で行列の内積を取っています。式でかくと次のようになります。
アウトプットされた行列のi,j成分を O_{i,j},
インプットされた行列のi,j成分を I_{i,j},
カーネルのi,j成分を K_{i,j}とすると
 { \displaystyle O_{i,j}= \sum_m\sum_n I_{i+m, j+n}K_{m,n} \tag{1} }


数学で言うところの畳み込み

畳み込みの定義

2次元の畳み込みは次のように定義されています。
 { \displaystyle (f*g)(a,b)= \int\int g(a-x,b-y)f(x,y)dxdy \tag{2} }
離散値の場合は行列で表現できて
 { \displaystyle (f*g)_{i,j} = \sum_m\sum_n g_{i-m, j-n}f_{m,n} \tag{3} }
となります。

畳み込み層の処理と比較

(1)と(3)は非常に似てますが、(1)では {i+m, j+n}、(3)では {i-m, j-n}となっていて、添え字が違うことに気付きます。
実は(1)の処理は相互相関(cross-correlation)と呼ばれていて畳み込みとは別物です。

相互相関

相互相関と畳み込みの相違点

まずは相互相関と畳み込みの違いを見ます。
以後、簡単のために1次元実数値連続関数を扱います。
1次元実数値連続関数の畳み込み
 { \displaystyle (f*g)(a) = \int_{-\infty}^{\infty} g(a-x)f(x)dx \tag{4} }

1次元実数値連続関数の相互相関
 { \displaystyle (f \star g)(a) = \int_{-\infty}^{\infty} g(a+x)f(x)dx \tag{5} }
((5)の関数が実数値でない場合は f(x)の代わりに複素共役 f^{*}(x)を取る必要がある。)

交換律

畳み込みの重要な性質の一つとして交換律があります。
ここで x' = a-xとすると
\begin{align}
(f*g)(a) &= \int_{-\infty}^{\infty} g(a-x)f(x)dx\\
&= \int_{\infty}^{-\infty} g(x')f(a-x')d(a-x')\\
&= \int_{\infty}^{-\infty} g(x')f(a-x')d(-x')\\
&=\int_{-\infty}^{\infty} f(a-x')g(x')dx' = (g*f)(a)
\end{align}
つまり、
 f*g = g*f と言う交換律が成り立つことがわかります。

しかし、(5)の相互相関の形では交換律は満たしません。

フーリエ変換

畳み込みのフーリエ変換がそれぞれの関数のフーリエ変換の積になってるは有名な定理で、工学などでもよく応用されます。
\begin{align}
F[f*g] &= \int_{-\infty}^{\infty}\left(\int_{-\infty}^{\infty} g(a-x)f(x)dx\right)e^{-ika}da\\
&= \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} g(a')f(x)e^{-ik(a'+x)}dxda'\\
&=\int_{-\infty}^{\infty}f(x)e^{-ikx}dx \int_{-\infty}^{\infty}f(a')e^{-ika'}da' \\
&= F[f] F[g]
\end{align}
式変形の二行目では a - x= a'とした。
これを相互相関でやると
\begin{align}
F[f\star g] &= \int_{-\infty}^{\infty}\left(\int_{-\infty}^{\infty} g(a+x)f(x)dx\right)e^{-ika}da\\
&= \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} g(a')f(x)e^{-ik(a'-x)}dxda'\\
&=\int_{-\infty}^{\infty}f(x)e^{+ikx}dx \int_{-\infty}^{\infty}f(a')e^{-ika'}da' \\
&= F^{*}[f] F[g]
\end{align}
ここでは a + x= a'とした。
フーリエ変換複素共役を取ったものとフーリエ変換に積になっています。(クロススペクトルと言う。)

非常に似た形をしてますが性質の相違点はいくつかあるようです。

相互相関の意味

相互相関の意味ですが、座標aでの二つの関数の類似度を表しています。似てるほど相互相関は大きくなります。
例えば、ノイズに混ざった二つの信号があった場合に相互相関を使ってそれが同じ信号かどうか判断できます。
(参考: https://qiita.com/inoory/items/3ea2d447f6f1e8c40ffa
また、相互相関の性質を利用してフィルターなのども出来ます。

import numpy as np
import matplotlib.pyplot as plt

sig = np.repeat([0., 1., 1., 0., 1., 0., 0., 1.], 128)
sig_noise = sig + np.random.randn(len(sig))
corr = np.correlate(sig_noise, np.ones(128), mode='same') / 128


clock = np.arange(64, len(sig), 128)
fig, (ax_orig, ax_noise, ax_corr) = plt.subplots(3, 1, sharex=True)

ax_orig.plot(sig)
ax_orig.plot(clock, sig[clock], 'ro')
ax_orig.set_title('Original signal')

ax_noise.plot(sig_noise)
ax_noise.set_title('Signal with noise')

ax_corr.plot(corr)
ax_corr.plot(clock, corr[clock], 'ro')
ax_corr.axhline(0.5, ls=':')
ax_corr.set_title('Cross-correlated with rectangular pulse')

ax_orig.margins(0, 0.1)
fig.tight_layout()
fig.show()

出力

f:id:tdualdir:20180502111957p:plain
図3.相互相関を使ったフィルター






畳み込み層に「畳み込み」を適応するとどうなるのか?

畳み込み層に「畳み込み」を適応するとどうなるのか?
結論から言うと何も問題ないです。ニューラルネットワークの層で相互相関と畳み込みの相違点は関係ありません。
ただカーネルの上下左右を反転して学習してるだけです。(このカーネルをフリップカーネルと言います。)
図2の様にインプットのラベルを−1から始めてカーネルを反転すると畳み込みの式と一致してることがわかると思います。

f:id:tdualdir:20180501235156p:plain
図2. 「畳み込み」を適応した畳み込み層の処理


 { \displaystyle O_{i,j} = (f*g)_{i,j} = \sum_m\sum_n I_{i-m, j-n}K_{m,n} \tag{6} }

終わりに

な ぜ Convolutional と 名 付 け た し。
まあ、ただの名前だし、数学の用語が誤用されることはよくあることなのであまり気にしても仕方ないね。

notebookはここに置いときますね。
github.com


ツイッターやっているのでフォローお願いします!
↓今すぐフォローすべきキラキラ アカウント

じゃあの。

参考文献