本文へスキップ
ひもとくAI

ReLUとプーリング

レッスン 4/7

畳み込みの後に、ReLUを通す

CNNの1つの層は、次の3つの計算を順番に行います。

  1. 畳み込み: フィルターを滑らせて、特徴マップを作る(レッスン2・3)
  2. ReLU: 特徴マップの負の数を0にする(このスライド)
  3. プーリング: 特徴マップを小さくまとめる(次のスライド)

このレッスンでは、2と3を学びます。

ReLUは、第6章と同じもの

第6章のニューロンでは、内積とバイアスの後に、活性化関数を通しました。よく使われる活性化関数が ReLU で、「マイナスなら0、プラスならそのまま」(ReLU(z)=max⁡(0,z)\text{ReLU}(z) = \max(0, z))という規則でした。

畳み込みも、窓ごとに内積を計算しているので、1つ1つの位置がニューロンと同じ計算をしていると考えられます(実際のCNNでは、ニューロンと同じく、内積の後にバイアスも1つ足します。フィルター1枚につきバイアスは1つで、レッスン5で数えます)。そこで、第6章と同じように、畳み込みの結果にもReLUを通します。特徴マップの 全部のマスに、1つずつ ReLUを使います。

前のレッスンの手書きの「1」で確かめる

前のレッスンで、数字の1の画像に縦線用のフィルターを使った結果(6×6の特徴マップ)が、次の図です。0から離れているほど濃く塗っています。

0123450-3-38-421845201-18-35-302548172-19-40-293648113-17-41-313748114-3-48-453348155-2-43-46214822
数字の1の画像に、縦線用のフィルターを使った6×6の特徴マップ。左側の0〜2列目は-2から-48の負の数、右側の3〜5列目は11から48の正の数
0行目-3-38-42184520
1行目-18-35-30254817
2行目-19-40-29364811
3行目-17-41-31374811
4行目-3-48-45334815
5行目-2-43-46214822
数字の1の画像に、縦線用のフィルターを使った6×6の特徴マップ。左側の0〜2列目は-2から-48の負の数、右側の3〜5列目は11から48の正の数

左側の負の数は「左が薄く右が濃い」ふち(1の線の左のふち)、右側の正の数は「左が濃く右が薄い」ふち(1の線の右のふち)でした。ReLUを通すと、次のようになります。

012345000018452010002548172000364811300037481140003348155000214822
ReLUを通した後の特徴マップ。左側の0〜2列目はすべて0になり、右側の3〜5列目の正の数(11から48)はそのまま残る
0行目000184520
1行目000254817
2行目000364811
3行目000374811
4行目000334815
5行目000214822
ReLUを通した後の特徴マップ。左側の0〜2列目はすべて0になり、右側の3〜5列目の正の数(11から48)はそのまま残る

負の数がすべて0になり、「左が濃く右が薄い」ふちだけが残りました。このフィルターの出力は、ReLUの後では「この向きのふちが、どれくらい強くあるか」だけを表すようになります。

反対向きのふちも見つけたいときは、どうするのでしょうか。前のレッスンのとおり、CNNはフィルターを何枚も使うので、反対向きのふちに反応するフィルターを別に持てば よいのです。実際のCNNでも、学習によってそのようなフィルターが見つかります。

ReLUを通す理由は、第6章と同じです。活性化関数がないと、層を重ねても全体が1つの一次関数のようなものになってしまい、複雑な形を見分けられません。

プーリング:まとまりごとに、一番大きい値だけを残す

ReLUの後は、特徴マップを 小さくまとめる 計算をします。これを プーリング と呼びます。最もよく使われるのは、次の 最大値プーリング です。

  1. 特徴マップを、重ならないように2×2マスのまとまりに区切る
  2. それぞれのまとまりの中で、一番大きい値 だけを残す

6×6の特徴マップなら、2×2のまとまりが縦に3つ・横に3つできるので、結果は3×3になります。

012345000018452010002548172000364811300037481140003348155000214822
ReLUを通した6×6の特徴マップを、太い線で2×2のまとまり9個に区切ったもの。例えば左上のまとまり(0〜1行目・0〜1列目)は4マスとも0、上の真ん中のまとまり(0〜1行目・2〜3列目)は0, 18, 0, 25
0行目000184520
1行目000254817
2行目000364811
3行目000374811
4行目000334815
5行目000214822
ReLUを通した6×6の特徴マップを、太い線で2×2のまとまり9個に区切ったもの。例えば左上のまとまり(0〜1行目・0〜1列目)は4マスとも0、上の真ん中のまとまり(0〜1行目・2〜3列目)は0, 18, 0, 25
012002548103748203348
最大値プーリングの結果(3×3)。上の行から 0, 25, 48 / 0, 37, 48 / 0, 33, 48。それぞれ、元の2×2のまとまりの中で一番大きい値
0行目02548
1行目03748
2行目03348
最大値プーリングの結果(3×3)。上の行から 0, 25, 48 / 0, 37, 48 / 0, 33, 48。それぞれ、元の2×2のまとまりの中で一番大きい値

