Simulinkで機械学習
Simulinkは自動車などのダイナミックシミュレーションするのに適しています。
ですが、時間に依存しない例えばif文などの分岐やfor分のループをSimulinkで組むと、どうしても作業中に時間の概念が入ってきたり計算順序がごちゃごちゃになってしまい一筋縄ではいきません。
もちろんStateFlowなどがあれば便利ですが、そうでない場合はMatlabファンクションで組む必要があります。これはこれで慣れないと厄介ですが・・・
ということで今回はアイリスの分類をSimulinkだけでできないか検討してみました。結論としてはSimulinkだけで簡単なニューラルネットワークを組むことができました。そしてそのモデルは感動するくらいニューラルネットワークの教科書に出てくる図に似ていますが、普通にコマンド上ではfor文のループをSimulinkで実現しようとするとかなり面倒・・・
ですが、とりあえずできましたので掲載します。
外観はこんな感じでFor iteratorシステムとAssignment ブロックを使いベクトルデータを1ステップ内で順番に繰り返し処理をします。これが時間の概念無くしたfor文になります。
これがニューラルネットワーク本体です。真ん中の中間層二つと最後の出力層が一つという簡単なものです。右側ある3つのブロックが重みやバイアスの更新パラメータの計算ブロックです。
この書き方の場合、求めるものが更新パラメータということになります。ちなみにニューラルネットワークの出力を更新パラメータ計算ブロックに入力して、その出力をまたニューロンに戻すという行為は代数ループ問題となり、コマンドプログラムを書くときは意識しなかったものがSimulinkで扱うときは結構神経質になります。
で、ニューロンのブロック内ですがこんな感じになってます、教科書に出てくるニューロンそのものです。このニューロンのoutc1の手前にあるブロックの内部は活性化関数としてつかっているシグモイド関数が入ってます。
中身はこんな感じで個別ブロックでシグモイド関数を書いています。計算式を直接書くファンクションブロックもありますが今回の場合いろいろと制約がでて、うまく動作しなかったので個別ブロックで構成しました。結構Matlabで簡単に書けることをSimulinkで表現するのは大変です。
ちなみにファンクションブロックで書くとこんな感じです。
便利なのか不便なのかわかりませんが、そんなこんなでシミュレーションした結果がこちらです。
まず最初のものですが、更新パラメータ(6点)です。縦軸が値、横軸が学習回数です。100点X64回学習した結果ですが、初期値からゆらゆらしながら40回くらいから値が落ち着き始めます。実際30回程度でほぼ問題なくアイリスを分離できました。
次は横軸は同じく学習回数ですが縦軸はアイリス100点の分類結果です。見方としてはニューロンの活性化関数(シグモイド関数)の出力結果で画面中央の0.5を中心として0から1の範囲で値がばらついていますが、学習を重ねるにつれて0側と1側の二極化していることがわかります。結論から言えばserosaとvers、正解データ通り(0または1の分類)に分類されました。
なるほど、学習すると徐々にパラメータを更新するのか!
PID制御のようにループを時間かけて通すたびに積分値が徐々に加えられてターゲットとの差を詰めるのに似ているような似てないようなといった感じです。
ただこれって、仮に同じデータを例えば10000回くらい繰り返したとすると、更新パラメータはどこかで落ち着くのか?あるいは常に揺れ動くのか気になります。一応1000回くらいまで試しましたがパラメータが落ち着くような落ち着かないようなといったところで、ここがPID制御などのダイナミック系のパラメータと違うんだなと感心です。
なお、もしかするとMatlab/Pythonコマンドのプログラムと若干違う部分があるのか定かではありませんが、似たような値や傾向は出てきても全く同じ値が出てこない。
Simulinkあるあるです。
まとめ
・Simullinkでプログラムするとめんどくさい
・教科書に出てくるようなニューラルネットワークの形になる。
・なぜかMatlabコマンドのプログラムと答えが異なる
こんな感じです。ここまでライブラリやツールボックス使わずに簡単な機械学習ができて、それがどんなものか大体わかったので次回からはPythonでライブラリなど使ってみたいと思います。機械学習部分をPython、それ以外をMatlabあるいはMatlab/Python連携で進めてみます。