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

まとめ・ミニプロジェクト:CNNで手書き数字を見分ける

レッスン 7/7

この章の振り返りと、ミニプロジェクト

この章では、画像を見分けるのに向いたニューラルネットワーク、CNNを、部品から組み立てました。

  1. 画像は数の表。普通のニューラルネットワークは、どのマスが隣同士かという情報を使っていなかった
  2. 畳み込みは、窓を滑らせながら、窓の中とフィルターの内積を並べていく計算
  3. フィルターの数を工夫すると、縦線・横線などの模様を見つけられる。CNNでは、フィルターの数は学習で決まる重み
  4. ReLUとプーリングで、負の数を0にし、2×2のまとまりごとに一番大きい値を残して小さくまとめる
  5. 重みの共有で、フィルターを画像のすべての位置で使い回すので、重みが少なくて済む
  6. ソフトマックス関数で点数を確率に変え、交差エントロピーを誤差逆伝播で小さくして学習する

使った数学は、内積(第4章)、ReLU(第6章)、最大値、eze^z(第5章)、変化の割合の掛け算(第6章)と、どれもこれまでに学んだものでした。

ミニプロジェクト:CNNで手書き数字を見分ける

次の演習では、この章の部品を組み合わせたCNNを、NumPyだけで学習させます。部品のコード(畳み込み・ReLU・プーリング・ソフトマックス・誤差逆伝播)は用意してあり、各行に、この章のどのレッスンの計算かを書いてあります。自分で埋めるのは、第5章・第6章と同じ「前処理 → 分割 → 学習 → 評価」の流れの部分です。

  • フィルター16枚、2×2の最大値プーリング、15周の学習(32枚ずつ)
  • 重みとバイアスは1,610個(レッスン5)
  • 学習にかかる時間は数秒です

この設定で学習させると、テストデータでの正解率は約0.94になります。第6章の普通のニューラルネットワーク(約0.96、重み2,410個)とほぼ同じくらいの正解率を、少ない重みで出せます。

出典: 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

実験:CNNは、位置のずれに強いのか

CNNの説明では、よく「CNNは、画像の中の位置のずれに強い」と言われます。重みの共有(同じフィルターをどこでも使う)とプーリング(細かい位置を捨てる)があるからです。本当にそうなのか、実験で確かめました。

テストデータの画像を 右に1マスずらして(左端の列は0で埋める)、正解率がどう変わるかを測ります。

モデルそのまま右に1マスずらす
第6章の普通のニューラルネットワーク0.9640.431
この章のCNN(ミニプロジェクトと同じ)0.9360.453

どちらも大きく崩れました。 CNNの方が少しだけよいものの、たった1マスずれただけで、半分以上を間違えるようになります。

「CNNは位置のずれに強い」を、そのまま信じると誤解になります。ずれに強くなるのは、プーリングのまとまりの中に収まる、ごく小さなずれだけです。また、学習データの数字は、すべて枠の中央にそろえてありました。CNNは「中央にある数字」しか見たことがないのです。

ずらした画像でも学習させる

そこで、訓練データの画像を上下左右に1マスずつずらしたものを作り、元の画像と合わせて5倍の枚数で学習させました。このように、手元のデータを少し変えて学習データを増やす方法を、データ拡張 と呼びます。

テスト画像のずらし方普通に学習したCNNずらした画像でも学習したCNN
そのまま0.9360.980
右に1マス0.4530.962
下に1マス0.53くらい0.92くらい
右下に1マス0.22くらい0.73くらい
右に2マス0.11くらい0.47くらい

(「くらい」を付けたものは、乱数の種を3通りに変えて学習した結果の平均に近い値です)

ずらした画像でも学習すると、1マスのずれにはとても強くなりました。そのままの画像の正解率も上がっています。ただし、学習で見せていない2マスのずれには、まだ弱いままです。

分かること

  • モデルが強くなるのは、学習データで見たことのある変化に対してだけ
  • 「どんな変化に強くしたいか」を考えて、学習データを用意することが大切

このことは、画像に限らず、機械学習全体に言える大切な考え方です。

自分で書いた数字を判別してみよう

この章のCNNで、自分で書いた数字を判別できます。下の枠に、指やマウスで0〜9の数字を1つ書いてください。書き終わると、判別の結果が出ます。

ここに数字を1つ書く

コンピュータに見えている8×8

1マスずらす:

書いた数字は、このように8×8の濃さ(0〜16)に変えてから判別します。マス目をクリックするか、矢印キーで移動してスペースキーを押すと、マスの濃さを 0 → 8 → 16 と変えられます。書いた絵は、どこにも送りません。

判別に使うモデル

数字を書くか、見本を選ぶと、ここに結果が出ます

第7章のCNN(フィルター16枚)で判別します。学習の方法が違う2つのモデルを切り替えて、結果を比べられます。

