MotoJapan's Tech-Memo

技術めも

【行動認識 #6】tensorflowでCAE(Convolutional Auto-Encoder)を実装してみた

これの続き
【行動認識 #5】データ量別でCNNの性能差 - MotoJapan's Tech-Memo


今回はCAEの実装をしてみた。

CAEってなに?

CAEとは、Convolutional Auto-Encoderの略で、次元削減/圧縮テクニックの1つである。
AE(Auto-Encoder)のConvolutional版ということで、Convolution層を使い、情報量を少なくして特徴量を抽出する半教師学習。
特にCAEが画像などの多次元データを扱うにはそのままテンソル変換せずに使えるので筋が良い気がするのでこれで今回はやってみる。

構造はencoderとdecoderで構成され、

  • encoderの入力は画像等のデータ、出力は圧縮特徴量
  • decoderの入力は圧縮特徴量、出力は、画像等のデータ
  • decoderの出力とencoderへの入力が一致するように学習していく


活用方法は、次などがある。

  • 圧縮した特徴量を抽出できる
  • データが少ない場合の事は前学習として用い、encoder部分を再利用する
    • モデルの局所最適への落ち込みを回避できるという点。(最近だとデータが多いなら不要という話)

概要イメージは下記。

f:id:motojapan:20170815034208p:plain

詳細はいろいろなとこで記事になっているので他に譲ります。

実践

今回は前回に引き続き6行動のCAEを行う。
入力は、6ODF(加速度3軸、角速度3軸)の復号化。

今回のモデルは、Convolution + maxpooling 1 layer (=encoder) + unpooling + Deconvolution (=decoder) 1 layerで実装。
tensorflowだと、decoderは、tf.nn.conv2d_transposeが使える。
注意としては、ピクセル毎に回帰するので最後はsigmoidで0~1に収める必要がある。

結果

結果は例えばWALKを学習してみると、次の正解信号に対して、

f:id:motojapan:20170815032531p:plain

学習epochを回す毎にどんどん近づいていく。
(見てておもしろい)

f:id:motojapan:20170815032558g:plain

100[epoch]目以降はかなりオーバフィットさせ過ぎている感じもあるのでちょうどよいところ、
(WALKで言えば周期性が見えてくるところで)で打ち切る必要がありそうだ。

他の行動についてもすべてが並べてみるとなかなかの光景。

左上から右下までの順は次の通り。(横方向)
WALKING, WALKING_UPSTAIRS, WALKING_DOWNSTAIRS, SITTING, STANDING, LAYING
f:id:motojapan:20170815035856g:plain

学習曲線はこんな感じで学習できている。
f:id:motojapan:20170815104840p:plain

今後やりたいこと

  • 学習データが少ない状況で、CAEで事前学習
    • これで精度が上がるのであればいいなと。
  • 生成モデルとしてVAEの実装

以上。

【行動認識 #5】データ量別でCNNの性能差

これの続き
【行動認識 #4】Subjectを考慮してCNN層数別で性能差を確認 - MotoJapan's Tech-Memo


学習データ量別で確認してみる。

概要

もともとの総データ数は、7344件。
7344件 ⇒ ( 7344 x 128 [samples] / 50 [Hz] ) + 0.5 [overwrap rate] ⇒ 2.6 [hour]
これが100%⇒50%⇒25%と変化したときの精度差を確認。

結果

最終精度は下記

condition accuracy loss
full (100%) 0.9276 0.9687
half (50%) 0.9008 0.9108
quarter (25%) 0.8597 1.2324

tensorboardで学習進捗を書き出すとこんな感じ


f:id:motojapan:20170811170435p:plain

  • 学習データ量が多いほど精度向上がわかる
  • 大体80 [epoch]目でどれも精度的な収束は落ち着きがわかる
    • 比較的データが多いほうが初期精度も高い


