Azarashi Tech Blog

日常における日常的なことやテクノロジー的なこと

MFT2018向けダーツスキル解析(6) - DNNモデル改善⇒収束!

背景

  • 前回、データを再度プロットしたり、低次元に圧縮して可視化してみたりしたが、生データのクラスタリングだけでは無理っぽかった。
  • DNNモデルを工夫して、再度トライしてみる。

DNNモデル(改善版)

  • 前回のモデルに、Batch NormalizationとDropoutを追加してみた。
  • これで過学習抑えられて学習速度もあがるだろう、と思う。
  • まぁ最適なモデルになった、とはいえないけど、前回よりもかなりマシな構造になったはず。

f:id:surumetic-machine-83:20180803194536p:plain

学習

  • とりあえず1万エポック回してみた。Adamでlr=0.0001,beta_1=0.9, beta_2=0.999。
  • 以下のようなロスカーブ。valはそんなに小さくないけど、前回よりはマシ。
  • dropout入れてるからか、すごいグラフが振動している。大丈夫かな?
  • 1万エポック時点では、lossは以下のような感じ。
    • train loss : 0.0007517132
    • validation loss : 0.0585273126

f:id:surumetic-machine-83:20180803194525p:plain

推論テスト

  • 一通り、各スコア(0.0, 0.1, 0.6, 1.0)に対応するデータをもってきて、正しく結果が出てくるか試してみる。

テスト結果

  • スコア1.0のデータ例に対する推論結果 : 

    y_predicted : [0.99993074]

  • スコア0.6のデータ例に対する推論結果:

 y_predicted : [0.5921314]

  • スコア0.1のデータ例に対する推論結果:

    y_predicted : [0.05314487]

  • スコア0.0のデータ例に対する推論テスト結果:

    y_predicted : [0.01145243]

考察

  • それっぽい値が出た!!!!!
  • 1万エポックだけど、まだtrain lossが小さくなりそうなので、学習をもっとまわしてみるとしよう。

まとめ

  • DNNモデルの性能が悪かったのは、モデルの構造が良くなかったからのようです。
  • さて、またダーツ投げまくってデータ増しして性能を向上させますかね!()

追記 2018-08-04

  • 1万epoch学習させましたが、更に追加で9万epoch学習させました。
  • 以下のグラフの通り。やっぱりグラフの変動が大きすぎる気が・・・。train lossの変動の上(?)が最終的な性能くらいだと思っといたほうがいいのか?よくわからないけども。変動の下(?)はこれ以上下がらない雰囲気なので、学習時間は十分のように見える。
  • 最終的な収束値: train loss: 9.0574e-05 - val_loss: 0.0573

f:id:surumetic-machine-83:20180804040558p:plain

テスト結果

  • 推論値も良くなった。やっぱりスコア0.1の推論が少し悪い。僕の問題設定が悪いかも?インブルもブルもscore 0にすればよかったかなぁ。

  • スコア1.0のデータ例に対する推論結果 : 

y_predicted : [0.99999976]

  • スコア0.6のデータ例に対する推論結果:

y_predicted : [0.5994751]

  • スコア0.1のデータ例に対する推論結果:

y_predicted : [0.12352057]

  • スコア0.0のデータ例に対する推論テスト結果:

y_predicted : [2.8647633e-05]

MFT2018向けダーツスキル解析(5) - データの特徴を再確認

MFT2018はついに明日ですね!

ダーツを投げた時の人の各種データを取る仕組みだけできてますが、 肝心のデータを解析して上手い下手判定をしてくれる部分が全然できてないのでやばいです笑

データ取りの仕組みは、それはそれで結構イイ感じにできたと思うので、そっちをメインにフィーチャする感じですかね。 まぁデータ解析は、ベストエフォートでできるところまで頑張ってみます。

今回

  • テキトーにデータをテキトーに作ったDNNに突っ込んで結果を見るのは一旦やめて、きちんとデータを見るところから始めます。
  • 各種スコアにおけるグラフを今一度チェックしてみます。

データ確認

スコアの対応表の再掲

  • ダーツのスコアは、以下のように0.0, 0.1, 0.6, 1.0の4種にわけることにしています。

