ニューラルネットで声から体調を推定するシステムを作りました
IDCフロンティア主催のIoTと健康をテーマにしたハッカソン、サバフェス 2016で Healthy Voice Netというシステムを作ったので紹介します。大雑把に言うと、ニューラルネットワークを用いて声色を分類することで、声から体調が分かるシステムです。
プレゼンテーション
デモ動画
ソースコード
概要
Healthy Voice Netは、体調による声色の違いをニューラルネットワークを使って学習させることで、声から体調を推定できるシステムです。
見た目はこんな感じ。
ニューラルネットの学習
データの用意
体調の良い時、寝不足の時、風邪気味の時の声をたくさん録音しておきます。今回は「おはよう」という決め打ちの文言を、それぞれ約30回ずつ録音したファイル(wav, mono, 16bit, 44.1kHz)を用意しました。データ数は多ければ多いほど良いと思いますし、ノイズへの耐性を強くするために、様々な環境で録音するほうが好ましいです。
音声の前処理
前処理として、録音した音声ファイルをFFTにかけ、さらに音量を正規化します。これは、体調の良し悪しが音声のスペクトルに現れるという仮定のもと、波形の違いをニューラルネットに学習させるためです。音声の録音にはPyAudioを、FFT変換にはscipyをそれぞれ利用しています。
ニューラルネットの構成
ニューラルネットは、4層の全結合のものを利用しています。
- 入力層: 20000次元 (1Hz〜20kHzの各周波数の音量に対応)
- 中間層1: 100次元
- 中間層2: 20次元
- 出力層: 3次元 (良好、寝不足、風邪気味の各体調に対応)
ニューラルネットの生成、学習にはChainerを利用しました。
学習の実行
約100個の音声ファイルに対して60世代ほど学習をさせました。学習にかかる時間はCPUを利用しても10分程度です。学習データが少ないためか、かなり過学習になる傾向があり、50〜60世代くらいまでは精度が上がっていくのですが、逆にそこから先はテストデータに対する精度が落ちてしまいました。本来ならば現在の100倍〜1000倍くらいの学習データが必要だと思います。
体調の推定
システムの構築
システムの構築には以下のデバイスを利用しました。
- Raspberry Pi2 Model B
- サンワサプライ USBマイクロホン MM-MCU01BK
- タクトスイッチ 1個
- LED 3個
- 1kΩ抵抗 3個
- LCD 1個
- ブレッドボード・ジャンパワイヤ
LEDとスイッチは以下のように配線しています。
LCDの表示方法については以下の記事を参照してください。
上記のようにデバイスを構成して、Raspberry Piでpythonのスクリプトを動かすと、デモ動画のように動作します。
推定精度
ノイズの少ない環境においては、僕の3つの声色はかなり高い精度で推定できました。特に寝不足風の声に関しては、かなり声色に癖があったためか、ほぼ100%の確率で正しく推定できています。一方で、ノイズに対する対策を一切行っていないので、周辺の雑音が多い環境では普通の声が風邪気味と推定される確率が高かったです。
クラウドとの連携
ブラウザでの結果確認
今回のハッカソンがIDCフロンティア主催のサーバーフェスタということで、IDCFクラウドを利用してデータの表示や他のシステムとの連携を行っています。
推定された体調や録音された音声は、以下のページからブラウザ上で確認可能です。
- Healthy Voice Net (2016年4月末くらいまではアクセス可能)
上記のページでは単に結果を見られるだけでなく、ページ内のフォームで正しい体調を指定することで、ニューラルネットの学習用データが追加され、推定精度を高めることができます。ページの表示にはdjangoを利用しています。
myThingsとの連携
myThingsのIDCFクラウドチャンネルを利用することで、体調が推定された際に、myThingsからGmailやSlackなどのサービスへ通知を飛ばすことが出来ます。面倒なのかと思いきや、環境構築用のスクリプトが用意されていたので、ものの1時間程度でスマホにプッシュ通知を飛ばすことができました。しかも、クーポンを利用すると半年くらい無料でサーバが利用できるので超オススメです。
さいごに
本システムを持って乗り込んだサバフェスですが、なんとIDCF賞をいただくことができました。叙々苑で美味しい焼き肉食べてきます!
参加賞としてRaspberry Piやセンサー、microSDカード等を提供してくださった主催者、スポンサーの皆様、色々とお話をさせていただいた参加者の皆様、どうもありがとうございました!
サバフェスは本当に素敵なイベントです!次回以降も是非参加したいと思います!
ROSのbagファイルから特定トピックをcsv形式で出力する
めちゃくちゃ簡単。
環境
- Ubuntu 14.04
- ROS Indigo
bagファイルをcsv形式で出力
以下のコマンド1行でいける。
$ rostopic echo -b bagファイル.bag -p /トピック名 > csvファイル.csv
例えば、Twist形式だと以下のようになる。
$ rostopic echo -b bagファイル.bag -p /velocity %time,field.linear.x,field.linear.y,field.linear.z,field.angular.x,field.angular.y,field.angular.z 1458645072419031373,0.133069615205,0.0,0.0,0.0,0.0,0.5369403653 1458645072485691182,0.143589122067,0.0,0.0,0.0,0.0,0.447242712703 1458645072552957164,0.153924085326,0.0,0.0,0.0,0.0,0.377736128001 1458645072620157095,0.164047896997,0.0,0.0,0.0,0.0,0.322948435252 1458645072687306707,0.173941054616,0.0,0.0,0.0,0.0,0.279093465935 1458645072754349028,0.183588971233,0.0,0.0,0.0,0.0,0.24350186043 ...
特定の速度成分のみを取り出すのも簡単。
$ rostopic echo -b bagファイル.bag -p /velocity/linear/x %time,field 1458645057721221180,0.191296330546 1458645057788266707,0.18462966388 1458645057856087891,0.177962997213 1458645057922422050,0.171296330546 1458645057989690875,0.16462966388 ...
参考URL
aitendoの脈波センモジュールをArduinoで使ってみる
aitendoの脈波センモジュールをArduinoに接続して脈波を取ってみます。
必要なもの
- 脈波センモジュール - aitendo
- Arduino Uno
- ジャンパーワイヤ3本(センサモジュールに付属)
接続方法
基板にマイナスマークのついている端子をArduinoのGNDに、プラスマークの端子を5Vに、S(シグナル)の端子をアナログ(A0〜A3)のどこかに接続します。
スケッチのダウンロード
続いて、Githubのリポジトリからスケッチをダウンロードします。
$ git clone https://github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino.git
クローンされたディレクトリを開き、その中のPulseSensorAmped_Arduino_1dot4
ディレクトリをArduinoのワークスペースにコピーします。
$ cd PulseSensor_Amped_Arduino $ cp -r PulseSensorAmped_Arduino_1dot4 ~/Documents/Arduino
スケッチの編集
ArduinoでスケッチファイルPulseSensorAmped_Arduino_1dot4.ino
を開き、以下の行を編集します。
// pulsePinの値をセンサーを接続したピン番号に変更する int pulsePin = 0;
void loop(){ // 中略 // LEDを光らせないので以下の1行をコメントアウト // ledFadeToBeat(); }
スケッチの実行
スケッチを実行し脈波センサに指を当てると、シリアルモニタに測定値が流れていきます。
S911 S911 S335 B104 Q572 S0 S158 S550 S891 S911
Sから始まるのがセンサーの測定値、Qから始まるのが前の心拍からの経過時間、Bが現在の心拍数を表しています。
うまく脈波が取れない場合は、下図のように結構強めに指を押し当てるのがポイントです。
シリアルプロッタで可視化
以下のようにプログラムを修正すると、シグナルの値のみをシリアルプロッタで可視化することが出来ます。
PulseSensorAmped_Arduino_1dot4.ino
void loop(){ // 中略 // 以下の1行をコメントアウト // serialOutputWhenBeatHappens(); }
AllSerialHandling.ino
void sendDataToSerial(char symbol, int data ){ // 以下の1行をコメントアウト // Serial.print(symbol); Serial.println(data); }
一応パルスらしきものが取れていますね。
参考URL
iframeを含んだページでBootstrapのメニューが開閉しない
Bootstrapで、iframeが含まれているページを作った時に、navbarが開閉できないという問題に遭遇しました。
問題のiframeは以下の通り。
<iframe src="hoge.html" class="hoge" name="hoge" width="340" height="200">
原因は単純で、</iframe>
で閉じるのを忘れていただけで、以下のように修正したら無事動くようになりました。
<iframe src="hoge.html" class="hoge" name="hoge" width="340" height="200"></iframe>
参考URL
ArduinoでSRF02のI2Cアドレスを書き換え
Arduinoで超音波距離センサ SRF02のI2Cアドレスを書き換える方法です。
元のアドレスを確認
デフォルトではSRF02のアドレスは0xE0(224)なので、I2CScanerのスケッチを利用すると、0xE0の上位7bitである0x70(112)にデバイスが見つかります。
シリアルモニタの出力結果
I2C device found at address 0x70 ! done
I2Cアドレスを変更
同一センサを複数個利用するケースでは、各センサのアドレスをそれぞれ別の物にする必要があります。
以下のスケッチを実行すると、SRF02のアドレスが224から226に変更されます。
変更後のアドレスを確認
再度I2CScannerを実行すると、確かにアドレスが226(上位7bitは0x71=113)に変更されています。
I2C device found at address 0x71 ! done