Convolutional Neural Networkを理解しよう

この記事はeureka Native Engineer Advent Calendar 2017の24日目の記事です。
23日目は竹内さんの「Clojureでマルチプラットフォーム開発」でした。

はじめに

こんにちは。PairsのiOSエンジニア、Johnです。最近Machine Learningが話題になっていますが、ネイティブエンジニアの皆さんは使っていますか?

ネイティブ開発で使えるフレームワークについて記事が多いと思います。

nn_1

例えばiOSの場合は、CoreML(右側)の使い方について 、 仕様書やサンプルコードは検索しやすいと思いますが、そもそも自分のアプリ用の機械学習モデルをどうやって作れるか(左側)はよくハードルになるところでしょう。

今日は初心者もわかるように、画像認識の機械学習モデルを作る基盤知識について話します。

ツールをインストール

まず、必要なツールをインストールしましょう。今回、シンプルにやりたいので、以下のツールをダウンロードすれば良いと思います:

バックエンドとは、Neural NetworkとDeep Learning自体を実行・処理するものです(例:Tensorflow、Theano)。フロントエンドはトレーニング用のユーティリティなどのフレームワーク(例:Keras、Caffe)
それぞれを詳しく説明すると長くなりますので、ドキュメンテーションを参考してください。今回は早速ハンズオンで触ってみましょう。

デモアプリをダウンロード

存在しているデモアプリをダウンロードして、そのモデルを見てみましょう:

GitHub – r4ghu/iOS-CoreML-MNIST: Real-time Number Recognition using Apple’s CoreML and MNIST

このサンプルプロジェクトは、CoreMLを使った手書きの数字を認識するiOSアプリです。
nn_2

Convolution Layers

モデルを作ったKerasのphpスクリプトを開く前に、少し必要な知識について話します。

画像認識用のNeural Networkには「Convolution」というアルゴリズムがよく使われています。画像加工の開発に経験のある人は聞いたことのある単語だと思います。

nn_3

Blur、Edge Detect、Sharpenフィルターなどの基盤です。Convolutionのアルゴリズムが各ピクセルのまわりの性質が取り出せる特徴があります。そのため、目立たせたい性質をNeural Networkに学習させることができます。

nn_4

Sequentialモデル

さて、アプリのモデルを生成したPythonスクリプトを開いてみましょう。プロジェクトフォルダの /nnet/train.py ファイルをテキストエディターやPythonのエディターで開きます。真ん中の辺にこのコードがあります:

# Model
model = Sequential()