f:id:surumetic-machine-83:20180801180459p:plain

生データを凝視してみる。

  • 何はともあれ、各種スコアのナマのデータを比較して、上手い下手が判別できるか見てみます。
  • 各スコアごとに、とりあえず意味の強そうな「親指の指圧=finger1」「親指の曲げ=finger0」「人差し指の曲げ=finger2」「中指の曲げ=finger4」を適当に6サンプルずつ拾ってグラフを比較してみます。

各スコアのグラフ

  • インブル(loss score=0.0)のときの例6個 f:id:surumetic-machine-83:20180803171521p:plain

  • ブル(loss score=0.1)のときの例6個 f:id:surumetic-machine-83:20180803171525p:plain

  • 内側シングル+トリプル(loss score=0.6)のときの例6個 f:id:surumetic-machine-83:20180803171528p:plain

  • 外側シングル+ダブル(loss score=0.0)のときの例6個 f:id:surumetic-machine-83:20180803171532p:plain

凝視してみたが・・・

  • なるほど、わからん
  • 例えばうまくインブルに入っているデータ同士でも、結構データにはばらつきがありそう。「インブルに入るべくして入ったケース」と「インブルにたまたま入ったケース」があるのだろうが、それを区別できないといけないようだなぁ。
  • クラスタリングしたら何か分かるかも?

生データをt-SNEで低次元に落として可視化してみる。

  • データの可視化手法でよく使わっるPCAとかt-SNEを使って、生データを低次元で可視化してみる。低次元に落とした時に、きちんとデータがスコアごとにグループ分けされるか確認したい。
  • なお、今のところ「ダーツの矢が刺さった2秒前までの指と体の動きの時系列データ」を記録してきたが、実質投げるのに関係していそうなのは1秒前までなので、1秒前までのデータのみ切り取って来て使うことにする。

PCAの結果

  • クラスごとに、うまくグループ分けできていない・・・。インブルだろうがダブルだろうが、近さが変わらない。 f:id:surumetic-machine-83:20180803172257p:plain

tSNEの結果

  • PCAよりも、うまく次元圧縮できると話題のt-SNEだが・・・
  • やっぱりうまくグループ分けできていない。インブルだろうがダブルだろうが、近さが変わらない。

  • t-SNEで2Dに次元圧縮

f:id:surumetic-machine-83:20180803172320p:plain

  • t-SNEで3Dに次元圧縮 (plotlyで描画)

まとめ

  • 今回は、ダーツを投げた時の指・体の時系列データが、スコアに応じて優位に差があるかどうかをチェックしてみました。
  • 結果、生データを純粋に見比べても、よくわからないし、次元圧縮をしてみてもグループ分けされていませんでした。
  • DNNとかで、うまく特徴抽出してやった結果をうまくt−SNEかけてプロットすれば、いい感じにグループ分けされるのかもしれません。
  • もう一回良いDNNを設計する方向性で頑張ろうかな。あとデータまし・・・。

余談

  • t-SNEもplotlyも始めた使ってみたけど、いいツールだなぁ。
  • あと一ヶ月時間がほしい・・・。

MFT2018向けダーツスキル解析(4)

背景

  • 前回、性能はよくわからないですが、指の動きと指圧、そして体の関節位置の時系列データから、ダーツのスコアを推定するDeep Neural Network(DNN)を作りました。
  • ほんとにこれで収束してんのか?というところ今一度値を見て調べてみようと思います。

どうチェックするの?

  • スコアが0のデータ、0.1のデータ、0.6のデータ、1.0のデータを入力して、モデルがどんな出力を返すのか見てみます。

結果

  • いや、すごい恥ずかしいのですが、モデルにどのデータを入力しても、「0.5336971」が帰ってきました笑
  • ただの平均値計算になってましたね!いやぁ、お恥ずかしい!ああっ!!!(寝不足のテンション)

次のステップ

  • しかしこれで、収束してないことがわかりました。前のデータで、validation気にせずlossが小さくできていた例をみました。要は、validationを犠牲にしてでもlossを降下する方向性へもっていくべきだったのですね。
  • 汎化性能維持するために、Dropoutとか入れてみる必要があるかもしれません。
  • データの質以前の問題ということで、ハイパーパラメータチューニングに手を出すか?

