(Deep Learning) CIFAR-10で正解率90%を目指す(1~3日目)

結構ラフな感じで記事を書いた。ぜひラフな気持ちで読んでいただければと思う。

1日目

1日目は目的・背景・評価基準を明確にし、単純なDNNをトレーニングし解析すること。

目的と背景

今まではMNISTデータを中心に扱い、参考書を使用しながらモデルを構築・トレーニングさせたが、自ら目標を設定してオリジナルのモデルを構築することは一切していないため飽きが来た。知識もある程度ついてきたところで、自ら目標を設定し試行錯誤しながら目的を達成させる経験を積みたいと思った。

評価基準

評価基準は単純だ。題に示している通り、画像のデータセットであるCIFAR-10を使用して、テストデータにおける正解率90%を達成することである。なぜ90%にしたのかというと、90%以上の正解率を実現している先駆者が多くいることから実現不可能でない、程よい目標と考えたためだ。

CIFAR-10について簡単に

クラスは10種類(飛行機、自動車、鳥、猫、鹿、犬、カエル、馬、船、トラック)、32×32のRGBカラー画像となっていて、一枚の画像に含まれる数値の数は、32x32x3=3072である。画像の数は、60000枚で、学習&検証用は50000枚、テスト用が10000枚ある。

ここからが今回の本題

先に以降で説明するプログラムを示しておきます。本文中ではプログラムコードについてあまり触れない。

1日目にすること

畳み込みニューラルネットワーク等を使用せずに、DNNでどこまで正解率が得られるかを確かめる。

作成したモデル

モデルの名前はオリジナルだが、内容が極力推察しやすいような名前にした。

  • ThreeLNN_model
    入力層のノード数が3,072個、中間層のノード数が10,000個、出力層のノード数が10個の3層ニューラルネットワーク。
  • ThreeLNN_model_big
    ThreeLNN_modelよりも中間層のノード数を増やしたモデルで、中間層のノード数が100,000個の3層ニューラルネットワーク。
  • ThreeLNN_model_small
    ThreeLNN_modelよりも中間層のノード数を減らしたモデルで、中間層のノード数が1,000個の3層ニューラルネットワーク。
  • ThreeLNN_model_drop
    ThreeLNN_modelの中間層にドロップアウトを適用したモデル。
  • FourLNN_model
    2つの中間層のノード数が各々、1,000個の4層ニューラルネットワーク。
  • FourLNN_model_drop
    FourLNN_modelの各中間層にドロップアウトを適用したモデル。
  • MyLNN_model_1
    私が適当に定義した深層ニューラルネットワーク(DNN)で説明は後述。

結果

以下ではモデルのsummary()、訓練&検証時の正解率・誤差関数の値のグラフを同時に示す。

ThreeLNN_model

図1
図2

合計パラメータ数は30,830,010個。

グラフから分かる代表的なことを以下に箇条書きで示す。

  • 訓練が進むにつれ訓練データの正解率は増加し続ける。
  • 訓練が進んでも検証データの正解率は50%付近で改善が見られない。
  • 訓練が進むにつれ訓練データの誤差関数の値は減少し続ける。
  • 訓練が進んでも検証データの誤差関数の値は1.5付近で改善が見られない。エポックが40回目あたりからグラフが上昇し始めており微妙ではあるが過学習になっている。

雑談だが単純計算で、合計パラメータ数30,830,010×4バイト(float32)÷1000000=123.3MBなので、シングルボードコンピュータのNanoPiでも実装できる大きさのモデルであることが分かる。

ThreeLNN_model_big

図3
図4

合計パラメータ数は308,300,010個。ThreeLNN_modelと同じく50%付近で正解率が停滞している。ThreeLNN_modelの結果を重ねて可視化してみる。

図5

中間層のノード数を増やしたことでモデルのキャパが上がり過学習が悪化した。この場合、中間層のノード数を増やしたことに利点はなさそう。

中間層のノード数が多いモデルの方が、検証データの正解率が50%に到達する時間が微妙に短く、また過学習に陥る速さもはやい。

ThreeLNN_model_small