f:id:motojapan:20170811170803p:plain

  • データ量が少ないとOverfitによる乖離傾向が強くなる


confusion matrixはどうだろう。

testデータの左からfull/half/quarterの順

f:id:motojapan:20170811174843p:plain

  • 特に姿勢系のSITTING/LAYINGの精度劣化が著しい(これは結構面白い)

SITTING/LAYINGは、0.87->0.77に落ち込み、誤検出の漏れ先はほとんどが姿勢系

まとめ

  • 学習データ量が多いほど、汎化性能は高くなっている
    • いろいろな行動パターンが学習できている
  • 学習データ量が多いほど、収束タイミングは早くなっている
    • epochを回すのもいいがデータが多ければepochをそこまで回さなくてもよいかも
  • 姿勢系は遷移系に比べてデータが必要
    • 繰り返し動作と単発動作だと、繰り返しの方が特徴量抽出しやすいのかも

以上。

【行動認識 #4】Subjectを考慮してCNN層数別で性能差を確認

これの続き
【行動認識 #3】機械学習/深層学習で人間行動認識 ~CNNしてみる~ - MotoJapan's Tech-Memo

前回はtrainデータでSubject未考慮で精度を検証した。(trainデータ内)
その精度は、93.43%

今回はtrain/testのそれぞれを使って評価
加えて、Convolution+MaxPoolingのペア層の数を変えて評価

前回との差

学習データ Subject CNN層数
前回 trainデータを7:3で分割して評価 (5136件:2194件) 14名 分割時に未考慮 (Conv + Pooling) x 2
今回 trainデータ(7344件) / testデータ(2944件) 20名 予めSubject単位で分割(14名/6名) (Conv + Pooling) x 1~3

結果

200[epoch]回した結果を載せる

model accuracy loss epoch throughput
(Conv + Pooling) x 1 90.86% 0.8690 165 1070 [fps]
(Conv + Pooling) x 2 92.76% 0.9687 184 314 [fps]
(Conv + Pooling) x 3 92.23% 0.9871 95 130 [fps]

f:id:motojapan:20170811004015p:plain

精度としては、0.67%程悪化したが、想像より精度劣化は無い印象

まとめ

  • 6 Subjects-vs-restで評価したがCNN2層で92.76%は出る
  • CNN3層だと収束が早いOverfitもしやすい
  • CNN層を減らすほど、スループット非線形(指数的?)に改善していく
  • 動きの再現性が低い可能性がある
    • 前回との差分を見ると極端な精度劣化かがないことから同じSubject内の同じ行動であっても毎回同じような動きではない可能性がある

【行動認識 #3】機械学習/深層学習で人間行動認識 ~CNNしてみる~

これの続き
【行動認識 #2】機械学習/深層学習で人間行動認識 ~データ確認~ - MotoJapan's Tech-Memo

やりたいことの1つでもあるtensorflowを使った。

結果

1. 精度

下記条件で検証して、精度としてはCNN(Convolutional Neural Network)で93.43%程度でた。

testセットの結果(93.25%時点)
f:id:motojapan:20170807231813p:plain

条件

  • データは、trainデータをtrainセット/testセットに7:3で分割 (Subject未考慮)
  • 精度は、testセットに対して分類した結果

2. tensorflowを使って良かった点

  • 実行速度が速い(いちいちpython層まで帰ってこない)
  • tensorboardがめちゃ使える
  • tensorflow mobileにも使える(まだやってないけど)
  • コミュニティが大きく、文献が多い

3. 逆に辛かった点

  • chainer上がりなので計算グラフを先に作るという概念なくて最初辛かった(慣れればOK)
  • 動的に計算グラフを更新できない(とりあえず簡単にはできなそう)
  • 学習中のネットワークのデバックができない(やり方がわからない)

Data

入力データは、前回の通り、下記の計6軸。

# 重力未分離加速度情報
total_acc_x_train、total_acc_y_train、total_acc_z_train
# 角速度情報
body_gyro_x_train、body_gyro_y_train、body_gyro_z_train

