logo

畳み込み層 📂機械学習

畳み込み層

定義

W\mathbf{W}k×kk \times k行列としよう。Mn×n=Mn×n(R)M^{n\times n} = M^{n\times n}(\mathbb{R})をサイズがn×nn \times nの実数行列の集合としよう。畳み込み層convolutional layerCW:MnnM(nk+1)×(nk+1)C_{\mathbf{W}} : M^{nn} \to M^{(n-k+1) \times (n-k+1)}は次のように定義される関数である。XMn×n\mathbf{X} \in M^{n\times n}Y=CW(X)\mathbf{Y} = C_{\mathbf{W}}(\mathbf{X})に対して、

Yij=[w11w12w1kw21w22w2kwk1wk2wkk][Xi,jXi,j+1Xi,j+k1Xi+1,jXi+1,j+1Xi+1,j+k1Xi+k1,jXi+k1,j+1Xi+k1,j+k1]=q=1kr=1kWqrXi+q1,j+r1 \begin{align*} Y_{ij} &= \begin{bmatrix} w_{11} & w_{12} & \cdots & w_{1k} \\ w_{21} & w_{22} & \cdots & w_{2k} \\ \vdots & \vdots & \ddots & \vdots \\ w_{k1} & w_{k2} & \cdots & w_{kk} \end{bmatrix} \cdot \begin{bmatrix} X_{i, j} & X_{i, j+1} & \cdots & X_{i, j+k-1} \\ X_{i+1, j} & X_{i+1, j+1} & \cdots & X_{i+1, j+k-1} \\ \vdots & \vdots & \ddots & \vdots \\ X_{i+k-1, j} & X_{i+k-1, j+1} & \cdots & X_{i+k-1, j+k-1} \end{bmatrix} \\ &= \sum_{q=1}^{k} \sum_{r=1}^{k} W_{qr} X_{i+q-1, j+r-1} \end{align*}

XijX_{ij}X\mathbf{X}ii行、jj列の成分である。

説明

畳み込み層は、与えられたW\mathbf{W}に対して、X\mathbf{X}2次元離散畳み込みWX\mathbf{W} \ast \mathbf{X}に送る写像である。W\mathbf{W}を呼ぶ言い方は様々で、カーネルkernelフィルターfilterウィンドウwindowなどがある。上の定義では正方行列として定義したが、W\mathbf{W}k1×k2k_{1} \times k_{2}行列として、Mn×nM^{n \times n}Mn1×n2M^{n_{1} \times n_{2}}として一般化して考えても問題ない。畳み込み層で出力を計算するプロセスをアニメーションで見ると以下の通りである。1

畳み込み層と活性化関数を合成した関数を畳み込みニューラルネットワークconvolutional neural network, CNNと呼ぶ。CNNは主にイメージに関連する作業で良い性能を示す。MLPの場合、値が層を通過するたびに全結合層に送られるため、データの次元が大きく層が深いとニューラルネットワークのパラメータが非常に多くなるという短所がある。一方で畳み込み層ではパラメータの数が入力データの大きさに関係なくカーネルのサイズにのみ依存するため、線形層と比較してパラメータの数を劇的に減らすことができるという長所がある。

歴史的には視神経が大脳でどのように作用するかを模倣して提案された。

ストライド

カーネルがWRk×k\mathbf{W} \in \mathbf{R}^{k \times k}で与えられた畳み込み層CWC_{\mathbf{W}}に対して、Y=CW\mathbf{Y} = C_{\mathbf{W}}が以下のように定義されるとき、順序対(s1(s_{1}s2)s_{2})ストライドstrideという。XMn×n\mathbf{X} \in M^{n \times n}に対して、

Yij=q=1kr=1kWqrXs1(i1)+q,s2(j1)+r Y_{ij} = \sum_{q=1}^{k} \sum_{r=1}^{k} W_{qr} X_{s_{1}(i-1)+q, s_{2}(j-1)+r}

このときiijjの範囲は、

i=1,2,,n(k1)s1+1,j=1,2,,n(k1)s2+1 i= 1, 2, \dots, \left\lfloor \frac{n-(k-1)}{s_{1}} \right\rfloor + 1, \quad j=1, 2, \dots, \left\lfloor \frac{n-(k-1)}{s_{2}} \right\rfloor + 1

\left\lfloor \cdot \right\rfloorフロア関数である。

畳み込みを直感的に説明すると、カーネルを1カ所ずつ移動させながらデータX\mathbf{X}と重なる部分に対して内積を行うということである。しかしこの時にカーネルが必ずしも1カ所ずつ動くという法律はない。つまりストライドとはカーネルが1回の動きで進行する距離を意味する。特に言及がなければ通常stride=(1,1)\text{stride} = (1, 1)が基本であり、コードでも通常これがデフォルト値である。

