はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unityでもゼロから機械学習を作る【重回帰モデル】

はじめに

前回は単回帰モデルについて実装してみました。

www.hanachiru-blog.com


単回帰モデルでは入力変数が1つだけでしたが、今回は入力変数が2つ以上である重回帰モデルを実装していきたいと思います。

また当初の予定通りライブラリは一切使わずにいきたいと思うのでよろしくお願いします。

では早速いきましょう。

使う式たち

単回帰モデルと重回帰モデルで、実は式はほぼ変わりません。

損失関数

  L(w_0, w_1,…,w_n) = \frac{1}{2M} \sum_{m=0}^{M-1} (yp^{(m)} - yt^{(m)})^2

  yp^{(m)} = w_0x_0^{(m)} + w_1x_1^{(m)} + … + w_nx_n^{(m)}

損失関数の偏微分

  \frac{\partial L(w_0, w_1,…,w_n)}{\partial w_i} = \frac{1}{M} \sum_{m=0}^{M-1} yd^{(m)}・x_i^{(m)}  (i = 0, 1,…,n)

  yd^{(m)} = yp^{(m)} - yt^{(m)}

繰り返しのアルゴリズム

前回大切な3つの式として紹介したものですが、こちらも全て同じ式です。

  yp^{(k)(m)} = \boldsymbol{w}^{(k)}・\boldsymbol{x}^{(m)}   (1)

  yd^{(k)(m)} = yp^{(k)(m)} - yt^{(m)}  (2)

  w_i^{(k+1)}  = w_i^{(k)} - \frac{α}{M} \sum_{m=0}^{M-1} yd^{(m)}・x_i^{(m)}  (i = 0, 1,…,n)  (3)


これらの式がどういったものか忘れてしまった方は、前回の単回帰モデルの記事を見直してみると良いでしょう。

方針

学習データがこんなイメージになっています。

 x_1^{(0)}  x_2{(0)} ・・・  x_n{(0)}  yt^{(0)}
 x_1^{(1)}  x_2^{(1)} ・・・  x_n{(1)}  yt^{(1)}
: : : : :

前回はダミー変数を加えた x_0 x_1の二つだったのでUnityEngine内のVector2構造体を用いましたが、N次元ベクトルの定義はありません。

また行列を調べてみてもMatrix4x4しか見つけられませんでした。

なので自分で配列(もしくはリスト)を使ってN次元ベクトルを作成して、内積などの関数を作るしかありません。


Utils.cs


というわけでなるべくUnityEngineのVector2Vector3を真似て必要最低限の機能を備えたVectorNを作ってみました。

データセットと一緒に.unitypackageに入れておくのでよければ使ってみてください。

学習データを取得する

前回同様に学習データを配布します。

https://drive.google.com/file/d/19kKndpbUx0OXXgfNZaUeT3x6McJ7YZ8Y/view?usp=sharing

今回使うデータは左からtotal sulfur dioxide(=亜硫酸濃度)density(=密度)phsulphates(硫酸塩濃度)alcohol(アルコール度数)になっていて、一番右が正解値であるquality(0-10 の値で示される品質のスコア)になっています。

それぞれデータが1000個ずつですね。

さすがにこの領域になると人間では簡単に予想できない領域になってきます。単回帰モデルは2次元座標でプロットできましたが、この場合は6次元座標が必要になります。

f:id:hanaaaaaachiru:20200223162237p:plain


加えてUnityでデータセットを読み込むスクリプトも作成しました。

一応入力変数がいくつでも対応できるようになっているので、もっと入力変数を増やしたり減らしたりして遊んでみてください。また前回のデータセットも使い回すこともできます。(コードの上の方にあるFILE_NAMEを読み込みたいcsvの名前にしてください)

DatasetReader.cs


コードを作成する

何度もいいますが前回のコードから変更する箇所は少なく、Vector2 -> VectorNに置き換え,それに伴う修正をするだけです。

実際にコードを比較してみると分かりやすいでしょう。

上が前回のもので、下が今回のものです。

SimpleRegressionModel.cs


MultipleRegressionModel.cs


結果

実行してみるとこんな関数が得られました。

yp = 0.8994683 -0.006115932 x1 + 0.8996908 x2 + 0.6475574 x3 + 0.937806 x4 + 0.131661 x5

f:id:hanaaaaaachiru:20200223164220p:plain

損失関数値の変化はこんな感じ。

f:id:hanaaaaaachiru:20200223172309p:plain
f:id:hanaaaaaachiru:20200223172305p:plain

また想像がつくかもしれませんが、入力変数が増えるほど計算に時間がかかるので繰り返し回数を減らしています。

さらに学習率_alphaを前回と同様の0.01にしていると損失関数値がNaNになってしまいます。

これは学習率が大きすぎて、損失関数値がどんどん大きくなってオーバーフローしてしまっているからです。

これを適切に減らしてあげると今回のようにうまくいきますが、また小さすぎるといつまで経っても損失関数値が小さくなりません。

このことからも学習率は重要なパラメーターであることが分かり、最終的には試行回数を増やして適切な値を探していくしかないというわけです。

さいごに

これで重回帰モデルができました。

といってもやはり処理に時間がかかってしまっています。

次はComputeShaderを使って高速化してみるか、ロジスティック回帰モデルをやろうと思います。

ではまた。

参考