ラベルデータは、次の6行動。
WALKING(0), WALKING_UPSTAIRS(1), WALKING_DOWNSTAIRS(2), SITTING(3), STANDING(4), LAYING(5)

1データは、特に前処理せずに1軸あたり128 [samples]ずつ突っ込む。

Network

まず下記の感じで、[Convolution層 + pooling層] x 2で作って回す。
tensorboardでvisualize!

f:id:motojapan:20170808003624p:plain

忘れそうだらtensorboardの実行方法を記載。

>tensorboard --logdir=[target_logdir]

ちなみに精度やロスを出すときに、trainとtestのディレクトリを分けておくと、
tensorboardが色分けしてくれる。

Accuracy/loss

精度とロスはこんな感じになりました。
一応、学習はちゃんと進んでいる。

200 epoch 回したが、189 epoch目でtestがbestに。

epoch=189 train test
accuracy 0.9998 0.9343
loss 0.0004 0.5572

学習曲線は以下。(ありがとうtensorboard)
(※ただ、結局細かいところは自分でダンプした方がいい。)

Accuracy graph
f:id:motojapan:20170808003927p:plain
Loss graph
f:id:motojapan:20170808004420p:plain

analysis

実行速度(throughput)

環境は、Ubuntu 16.04 LTS / RAM 4G / Core-i7 CPU
このnetworkで 314.039 frame/secでした。

混合行列 (confusion matrix)

200 epoch目の結果で考察
bestの189 epochと比較してもそこまで大きく違わないので。

f:id:motojapan:20170808002615p:plain

trainから分かること
  • ちゃんとOverfitするだけの表現力がある
testから分かること
  • WALK系[WALKING(0), WALKING_UPSTAIRS(1), WALKING_DOWNSTAIRS(2)]と、WALK系以外[SITTING(3), STANDING(4), LAYING(5)]は分離できている。(予想通り)
    • ちなみに、WALK系は遷移系統、SITTING/STANDING/LAYINGは姿勢系統の動き。
  • WALKING_DOWNSTAIRSの推定はまず間違えない。
  • WALKINGは、UPSTAIRS, DOWNSTAIRSの一部であるから、間違える可能性がある。
  • 姿勢系統は、ぼちぼちお互いに勘違いするケースがあるが、0.87は精度が出せている。
    • 姿勢は、動きが少なく、特徴的な変化が少ないかもしれない。

同一Subjectが含まれる学習でも上記のような結果。

他の考察もそのうち。

【行動認識 #2】機械学習/深層学習で人間行動認識 ~データ確認~

この続き
【行動認識 #1】機械学習/深層学習で人間行動認識 ~事始め~ - MotoJapan's Tech-Memo

データセットは下記
UCI Machine Learning Repository: Human Activity Recognition Using Smartphones Data Set

ライセンスは次の通り。

This dataset is distributed AS-IS and no responsibility implied or explicit can be addressed to the authors or their institutions for its use or misuse. Any commercial use is prohibited.


「Human Activity Recognition Using Smartphones Data Set」『UCI Machine Learning Repository』データセット内 README.txt より。
URL: https://archive.ics.uci.edu/ml/datasets/human+activity+recognition+using+smartphones

データセットについて構造確認

train側だけだとこんなイメージ(test側もあり)

  • body_acc_x_train # 重力分離済み加速度情報 (★1)
  • body_acc_y_train
  • body_acc_z_train
  • body_gyro_x_train # 角速度情報 (★1)
  • body_gyro_y_train
  • body_gyro_z_train
  • total_acc_x_train # 重力未分離加速度情報 (★1)
  • total_acc_y_train
  • total_acc_z_train
  • X_train # 特徴量 (★1)
  • y_train # 行動ラベル (★2)

