Take’s diary

Macとマイコンに関すること--ワクワクの製作日記

NVIDIA TX1+OpenFremeworks+DIGITS でTensorRT をさらに加速させる。

メーカー側のお題みたいですが、

 今回はDIGITSで学習させたDetectNET学習済みデータが、TX1で応用可能かどうか確認してみることにしました。さらに、OpnFrameworks(以降OF)のofThreadでマルチスレッド化。ディープラーニング技術が現実的にTX1で簡単に実現可能かどうかもテストしてみました。

f:id:TAKEsan:20170203172051p:plain

実際に母艦環境でKITTIを学習させ(早い話、車の認識)、このデータを利用してTX1に接続したWebカメラで、iMac上の動画を読み取らせて、車を認識させた上にBox2Dでバウンディングパーティクルを車の中心から吹き出させています。60fps!!滑らか〜〜。

         

Movieで再現するとこんな感じ。Box2Dの吹き出すパーティクルについては、多摩美術大学の田所先生のソースを応用させていただきました。

まずDIGITSで学習させたDetectNETデータが、TX1で実行可能か?

 以前使用した学習済みデータは、Jetson-inferense をビルド時に自動的にダウンロードされたデータを使っていました。

github.com

が、現実的に母艦環境のDIGITで学習させたデータが利用できるんでしょうか?。以前も書いたように、「この人なんか怪しい」。GitHub上の質疑応答を見てもなんだかなーです。実際、作者本人以外ネット上で公開している方が存在していないみたいです。で、やってみました。もともとテストデータは人物の認識でした。今回はカメラで取り込んだ動画で、「車」の認識を実現させて見ます。

 まず、当然ですが学習させることから始めます。日本語環境ではこの方のブログがベスト。

soralab.space-ichikawa.com

 私の母艦環境はGTX1080+i7 6700Kなので、縮小データでなく実データで学習させて見ました。3.5時間程度必要。3.5時間といっても30エポックなので、GTX1080はそれなりにかなり早い(現実的なスピード)と思われます。そして車を認識しているかどうか確認してから、作成されたファイルをTX1にコピーします。必要なデータは3つで以下の通り。

f:id:TAKEsan:20170203141858p:plain

わかりにくいのですがデータの保存先がDIGIT上に表示されています(矢印部分) 。ソララボさんが主張している通りグラフが変です。

f:id:TAKEsan:20170203141937p:plain

必要なデータはdeploy.protitxtと、各エポックで作成されるスナップショットデータの一番最後と、

f:id:TAKEsan:20170203141934p:plain

           KITTI変換データのmean.binaryprotoファイルです。

さらに、deploy.prototxt の一番最後を消します。(どうやらPythonクラスはTensorRTでは実行できない模様)

f:id:TAKEsan:20170203141931p:plain

この3つを「car」とか名称をつけたフォルダにまとめて、この前のTX1上のOFプロジェクトのbinにコピー。

takesan.hatenablog.com

さらにプロジェクト中のsrc/ofApp.cppの最初の方2箇所を修正追加(赤部分)

#include "ofApp.h"

#include <include/cudaMappedMemory.h>

#include <include/cudaNormalize.h>

#include <include/detectNet.h>

#include <include/cudaRGB.h>

#include <include/cudaNormalize.h>

 

//標準では、PEDNET,PEDNET_MULTI,FACENETの指定可能。それぞれped-100multiped-500face-120に対応 binフォルダの中にリンクフォルダを入れておく

//リンクファイルは、jetson-inference/build/aarch64/bin に入ってる。

detectNet::NetworkType networkType = detectNet::PEDNET;

//他の学習済みデータを使う場合はCreateを次の用に変更

detectNet* net = detectNet::Create("car/deploy.prototxt.bak", "car/snapshot_iter_19140.caffemodel", "car/mean.binaryproto");

//Create("multiped-500/deploy.prototxt", "multiped-500/snapshot_iter_178000.caffemodel", "multiped-500/mean.binaryproto" );

//この場合はmultiped-500。必要なのは3つのファイル jetson-inference/detectNet.cpp 参照。後の2つの引数がデータ種類によって違うので注意。

//detectNet* net = detectNet::Create(networkType);

....................

 

 最初は時間がかかります(変換作業により3〜4分)が、2回目以降は簡単に実行できるようになります。自分で作成したデータの学習結果がTX1+OFで自由自在に応用できるようになります。が.........、カクカク画面が気に入らない。このままでは、本来のOF上画像処理を始めTX1のGPIOに接続した外部機器までもがカクカクになってしまう...。ってことで次の段階。

