前回はディープラーニングにおける「問題」に対する「答え」の作り方を記述しました。
今回は用意したデータに従って構築する「学習モデル」について述べてみたいと思いますが、僕はど素人なので違っていることも多々あると思います。
間違った記述があれば是非、やんわりご指摘いただければ幸いです。(ガラスのハートです)
というかはっきり言ってよく解らないまま書いています!
けどkerasを使うとこんな程度の認識で構築できちゃいますよーってことです。
モデルの構築とは
ディープラーニングに用いる「人工神経」に対してどういった振る舞いをする神経ネットワークにするか?
という内容であり、ハッキリ言って「決まりはありません!」というかおそらく世界中誰もが「この関数の組み合わせで何でもOK!!」という最適な構築方法を解明していません!
神経の数をいくつにするのか?何段のネットワークを形成するのか?という問題は、実際にモデルを構築して実働実験してみて結果が良ければ良し!という状態ではないでしょうか?
神経数が多ければ多いほど結果が良いとも限らないというのも面白いところ。
人工神経細胞へ刺激が入ると、細胞がどのように適切に処理して活性化するか?否か?を決める「活性化関数」という関数が多種多様に存在し、
シグモイド、ソフトサイン、ソフトプラス、ReLU、切断冪関数、多項式、絶対値、動径基底関数、ウェーブレット、maxout
などがWikipediaに載っているけど、グラフでは表せないような関数もあり素人にはよく解らないのです。
とにかく深く考えずに「中間層」にはこれらの活性化関数の数やら層数などを組み合わせて「考える」神経を構築していく。というのがよく用いられる手法なのです。
最終的に決定した出力を統括するのが「出力層」で
回帰、二値分類、多クラス分類
という活性化関数が利用され、「答え」として割合が出力されます。
例)0〜4番までの選択肢の場合
[ 0.001 , 0.3 , 0.983 , 0.12 ]
この場合、2番が最有力候補となり「答えは2」と出力されます。
神経細胞が「活性化」するかしないかを決める「計算方法」が上記中間層の「活性化関数」
ということだが、よく解らない!
素人がKerasで扱う程度ではあまり気にすることなく中間層にはReLU関数を使っていればいいんじゃないの?って感じでOK(だと思う)。
kerasでこの神経モデルを構築するのはすごく簡単だ。この辺でkerasの「人に易しく」の理念が伺えるところです。
hidden_units_first = 300 #入力層の神経数
hidden_units = 100 #中間層の神経数
n_classes = 3 #出力層の神経数(答えの数)
dropout = 0.3 #ドロップアウト割合
model = Sequential()
model.add(Dense(hidden_units_first, activation='relu', input_shape=(【入力次元数】,))) #入力層
model.add(Dropout(dropout))model.add(Dense(units=hidden_units, activation='relu')) #中間層
model.add(Dropout(dropout))model.add(Dense(units=n_classes, activation='softmax')) #出力層
と、予め用意されていある関数をaddで追加していくだけなのです。
ドロップアウトは、ある一定の学習結論に達した神経の繋がりを部分的にカットして考えの「まんねり」を防ぐという役割があるそうな。
ここで簡単な図を元に脳神経細胞の話になるが、
「活性化」とは、神経細胞の「①樹状突起(じゅじょうとっき)」へ刺激が加わったら「②神経細胞体(しんけいさいぼうたい)」が受け取った刺激に対して反応して「③軸索(じくさく)」へインパルス(電気刺激)を発生させる状態のことを言うのです。
発生されたインパルスで軸索終末部(軸索の先)から次の神経の樹状突起へ向けて「神経伝達物質」が放出されることで次の神経が刺激を受け取る。
上記を複雑な繋がりで繰り返すことで脳は情報を処理をしているのです。
※実際の脳では「コネクトーム」と言われる脳神経マップが確認できます。
上図の青矢印は、機械学習で用いられている「重み(wait)」と言われている部分で、1つの神経細胞からは一定の刺激を次の神経細胞へと流しているが、受け取る側の神経細胞はどこからの神経の刺激をどの程度の容量(重要度)として受け取るか?ということを決定しています。この重要度(重み)こそが「学習」なのです。
(実際の脳神経細胞の場合は神経細胞同士を繋ぐ「間隙」という隙間や伝達物質や受容体といったもっともっと複雑な構造をしている。※最近の研究では伝達コードと考えられていた③軸索自体も何かしらの伝達処理をしているのでは?と考えられているのでもっと複雑。)
人の脳の少しややこしい話になりましたが機械学習の話でこれは避けて通れない話なので、漠然とでも頭に入れておくしかないのです。
Kerasの使い方としては結局
何個の「神経細胞」をどの「活性化関数」として「何層」用意するか
ということになります。
人間の脳は、脳神経細胞だけで約140億個とされています。
「え?じゃあ140億の脳神経モデルを作ればスゴイAIができるんじゃないの?」と思うかもしれませんが、そう単純な話ではありません。
そんな数の神経細胞を定義するのはパソコンではメモリー不足でまず無理ですし、人間の脳細胞は実はもっと複雑です。
↓下記リンク先の資料ではスーパーコンピュータで脳神経シミュレートに成功しています。(kerasではありませんが、規模的にはこういうことです)
スパコンで17億の脳神経細胞と10超のシナプス(神経接合部)を再現しています。
まあそういうわけでパソコンで扱えるデータなんて高々知れているもので、出来るだけお膳立てして単純なデータを入力してあげる必用があります。
白か黒で10×10ピクセル程度で文字として認識できるという手書き文字あたりがやはり扱いやすい最適な課題だと思います。
特に画像入力の場合、入力されたデータをそのまま中間層に持って行くのではなく、「畳み込み層」や「プーリング層」といったできるだけ単純なデータ、特徴を保ったまま圧縮して入力するという方法が用いられています。
↓のサイトが簡単でわかりやすいです。
この一見ややこしい「畳み込み層」「プーリング層」もkerasでは複雑な構造を理解する必用もなく扱う関数が用意されています。
Conv2D
MaxPooling2D
などという関数がそれにあたります。
例)2D画像の場合
model.add(Conv2D(filters=filters, kernel_size=(10, 10), activation='relu', input_shape=input_shape))
model.add(Conv2D(filters=filters, kernel_size=(10, 10), activation='relu'))
model.add(MaxPooling2D(pool_size=(5, 5)))
model.add(Dropout(dropout))
model.add(Flatten())
これも中間層と同じようにaddで追加するだけです。
それから中間層を構築します。
そして、個人的にこれは便利だなーと思ったのが1D用の畳み込みやプーリング層。
これだとグラフ等のデータを特徴を保った状態で入力することが出来るのです!
例)グラフの場合
model.add(Conv1D(filters=filters, kernel_size=(10), activation='relu', input_shape=input_shape))
model.add(Conv1D(filters=filters, kernel_size=(10), activation='relu'))
model.add(MaxPooling1D(pool_size=(5)))
model.add(Dropout(dropout))
model.add(Flatten())
テストが足りてなくてあまり具体的コードが書けなかったけど、サンプルコードはWebでも色々出回っているので「kerasでのニューラルネット構築ってこういう感じなのか〜」と感覚的に掴めていただけたら幸いです。