分類問題を解くのであれば、★2が正解ラベルであり、★1を駆使して分類する。
今回はより生に近い値でやりたいので、入力は重力未分離加速度情報(ax,ay,az)と角速度情報(gx, gy, gz)のみを利用。

ではデータの中身を眺める。

データセットの中身確認

trainデータだけでも、7352件/21名分あるのでまずこれを味見。

同一被験者/行動違いのデータを確認(時間領域)

被験者1(Subject1)内でのランダムに取り出した各Actionのノルム違い

total_norm_acc_train
f:id:motojapan:20170805005540p:plain
body_norm_gyro_train
f:id:motojapan:20170805005534p:plain

  • 明らかにWALK系とそれ以外で分離可能
  • この分離は、最大値、最小値、標準偏差を考察したが、標準偏差は加速度/角速度共に10^{-1}10^{-2}のorder差が見える

異なる被験者/同一行動のデータを確認

シンプルそうなSTANDINGで確認。

total_norm_acc_train
f:id:motojapan:20170805012236p:plain
body_norm_gyro_train
f:id:motojapan:20170805012300p:plain

  • total_acc_trainは、Subject3,5はオフセットしているように見える
    • これは最初から平均値等でキャンセルした方が良さそう。
  • body_gyro_trainは、かなり小さい値なので、その辺りで安定している
    • Subject11が持つ0.14[rad/s]付近のデータでも8.02[dps]と考えるとかなり小さい。

同一被験者/異なる動きのデータを確認(周波数領域)

周波数領域についても見たい。


・total_norm_acc_train

SITTING/STANDING/WALKING
f:id:motojapan:20170805015949p:plain

[SITTING/STANDING] [WALKING]という分離ができそう

・body_norm_gyro_train

SITTING/STANDING/WALKING
f:id:motojapan:20170805020155p:plain

[SITTING] [[STANDING] [WALKING]]という分離ができそう
・SITTINGはかなり限られた低周波が反応
・WALKが高周波の部分が良く反応している

他の分析

同一被験者/異なる試行のデータを確認

SITTING (周期性なし)
f:id:motojapan:20170805014848p:plain