例えば、上の真ん中のまとまり(0〜1行目・2〜3列目)は 0,18,0,250, 18, 0, 25 の4マスなので、一番大きい25が残ります。上の右のまとまり(0〜1行目・4〜5列目)は 45,20,48,1745, 20, 48, 17 なので、48が残ります。

なぜ、一番大きい値だけを残すのか

特徴マップの値は、「そのあたりに、フィルターが探している模様がどれだけ強くあるか」を表していました。2×2のまとまりの中で一番大きい値を残すと、「このあたりのどこかに、その模様がある」 という情報は残したまま、「正確にはどのマスか」 という細かい位置の情報を捨てることになります。

  • 数が減る: 36個の数が9個になります。次の層の計算や、重みの数が少なくて済みます
  • 小さなずれに少し強くなる: 模様が1マスずれても、同じまとまりの中に収まっていれば、プーリングの結果は変わりません

ただし、「少し」強くなるだけです。ずれがまとまりの境目をまたぐと、結果は変わります。どれくらい強くなるかは、レッスン7の実験で、実際の数値で確かめます。

NumPyでReLUとプーリングを書く

ReLUは、NumPyの np.maximum を使うと1行で書けます。np.maximum(配列, 0) は、配列の全部のマスで、そのマスの値と0を比べて大きい方を残します。第6章の式 max⁡(0,z)\max(0, z) を、全部のマスにまとめて使う計算です。

import numpy as np

fmap = np.array([[-3, 18],
                 [25, -40]])
np.maximum(fmap, 0)    # → [[0, 18], [25, 0]]

最大値プーリングは、畳み込みと同じく2重の for 文で書けます。違いは、窓を 1マスずつではなく、2マスずつ 動かすことと、窓の中で 一番大きい値 を取り出すことです。

def max_pool(fmap):
    h, w = fmap.shape
    out = np.zeros((h // 2, w // 2))       # 縦も横も半分の大きさ
    for i in range(h // 2):
        for j in range(w // 2):
            window = fmap[2*i:2*i+2, 2*j:2*j+2]   # i番目・j番目の2×2のまとまり
            out[i, j] = window.max()             # その中の一番大きい値
    return out
  • h // 2 は、割り算の答えの整数の部分です(6 // 2 は 3)
  • i 番目のまとまりは、2*i 行目から2行分です。i = 0 なら0〜1行目、i = 1 なら2〜3行目、i = 2 なら4〜5行目と、2行ずつ進みます
  • window.max() は、配列の中で一番大きい値です

よくある誤解

  • 「プーリングにも、学習で決まる重みがある」: 最大値プーリングは、決まった規則(一番大きい値を残す)で計算するだけで、重みはありません。学習で調整されるのは、畳み込みのフィルターの方です
  • 「プーリングで情報が減るのは、よくないこと」: 捨てているのは「正確にはどのマスか」という細かい位置の情報です。数字を見分けるには、「このあたりに縦線がある」が分かれば十分なことが多く、数が減ることで計算も軽くなります
  • 「最大値ではなく、平均をとってもまったく同じ」: 平均をとる 平均値プーリング もありますが、結果は違います。弱い反応が混ざると、強い反応が薄まってしまいます。模様があるかどうかを見るには、最大値プーリングがよく使われます。なお、特徴マップ1枚の全部のマスの平均を1つの数にする Global Average Pooling(大域平均プーリング)は、最近のCNNで、最後の層の手前によく使われます

受容野:出力の1マスは、画像のどの範囲を見ているか

出力の1マスの値が、元の画像のどの範囲のマスから計算されたかを、そのマスの 受容野(じゅようや)と呼びます。

  • 3×3の畳み込みの出力の1マスは、画像の3×3の範囲を見ています
  • その後の2×2の最大値プーリングの1マスは、畳み込みの出力の4マスを見ています。この4マスは、画像の中で1マスずつずれた3×3の範囲を見ているので、4つの範囲を合わせると、画像の4×4の範囲を見ていることになります

層を重ねるほど、1マスが見る範囲は広がります。最初の層は短い線のような小さな模様を、後ろの層ほど大きな形を見つけられるのは、このためです。

CNNの手本になった、脳の研究

1950〜60年代に、ヒューベルとウィーゼルは、ネコの脳の、目から入った情報を処理する部分を調べました。そして、決まった位置の、決まった向きの線にだけ反応する 単純型細胞 と、線の位置が少しずれても反応する 複雑型細胞 があることを見つけました。単純型細胞は畳み込み(決まった模様を探す)、複雑型細胞はプーリング(少しのずれを気にしない)に似ています。この仕組みを手本に、1980年に福島邦彦が発表した ネオコグニトロン が、CNNの原型だと言われています。

振り返り

  • CNNの1つの層は「畳み込み → ReLU → プーリング」
  • ReLUは、特徴マップの全部のマスで、負の数を0にする(第6章と同じ)
  • 最大値プーリングは、2×2のまとまりごとに一番大きい値を残す。縦も横も半分になり、重みはない

演習

演習を読み込んでいます…