書いた数字は、どう処理されているか

書いた線は、そのままではCNNに入力できません。学習データと同じ形にそろえてから判別します。

  1. 書いた部分を切り出し、縦横の比を保ったまま、高さを枠いっぱいにそろえて中央に置く
  2. 線の太さを、学習データの平均と同じくらいの濃さになるように描き直す
  3. 4×4の小さな点のまとまりごとに黒い点を数えて、8×8(濃さ0〜16)にする

書く枠の横(スマホでは下)の「コンピュータに見えている8×8」が、実際にCNNに入力している絵です。学習データの作り方(元のデータの説明に書かれている方法)をまねています。

試してみてほしいこと

  • 書き方を変える: 大きく・小さく、太く・細く、傾けて書くなどして、結果がどう変わるかを見てみましょう。上の処理の1のとおり、大きさと位置は自動でそろえるので、枠の端に小さく書いても結果はあまり変わりません
  • ずらしてみる: 「1マスずらす」のボタンで、8×8の絵をずらします。「普通に学習したモデル」と「ずらした画像でも学習したモデル」を切り替えて、前のスライドの実験の結果を自分の目で確かめましょう。例えば、見本の「数字の0(1枚目)」を選んで「左へ」を1回押すと、普通に学習したモデルは2と答えますが、ずらした画像でも学習したモデルは0と正しく答えます
  • マス目を塗る: マス目をクリックするか、矢印キーで移動してスペースキーを押すと、マスの濃さを変えられます。どのマスを変えると結果が変わるかを調べてみましょう

思ったより当たらないときは

自分で書いた数字は、テストデータの正解率(0.94〜0.98)ほどは当たらないかもしれません。学習データは、43人が決まった用紙に書いた数字を、決まった手順で8×8にしたものです。画面に指で書いた線は、太さ・形・書き癖が違います。学習データと違う種類のデータには弱い ことは、前のスライドの「ずれ」の実験と同じで、実務でもよく起きる問題です。

書いた絵は、このブラウザの中だけで使います。どこにも送らず、保存もしません。

よくある誤解と、この先へ

よくある誤解

  • 「CNNは、位置のずれに強い」: 1マスずれただけで、正解率は約0.94から約0.45に下がりました。強くなるのは、プーリングのまとまりに収まるごく小さなずれや、学習データで見たことのあるずれだけです
  • 「テストデータで正解率0.98なら、どんな手書き数字でも98%当たる」: テストデータは、学習データと同じ人たち・同じ方法で作ったものです。書く人や方法が変わると、正解率は下がります。「テストデータの正解率」は、「学習データと似たデータでの正解率」だと考えましょう
  • 「データ拡張をすれば、どんな変化にも強くなる」: ずらした画像で学習しても、2マスのずれにはまだ弱いままでした。強くなるのは、学習データに加えた種類の変化だけです

振り返り

  • CNNは「畳み込み → ReLU → プーリング」で画像の模様を見つけ、最後の層とソフトマックスで確率を出す
  • 前処理・分割・学習・評価の流れは、どのモデルでも同じ
  • モデルは、学習データで見たことのある変化にしか強くならない。データ拡張で、強くしたい変化を学習データに入れる

この先へ

実務で使われるCNNは、この章のCNNを大きくしたものです。

  • 「畳み込み → ReLU → プーリング」の組を何回も重ねる(層が深いほど、線 → 角や曲線 → 部品 → 物全体、のように複雑な模様を見つけられる)
  • カラーの画像では、フィルターも赤・緑・青の3枚分の重みを持つ
  • 学習の計算は、レッスン6で見たPyTorchなどのライブラリに任せる

中身は、この章で自分の手で計算した部品と同じです。例えば、ミニプロジェクトの windows 関数は、画像の窓の中身をすべて横に並べた大きな表を作り、畳み込みを @(行列の積)1回で計算できるようにしていました。この工夫は im2col(image to column、画像を列に並べる)と呼ばれ、実際のライブラリでも使われている方法です。

いろいろなデータ拡張

この章では「ずらす」データ拡張を試しました。画像のデータ拡張には、ほかにも次のようなものがあります。

  • 左右や上下を反転する(Flip)、少し回転する(Rotate)、一部を切り抜いて使う(Crop)
  • 明るさ(Brightness)やコントラスト(Contrast)を変える、一部を塗りつぶす(Erase)、少しノイズを加える
  • 2枚の画像と正解を、割合を決めて混ぜ合わせる(MixUp)

ただし、見分けたいものが変わってしまう変化は使えません。例えば数字の画像を左右反転すると、2や3は数字ではない形になり、上下を反転すると6が9のように見えてしまいます。「どんな変化なら、正解が変わらないか」を考えて選ぶことが大切です。

演習

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