ここは好奇心で中間層のノード数を減らしてみる。

図6
図7

やはり、検証データの正解率が50%付近で停滞している。

ThreeLNN_model_drop

図8
図9

上のグラフから読み取れることを箇条書きで示す。

  • 検証データを入力したときの正解率のグラフの方が訓練データの正解率のグラフより上に位置している。つまり、検証データの正解率のほうが高い。これは、検証時にドロップアウトが適用されず、アンサンブル学習による予測器になっているためだと考えられる。
  • 誤差関数のグラフを見る限り上昇は見られず、過学習は起こっていないと考えられる。
  • しかし、やはり正解率は50%付近で停滞してしまっている。

FourLNN_model

図10
図11

以前のモデルと比べてグラフからは特に改善は無し。一方で注目すべき点がある。一番最初に示したThreeLNN_modelの合計パラメータ数30,830,010個よりも、今回のモデルFourLNN_modelの合計パラメータ数4,084,010個のほうが圧倒的に少ないにもかかわらず、過学習の度合いが悪化している。ここから、パラメータ数が少なくても、多層にすることでモデルの表現能力、つまりキャパシティは上昇するといえる。

FourLNN_model_drop

図12
図13

ドロップアウトを適用したら過学習は改善されている。しかし、検証データの正解率50%の壁は破れない。

MyLNN_model_1

このモデルは、過学習覚悟で、さらに深層にしても検証データの正解率50%付近脱却ができないのかを確かめるべく実験した。2・4層目はLeakyReLUを使用してみた。

図14
図15

やはり過学習が悪化しただけだった。訓練データについてはもはや正解率100%に届きそうな感じである。

考察

一応ここまでの結果で学んだことを箇条書きでまとめておきたいと思う。

  • 入力次元の数、出力次元の数および全パラメータ数が同じ2つのニューラルネットワークを用意した時、深層にすると過学習が顕著になる。深層学習になればなるほど非線形写像を何度も繰り返すため、モデルの表現能力が上昇することは納得できるが疑問も残る。
    • 深層にして表現能力を上げても、なぜ検証データでの正解率50%の壁を抜けられないのか?
    • 深層にすることで訓練データに対する適応能力、つまり細かな部分まで覚える能力(つまり過学習)は上昇しても、データの本質的な特徴を学習する能力は深層にしても大きく上昇しないのか!?
  • ドロップアウトを適用することで過学習を防ぐことができる。検証時およびテスト時はアンサンブルによる予測器となるため、正解率が検証時よりも高くなる傾向がある。
  • 深層学習にすると訓練データにおける正解率が高くなるため、上手くいったように錯覚してしまいがちになる。そのため、最初は表現能力の高くないモデル(3層NNなど)で得られる能力を測ってから深層にしていく方がよさそうだ。

2日目

今回はオートエンコーダによる事前学習がどの程度モデル全体の学習に影響するか確認することが目的になるが、これは建前で本音はオートエンコーダを使ってみたいな~といったところ。昔は勾配消失問題により低次の層まで学習が行えず、結果として出力層に近い部分でのみ学習が行われ、深層にする効用が得られなかったため、オートエンコーダによる事前学習である程度次元圧縮&特徴抽出したうえでニューラルネットワークを上層に追加する形で深層学習を実現させていた。現在ではReLUが活性化関数で使用され、これは正の領域で微分が1であり、何度も層を経ても勾配が消失する心配がなく、深層学習が可能になった。現在ではオートエンコーダを使用する理由はほぼないと思われるし、1日目の最後に行った深層ニューラルネットワークとほぼ同じようなグラフが描画されるのではないか。

作成したモデル

細かいモデルの説明は端折る。

  • AutoEncoder_3072_100_3072
    入力次元数3072を100次元にエンコードし、再度3072次元にデコードするニューラルネットワーク。これは試しに行っただけであり、今回のメインは以下で定義する各々のエンコーダーを積層にしたスタックドオートエンコーダ(積層自己符号化器:以下SAE)である。
  • enc (モデルをリストでまとめたもの)
    SAEを構築するために用意。
  • dec (モデルをリストでまとめたもの)
    対応するencを学習させるためのデコーダユニット。
  • model (モデルをリストでまとめたもの)
    任意のencと対応するdecを一つにまとめてネットワークモデルにしたもの。
    これで学習したもののエンコーダ部分のみを取り出し、あとで結合しSAEを構成したのち、識別機を上位に加えDNNモデルを構築する。
  • DNN
    SAEに識別器として3層ニューラルネットワークを追加したもの。