カーネルのサイズがk1×k2k_{1} \times k_{2}、入力行列のサイズがn1×n2n_{1} \times n_{2}、ストライドが(s1,s2)(s_{1}, s_{2})ならば畳み込み層の出力行列のサイズは次のようになる。

(n1(k11)s1+1)×(n2(k21)s2+1) \left( \left\lfloor \frac{n_{1} - (k_{1}-1)}{s_{1}} \right\rfloor + 1 \right) \times \left( \left\lfloor \frac{n_{2} - (k_{2}-1)}{s_{2}} \right\rfloor + 1 \right)

パディング

順序対(p1,p2)(p_{1}, p_{2})に対して、次のような関数、または順序対自体をパディングpaddingという。

padding:Mn×n(R)Mn+2p1×m+2p2(R)X[Op1×p2Op1×mOp1×p2On×p2XOn×p2Op1×p2Op1×mOp1×p2] \begin{align*} \operatorname{padding} : M^{n \times n}(\mathbb{R}) &\to M^{n+2p_{1} \times m+2p_{2}}(\mathbb{R}) \\ \mathbf{X} &\mapsto \begin{bmatrix} O_{p_{1} \times p_{2}} & O_{p_{1} \times m} & O_{p_{1} \times p_{2}} \\ O_{n \times p_{2}} & \mathbf{X} & O_{n \times p_{2}} \\ O_{p_{1} \times p_{2}} & O_{p_{1} \times m} & O_{p_{1} \times p_{2}} \end{bmatrix} \end{align*}

上の形はブロック行列であり、OO零行列である。簡単に言えば行列の上と下に値を追加して埋めることである。パディングを与える理由は畳み込み層の共域Mnk+1×nk+1M^{n-k+1 \times n-k+1}の次元が定義域Mn×nM^{n \times n}の次元より小さいためである。この言葉はある画像を畳み込み層に繰り返して入力すると画像のサイズが徐々に小さくなることを意味する。パディングを与えるとこれを防ぐことができる。畳み込み層にパディングを与えるということは入力X\mathbf{X}と畳み込みCWC_{\mathbf{W}}の間にパディングを合成するという意味である。

CWpadding(X) C_{\mathbf{W}} \circ \operatorname{padding} (\mathbf{X})

つまりあらかじめX\mathbf{X}を拡大しておくことで、CWC_{\mathbf{W}}を通過してサイズが小さくなっても元のサイズを維持できる。kk奇数の時、p=(k1)/2p = (k-1)/2でパディングを与えると入力行列の大きさが変わらない。

上ではパディングを行列の上下左右に00を追加することで定義したが、埋める値が必ずしも00である必要はない。実際にPyTorchには様々な手法のパディングが実装されている。特に00を埋めたパディングをゼロパディングzero paddingという。

カーネルの大きさがk1×k2k_{1} \times k_{2}、入力行列の大きさがn1×n2n_{1} \times n_{2}、ストライドが(s1,s2)(s_{1}, s_{2})、パディングが(p1,p2)(p_{1}, p_{2})ならば畳み込み層CWpaddingC_{\mathbf{W}} \circ \operatorname{padding}の出力行列の大きさは次のようになる。

((n1+2p1)(k11)s1+1)×((n22p2)(k21)s2+1) \left( \left\lfloor \frac{(n_{1} + 2p_{1}) - (k_{1}-1)}{s_{1}} \right\rfloor + 1 \right) \times \left( \left\lfloor \frac{(n_{2} - 2p_{2}) - (k_{2}-1)}{s_{2}} \right\rfloor + 1 \right)

チャンネル

カーネルが行列ではなくテンソルであることもある。W\mathbf{W}が大きさがk×k×ck \times k \times cのテンソルである場合、ccW\mathbf{W}のチャネルchannelという。入力行列のサイズがn×nn \times nでカーネルのサイズがk×k×ck \times k \times cの時、Y=CW(X)\mathbf{Y} = C_{\mathbf{W}}(\mathbf{X})の大きさは(nk+1)×(nk+1)×c(n-k+1) \times (n-k+1) \times cである。函数値は以下のように計算される。

Yij=q=1kr=1kWqrXi+q1,j+r1 Y_{ij\ell} = \sum_{q=1}^{k} \sum_{r=1}^{k} W_{qr\ell} X_{i+q-1, j+r-1}

この時ii, jj, \ellの範囲は、ストライドが(s1,s2)(s_{1}, s_{2})の時、

i=1,2,,n(k1)s1+1,j=1,2,,n(k1)s2+1=1,,c i= 1, 2, \dots, \left\lfloor \frac{n-(k-1)}{s_{1}} \right\rfloor + 1, \quad j=1, 2, \dots, \left\lfloor \frac{n-(k-1)}{s_{2}} \right\rfloor + 1 \\[1em] \ell = 1, \dots, c