« WebRTCでリアルタイム画像処理してみた | メイン | 続・JavaScriptの顔認識ライブラリをチューニングしたら実用レベルになったという話(データ編) »

JavaScriptの顔認識ライブラリをチューニングしたら実用レベルになったという話

2012/05/08 追記
再度検証して検証データを公開しました。
追記終わり。
JavaScriptの顔認識ライブラリにccv.jsという有名なものがある。
ただ、WebRTCで顔認識させようとすると遅くてしかたがなかった。
最初は速いこともあるが、10回ぐらい認識をさせるとすぐに遅くなる。
とりあえず、デモ。
そこで、チューニングをしてみることにした。
まず、JavaScriptの定番の高速化を試してみた。
例えば、正の数で使える「Math.floor(x)」を「(x | 0)」に、整数で使える「x * Math.pow(2, y)」を「x << y」にする等。
これで、10~30%高速化できた。

次に、遅くなっている部分を調べたら、Web Workersで分散するための仕組みが遅くなる原因だとわかった。
これは、Web Workersを使わない場合にも影響が出ていた。
じゃあ、Web Workersを使えば速くなるのかといえばその逆で、20倍遅くなっていた。
詳しくは調べてないけど、多分Workerスレッドに処理データを渡す時にJSON化が走っているためっぽい。
(ちなみにccv.jsは、Worker数をひとつしか指定できない。)
この仕組みを全て外したのに加え、functionの呼び出しコスト等を考えて処理を色々弄ってみた。
これで、150~250%も高速化できた。
さすがにこれには驚いた。
(前述のデモと同時に開くと遅いので注意。)
手元の環境では、190ms~230msぐらいで処理できている。
これなら、実用でもなんとか使えるんじゃないかと。

あと、顔認識の知識がなかったので、gihyo.jpの記事を読んでからコード読むとかなり理解できたことを書いておく。
2012/05/04 追記
ちょっと勘違いされそうな書き方だったので2点追記します。

1点目。
オリジナルのコードでは、同期/非同期を切り替えるためにparallableという関数を定義しています。
主観ですが、このparallableを使うと、(通常では問題ないレベルで)メモリを比較的大きめにとるようです。
しかしWebRTCを使ってリアルタイムで処理を行うと、10回ぐらい顔認識を行うとGCが実行され始めるようです。
勘でしかありませんが、GCの処理が邪魔をして、顔認識のリアルタイム性が落ちてしまっていると感じました。

2点目は、Web WorkersとJSON化について。
非同期で処理を行った場合、処理時間が20倍になってしまうのですが、気になったので確認しました。
Workerスレッドには、基本的なオブジェクトしか渡せません。
parallable内ではtryの中で一度postMessageを実行し、catchされた場合にJSON化して文字列としてpostMessageを実行していました。
ccv.jsがWorkerスレッドに渡そうとしていたのは、CanvasPixelArrayを含むオブジェクトのため、JSON化されてしまいます。
手元の環境ではこのJSON化の処理に2000ms以上かかっていました。
次に時間がかかっていたのは、WorkerスレッドがJSON化された文字列を受け取ったところです。
JSONをparseするのに、手元の環境で1500ms程かかっていました。
WorkerスレッドからメインスレッドへのpostMessageは、JSON化されていませんでした。
2012/05/04 追記2
ccv.jsについてもう少し説明。
ccv.jsは、OpenCVの一部の機能をJavaScriptに移植したもののようです。
OpenCVはコンピュータビジョン(Computer Vision)のためのライブラリで、画像解析等でよく使われる処理をAPIとしてまとめたものです。
ccv.jsには、画像内のオブジェクト検出のAPIと、オブジェクト検出の前処理として必要なグレースケール化のAPIが含まれています。
オブジェクト検出には、機械学習の学習結果データが必要になるのですが、ccv.jsには顔検出の学習結果データが添付しています。
といっても、傾きなしの正面向きのデータしか含まれていないようで、現段階では用途は限られると思います。
このような理由のため、現バージョンのccv.jsは「顔検出のためのJavaScriptライブラリ」という認識がされています。
他のオブジェクト検出の学習結果データを準備すれば、他の色々な物を検出できるはずです。
2012/05/04 追記3
このエントリーのタイトルに「顔認識」と入っていますが、実はこれは誤りでした。
正確には「顔検出」です。
顔検出は画像の中から顔を探し出すことを指し、顔認識はその顔が誰なのかを判断することを指すようです。

コメント (5)

Yasushi Ando [TypeKey Profile Page]:

こんばんは。あんどうと申します。
ちょっとしたサンプルを作っているんですが、ccv.jsが遅くて困っていました。もしよろしければ代わりにこちらで紹介されている修正版ccv.js(ccv_for_realtime.js)を利用させていただきたいんですが大丈夫でしょうか?

Yasushi Ando [TypeKey Profile Page]:

こんばんは。あんどうと申します。
ちょっとしたサンプルを作っているんですが、ccv.jsが遅くて困っていました。もしよろしければ代わりにこちらで紹介されている修正版ccv.js(ccv_for_realtime.js)を利用させていただきたいんですが大丈夫でしょうか?

Kanasansoft [TypeKey Profile Page]:

この後に、pull request用に整理した物(rejectされましたが...)があるのでご参照下さい。
(全部書き変えるのではなく、遅い部分だけ抜き出して書き変えています。)
https://github.com/Kanasansoft/ccv/blob/for_realtime/js/ccv_for_realtime.js
使い方は、あんどうさんのBox2DJSと組み合わせたこちらが参考になるかと思います。
http://www.kanasansoft.com/weblab/2012/06/face_with_flying_object.html

Kanasansoft [TypeKey Profile Page]:

サンプルと言いつつ、今見たら非常にわかりにくいですね...。
顔検出の前処理のグレースケール化は元のccv.jsを使い、
顔検出の部分だけccv_for_realtime.jsを使うようになっています。
つまり、ccv_for_realtime.jsを読み込んで、
ccv.detect_objects
となっているところを、
ccv_for_realtime.detect_objects
に書き変えるだけでOKです。

Kanasansoft [TypeKey Profile Page]:

あと、バッドノウハウになりますが、
顔検出の精度がある程度悪くても良いなら、
渡す画像を小さくしてやると更に高速になります。
http://www.kanasansoft.com/weblab/2012/06/face_with_flying_object.html では
この処理をはさみ更に高速化させています。

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

Google

タグ クラウド