結果

AutoEncoder_3072_100_3072

図16
図17

図17の一行目の画像はCIFAR-10そのもので、二行目は図16のencoding_layerの出力となっている。三行目はdecoding_layerの出力である。1行目と3行目を比べると元の画像の雰囲気は残っているが、何の画像かは分からない。

enc (モデルをリストでまとめたもの)

特に解説するほどのものではない。SAEを構築するために必要だった。プログラムを見ていただければわかると思う。

dec (モデルをリストでまとめたもの)

特に解説するほどのものではない。SAEを構築するために必要だった。プログラムを見ていただければわかると思う。

model (モデルをリストでまとめたもの)

特に解説するほどのものではない。SAEを構築するために必要だった。 プログラムを見ていただければわかると思う。

DNN

図18

1日目の深層全結合ニューラルネットワークの結果とほぼ同じになっている。ReLUが登場するまでは、シグモイド関数や双曲線正接関数が活性化関数として使用され、低次の層まで勾配が届かない(勾配消失問題)ため、オートエンコーダによる事前学習でDNNを実現させていたが、ReLUが使用されるようになって以降、勾配消失問題が大きな問題にならなくなったため、オートエンコーダによる事前学習に大きな利点があるわけではなくなっていることが改めて見て取れる。

考察

特になし

はじめてオートエンコーダをコーディングしたので、考察できるほどまだ知識と経験がありません。今回は貴重な経験として記憶にしまっておきます。

3日目

もう少しだけオートエンコーダで遊んでみる。

訓練後のオートエンコーダにオリジナルの絵を入力すると、画像を加工して出力してくれるため試した。使用するオートエンコーダは、2日目に使用したSAEのモデルに積層デコーダを追加したモデルで、3072次元-2304次元-1024次元-400次元-100次元-25次元-100次元-400次元-1024次元-2304次元-3072次元のニューラルネットワークである。各層で独立に訓練したものを、kerasのFunctional APIで結合した。

結果

入力した画像はペイントで適当に描いた、車・飛行機・猫の絵である。ひどい絵だ…。というのも、ピクセル数が少なすぎて、綺麗に描く気がおきなかったのが主な原因だが…。

図19

図19の3枚を、各々で学習したオートエンコーダとデコーダを結合しただけのSAEに入力して得られた3枚の画像が図20になる。うん…!? 全く学習できていない!?

図20

取り合えず、気にせずSAEをx_trainでモデル全体をトレーニングした。先ほどは単に合体させただけのSAEだったが、トレーニング後のSAEの出力は図21のようになった。

図21
  • (左):なんとなく車と分かる。
  • (中):飛行場の飛行機を正面から撮った感じかな?
  • (右):何かの動物っぽい。

元の画像と比較すると写真っぽく修正された感じはする。左の出力は車と分かるが、真ん中と右は無理があるかも。私の作成した画像が悪かった可能性を否定できないが、32×32の画像では表現力に無理があるため、この程度で終わりにする。

疑問

SAEを全体で学習しなおすことでまともになったが、オートエンコーダを各々独立で学習させて合体させたモデルの出力が全く的を射ていないが、果たしてオートエンコーダとして役に立ったのか?SAEの再学習は下手したらデコーダの部分のみ行われた可能性もある。要するに、全体を学習する前のSAEと学習後のSAEにおいてノード数が25個の層の出力(符号)に変化があったのかどうか。

確認したかったがFunctional APIで結合したモデル以外に、結合に使用したencとdecのモデルの方を保存しないといけないことを知らず、Google Colabの接続が切れて確認できず。諦める。

考察

なし。経験を積んだ。この程度でお許しを。

Follow me!