【行動認識 #1】機械学習/深層学習で人間行動認識 ~事始め~
人間行動認識 ( Human Activity Recognition ) の領域の話。
去年の3月頃にやっていたが途中になっていたこともあったので、追試も兼ねて再開。
(tensorflowの勉強もしたいし)
人間行動認識 ( Human Activity Recognition ) とは
私の認識では、カメラやセンサ等、様々な機器から得られた情報を基に、人間の行動を学習/推定する認識技術テーマ。
既存で様々な研究が進んでいて、
データであれば、
- RGB画像、デプスなどの光学系
- 加速度、角速度、気圧などのセンサ系
などがある。
行動であれば、
- Standing, Sittingなどの姿勢系
- Walking, Runningなどの遷移系
- その他、より特徴的な動き
など多岐にわたる。
詳しくは後々まとめる。
データセット
個人的なモチベとしては、スマホでとれるセンサ系データを扱いたい(去年は扱っていた)
まず触ってみるのにいろいろ探したが、一番簡単に扱えそうな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
つまりこういうこと(だよね?)
- 加速度/角速度には、ノイズフィルタを適用
- 各データ(各軸)は128samplesのウィンド、オーバーラップは50%
- 加速度には、バターワスフィルタで重力成分を分離
- 特徴量ベクトルを時間/周波数領域から取得
今日は以上、次回は実際にデータを眺めたりしたい。
【Linebot #3】家の温度をLineで通知するアプリ (BME280使用)
家の温度をサーバーに通知して、自分のスマホに通知したい。
でも開発は最小にしたいので、Linebotとして開発した。
サーバサイドのみの開発で済むしね。
忘れそうなことや注意点を書き残し。
主に、サーバーサイドとクライアントサイドのpython実装とかとか。
できたもの
自動通知された時
日中部屋は地獄のように熱い orz (外の方が涼しい)
温度取得に使ったもの
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をインストール(割愛)
4. 初期設定とか
$sudo apt-get update $sudo apt-get upgrade
5. I2Cを有効化、ツールインストール
$sudo raspi-config
“5 Interfacing Options” -> “P5 I2C”でEnableを選択
カーネルモジュールがロード確認 (無事、i2c_devがある)
$lsmod
I2C関連ツールをインストール
$sudo apt-get install i2c-tools $sudo apt-get install python-smbus
6. BME280を繋いでI2C接続確認
実際の配線とかは※1を参考にしているので割愛
こんな感じ
接続確認は以下
$ i2cdetect -y 1
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を返すとブラウザからはこんな感じで見えます。
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. [からあげ]
【Linebot #2】herokuでブックマークアプリを作ってみた
普段気になるURLをブックマークしているが、また見返すことなく、あっという間に埋もれてしまう。
なので、LINEアプリとしてメモも書けるブックマークアプリを作ってみた。
後々は、特定のアドレスに定期送信したり、Slackにnotifyしたり、傾向解析したりする予定。
検討
DB周りはこの辺で検討
【Linebot #1】windows8.1(local)とherokuでpostgreSQL環境構築 (psycopg2) - MotoJapan's Tech-Memo
Messaging APIの使いまわしはこの辺で検討
【Messaging API #2】reply_messageで「request body has 1 error」が起きる (python) - MotoJapan's Tech-Memo
イメージ図
シーケンス図
- 構成要素は、LineApp, Line server Heroku sever, Postgres server。
- 実装作業は、Heroku severのみで、Postgres serverは、HerokuにDeployしたコードからSQLでいじる程度。
登録 (Store)
- URLとメモ(optional)を登録すると、タイトルを自動生成して送り返してくる
履歴確認 (Restore)
- 過去の登録内容(登録時刻、タイトル、メモ、URL)が表示される
結構簡単にできる。
【Linebot #1】windows8.1(local)とherokuでpostgreSQL環境構築 (psycopg2)
Linebotを最近書いているのですが、そろそろオウム返しbotだけだとつまらないので、データベースを組み込みたいなと。
もともとsqlite3を使っていたのですが、Herokuはsqliteが簡単に使えないことをdeploy時に気づき、やむなくpostgres対応を考えることに。。
そこまでの手順とハマったことの覚書です。
手順は次です。
1. ローカルのwindows環境でpostgresをインストール・動作確認
2. heroku環境でpostgresをAddon追加・動作確認
1. ローカルのwindows環境でpostgresをインストール・動作確認
まず動作確認用のローカル環境を準備
1.2. pythonから実行するためのモジュール(psycopg2)をインストール
次でインストール
>pip install psycopg2
動作確認
>python Python 3.4.3 |Anaconda 2.3.0 (64-bit)| (default, Mar 6 2015, 12:06:10) [MSC v.1 600 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import psycopg2 >>>
エラーなしでOK!
たった手順2つで簡単に環境が揃いました。
あとは、psycopg2のAPIで接続やテーブル作成してみて動いていることを確認。
2. heroku環境でpostgresをAddon追加・動作確認
実はherokuでのpostgres環境構築は、windows環境よりはるかに楽でした。
(というかwindows側いらなかったと反省、インストールも早いし)
やることは、「herokuアプリケーションに heroku-postgresql Addonを追加」する。
herokuはpostgresをaddonとして対応(無料)しているのでこれを使う。
しかもheroku-postgresqlはherokuと独立したインスタンスを提供されます。
なので、ローカルで動作確認したい場合は、上記1.1で飛ばして、ローカルからpsycopg2で接続すればおk!
2.1. heroku-postgresql Addonの確認
確認方法1 (GUI)
https://dashboard.heroku.com/apps/application_id/resources
※application_idは自分のlinebotをdeployしているアプリケーションID
ここにheroku-postgresql Addonがあるか確認
確認方法2 (CUI)
>heroku addons --app <application_id>
無ければ次へ。
2.2. heroku-postgresql Addonの追加
>heroku addons:add heroku-postgresql --app <application_id>
下図のように、https://dashboard.heroku.com/apps/application_id/resourcesに追加されています。
2.3. heroku-postgresql Addonの設定取得
>heroku config --app <application_id> DATABASE_URL: postgres://aaaa:bbbb@cccc:dddd/eeee LINE_CHANNEL_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxx LINE_CHANNEL_SECRET: yyyyyyyyyyyyyyyyyyyyyyyyyyy
今回重要なのは、[DATABASE_URL]説明は次の通りです。
aaaa | user_name |
bbbb | password |
cccc | server_name (私の環境はawsの模様) |
dddd | port |
eeee | database_name |
psycopg2での接続は次のような対応になります。
import psycopg2 user = aaaa pwd = bbbb server = cccc port = dddd db = eeee con = psycopg2.connect("host=" + server + " port=" + port + " dbname=" + db + " user=" + user + " password=" + pwd)
なので、ローカル環境でもdeploy先のherokuでも上記で繋げばOKです。
【Messaging API #2】reply_messageで「request body has 1 error」が起きる (python)
herokuにdeployしていた下のコード。
ちゃんと動いていたはずのreply_messageがいつからかErrorを吐いて終了していたので覚書。
変な文字列でも入れたのかと切り分けを進めたが、結果的には、contentsの文字列が長すぎた模様。
line_bot_api.reply_message( event.reply_token, TextSendMessage(text=contents) )
大体、マルチバイト含んで2000文字近く送ろうとした時に落ちてる。
OK | NG | |
len(contents) | 1709 | 2008 |
len(contents.encode(utf-8)) | 2401 | 3092 |
headerとかもろもろのオーバーヘッドがあるので、具体的によくわかないけど目安がてら。
対策は下記2つ。
1. contentを分けて、reply_messageを細かく送信
予想はしていましたが、結果としてもダメでした。
event.reply_tokenは、①30秒以内に、②1度のみ送信できるルールでした。
2. contentを分けて、push_messageを細かく送信
これは成功しました。
(例)
for content in contents.split('\n') try: line_bot_api.push_message(user_id, TextSendMessage(text=content)) except LineBotApiError as e: print(e)
めでたしめでたし。
【Messaging API #1】 クライアントのユーザID(user_id)とアカウント名(display_name)の取得方法 (python)
久しぶりにMessaging APIを使ってLinebotを書いてますが、メッセージを送信してきたクライアントのユーザIDとアカウント名の取得方法を忘れそうなので、書き残し。
クライアント側から「おはようございます」とpostすると、Webhookされたサーバーサイドのeventの中にこんな情報が入ってきます。
eventはWebhookParserでparseした中にiteratableで入っています。
event { "message": {"id": "xxx", "text": "おはようございます", "type": "text"}, "replyToken": "yyy", "source": {"type": "user", "userId": "zzz"}, "timestamp": 14994xxxxxxxx, "type": "message" }
ここで得られる"userId": "zzz"が、ユーザIDに相当し、ここからget_profileでアカウント名を得ます。
if isinstance(event.source, SourceUser): profile = line_bot_api.get_profile(event.source.user_id) user_id = event.source.user_id # ユーザID (zzz) user_disp_name = profile.display_name # アカウント名
終了です。
これで得られたユーザIDでDB登録をしたりできますね。
【kaggle⑤】初心者がタイタニック号の生存予測モデル(Titanic: Machine Learning from Disaster)をやってみる(機械学習、DeepLearning)
これの続きで、今回で一通り終わります。
【kaggle④】初心者がタイタニック号の生存予測モデル(Titanic: Machine Learning from Disaster)をやってみる(学習データ相関確認、分割、正規化) - MotoJapan's Tech-Memo
3. 機械学習
今回は下記6パターンをそれぞれ比較しました。
・Random Forest
・K Nearest Neighbor
・SGDClassifier(パーセプトロン)
・Support Vector Machine
・Gradient Boosting Decision Tree
・Deep Learning(by Chainer)
精度面では結論から言うといまのところ、Support Vector Machineが最も優秀でした。
Random Forest / Support Vector Machine / Deep Learning (by Chainer) がタイでベストスコア。(K Nearest Neighborが6%程悪い)
(17/07/15更新)
上記の内、古典的アルゴリズムは、sklearnに含まれています。
Deep LearningはChainerでシンプルなFFNNを構成しています。
実装はすべてgitにあるので参考にしてください。
sklearnに含まれているものは、どれも同じような呼び方で3行程度書けば学習もでき、評価もsklearn.metricsを使うと簡単です。(素晴らしいですね)
学習方法
sklearnに含まれるアルゴリズムでは、次の5手順で基本的には終わり
K近傍法の場合は下記
#1.アルゴリズムのインポート from sklearn.neighbors import KNeighborsClassifier #2.パラメータを指定してアルゴリズムインスタンス生成 knc = KNeighborsClassifier(n_neighbors=3) #3.学習データで学習 knc.fit(x_train_std, y_train) #4.評価データで推定 y_true, y_pred = y_eval, knc.predict(x_eval_std)
ここでのパラメータはハイパーパラメータと呼ばれており、値によって精度が大きく変わる。
理詰めでハイパーパラメータのあたりをつけるのも良いが、組み合わせ爆発を起こすため、自力で求めず、グリッドサーチといった手法を使う方がベター
pythonには、sklearn.grid_search があるのでこれを使ってインスタンスを生成してベストなパラメータを求める。
今回は、Support Vector Machine / Gradient Boosting Decision Tree で利用。
精度評価
精度評価にはprecision, recall, f1 scoreが用いられるが、忘れやすいので、ここに書き残しておく。
説明 | 数式 | |
precision | 適合率 (正確性:システムが正しいと判定したものの内、本当に正しく判断できたのの割合) | tp/(tp+fp) |
recall | 再現率 (網羅性:正しく判断されるべきものの内、本当に正しく判断できたのの割合) | tp/(tp+fn) |
f1 score | F値 | (2×適合率×再現率)/(適合率+再現率) |
pythonでは上記の情報を1行でかける
from sklearn.metrics import classification_report print(classification_report(y_true, y_pred, target_names=["not Survived", "Survived"]))
これを用いて各精度比較を進める。
各精度比較
データ正規化比較
各アルゴリズムを100回実行した場合の平均値は下記の通りとなりました。
これはF値ではなく、kaggleで扱われる単純な認識精度となります。
正規化による精度改善がうかがえます。
以上、精度 78.974% (順位1777位タイ / 7082 teams) の話でした。
時間ができたら、もっとしっかり特徴量設計したいなぁ。
精度向上のための特徴量ToDo
- 年齢ではなく年齢層を用いる
- 1桁精度の年齢は実は不要な可能性がある
- データ数を間引く
- 全データを必ず使わなければならないというルールはなく、むしろ無理やりフィッティングすることで汎化性能が下がる可能性が高い
- 信頼性のあるデータのみを使うほうがよいかも