小型IoT端末開発キット「SensorTile.box」 を使って機械学習を体験④

前回の記事[“小型IoT端末開発キット「SensorTile.box」 を使って機械学習を体験③”](https://qiita.com/ykawano/private/d2c289e2b1d3cdb06734)からの続きです。
今回は、ディシジョン･ツリーの評価テストを行います。前回作成した機械学習モデルをSensorTile.boxに設定して動作検証してみます。

# 1. ~ 4.　（機械学習セットアップ）

→ [記事③](https://qiita.com/ykawano/private/d2c289e2b1d3cdb06734)を参照してください
データ収集およびUnico-GUIツールを使った機械学習作業を紹介しています。

# 5. 評価

今回の学習データはインターンシップ学生さんに協力してもらい収集しました。評価（Test）は別の人間（当記事執筆者）が行っているので、最低限の汎用度の確認はできると思います。

## 5-1. 準備

### スマートフォンのセットアップ

スマートフォンをパソコンに接続し、前回作成したucfファイルをスマートフォン内の任意のフォルダにコピーします。
今回は、STMicroelectrnics\MLC以下に適当なフォルダ（“ucf_Test”）を作ってそこに置きました。

![400_ucf_smartphone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/a99e837f-13ac-6281-44b5-317cd6c8d4a7.png)


STBLESensorにて、MLCが使えるようにセットアップします。まずは以下の手順でExpert modeから新規アプリ作成へ進みます。

![401_stblesensor_mlc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/6d533e69-db61-7019-53e7-3090555b2356.png)

まず入力センサとしてMLC Virtual Sensorを選択します。その後セットした入力センサの編集ページに入り、“SELECT A UCF FILE”をクリックして先ほどスマートフォンにコピーしたucfファイルを指定します。

![402_stblesensor_mlc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/6e737c21-b1b8-78e1-4a51-c0a5b613b575.png)

アプリを保存して完了です。
ここではアプリ名を“mlc stop&walk”としました。

![403_stblesensor_mlc3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/16c443d7-b9af-a3af-41ed-87ec5192a4bc.png)

スマートフォン側のセットアップはこれで完了です。

### 取り付け

データ収集時と同じように、左足首に取り付けます。軸の向きも同じ方向に合わせます。

![410_ankleSetup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/7a483c36-ff46-dcd0-2081-e61d7936fe25.png)


## 5-2. 結果 & 検証

### 試験 1 

実際に各動作を行ってみます。
歩行時はほぼ正しく判定されましたが、直立時や座っている時に誤判定される場合がありました。

|ディシジョン･ツリー    |直立      |座る＆リラックス   |座る＆貧乏ゆすり   |歩行   |ゆっくり歩行   |
|:------------:|:---------:|:--------:|:--------:|:--------:|:--------:|
|（1）Mean_ACC_X 判定    |△      |△   |△   |○   |○   |

△例: 直立静止状態でも、”walk”と表示される場合など。

### 検証 1

今一度ディシジョン･ツリーを見直してみます。


![410_tree_mean_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/59e9deb6-6990-4f4a-c7b9-5fc44e7f887b.png)


**「ACC_X値のMeanが0.99gより大きい → 歩いている」**
というディシジョン･ツリー内容ですが、SensorTile.boxのX軸が鉛直の場合ほぼ1gになるので、これでは足首が地面に対して垂直で静止している時でも「歩いている」と判断されてしまいます。

arffファイルには各Featureとして演算された結果が格納されているので、Meanデータについてグラフ化してみました。
見方としては、左半分が静止時（1~25 : stop1~5）で、右半分が歩行時（26~50 : walk1~5）です。
確かにwalk1~5についてはACC_Xの値が1を超えてるので判定ラインとして使えそうですが、stop1（直立）およびstop2（座って貧乏ゆすり）あたりの値もほぼ1に近いので、かなり微妙です。


![411_arff&tree_mean_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/acbd635f-fd1c-6476-602e-228f76d678dc.png)


（グラフ解説）
このグラフは、各モーションを全て横に繋げたようなイメージで、以降のグラフも同様です。横軸は時間と考えて問題ありません。“stop1”（直立）などの1モーション（1ファイル）は約10秒間分の記録です。センサODR = 26、Window Length = 52設定の場合、約2秒おきにFeatureが算出されるので（52/26）、1モーション区間に約5個のデータ･ポイントが存在します。

![412_motion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/b4b73450-e520-b234-2454-aa3205005135.png)






### 試験 2 Featuresを“Variance”に設定して評価

ディシジョン･ツリー作成時に選択したFeatureは、ACC_X軸のMean（平均値）でした。
別のFeatureも試したいので、個別に選択して再度作りなおします。Unico-GUIに戻り、Variance（分散）のみ選択して再度ucfファイルを作成します。

![420_unico_vari.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/bbd8ab92-dfe3-a5ae-4734-1ce2321ff51f.png)

#### 実行&結果2
5-1．準備にてSTBLESensorで作った“mlc stop&walk”アプリの編集ページを開き、ucfファイルを置き換えます。同じように試験すると、今度は正常に判定されました。

|ディシジョン･ツリー    |直立      |座る＆リラックス   |座る＆貧乏ゆすり   |歩行   |ゆっくり歩行   |
|:------------:|:---------:|:--------:|:--------:|:--------:|:--------:|
|（2）Variance_ACC_X 判定    |○ （=stop）     |○ （=stop）  |○ （=stop）  |○ （=walk）  |○ （=walk）  |


### 検証 2

ディシジョン･ツリーは以下のように生成されました。
**「ACC_X値のVarianceが0.06836より大きい → 歩いている」**

![421_tree_vari.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/620dffd8-781b-a646-5e7a-851f49adb0d6.png)


試験1同様、arffファイルでグラフ化してみましょう。
貧乏ゆすり時のデータ（Stop2あたり）が少しふくらんでいますが、その他の静止時期間についてはほぼゼロに近く、おおむね区別できそうです。

![422_arff&tree_vari_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/93a97147-7119-5964-4d38-50dda9792059.png)




### 試験3 その他のFeatures

その他３つのFeaturesも試してみます。同じように１つずつFeatureを選択してucfファイルを作成後、各動作を試験しました。
+ Energy
+ Peak-to-Peak
+ Zero-Crossing


#### 実行&結果3
EnergyとPeak to Peakについては少し誤判定がありましたが、おおむね問題ないようです。

|ディシジョン･ツリー    |直立      |座る＆リラックス   |座る＆貧乏ゆすり   |歩行   |ゆっくり歩行   |
|:------------:|:---------:|:--------:|:--------:|:--------:|:--------:|
|（3）Energy_ACC_X 判定    |○ （=stop）     |○ （=stop）  |○ （=stop）  |○ （=walk）  |△*1   |
|（4）PtoP_ACC_X 判定    |○ （=stop）     |○ （=stop）  |○ （=stop）  |○ （=walk）  |△*1  |
|（5）Zero-cross_ACC_Y 判定    |○ （=stop）     |○ （=stop）  |○ （=stop）  |○ （=walk）  |○ （=walk）  |

*1 ゆっくり歩く程度によってはstop判定になる場合あり

##### Energy　検証
“Energy”は、最初に作成されたディシジョン･ツリーにおけるMean（平均値）とグラフ的には似ています。
こちらもACC_Xが判定値として採用されてますが、Meanの時と同様に判定ラインとしてはきわどい感じがします。取り付け方向がズレた場合、判定エラーになりそうなので、方向に依存しない **ACC_V** を使った方がベターです。

![430_arff&tree_energy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/d80b0991-a8de-0c2d-0d95-713eda4113f1.png)



##### Peak-to-Peak　検証
“Peak-to-Peak”はVarianceのグラフと似てます。
ここでもACC_Xが採用されていますが、貧乏ゆすり時（Stop2）の値が判定ラインと近いです。より激しい貧乏ゆすりの場合オーバーしてしまう可能性があります。今回の設置方向条件では、（貧乏ゆすり時の振動方向と関係なさそうな）ACC_Yを使った方がより安全な判定ができるでしょう。

![431_arff&tree_P2P.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/730db9d1-4cd9-bd37-8039-80cd189d1c05.png)



##### Zero-Crossing　検証

“Zero-Crossing”は、**設定された振れ幅値（ヒステリシス→Threshold: gで設定）を超えた回数** をカウントします。今回、ディシジョン･ツリー作成時にThreshold = 0.3gに設定したので、± 0.3gを超える振れ幅がカウント対象です。これまではACC_Xばかり判定値として採用されていましたが、今回はさすがに使えなかったようで、**ACC_Y** が選択されていました。ACC_Xを選択した場合、貧乏ゆすり時（Stop2）の値が大きいので、Walk時との判別ができないのは明らかです。

![432_arff&tree_Zcross.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/2685d937-a32c-0549-db63-ecbcb7799930.png)


ちなみに、Zero-CrossingのThreshold値を変えてみると様子が変わりました。
Thresholdを2倍（0.6g）にすると、貧乏ゆすり時のカウントがほぼ消えています。振動の振れ幅が把握できるのであれば、最適なThreshold値を設定するのもひとつの手です。

![433_arff_Zcross_Th.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/c0e750e7-4067-3a41-7b13-78126a6013ab.png)



## 5-3. 全体感想

今回の動作モデルでは、arffデータグラフの様子から、 **Variance（分散）** や **Peak-to-Peak**、**Zero-Crossing**などのFeatureが適していると予想できます。なお、Mean（平均値）では、静止状態と歩行状態の区別が難しいということもわかりました。
判定自体が2択とシンプルだったので、グラフ観察によりマニュアル的に適切な判定Featureを予想できましたが、実際にはデータがもっと複雑･大量で、判定クラスも多種になるケースもあるはずです。その場合、人間の観察眼だけで行うと手間がかかる上に面倒なので、機械学習ツールの活用が有効です。


##### Unico-GUIツールFeature設定についての注記

データ内容やConfiguration設定、クラス分け条件に依るのかもしれませんが、複数のFeaturesをセットしても上の方にあるFeatureばかりが条件式として採用される傾向にあります。Features設定項目は上から順にMean→Variance→Energy→･･･と並んでいるので、Meanばかりが採用されるケースが多いようです。
最適なFeatruesを選んでいるというより、“上から順にFeaturesを試していって、それで判定できればOK”といった印象です。また、今回5つのFeaturesを試しましたが、最後のZero-Crossを除き全てX値での判定でした。各軸についてもX→Y→Zという順番で評価されているようで、明らかにXよりYの方が判定値として適切では?と思われるケースでも、Xが選択されていました。そのため、ディシジョン･ツリー作成作業におけるFeatures設定時に、最適な軸を自分で選ぶことを推奨します。


##### 応答時間と安定度の関係

この記事では省略しましたが、WL（Window Length）値設定条件によっても判定の安定度・応答時間（例：座った状態から歩き始めて、判定結果が“stop”→“walk”に変化するまでの時間）が変わる様子が観察されました。ここまでの記事内では、すべてWL = 52と設定していたので、判定確定には約2秒（52/26）かかる仕様になっています。応答時間をもう少し早めたいという場合、単純にWLを小さくすると判定間隔は短くなります。例えばWL = 26とすると1秒ごとの判定になりますが、各Featuresのarffグラフで見たところ、下図のようにデータが暴れるため注意が必要です（→Features演算前のフィルタ設定により改善できる可能性はあります）。そこで、Meta-Classifierを使って判定結果の安定度を高める方法もあります。しかし、Meta-Classifierは遅延的な要素を含んでいるので、せっかくWLを小さくして応答を早めようとしても、Meta-Classifierを追加したことで鈍い反応になってしまう可能性もあります。
今回のようなアクティビティ検出動作モデルの場合、最初の試行としては、WLについて26~52の間で最適な値を選ぶことを推奨します。




![500_Summary_WL=26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/bfe6c56c-4732-f99b-3fbc-37983e3d5d78.png)








# 6. 最後に（次回予定）

今回の記事では、当初の予定どおり静止/歩行の2判定のみとしましたが、次回はもう少し判定種類（クラス数）を増やした場合の学習を試してみたいと思います。


## 補足

記事③内で少しコメントしましたが、SensorTile.boxとData recorderアプリを使ってデータ収集を行う場合に知っておくべき補足情報です。

### 補足A.

##### SensorTile.boxの向きと各内蔵センサの向きの関係

SensorTile.boxのData recorderアプリで加速度センサ･データをログすると、実際のセンサ側（センサ個体）のオリエンテーションとは異なる向きに変換後、記録されます。

![600_apend_orientation_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/a96915cb-cfb8-de53-0453-62c0f2ec1e33.png)



ログ記録例（SDカード）：3つの加速度センサをオン
（アプリ作成時、センサ選択画面でチェックを入れた順番にログのカラム（列）が左から並ぶので、メモしておく必要がああります。下表の順番とは限らないので要注意）
SensorTile.boxは縦置き（USBコネクタ部上向き）: Y値 = +1g
各センサ個別の軸向きは違うはずだが、**全て“SensorTile.box”本体としての向きに統一** されている。

![601_append_SDlog.png_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/9cd4665a-dd46-5723-8461-fba4f5951847.png)



センサに設定するucfファイルの内容はあくまでセンサ側から見た軸（に基づくデータ）に合わせる必要があります。Unico-GUI→MLC作業開始時のデータ入力の前段階で、csvファイルの列を操作するなどの変換処理を行っておいてください。例えば、LSM6DSOXの加速度センサ･データを入力する際、以下のような変換が必要です。

![602_append_transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/8e4169c5-7e4f-5527-7b5f-09cae52020a0.png)

### 補足B.

##### Unico-GUIへの入力データ･フォーマット

Unico-GUIの仕様として、csvファイル入力時の各カラムは **加速度X-Y-Z、ジャイロX-Y-Zの順番** にデータ列が並んでいる必要があります（仮にcsvファイルの先頭カラム名が“accX[mg]”などとあったとしても、そのカラム名を認識してUnico-GUIの“Acc X”列に取り込まれるわけではない = 取り込み時、csvファイルにある先頭行のカラム名は無視され、単に左列から“加速度X”、“加速度Y”、・・・の順番で取り込まれる）
今回ジャイロ･データは使用しませんでしたが、STBLESensorでのData Recorderアプリ作成時にジャイロセンサを先に選んでしまうと、ジャイロ･データ列が一番左にくるのでUnico-GUIへ正常に入力されません。なお、タイムテーブル列に関しては自動で無視されるので、RTC（Time）やRTC（Date）を先に選択しても問題ありません。


![603_append_inputcsv_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/c6d19340-4c38-5197-8ad0-87162ac6d0e4.png)


~ 補足終わり