畳み込みニューラルネットワーク その1


AIって結局何なのかよく分からないので、とりあえず100日間勉強してみた Day69


経緯についてはこちらをご参照ください。



■本日の進捗

  • 畳み込みニューラルネットワークの概要を理解
  • im2colを理解


■はじめに

今回も「ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装(オライリー・ジャパン)」で、深層学習を学んでいきます。

今回からこれまでの基本的なニューラルネットワークから発展させた畳み込みニューラルネットワークを学んでいきます。

■畳み込みニューラルネットワーク

畳み込みニューラルネットワーク(convolutional neural network:CNN)とは、画像データや音声データなどの視覚的で時間的なパターンを効率良く捉えることのできるモデルです。

これまでの全結合層(Affine層)を用いた基本的なニューラルネットワークでは、入力層と出力層の全てのニューロンに接続されるためデータ規模(画像のピクセル数など)が増えると入力層のニューロンも同時に増えてパラメータも増大します。また、形状を無視して入力層の全てのニューロンを同次元のニューロンとして扱うため空間情報が欠落します。

画像データであれば、あるピクセルとその隣り合うピクセルには、例えば目の下に鼻が、鼻の下に口があるように、その関連性には重要な情報が含まれているでしょう。畳み込みニューラルネットワークでは特徴マップ(入力データ)の空間情報をある程度保ったまま取り扱うので画像認識など優れています。

■CNNの処理

CNNでは基本的なニューラルネットワークとは異なった処理を行います。

まず入力データをチャンネル数、縦、横という形状情報を持った特徴マップとして保持します。この特徴マップに対して同様に形状情報を持った(ただし特徴マップより少し小さな)フィルター(またはカーネル)をストライド(stride)と呼ばれる処理で少しずつずらしながら、各位置で内積を繰り返して出力特徴マップを得ます。

An Introduction to Convolutional Neural Networks より引用

出力サイズの調整のために、上記の畳み込み演算を行う前にパディング(padding)と呼ばれる処理で特徴マップの周囲を0で埋めて入力特徴マップのサイズを広げます。

データ形状のサイズで、高さをH、幅をW、パディングをP、ストライドをSとすると、畳み込み演算後のサイズは下記のように記述できます。

$$ H_{out} = \frac{H_{in} + 2P \ – H_{filter}}{S} + 1 $$

$$ W_{out} = \frac{W_{in} + 2P \ – W_{filter}}{S} + 1 $$

■im2col

畳み込み演算でのずらしながらの計算をfor文で処理するとあまり効率的に計算できません。入力画像データを行列に展開して行列計算しやすい形に変換する関数としてim2col(image to column)と呼ばれる良く知られた関数があります。

例えば5×5ピクセルの画像データがあるとします。

任意でパディングを1ピクセル加えると特徴マップは下記のように変換されます。

この特徴マップを3×3サイズのフィルターでストライド1でim2colを実行すると下記のようになります。

この変換を素早く行える形に実装したものがim2col関数です。

まず、データ数(バッチサイズ)をN、チャンネル数(モノクロなら1、RGBなら3)をC、入力画像の高さをH、入力画像の幅をWとして形状を取得します。

N, C, H, W = input_data.shape

先ほどの式で出力サイズを算出します。

out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1

NumPyのpad関数を使ってパディングを追加し、フィルターでスライドする配列を初期化します。

img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

フィルターの高さと幅のインデックスをy, xとして取得し、フィルターのスライドに対応する領域を指定してcol変数に画像データをフィルターサイズに合わせて展開します。

for y in range(filter_h):
    y_max = y + stride * out_h
    for x in range(filter_w):
        x_max = x + stride * out_w
        col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

最後にcol配列の次元を入れ替えて、2次元配列に戻します。

col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)

以上をまとめると、im2col関数は下記のようになります。

def im2col(input_data, filter_h, filter_w, stride, pad):
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1
    out_w = (W + 2*pad - filter_w)//stride + 1

    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    for y in range(filter_h):
        y_max = y + stride*out_h
        for x in range(filter_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    return col




■おわりに

今回は畳み込みニューラルネットワークから、その計算を行うために用いるデータ形式の変換を行う関数を定義しました。

CNNの処理自体は記述していませんが、前処理として大変重要になる処理なので、何を行っているかを理解しておくことは非常に重要です。

■参考文献

  1. Andreas C. Muller, Sarah Guido. Pythonではじめる機械学習. 中田 秀基 訳. オライリー・ジャパン. 2017. 392p.
  2. 斎藤 康毅. ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装. オライリー・ジャパン. 2016. 320p.
  3. ChatGPT. 4o mini. OpenAI. 2024. https://chatgpt.com/
  4. API Reference. scikit-learn.org. https://scikit-learn.org/stable/api/index.html
  5. PyTorch documentation. pytorch.org. https://pytorch.org/docs/stable/index.html
  6. Keiron O’Shea, Ryan Nash. An Introduction to Convolutional Neural Networks. https://ar5iv.labs.arxiv.org/html/1511.08458


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です