WALKING (周期性あり)
f:id:motojapan:20170805014921p:plain

  • 傾向が見えるものもあるが、たまに特異な動きをするものもある(個人内ばらつき
  • 目視だが、行動によって周期性の無い動き周期性のある動き、その再現性が確認できる

以上。

簡単なデータ分析だが、組み合わせ次第で分離可能性は確認できる。

次回は学習。

【行動認識 #1】機械学習/深層学習で人間行動認識 ~事始め~

人間行動認識 ( Human Activity Recognition ) の領域の話。
去年の3月頃にやっていたが途中になっていたこともあったので、追試も兼ねて再開。
(tensorflowの勉強もしたいし)

人間行動認識 ( Human Activity Recognition ) とは

私の認識では、カメラやセンサ等、様々な機器から得られた情報を基に、人間の行動を学習/推定する認識技術テーマ。

f:id:motojapan:20170801234935p:plain



既存で様々な研究が進んでいて、
データであれば、

  • RGB画像、デプスなどの光学系
  • 加速度、角速度、気圧などのセンサ系

などがある。

行動であれば、

  • Standing, Sittingなどの姿勢系
  • Walking, Runningなどの遷移系
  • その他、より特徴的な動き

など多岐にわたる。

詳しくは後々まとめる。

やりたいこと

  • 行動認識のデータセットをいじり倒したい
  • tensorflowを勉強したい
  • 機械学習やら深層学習の知見を深めたい

データセット

個人的なモチベとしては、スマホでとれるセンサ系データを扱いたい(去年は扱っていた)

まず触ってみるのにいろいろ探したが、一番簡単に扱えそうなUCIから提供されるデータセットを利用。
UCI Machine Learning Repository: Human Activity Recognition Using Smartphones Data Set

一応、日本のデータセットも探した。
特に、大きいところだと、Human Activity Sensing Consortium(HASC)というコミュニティもあるが、簡単にアクセスできるデータが少なかったので今回は諦める。

ちなみに、UCIから提供される上記のデータセットは、2015年のUpdate版もある。
UCI Machine Learning Repository: Smartphone-Based Recognition of Human Activities and Postural Transitions Data Set

An updated version of this dataset can be found at [Web Link]. It includes labels of postural transitions between activities and also the full raw inertial signals instead of the ones pre-processed into windows.


「Human Activity Recognition Using Smartphones Data Set」『UCI Machine Learning Repository』より。
URL: https://archive.ics.uci.edu/ml/datasets/human+activity+recognition+using+smartphones

データについて

重要なことを書き残し

被験者 ボランティア 30人
年齢 19-48歳
行動種類 WALKING, WALKING_UPSTAIRS, WALKING_DOWNSTAIRS, SITTING, STANDING, LAYING
データ収集デバイス smartphone (Samsung Galaxy S II)
バイス上のセンサ 3軸加速度、3軸角速度
サンプリングレート 50 [Hz]
ラベリング手法 同時に撮影した映像からラベルを手動生成
データセット 学習データ:テストデータ=7:3 (被験者単位で分割)

データセットについては次の記載がある。

The sensor signals (accelerometer and gyroscope) were pre-processed by applying noise filters and then sampled in fixed-width sliding windows of 2.56 sec and 50% overlap (128 readings/window). The sensor acceleration signal, which has gravitational and body motion components, was separated using a Butterworth low-pass filter into body acceleration and gravity. The gravitational force is assumed to have only low frequency components, therefore a filter with 0.3 Hz cutoff frequency was used. From each window, a vector of features was obtained by calculating variables from the time and frequency domain.


「Human Activity Recognition Using Smartphones Data Set」『UCI Machine Learning Repository』より。
URL: https://archive.ics.uci.edu/ml/datasets/human+activity+recognition+using+smartphones

つまりこういうこと(だよね?)

  1. 加速度/角速度には、ノイズフィルタを適用
  2. 各データ(各軸)は128samplesのウィンド、オーバーラップは50%
  3. 加速度には、バターワスフィルタで重力成分を分離
  4. 特徴量ベクトルを時間/周波数領域から取得

今日は以上、次回は実際にデータを眺めたりしたい。

【Linebot #3】家の温度をLineで通知するアプリ (BME280使用)

家の温度をサーバーに通知して、自分のスマホに通知したい。
でも開発は最小にしたいので、Linebotとして開発した。
サーバサイドのみの開発で済むしね。
忘れそうなことや注意点を書き残し。
主に、サーバーサイドとクライアントサイドのpython実装とかとか。

できたもの

自動通知された時
日中部屋は地獄のように熱い orz (外の方が涼しい)
f:id:motojapan:20170722121708p:plain

システム図

  • 家で稼働しているraspberry piから温度センサ値を取得
  • herokuに定期通知
  • MessagingAPIを用いて、自作Lineアプリに温度を定期通知、もしくは、要求する。

f:id:motojapan:20170722120819p:plain

温度取得に使ったもの

1. 温度センサ
使用した温度センサはBME280。
温度だけでなく、気圧、湿度も取得可能。
これ↓↓↓
BME280使用 温湿度・気圧センサモジュールキット: センサ一般 秋月電子通商 電子部品 ネット通販

2. Raspberry Pi 3 Model B
https://www.amazon.co.jp/Raspberry-Pi-TSI-PI018-Clear-Pi3-Model/dp/B01D1FR29M

やったこと(忘れやすいことのメモ)

1. raspberry piにraspbianをインストール(割愛)
2. raspberry piにログイン

Raspbianの初期パスワード

username password
pi raspberry
4. 初期設定とか
$sudo apt-get update
$sudo apt-get upgrade
5. I2Cを有効化、ツールインストー
$sudo raspi-config

“5 Interfacing Options” -> “P5 I2C”でEnableを選択
カーネルモジュールがロード確認 (無事、i2c_devがある)

$lsmod

f:id:motojapan:20170722123534p:plain

I2C関連ツールをインストー

$sudo apt-get install i2c-tools
$sudo apt-get install python-smbus
6. BME280を繋いでI2C接続確認

実際の配線とかは※1を参考にしているので割愛

こんな感じ
f:id:motojapan:20170722124641p:plain

接続確認は以下

$ i2cdetect -y 1

f:id:motojapan:20170722123444p:plain

7. raspberry piから温度取得(割愛)

※1がわかりやすいのでそちらを参照しました。

8. 温度情報をHerokuに送信する

raspbianはpython2.7系なので、次のコードでクライアントサイドを実装
urllibを使います。
今回はPOSTになります。

#the case of python 2.7
import urllib 
def post_message(t, p, h):
    print('post')
    data = {}
    data["temp"] = t
    data["pres"] = p
    data["hum"]  = h
    server_addr = 'https://xxxxxxxxx.herokuapp.com/info'
    try:
        data = urllib.urlencode(data).encode("utf-8")
        res = urllib.urlopen(server_addr, data=data)
        res = res.read().decode("utf-8")
        print(res)
    except:
        print('error')

3系だったらこんな感じのはず

#the case of python 3.xx
import urllib.request, urllib.parse
def post_message(t, p, h):
    print('post')
    data = {}
    data["temp"] = t
    data["pres"] = p
    data["hum"]  = h
    server_addr = 'https://xxxxxxxxx.herokuapp.com/info'
    try:
        data = urllib.parse.urlencode(data).encode("utf-8")
        with urllib.request.urlopen(server_addr, data=data) as res:
           res = res.read().decode("utf-8")
           print(res)
    except:
        print('error')
9. 温度情報をHeroku側で受信する

サーバーサイド。こっちはflaskです。
linebot側はこの辺の知識を活用です。
【Linebot #2】herokuでブックマークアプリを作ってみた - MotoJapan's Tech-Memo
今回はPOSTを受ける。

#the case of python 3.xx
@app.route("/info", methods=['POST'])
def info():
    param_t = float(request.form['temp'])
    param_p = float(request.form['pres'])
    param_h = float(request.form['hum'])
    content = ' temp : {0:3.1f} deg \n hum  : {1:2.1f} % \n pres  : {2:4.1f} hPa '.format(param_t, param_h, param_p)
    user_id = 'yyyyyyyyyyyyy'
    line_bot_api.push_message(user_id, TextSendMessage(text=content))
    return 'POST OK!'

注意
GETも同様に書けばよいですが、param_t, param_p, param_hをグローバル変数にいれておいて、GETするのは危険です。
Herokuは定期的に寝てしまうので、寝ると消えるようです。
ちゃんとDBに登録したものを返すようにしましょう。

HTMLを返すとブラウザからはこんな感じで見えます。
f:id:motojapan:20170722131251p:plain

10. raspberry piスクリプトを起動し続ける

普段はteratermから接続していますが、セッションを切るとプロセスもきれる。
なので、次の2つ方法で、永続化をします。

1. rc.localに書き込む
これは起動時に実行されるスクリプトを指定できます。

$sudo emacs /etc/rc.local

重要なのは、「exit 0」の前に書くこと。

sudo python [target].py & #<-ここを追記
exit 0


2. 実行時にnohupを使う
これはセッションを切ってもプロセスを残す方法です。

$nohup sudo python [target].py &


以上、のんびりやっても半日くらいもあればできました!

参考資料

※1: BME280をRaspberryPiから動かす話(すごくわかりやすい)
Raspberry Pi + BME280モジュールで自動で温度・湿度・気圧を測定してグラフ化する - karaage. [からあげ]