うううう・・・

この分野はまだまだ素人なので、色々とハマりますね・・・。

余談

  • Maker Faire、ヘタしたらただのダーツの矢を投擲するデータをロギングするシステムを展示するだけになってしまうかな・・・。それは避けたい・・・。
  • あと残り一日になってしまった・・・。

とりあえず一回寝ますかね。

MFT2018向けダーツスキル解析(3)

前回

  • 指および体の動きの時系列データを正規化して2Dの時空間マップにしました。

今回

  • 時空間マップからスコアを推定するDeep Neural Network(DNN)をいくつか作り、学習させ、収束するかみてみます。
  • 結論から言って、途中までやって「お、うまくいくんではないか?」と思ったら、案外「うまくいってなかったなぁ・・・」っていう結果です。

学習環境

  • GPU : GTX780Ti

    • 新入社員のときに買ったけど、随分時代遅れになっちゃったなぁ・・・
  • 学習フレームワーク : Keras

    • BackendはTensorflow

方針

  • 今回は、まずシンプルなFully-Connected層だけで構成されたモデルを試します。
    1. fingerデータ(指の動き・指圧の時系列データ)から、スコアを推定するDNN①を作る
    2. bodyデータ(各関節位置の時系列データ)から、スコアを推定するDNN②を作る
    3. DNN①とDNN②の中間層を統合してスコアを推定するDNN③を作る
  • ちなみに「時系列データを扱うならRNNかLSTM使うの?」と思われるかもしれませんが、今回入力は連続値ですが固定長で、しかも出力は1つですので、すごいシンプルなため、使う必要はないと判断しています。

fingerデータからスコア推定トライ

fingerデータからスコア推定モデル(シンプル)

  • 以下のようなモデルを作り、学習してみる。
    • Fully Connectedレイヤを3つくっつけただけ。

f:id:surumetic-machine-83:20180802114844p:plain

学習結果

  • とりあえず、SGDとAdamで10000エポック学習して見た。
  • SGDはかなりlossが小さくなるけどvalが悪くなってるので、過学習気味。
  • Adamはloss: 0.0378 - val_loss: 0.0374止まりだけど、valと同等で、収束がかなり早い模様。

SGD (Learning Rate = 0.01, Momentum= 0.9) f:id:surumetic-machine-83:20180802125312p:plain

Adam (lr=0.01, beta_1=0.9, beta_2=0.999, decay=0.0) f:id:surumetic-machine-83:20180802125531p:plain

ふむ、で結局、fingerデータだけで、どのくらい的中できるの?

  • 今回のlossは、mean_squared_errorとなっている。なので、これにsqrtかければ、RMSEになる。
  • RMSEにすれば、元の単位系と比較しても問題ないはず。
  • 今回の場合、ADAMで試した結果を使うとして、sqrt(0.0374) = 0.194。大体誤差±0.2ポイントくらいってことかな。
  • もしかすると、インブルかブルかは見分けられないけど、もしかしたらブルかそれ以外は0.5ポイント差があるので、区別できるかもしれない。

fingerデータからのスコア推定に関する考察

  • テキトーなわりにいい感じでは。思ったよりfigerデータには情報量があるかもしれない。
  • もしくは、一部のデータの偏りが大きいから、マジョリティに寄る出力を出しているだけなのかもしれない。

bodyデータからスコアの推定トライ

bodyデータからスコア推定モデル(シンプル)

  • bodyについても、同じくシンプルなモデルで学習させてみる。
  • fingerよりも次元が多いので、気持ち中間層多めに作ってみた。

f:id:surumetic-machine-83:20180802133832p:plain

学習結果

  • fingersデータでうまくいったAdamで実施
  • learning rate=0.001で結構いい感じに収束した。

Adam (lr=0.001, beta_1=0.9, beta_2=0.999, decay=0.0) f:id:surumetic-machine-83:20180802143031p:plain

  • ちなみにlearning rate(=lr)が、fingersのときにはここでは0.001にしてある。これが0.01のままだと、lrが小さすぎるがために全然学習が進まない。

