CNN#
畳み込みを使うネットワーク
全結合層の問題点#
画像は縦・横・チャンネル方向の3次元あるが、全結合層に入力するときは1次元にすることになり、形状・位置関係を上手く扱えない。
畳み込み(convolution)層 は形状を維持する
計算#
畳み込み層#
チャネルごとに、カーネル(フィルター) と呼ばれる行列を画像の行列と要素ごとに積をとり、総和をとる
import numpy as np
img = np.array([
[1, 2, 3, 0],
[0, 1, 2, 3],
[3, 0, 1, 2],
[2, 3, 0, 1],
])
ker = np.array([
[2, 0, 1],
[0, 1, 2],
[1, 0, 2],
])
H, W = img.shape
K = ker.shape[0]
conv = np.zeros((H - K + 1, W - K + 1))
for i in range(H - K + 1):
for j in range(W - K + 1):
conv[i, j] = (img[i:i+K, j:j+K] * ker).sum()
conv
array([[15., 16.],
[ 6., 15.]])
パディング#
畳み込みを行う際に、入力データの周囲に固定のデータ(例えば0など)を埋めることがある。これを パディング(padding) という。
パディングにより畳み込み後の行列のサイズを調整できる
import numpy as np
# padding
img = np.array([
[1, 2, 3, 0],
[0, 1, 2, 3],
[3, 0, 1, 2],
[2, 3, 0, 1],
])
H, W = img.shape
img_pad = np.zeros((H+2, W+2))
img_pad[1:-1, 1:-1] = img
img_pad
array([[0., 0., 0., 0., 0., 0.],
[0., 1., 2., 3., 0., 0.],
[0., 0., 1., 2., 3., 0.],
[0., 3., 0., 1., 2., 0.],
[0., 2., 3., 0., 1., 0.],
[0., 0., 0., 0., 0., 0.]])
# 畳み込み後も 4 x 4 を維持
img = img_pad
H, W = img.shape
conv = np.zeros((H - K + 1, W - K + 1))
for i in range(H - K + 1):
for j in range(W - K + 1):
conv[i, j] = (img[i:i+K, j:j+K] * ker).sum()
conv
array([[ 7., 12., 10., 2.],
[ 4., 15., 16., 10.],
[10., 6., 15., 6.],
[ 8., 10., 4., 3.]])
プーリング層#
プーリング(pooling) は縦方向・横方向の空間を小さくする演算
例えば、特定の範囲における最大値を取得する max poolingがある
# 2 x 2 の範囲で最大値をとる
img = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])
K = 2 # 範囲
H, W = img.shape
# 1ずつずらして最大値をとっていく
pool = np.zeros((H - K + 1, W - K + 1))
for i in range(H - K + 1):
for j in range(W - K + 1):
pool[i, j] = np.max(img[i:i+K, j:j+K])
pool
array([[5., 6.],
[8., 9.]])