プーリングとコンボリューションの実装
今日もアウトプット。
今日はプーリング層について。
プーリング層
プーリングとは、各プーリング層で対応する値の最大値をとってくる演算のこと。
目的は、過学習の抑制や、位置変化に対しても対応ができるようになる点。
図のほうがわかりやすい。
特徴はおよそ2点
・学習するパラメータがない。
なぜなら、単純にプーリング層に沿って最大値を取るだけだから
チャンネル数は変化しない
プーリングの演算によって、出力チャネルは変わらない
→Convはフィルターの数で出力のチャネル数が変わった
Convolution / Pooling層の実装
畳み込み層やプーリング層の実装はとても複雑である。
なんせ、CNNにおいて、各層に流れるデータは4次元。
(10,2,30,30)で表される。
30×30サイズで2チャンネルのデータが10個あるってこと。
パイソンで実行。
import numpy as np x = np.random.rand(10,2,30,30) print(x.shape) #全チャネルの次元数 print(x[0]) #一つ目のデータの次元数 print(x[0].shape) #(2,30,30) -> 1個目の次元数 print(x[1].shape) #(2,30,30) -> 2個目の次元数
im2colで4次元データを2次元データに
CNNでは、なんせ大量のデータを計算するので、
計算自体やたらめんどくさい。
そんな時は、im2colを使えば難なくクリア。
こいつは中々やり手なやつで、
入力データに対して、フィルターを適用するすべての領域を横方向に展開するって
言われても図で見たほうが早い。
つまりは、3次元(バッチサイズが加わったら4次元)のでーたにたいして、まさかの2次元配列を実行してくれる。
こうすることで、多少のメモリは食うものの、
行列の計算ライブラリを使って、大きな掛け算ができたり、する。
整理しておくと、im2colは3次元配列に対して、
横方向の配列に変換してくれる。
使われる場所は入力データからフィルター(カーネル)に行くときに行列の配列に変えて、更にそこから内積を求めてくれる。
そして、そのままでは全結合層ニューラルネットワークと同じになるので、
そこから4次元になんとリシェイプしてくれる。
パイソンでイメージをつかむためにコードでも記載する
class Convolution: #初期化 def __init__(self,w,b,stride=1,pad=0): self.w = w self.b = b self.stride = stride self.pad = pad #順伝播 def forward(self , x): #重み fn , c , fh , fw = x.shape out_h = int(1 + (h + 2 * self.pad - fh) / self.stride) out_w = int(1 + (w + 2 * self.pad - fw) / self.stride) col = im2col(x , fh , fw ,self.stride , self.pad) #行列変換 col_w = self.w.reshape(fn , -1).T #内積 out = np.dot(col , col_w) + self.b #2次元の配列を4次元に変換 out = out.reshape(n , out_h , out_w , -1).trainspose(0,3,1,2) return out
#プーリング層の実装 """ パラメータを保持しない層で畳み込みを行わない。 その代わり、位置変化に対して対応可能になる。 過学習を抑えることができるのがメリット """ class Pooling: def __init__(self,pool_h , pool_w , stride=1,pad=0): self.pool_h = pool_h self.pool_w = pool_w self.stride = stride self.pad = pad def forward(self , x): n , c , h , w = x.shape out_h = int(1+(h - self.pool_h) / self.stride) out_w = int(1 + (w - self.pool_w) / self.stride) #初期化 col = im2col(x , self.pool_h , self.pool_w,self.stride,self.pad) col = col.reshape(-1,self.pool_h * self.pool_w) out = np.max(col,axis=1) out = out.reshape(n , out_h , out_w,c).transpose(0,3,1,2) return out
コメントとかそろってないけど、ご勘弁。
では、また。