Adam (lr=0.01, beta_1=0.9, beta_2=0.999, decay=0.0) f:id:surumetic-machine-83:20180802144222p:plain

  • 逆にもっとlrを小さくすると、下図のように過学習して変な風になった。調整難しいなぁ。

Adam (lr=0.0001, beta_1=0.9, beta_2=0.999, decay=0.0) f:id:surumetic-machine-83:20180802143336p:plain

bodyデータからのスコア推定に関する考察

  • bodyデータの学習でのval_lossの収束時の値も、ほぼ0.0374で、fingersによる結果と同じだった。sqrt(0.0374) = 0.194。大体誤差±0.2ポイント。
  • fingersとbodyによる推定結果にほとんど差がないことがわかった!と言ってもいいかな?と一瞬思ったが、それはないだろう。
  • データのバイアスがありすぎて、そっちのほうこうによった値をテキトーに出力するDNNができあがってしまった気がしている。

finger+bodyデータからスコアの推定トライ

  • finger, bodyともにだいたい同じ誤差に収束している感じがかなりあやしいが・・・何はともあれ、DNN③を作って学習してみる。
    • まぁとにかく、今回は最後まで走り抜けます。
  • 理想的には、finger単体、body単体よりも良い結果となってほしいが・・・

fingers+bodyデータからスコア推定モデル(シンプル)

  • 前節までで説明していたモデルを、最終出力層を除いて、単純にもってきて、後段を2つのFully-Conncectedでくっつけたモデルですね。

f:id:surumetic-machine-83:20180802150845p:plain

学習結果

  • Adamでlr=0.0001で学習。
  • 今までで学習したfingersデータによるスコア推定DNNと、bodyデータによるスコア推定DNNの学習済みのパラメータをロードして、事前学習させた状態から学習を開始させました。
  • 結果は下図の通り。学習開始時点から、ほとんど値が変化していない。収束したときの値はまさしく、finger単体およびbody単体と同等の結果・・・。ううううう・・・。

f:id:surumetic-machine-83:20180802155259p:plain

finger+bodyデータからのスコア推定に関する考察

  • はい、これは間違いなくデータのバイアスか何かが悪さしていて、まともに学習しきれていないですね。
  • データを洗いなおして出直しますか。

まとめ

  • うまくいったかな?と思いましたが甘かったですね。
  • モデルの見直しだけなく、学習データの見直しをしないといけないですね。
  • 最近書いてるブログが本当にただのメモで、説明が下手すぎて誰にも理解されないレベルかもしれません。そのうちきちんとまとめよう。

次回

  • 一旦、今回作ったモデルでどの程度の性能か検証
  • 学習データのなかで、ある数値にバイアスがでていて学習に悪影響を及ぼしていないかチェックする。
  • うまくいったら、ハイパーパラメータチューニングを試す。

MFT2018向けダーツスキル解析(2)

前回(数時間前)までのあらすじ

  • ダーツスキル解析のために、どういうデータをどのように撮っているかについて説明。
  • データをプロットしてみて、正規化が必要と確認。
  • データの正規化を施して、データの特徴が見やすくなったことを確認
    • 初投稿時からちょこちょこ追記
  • ラーメン食べてきました。

今回

  • Deep Neural Networkへの入力にするため、各データの二次元の時空間マップに変換します。

時空間マップ

  • その名の通り、1つの軸が時間で、もうひとつの軸が空間的なデータになっているもの。
    • 空間といっても、今回は指の曲げ度合、指圧、関節の位置など、ばらばらですが・・・。
  • 前回までの進捗で、各データがすべて0〜1ないしは-1~1に揃えたので、すでにマップにしやすい状態になっています。
  • 曲げ度合と指圧で1つのマップ、関節の位置で1つのマップという風にして、2つのマップを作りました。
    • そしてseabornを使って綺麗に描画します。

元データ

  • 前回の投稿で扱ったデータと同じく、以下の動画の水準

f:id:surumetic-machine-83:20180801173920g:plain

指データの時空間マップ

f:id:surumetic-machine-83:20180801215228p:plain

関節データの時空間マップ

f:id:surumetic-machine-83:20180801215200p:plain

