eyecatch
Sun, Mar 25, 2018

機械学習のHello World: MNISTの分類モデルをKerasで作ってみた

機械学習のHello WorldとしてよくやられるMNISTの分類モデルをKeras on TensorFlowで作ってみた話。 (adsbygoogle = window.adsbygoogle || []).push({}); MNISTとは 手書き数字画像のラベル付きデータセット。 6万個の訓練データと1万個のテストデータからなる。 CC BY-SA 3.0で配布されているっぽい。 一つの画像は28×28ピクセルの白黒画像で、0から9のアラビア数字が書かれている。 画像とラベルがそれぞれ独特な形式でアーカイブされていて、画像一つ、ラベル一つ取り出すのも一苦労する。 Kerasとは Pythonのニューラルネットワークライブラリ。 バックエンドとしてTensorFlowかCNTKかTheanoを使う。 今回はTensorFlowを使った。 やったこと KerasのMNISTのAPIとかコードサンプルとかがあけどこれらはスルー。 MNISTのサイトにあるデータセットをダウンロードしてきて、サイトに書いてあるデータ形式の説明を見ながらサンプルを取り出すコードを書いた。 で、KerasでVGGっぽいCNNを書いて、学習させてモデルをダンプして、ダンプしたモデルをロードしてテストデータで評価するコードを書いた。 コードはGitHubに。 ネットワークアーキテクチャ 入力画像のサイズに合わせてVGGを小さくした感じのCNNを作った。 VGGは2014年に発表されたアーキテクチャで、各層に同じフィルタを使い、フィルタ数を線形増加させるシンプルな構造でありながら、性能がよく、今でもよく使われるっぽい。 VGGを図にすると以下の構造。 実際はバッチ正規化とかDropoutもやるのかも。 プーリング層は数えないで16層なので、VGG-16とも呼ばれる。 パラメータ数は1億3800万個くらいで、結構深めなアーキテクチャ。 VGG-16は244×244×3の画像を入力して1000クラスに分類するのに対し、MNISTは28×28×1を入れて10クラスに分類するので、以下のような7層版を作った。 これでパラメータ数は27万個くらい。 訓練データのサンプル数が6万個なので、パラメータ数が大分多い感じではある。 コードは以下。 inputs: Tensor = Input(shape=(IMAGE_NUM_ROWS, IMAGE_NUM_COLS, 1)) x: Tensor = Conv2D(filters=8, kernel_size=(2, 2), padding='same', activation='relu')(inputs) x = Conv2D(filters=8, kernel_size=(2, 2), padding='same', activation='relu')(x) x = MaxPooling2D(pool_size=(2, 2))(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = Conv2D(filters=16, kernel_size=(2, 2), padding='same', activation='relu')(x) x = MaxPooling2D(pool_size=(2, 2))(x) x = Flatten()(x) x = Dense(units=256, activation='relu')(x) x = Dense(units=256, activation='relu')(x) predictions: Tensor = Dense(NUM_CLASSES, activation='softmax')(x) model: Model = Model(inputs=inputs, outputs=predictions) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) 訓練・評価 上記モデルを6万個のサンプルでバッチサイズ512で一周(1エポック)学習させると、Intel Core i5-6300HQプロセッサー、メモリ16GBのノートPCで28秒前後かかる。 とりあえず3エポック学習させてみる。 (ml-mnist) C:\workspace\ml-mnist>python bin\ml_mnist.py train Using TensorFlow backend.
eyecatch
Fri, Jan 12, 2018

CourseraのDeep Learning SpecializationのImproving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimizationコースを修了した

CourseraのDeep Learning SpecializationのNeural Networks and Deep Learningコースを修了したのに続き、Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimizationコースを修了した。 (adsbygoogle = window.adsbygoogle || []).push({}); このコースは、ディープニューラルネットワークのチューニングなどについて学べる3週間のコース。 今のところ全部英語。 2018/1/5に始めて、1/12に完了。 8日間かかった。 修了したらまたCertifacateもらえた。 以下、3週分の内容をメモ程度に書いておく。 1週目 OverfittingやUnderfittingを防ぐテクニックについて。 動画 データ分割 深層学習のモデル構築は、検討(Idea)、実装(Code)、検証(Experiment)というサイクルの繰り返し(Iterative process)。 取り組む課題、課題のドメイン、データ量、マシンの構成などにより、ハイパーパラメータは変わるので、経験をもって事前に予測することは無理なので、サイクルをどれだけ速く回せるかが鍵。 データは、訓練データ(Training set)、Devデータ(Development set))(a.k.a. Cross-validation set)、テストデータ(Test set)に分割する。 訓練データで学習し、Devデータでハイパーパラメータを評価し、テストデータで最終的な評価と性能見積をする。 テストデータは無くてもいい。 サンプル数が1万くらいだった時代は、6:2:2くらいで分割してたけど、近年は数百万とかのデータを扱い、交差検証データやテストデータの割合はもっと小さくするのがトレンド。 98:1:1など。 Devデータとテストデータは同じようなものを使うべき。 訓練データは必ずしも同様でなくてもいい。訓練データは沢山要るので、別のデータソースからとることもある。 バイアス vs バリアンス でかいネットワークで正則化して大量データで学習させるのが吉。 正則化 過学習(Overfitting)を防ぐため、コスト関数を正則化(Regularization)すべし。 ロジスティック回帰ではL2ノルム(L2 norm)を使ったL2正則化が一般的。 L1正則化はあまり使われない。 L1正則化をすると、wがスパース行列になってモデルを圧縮できると言われることがあるが、経験上その効果はほとんどない。 正則化パラメータλはハイパーパラメータで、Devデータで評価する。 ニューラルネットワークでは正則化項にフロベニウスノルム(Frobenius norm)を使う。 Dropout(Inverted Dropout) ランダムにノードを無効化しながら学習することで過学習を防ぐ。 画像処理の分野では、特徴量の数が多く学習データが少ない傾向があるので、ほぼ常に使われる。 コスト関数が計算できなくなるのが欠点。 計算する必要があるときにはDropoutを無効化する。 データ拡張(Data augmentation) データを加工して増やせば、高バリアンス対策になる。 早期終了(Early stopping) 過学習するまえに学習を止めるテクニック。 訓練データとDevデータについてコストをプロットして、Devデータのものが上がる前に止める。 これは、直交化(Orthogonalization)の原則、つまり一度に一つのことを考慮すべきという原則に反していて、コストを最小化するという問題と、過学習を避けるという問題に同時に対処することになるので微妙。 普通は代わりにL2正則化使えばいいけど、λを最適化する手間を省きたいときには選択肢になりうる、というか実現場ではちょくちょく選択肢になる。 訓練データの正規化(Normalization) 訓練データの各特徴量について平均を0にして分散を1にすると学習が速くなる。 訓練データを正規化したらテストデータも正規化する。 その際、正規化パラメータは訓練データのものを使う。 勾配消失(Vanishing gradient)、勾配爆発(Exploding gradient) ニューラルネットワークの層が深くなると、層の出力や勾配が指数関数的に大きくなったり小さくなったりして、学習が難しくなる問題。 長年ディープニューラルネットワークの発展を妨げてきた問題。 パラメータのランダム初期化をすると防げる。 ガウス分布で作ったパラメータに特定の値を掛けてを分散が1/n(ReLUの時は2/n)になるように調整して、活性化関数に入力する値を約1に抑える。 掛ける値は活性化関数ごとにだいたい決まっていて((e.g.