f:id:TAKEsan:20170203141927p:plain

TX1側のOFのプロジェクトの中身です。初回でmake -j4 make run すると、〇〇〇.caffemodel.tensorcasdheが作成されるため実行までに3〜4分必要。ターミナルにエラーが表示されていなければ正常に動いてます。ハングしたんじゃないかと心配になりますが...。一度作成されれば次回からはスーイスイ。

               

          

      全体のスピードは、TX1のクロックスピードを最大にしても8ps程度のカクカク動画。

で、マルチスレッド化!!

 どんなことかって言うと、2台のTX1があって、1方はカメラ画像のみ、もう1方は人物や車の認識をしているとして、これを1つのTX1で実行してしまうのと同じことを実現させるのと同じ。マルチスレッドと言うんだそうです。前回までは1スレッドのみの実行だったので、物体認識に時間を取られ、単純な画像表示までカクカクになってました。が、マルチスレッド化すると画像表示が本来のスピードに戻ります。有り余った時間(CPUはIntel Jouleより多少遅いですが、なんつったってTX1は本格的なGPUと、CPUを4つ持ってるんですからこれを最大限使ってやります)でOF本来の画像処理が可能。一方、物体認識用のスレッドは本来のスピードで認識し続けます。やっと認識した結果を、早い方のスレッドに渡してやります。ただし認識処理部分が極端に遅いとイマイチなんですが、今回はまーまーなんで、知らない人はおおおおーっと思うことでしょうね。こんなことは昔から「C」をかじってきた人なら、すぐ思い付くでしょうが、できると分かっていても敷居が高くてなかなか踏み込めません。立て続けにTX1がらみのソフトをかじってきて、できたらいいなーってことをやってみました。TensorRT側はGPUを使っているので、うまくマルチススレッド化できるのかどうか疑問が残りましたが、OFのアドオンofThreadを使ったら、割とあっけなく動いてしまいました。結果は次の動画。

                

今回のカメラデータは1280x720です。そこそこ大きな画面ですが、60fps出てるのが確認できます。肝心の車の認識ですが、どうでしょうか。ほぼリアルタイムなのがわかると思います。この例では高速道路上の車の認識なんですが、街中に入ると若干遅れぎみになります(相対スピードの問題)。

 開発環境がOpenFrameworksなんで、朝飯前なんです。こんなところにフレームワークに乗っかってプログラムを作る意味が出てきます。マルチスレッド化についてはWEB上で画像での比較が見つかりません(私の場合はですが)。2つの動画の比較で、感覚だけでも理解できると思います。認識はほとんどリアルタイムって感じでしょ。画像表示部分に関しては、単純にカメラ画像と認識した部分の図形を表示しているだけですから、まだまだ沢山の画像処理などを実行させても力が有り余ってます。今回のOFプロジェクトはここからダウンロードできます。

take-detct-thread_X.zip 直

 

コンパイル済み実行ファイルと、学習済みデータも入れときましたので、Jetson-inferenseがビルドできていれば動くはずなんですけど、どうでしょうか?。今回はDetectNet上で2クラス以上の物体についても認識可能(色分け可能)にしました。

 ちょっと話が違いますが、今回取り上げたJetson-inferense。TX1のGPUクロックを最大にしても、認識スピードに変化がありません(作者がjetson_clocks.shを実行しなさいと書いているにもかかわらず)。前に試したZEDライブラリは倍近く早くなったのに、不思議。GPUメモリに画像を転送しないと動かないということは、確実に認識エンジンとしてGPUを使ってるはず。っということはまだ改良の余地があるカモです。この辺りも非常にアヤシイ!!。もうしばらくバージョンアップの動向を追っていく必要がありそうです。

調子に乗って

 別スレッドで実行している「クルマ」の認識結果を利用して、ofxBox2Dを使ってパーティクルを動かして見たのが冒頭の画像です。Box2Dで制御されたCircleの動きが自然であることが確認できると思います。一見複雑そうな処理も簡単に実現できました。

 これで「母艦環境でのDIGITSを使った学習-->TX1を使った現場での応用」の基本環境と流れができちゃいました。夢見ていたディープラーニング応用がとても簡単に!!。どうでしょうか?夢中になっちゃいますよね。

f:id:TAKEsan:20170203141542j:plain

                               では また。