Deep Neural Networkにどう入力したいか

  • イメージとしては、指と体の動きのデータから、ダーツスコアを推定する問題となる。 -いわゆるマルチモーダルっぽい雰囲気のネットワーク。
  • まず指の動き・圧力だけからスコアを推定するDNN①を訓練する
  • 次に体の関節位置だけからスコアを推定するDNN②を訓練する。
  • DNN①と②を統合するDNN③を作る。

f:id:surumetic-machine-83:20180801222032p:plain

次のステップ

  • DNNモデル設計して、データ突っ込んで訓練して結果を見る。

備考

  • 説明がどんどん雑になっていきます。すみません。
  • 時間がないので焦ってます。

MFT2018向けダーツスキル解析(1)

前回までのあらすじ

  • ダーツ投擲時の人の指・体の動きを取得するシステムを作った。
  • ダーツ投げまくった

今回

  • そこそこダーツを投げてデータを貯めたので、イマサラナガラ、本腰入れてそろそろ解析していこうと思います。
  • あと2日でMaker Faire 当日ですね!順調!\(^o^)/

どんなデータをとったか

  • 電子ダーツボードに矢が刺さってから、遡って2秒間の指・体の動きの時系列データ(とカラー画像&距離画像)を保存できるようにしました。
  • センサグローブも、RGB-Dセンサも30fpsにしているので、2秒間で60フレームのデータが得られます。
  • 実際、矢がボードにささる1秒前までくらいしかデータの意味はなさそうですが、なんとなく念の為倍の2秒にしました。

電子ダーツボードのデータ

  • 電子ダーツボードはキーボードと仕組みが同じなので、Bluetoothで繋いでおくと、矢がささったときにASCIIコードがパソコンに入力されます。
  • このコードを解析してスコアに変換します。
  • スコアは、低ければ低いほどよい、損失スコアとします。
  • スコアは、ここでは問題を簡単にするために「インブル(ど真ん中)」に近いほど0に近くなる、0〜1の値とします。

f:id:surumetic-machine-83:20180801180459p:plain

カラー画像

f:id:surumetic-machine-83:20180801173920g:plain

距離画像

f:id:surumetic-machine-83:20180801173941g:plain

指の曲げ度合いのデータ

  • 値が小さいほど「曲げている」ことを意味する。
  • 割と綺麗に動きが見えます。
    • finger0が親指の曲度合、
    • finger2が人差し指の曲度合、
    • finger4が中指の曲度合、
    • finger6が薬指の曲度合、
    • finger8が小指の曲度合、

f:id:surumetic-machine-83:20180801172406p:plain

指圧のデータ

  • センサグローブには親指しか感圧センサが入っていないので、親指の指圧finger1のみプロットします。

f:id:surumetic-machine-83:20180801172821p:plain

関節位置の座標データ

  • RGB-Dセンサから見た、キーとなる各関節の3D座標値
  • 正規化しないと使い物にならない気がしている。
  • ぱっとみではright hand, elbow, shoulderくらいでいいじゃん?と思うが、いろんな投げ方をこれから試そうとすると、各種値がブレるのだろうなぁ。

f:id:surumetic-machine-83:20180801204254p:plain

関節位置の座標データを正規化

  • 全データの「頭」の位置を拾ってきて、その平均値(x,y,z)を拾ってきて、すべてのデータからその分差し引く。
  • また、データの最大値の二倍くらいで全データを割ってやる。
  • 結果、全データが-1〜1になる。
  • グラフとしてプロットすると、以下のようになる。かなりグラフの特徴が見やすくなった。
    • あとなんとなくSeaborn使っておしゃれな描画にしてみた。

f:id:surumetic-machine-83:20180801204722p:plain

指の曲げ度合いと指圧のデータも正規化

  • これも関節のデータと同様、最大値の2倍くらいで割ってやった。
  • 平均値差っ引かなくても0以上のデータしかなかったし、各指でスケールに差がなかったから、平均値は差っ引いていない。
  • 関節とちがって、グラフの見た目はほとんど変わらないので図は割愛。
  • こちらの正規化は、-1〜1ではなく、0~1

次のステップ

  • センサデータを行列化
  • Deep Neural Networkの設計

余談

  • MFT2018直前、2日半の有休をとりました。