model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Conv2D(128, (1, 1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# Training
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)

これはレイヤーを組み込むコードです。Neural Networkについて軽く読んだことある人は、以下のような図を見たことがあると思います:

nn_5

インプット画像からアウトプットの「ラベル」を流す図です。上記のPythonコードは、このようなレイヤーを作成するものです。各レイヤーの意味を説明してみます。

1. model.add(Conv2D(32, (5, 5), ...)

Conv2D

Convolutionフィルターのことです。画像を32×32のグリッドでスキャンして、Convolution関数で5×5のグリッドに変換します。

nn_6

(図の×3は、rgbチャンネルの意味です。グレースケールの場合は ×1

2. model.add(..., activation='relu')

Activation

Activationというのは、次のレイヤーへ通す値の変換関数です。この例でいうと、Rectified Linear Unit(relu)という関数を使います。ReLuを理解するために、まず他のActivation関数を見てみましょう。

  • シンプル

nn_7

四捨五入して0と1に分ける関数です。この関数は単純すぎるのでファジーなデータにあまり合いません。

  • Sigmoid

nn_8

0と1に分けるより、0.5まわりに少しグラデーションを入れた関数です。

  • Tanh

nn_9

Sigmoidに似てますが、もっと切り立ったカーブです。

  • ReLu(Rectified Linear Unit)

nn_10

Neural NetworkにはReLuの関数が一番効果がいいらしいです。カーブではなく、スロープです。0以下を無視して、正数は線型方程式で処理する。線型方程式ですから、グラデーション関数より数倍早いです。

ということで、基本的にConvolutionのActivation関数はReLu以外をあまり使わないと思います。

3. model.add(MaxPooling2D(pool_size=(2, 2)))

MaxPooling

グリッドを2×2に分けてMAX値だけ取り出します。

nn_12

4. model.add(Dropout(0.5))

Dropout

定義した確率でランダムに値を捨ててしまいます。さて、学習させたいのになぜ学んだ値をランダムで捨てるか気になりますね。実は、このレイヤーが最適化する方法の一つです。

事例を考えましょう。例えば、二人の学生がいて、次の数学試験のために勉強をしています:

  • 学生A: 過去の質問と解答用紙を単純に暗記している
  • 学生B: 過去の質問と解答用紙を学んだが答えを特に覚えようとしない。その代わり、過去になかった問題も学んでみた。

次の数学試験にはどちらの学生が合格すると思いますか?機械学習でも、トレーニングデータをあまり暗記させないほうが良いのです。

5. Conv2DMaxPooling2DDropoutを繰り返して、Flattenする

Activationのマッピングレイヤーをスタックに重ねます。

nn_13

6. model.add(Dense(num_classes, activation='softmax'))

Dense

num_classesは、数字の文字数です。Denseレイヤーでは、最終レイヤーのグリッドから一番近いカテゴリの インデックス に変換します。例のモデルの場合は、0~9の一覧のインデックスが出力されます。(このアプリの場合、たまたまインデックスと数字が同じですが、Neural Networkはカテゴリのインデックスからしか判断ができません)

7. model.compile(loss='categorical_crossentropy', optimizer='adam', ...

Loss

画像のカテゴリを認識するNeural Networkを作りたいので、 categorical_crossentropy を使います。この compileの段階で、モデルのレイヤーをTensorflow(もしくは他のBackend)を用いてビルドさせます。

Optimizer

トレーニングをする時、大量のデータを学習しますが、その学習率(速度)によって実際の認識制度に影響がでます。そのため、学習の最適化をするアルゴリズムを定義します。以下、トレーニング途中の認識制度のビジュアルです:

nn_14

(⭐️は「最適解」の点)
Optimizerのビジュアルアニメーションで2つだけ説明をすると、

  • Momentum(緑)は、はじめは⭐にある点とはかけ離れたパスを辿っていますが、最後は⭐の近傍に到達することができています。
  • SGD(赤)は遅いですが、慎重に⭐️へ到達するためのパスを辿っています。

(このデモアプリで使っている adam というOptimizerはAdagradとAdadeltaのアルゴリズムと同じファミリー)
データと理想なモデルによって、どのOptimizerとそれぞれのパラメータを調整する必要があります。もしシンプルにやりたい場合は、 ada~から始まるOptimizerがおすすめです。(”ada”=adaptive、適応的)

8. model.fit(...

ここでTensorflowのトレーニングを実行し始めます。この関数でトレーニングのステップ数とデータ量を定義します。少なすぎると終わるまで認識制度が上がらない(Optimizerが⭐️までたどり着かない)ことがありますので何回か試して調整します。

おわりに

Kerasで画像認識Neural Network用のSequentialモデルを作成する基本のやり方を説明しました。/nnet/train.pyスクリプトを実行してから新しい .h5モデルファイルが上書きされます。それで/nnet/convert.pyを実行すると、.h5ファイルからCoreML用の.mlmodelファイルが作成されます。是非、いろいろなパラメータをいじってみて、手書き認識の挙動にどのように影響するのか遊んでみてください!

参考リンク

TensorFlow
– https://www.tensorflow.org/

Keras
– https://keras.io/
– https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html

MNIST CoreML Demo
– https://github.com/r4ghu/iOS-CoreML-MNIST

Convolutional Networks
– https://adeshpande3.github.io/A-Beginner%27s-Guide-To-Understanding-Convolutional-Neural-Networks/
– http://cs231n.github.io/convolutional-networks/#overview
– http://ruder.io/optimizing-gradient-descent/

  • このエントリーをはてなブックマークに追加

エウレカでは、一緒に働いていただける方を絶賛募集中です。募集中の職種はこちらからご確認ください!皆様のエントリーをお待ちしております!

Recommend

Go言語で覚えるTDD(テスト駆動開発)

Couples: powered by CoreStore