この章で学ぶこと:画像は数の表
第6章のミニプロジェクトでは、ニューラルネットワークで手書きの数字を見分けました。テストデータでの正解率は約0.96でした。
実際の画像認識(写真に写っているものを当てる、手書きの文字を読むなど)では、畳み込みニューラルネットワーク (たたみこみ、英語の頭文字で CNN )という形のニューラルネットワークが広く使われています。この章では、CNNの仕組みを、中学数学と第4〜6章で学んだこと(内積、ReLU、誤差逆伝播)だけで組み立てていきます。
最初のレッスンでは、その準備として、コンピュータの中で画像がどう表されているか を確かめます。
画像は、数を並べた表
方眼紙に数字を書き、マスごとに「どれくらい濃く塗られているか」を数で書き込む場面を想像してください。白いマスは0、真っ黒なマスは16のように決めれば、1枚の絵を「数の表」として書き表せます。
第6章で使った手書き数字のデータは、まさにこの形をしています。次の図は、1枚目の画像(数字の0)です。8行×8列のマスに、0〜16の濃さが入っています。
0 1 2 3 4 5 6 7 0 0 0 5 13 9 1 0 0 1 0 0 13 15 10 15 5 0 2 0 3 15 2 0 11 8 0 3 0 4 12 0 0 8 8 0 4 0 5 8 0 0 9 8 0 5 0 4 11 0 1 12 7 0 6 0 2 14 5 10 12 0 0 7 0 0 6 13 10 0 0 0 手書き数字のデータの1枚目。8行×8列のマスに0〜16の濃さが入っている。濃いマス(大きい値)が、数字の0の形の輪になって並んでいる。上と左の小さな数字は、行と列の番号(0から数える) 0行目 0 0 5 13 9 1 0 0 1行目 0 0 13 15 10 15 5 0 2行目 0 3 15 2 0 11 8 0 3行目 0 4 12 0 0 8 8 0 4行目 0 5 8 0 0 9 8 0 5行目 0 4 11 0 1 12 7 0 6行目 0 2 14 5 10 12 0 0 7行目 0 0 6 13 10 0 0 0
手書き数字のデータの1枚目。8行×8列のマスに0〜16の濃さが入っている。濃いマス(大きい値)が、数字の0の形の輪になって並んでいる。上と左の小さな数字は、行と列の番号(0から数える)
濃いマス(大きい値)をたどると、0の形の輪が見えてきます。コンピュータにとっての画像は、この 数の表 そのものです。表の1つ1つのマスを 画素 (がそ、英語で ピクセル )と呼びます。
現実の画像も、同じ仕組み
スマートフォンで撮った写真も、同じように数の表です。違うのは大きさと枚数です。
大きさ: 例えば縦3000×横4000マスなら、1200万マス(「1200万画素のカメラ」の画素は、このマスの数のことです)
枚数: カラーの画像は、赤・緑・青の3色の濃さを、それぞれ別の表で持ちます。表が3枚重なっていると考えてください
出典: Alpaydin, E. & Kaynak, C. (1998). Optical Recognition of Handwritten Digits [Dataset]. UCI Machine Learning Repository. https://doi.org/10.24432/C50P49 ライセンス: CC BY 4.0
NumPyで画像を扱う
scikit-learnの手書き数字のデータには、画像を 8行×8列の表のまま 取り出せる images があります。第3章で学んだNumPyの配列として扱えます。
from sklearn.datasets import load_digits
data = load_digits()
images = data.images
images.shape # → (1797, 8, 8): 1797枚、1枚は8行×8列
image = images[0] # 1枚目の画像(数字の0)
image.shape # → (8, 8)
image[2, 3] # → 2.0
shape は、配列が「何が、いくつずつ並んでいるか」を表します。(1797, 8, 8) は、「8行×8列の表が1797枚」という意味です。
image[2, 3] は、上から2行目・左から3列目のマス の値です。行と列の番号は、どちらも 0から数えます 。一番上の行が0行目、一番左の列が0列目です。書く順番は必ず 行、列 です。値が 2 ではなく 2.0 と表示されるのは、このデータの濃さが小数の形で保存されているためで、値の大きさは同じです。
0 1 2 3 4 5 6 7 0 0 0 5 13 9 1 0 0 1 0 0 13 15 10 15 5 0 2 0 3 15 2 0 11 8 0 3 0 4 12 0 0 8 8 0 4 0 5 8 0 0 9 8 0 5 0 4 11 0 1 12 7 0 6 0 2 14 5 10 12 0 0 7 0 0 6 13 10 0 0 0 1枚目の画像。太い枠のマスが image[2, 3](2行目・3列目)で、値は2。輪の内側に近い、薄いマス 0行目 0 0 5 13 9 1 0 0 1行目 0 0 13 15 10 15 5 0 2行目 0 3 15 2 0 11 8 0 3行目 0 4 12 0 0 8 8 0 4行目 0 5 8 0 0 9 8 0 5行目 0 4 11 0 1 12 7 0 6行目 0 2 14 5 10 12 0 0 7行目 0 0 6 13 10 0 0 0
1枚目の画像。太い枠のマスが image[2, 3](2行目・3列目)で、値は2。輪の内側に近い、薄いマス
第6章では、表を1列に並べ直していた
第6章で使った data.data は、同じ画像を 1行に並べ直したもの です。0行目の8個、1行目の8個、2行目の8個……と、左上から順に64個を並べています。
data.data.shape # → (1797, 64): 1枚は64個の数の並び
data.data[0][:24] # → [0, 0, 5, 13, 9, 1, 0, 0, 0, 0, 13, 15, 10, 15, 5, 0, 0, 3, 15, 2, ...]
1行は8個なので、「r r r 行目・c c c 列目のマス」は、並べ直すと r × 8 + c r \times 8 + c r × 8 + c 番目(0から数える)になります。例えば2行目・3列目は、2 × 8 + 3 = 19 2 \times 8 + 3 = 19 2 × 8 + 3 = 19 番目です。
1列に並べると、「隣のマス」が分からなくなる
画像では、隣り合うマスの関係 に大切な情報があります。線は、濃いマスが縦や横につながったものです。輪は、濃いマスが丸く並んだものです。
ところが、1列に並べ直すと、この関係が見えにくくなります。2行目・3列目(19番目)のマスのすぐ下にあるマスは、3行目・3列目、つまり 3 × 8 + 3 = 27 3 \times 8 + 3 = 27 3 × 8 + 3 = 27 番目です。表の上では隣なのに、並べ直すと8個も離れてしまいます。
実験:マスの並び順を入れ替えても、正解率はほとんど変わらない
第6章のニューラルネットワークが、隣のマスの関係を使っているかどうかを、実験で確かめました。64個のマスの並び順を、すべての画像で同じように でたらめに入れ替えてから、同じ設定で学習し直します。
並び順を入れ替えた1枚目の画像は、次のようになります。人間には、もう0には見えません。
0 0 0 0 1 0 12 9 6 14 13 5 11 8 2 0 15 0 9 0 15 0 13 0 8 0 3 7 11 0 0 0 0 0 8 12 5 0 0 0 4 0 0 8 13 10 0 15 10 0 12 0 0 1 2 5 0 8 4 10 0 5 0 0 1枚目の画像(数字の0)の64個のマスを、決まった順番で入れ替えたもの。濃いマスがばらばらに散らばり、輪の形は見えない 0行目 0 0 0 0 1 0 12 9 1行目 6 14 13 5 11 8 2 0 2行目 15 0 9 0 15 0 13 0 3行目 8 0 3 7 11 0 0 0 4行目 0 0 8 12 5 0 0 0 5行目 4 0 0 8 13 10 0 15 6行目 10 0 12 0 0 1 2 5 7行目 0 8 4 10 0 5 0 0
1枚目の画像(数字の0)の64個のマスを、決まった順番で入れ替えたもの。濃いマスがばらばらに散らばり、輪の形は見えない
それでも、ニューラルネットワークの正解率はほとんど変わりません。第6章のニューラルネットワークは、64個の入力を それぞれ別々の数 として扱っていて、どのマスが隣同士かという情報を使っていないからです。
なぜ、これが問題になるのか
8×8の小さな画像なら、これでも十分に学習できました。しかし、写真のような大きな画像では困ったことが起きます。
重みが多すぎる : 1000×1000マスの画像なら、入力は100万個です。隠れ層のニューロン1つにつき、100万個の重みが必要になります
同じ形を何度も覚え直す : 「縦の線」が画像の左上にあっても右下にあっても、同じ縦の線です。しかし、マスを別々に扱うと、位置ごとに別の重みで覚え直すことになります
次のレッスンからは、小さな範囲の隣り合うマスをまとめて見る 仕組み(畳み込み)を学びます。これが、2つの問題を解決する鍵になります。
よくある誤解
「コンピュータの中に、画像が絵のまま入っている」 : 入っているのは数の表だけです。「絵に見える」のは、画面に表示するときに、数を色の濃さに変えているからです
「ニューラルネットワークは、人間と同じように形を見ている」 : 上の実験のとおり、第6章のニューラルネットワークは、人間には読めない並び順でもほとんど同じように学習できます。人間とは違うやり方で数を扱っています
振り返り
画像は、画素(ピクセル)の濃さを並べた数の表。カラーの画像は3枚の表
NumPyでは image[行, 列] でマスの値を取り出す。番号は0から数える
1列に並べると、隣り合うマスの関係が見えにくくなる。第6章のニューラルネットワークは、この関係を使っていなかった