物体検出の出力が遅かったのでグリッドコンピューティングで実装した話

to3oi.hatenablog.com

以前作成したこの記事では物体検出の精度はまあまあいいものの、それにかかる時間が遅く、プレイ体験としては悪かった。
原因はCPU使用率が常に100%に張り付いていることだった。
新しくPCを組む時間も予算もないので、既存のものを使用して、なんとかCPU使用率100%を回避しつつ、1秒間にある程度の回数、物体検出をできるようにしたいというのが今回の目標です。

実際に使用していたPCのスペック

  • Core i7 9700K
  • RTX2080 Super
  • メモリ 32GB

原因究明

家の環境での物体検出は特に遅くなく、問題ありませんでした。
そこで、それぞれの環境の違いを見比べていった結果、今回書いたコードではスレッド数が足りてないという結論に至りました。
具体的には家のPCはAMD Ryzen 7 5700X 8-Core Processorでスレッド数が16あり、実際に使用していたPCでCore i7 9700Kでスレッド数が8で、家のPCより少なかったです。

解決策

幸い、このPCは何台か確保しており、同時に動かすことで対応できそうという結論に至りました。

そこで、まず以下のような構成でパソコンを配置して通信することにしました。
MasterPCではKinectの画像処理をしてClientPCにUDPで送信します。
ClientPCでは送られてきた画像に対して物体検出をし、その結果をMasterPCにUDPで返します。
というようなことをすれば、なんとなく動きそうな予感がしたので、実際に作成してみました。

通信は以下の順で実行することで動くと予想しました。 ※()内の数字はポート番号

ただし、通信周りは高校の頃勉強していた基本情報技術者の知識と2023年(今年)の3月頃から作っていたUnity上でUDPTCP/IPの通信を楽にするアセットUnityEasyNetの知識しかなかったので、実際に動くかわからない状態でスタートしました。
github.com

問題点

最初は上の画像のようにTCP/IPで通信する処理で実装していましたが、UDPで受け取りを開始し、最初の受信をした際エラーで落ちるという問題が起きました。
今回は時間がなく解決策を聞けそうな人もいなかったので、UDPに置き換えて実装することにしました。


TCP/IPでエラーが出ること以外は既存のコードもあるので特に問題なく実装(移植)できました。

グリッドコンピューティング

どのあたりがグリッドコンピューティングかという話

MasterPCからClientPCに画像データをUDPで送信するときに送信済みのClientPCのIPを保持しておき、物体検出の結果が返ってくるまでは再度画像を送信しないという処理を入れています。
これによりClientPCは同時に複数の画像の物体検出をすることはなくなり、ClientPC 1の物体検出結果を待っている間にClientPC 2に画像を送り物体検出をすると言うのを繰り返すことになります。
そしてこのあとClientPC1台あたりの物体検出にかかる時間を割り出し、連続した画像をClientPCに送るのではなく、ClientPC 1に画像を送り返ってくるまでの中間でClientPC 2に画像を送り物体検出の結果をなめらかにする処理を入れようとしましたが、ClientPCを2台接続した時点でほぼ毎フレーム物体検出の結果が返ってくるようになったので未実装で終わりました。

結果

最終的に30FPS以上出せるようになりました。

以下のリポジトリにそれぞれのコードがあります。 github.com github.com