ケチ上等！GPU費用を節約するため4台のカメラ映像を1度に映像解析するのに苦労した

![4画面スクリーンショット解析後_trimS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/4fb269db-f406-05f5-6c28-3352cc5f4491.jpeg)

#サマリー

　ここではディープラーニングによる映像解析を使った交通量調査システムを開発するにあたり、そもそも高額なGPUボード買えないため安いGPUをさらにケチって使い、4台のカメラ映像を同時に映像解析する方法を考えて苦労した話を紹介しています。「GPUがないなら、Teslaを買えばいいのよ？」というアントワネット思考な方は読まずにお帰りください。内容は以下の通りです。
・なぜGPU費用の節約を考える必要があるのか？
・ケチ作戦1：1枚のGPUボードで複数の映像を処理させよう⇒大失敗(10/5追記:大成功)
・ケチ作戦2：4台のカメラ映像を同時に解析させてみよう⇒成功
・苦労した点その１：車線の判別とログの分離
・苦労した点その２：速度と車間距離の算出
・処理速度とか解析精度とか雑感
・まとめ

#トップ画像とサンプルムービーについて

トップ画像は以下のサンプルムービーのスクリーンショットです。4つのカメラ映像を合成して1映像にしたものに、YOLO V3で主に車両を物体検知＆トラッキング＆速度算出に車間距離算出などを自動で行っております。
4映像同時処理のサンプルムービーは[こちら。](https://youtu.be/kXW7Co24v9A)
※映像解析済みの画像を4つ合成したものではありません。

#なぜGPU費用の節約を考える必要があるのか？
ディープラーニングと言えばNVidia製のGPUが定番ですが、NVidiaはコンシューマ向けGPU(GeForce GTXとかRTXとかのゲーミングPC用GPU)を2017年末よりデータセンターで使う事を禁止しています(一部ライバル対策の例外としてマイニングはOK)。よってデータセンター用途としては1枚数十～数百万円するTeslaなど高額なワークステーション・サーバ用GPUボードを選択する必要があり、価格も高騰。例えば平均的な価格と思われる某社でもTesla P40(VRAM24GB)のインスタンスが初期費用なしで時間課金が1時間349円(月額だと97000円)、Tesla V100(VRAM32GB)だと**初期費用が936000円**と個人&零細では「クラウド破産まったなし」の恐ろしい金額です。AMDのGPUを安く使えるGPU Eaterというクラウドサービスもあるようですが…。

そもそもコンシューマ用途であるGeForceシリーズでも1枚4万(RTX2060/6GB)～8.5万円(RTX2080/8GB)はするため、例えば32台のカメラから24時間365日送られてくるFHD映像をリアルタイム処理するには、下手をするとカメラ台数 × GPU台数(VRAMは最低6GB？)が必要となり、機材費が跳ね上がります。それを考えると監視カメラ沢山配置している中国は凄いなあ。
そんなわけで、「カメラ台数 × GPU台数」にならないよう節約を考えたわけです。なおVRM32GBとか積んでる高いTeslaはさすがに1台で4台とか8台分の処理はしてくれるかも？(すいません、使ったことありません。どなたかタダで1か月使える機会を恵んでください～)。


#ケチ作戦1：1枚のGPUボードで複数の映像を処理させよう⇒大失敗(10/5追記:大成功)

私の手元にあるGPUボードには、一世代前のコンシューマ向けGeForce GTX1080(8GB)が積んであります。仮想通貨のマイニング狂乱が過ぎ去ってから購入したので値下がりはしてましたが(当時12万円⇒7万円)。今は後継のRTX2080が85000円くらいですかね。
「いずれにせよ10万円近くするのに、FHD映像1つしか処理できないのはどうよ？」と思い、Anaconda Promptを2個立ち上げ、Windows環境で処理させてみました。そしたら、

    Error polling for event status: failed to query event: CUDA_ERROR_OUT_OF_MEMORY

という見たことないエラーが表示され、まったく処理できませんでした。
CPU(6コア)も負荷率がほぼ100%に張り付き、カーソルすら動きません。**大失敗です。**
やっぱりGeForceでは1枚でFHD映像を複数同時処理することはできないようです。トホホ。

**⇒(2019/10/5追記)**
コメントでアドバイス頂きまして確認したところ、kerasがGPUメモリを「あるだけ使い切る」設定になってました。これを40%に変更したところ、VRAM8GBでも無事にFHD映像の並行処理ができました。パフォーマンスなどについては測定してまた別記事で公開しますね。
**⇒(2019/10/5追記)**
こちらで記事にしました。[「Teslaが買えないのでGeForceで映像解析を3並列処理させてみた」](https://qiita.com/ComputerVision/items/dd20292a8b4aaab3e34f)


#ケチ作戦2：4台のカメラ映像を同時に解析させてみよう⇒成功

![4画面スクリーンショット解析前_trimS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/deb242e4-654d-5119-297c-e7726065657e.jpeg)

そこで方針を変えて、4つの映像を事前に1つにまとめて、それを処理させようと思いました。
イメージ的には、複数の監視カメラ映像を1つのモニターでまとめて表示させるアレですね。
Yolo V3で物体検知させるには、もちろんインプットの映像が高解像度であればよいのですが、4つのFHD映像を1つにまとめても、1つ当たりの映像サイズは960*540となりギリギリ使えそうです。
それよりもこれが成功すると、4枚必要だったGPUボードが1枚で済んで費用削減効果が大きいですね！

「4つの映像をリアルタイムで1つの映像にまとめる」には、画面分割器やUSBキャプチャーボード(HDMIをUSBに変換)などが必要になりますが、時間かかっていいなら映像編集ソフトでもマルチ映像は作れますね。いずれにせよ追加ハードウェアやソフトを買ってもGPUボード0.5枚分も費用は掛かりません。

そして結論から言うと、いろいろと苦労したものの、4映像を1度に処理させることは可能でした。処理時間も映像1本分よりはやや時間がかったものの、**4本分の処理時間を約1.22本分くらいに短縮できた**ためこれまた成功と言えます。

![4画面スクリーンショット解析後_trimS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/e2c60e82-3282-e8ec-2a35-a22f4daa4835.jpeg)

なお今回私が実施した映像解析は以下の項目です。
**・普通車やバストラックなど車両のみ検出。小型・大型に分類。
・検出した車両はトラッキングした（IDを付けた）
・車線情報(どの車線を走っているか)も個別に取得した
・車両の概算速度を算出した
・前方との車間距離を概算で算出した
・上記のログを出力した
・エビデンスとして、解析結果のビデオを出力した**

実施する項目が少なくなればなるほど処理時間も短くなりそう。車間距離とかね。


#苦労した点その１：車線の判別とログの分離

4画面分のマルチ映像を同時処理することにしましたが、もちろん通常の単画面映像と同じことがしたいです。ディープラーニング系の開発では、あきらめるとかガマンするというのは禁句ですから。逆をいうと、あきらめるのが嫌だったりガマンできない人がディープラーニングの開発に血道をあげているという感じですね。

今回のサンプルでは、まず車線に苦労しました。
4画面でザックリ17車線もあります。といっても、左上映像は反対車線は実は捨ててるし、右上映像も交差点の手前で1本から3本の車線に分かれる感じですね。実用上の車線は15と判断し、色違いのマスクを用意しました。こんな感じです。

![MultiImageTest02_mask15-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/55b577cc-d9a1-154f-fc28-312391c76a51.jpeg)

グレイの部分は除外領域です。除外領域では車両の検出を行いません。右下のマスクで上のあたりがグレイで塗りつぶされているのは、カメラから遠くなった車両は誤認識の原因となるので、わざと除外するようにしているからですね。詳しくは[「ディープラーニングで交通量調査の映像解析精度を上げるのに苦労した」](https://qiita.com/ComputerVision/items/2b5e8ed97610085a20c2)をご参照ください。

今回のシステムでは例えば車線のマスクカラーをLane_1=#FF0000と設定すると、Yolo V3が検出した車両のバウンディングボックスの中心点を求め、マスク画像に対応するピクセルのRGBを求めてそれが#FF0000だら「ID=4の小型車が123フレーム目にいるのは車線1でござんす」と解析結果のログに出してくれます。

現状では1つの解析結果ファイルに4画面・15車線分の情報が乗っかるわけなので、結構膨大になります。しかしExcelのフィルタ機能を使うなどして、「車線1～5までのログだけ表示！」とかやると**4画面のマルチ映像からでも1画面単位で解析結果が抽出できるわけです。**これはとても大事ですね。

言い換えると、今回のシステムでは車線の指定をフィルタにしてマルチ映像をもとの4映像それぞれのログに分離できるのです。マルチ映像でGPUは節約できたし、処理速度も速くなった。でも全部がグチャグチャになって、合体前の映像ごとにログを切り分けることができない…とかなっちゃうと、映像を合体させた意味もないですからね。

なお4画面分のマルチ映像での処理を考えると、1画面あたり最大で5車線分くらいはあった方がいいかもしれない（実際には5車線をフルで撮影するのは困難ですが)。となると、最大で20車線くらいは対応できた方がいいですね。でも今回の15色でも色をそろえるのは大変でした。システム的には車線として指定したRGBが1ポイント違っても見分けてくれるけど、マスク画像を作る側としては「隣の車線とは明確に異なる」「隣の画面とは色の組み合わせがハッキリ異なる」色を使いたい。私にはそんなに多くの「色のボキャブラリー」がないので色のチョイスに大変苦労しました。

ちなみにトップ画像の左上にあるFrame=685表示の下にある、15個のカラーブロックは左端からレーン(車線)1～15で使われている色を意味しています。

あ、よく考えたら中心点のXY座標の範囲でも頑張れば画面ごとにログを切り分けることができるかもですね。でもさらに車線単位に切り分けるのはムリそうですね。


#苦労した点その２：速度と車間距離の算出

![レーンとライン説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/a31ca12b-9671-ee70-a575-6bf33bcb449a.jpeg)

車両の車線位置が特定できたら、次はやっぱり速度を算出してみたいですよね。
速度の算出については[「ディープラーニングで映像から速度を正確に算出するのに苦労した」](https://qiita.com/ComputerVision/items/d5358632209c67dab325)で書いておりますが、私の設計ではトラッキングの利点を生かして「距離を設定した2本のラインを車両が通過する時間から疑似的に速度を求める」という手法をとってます。他の手法としては、トラッキングせずピクセルあたりの距離を設定して、概算で距離を出す方法もあるようですが、車両が検出された場所次第(カメラから遠い・近い)で「ピクセルあたりの距離＝算出した速度」が変動するので個人的には好きじゃありません。でもトラッキングから逃げたいなら、この方法もありかも？
※他に速度を簡単に算出できる方法をご存じの方はぜひアドバイスお願いします。ただしオプティカルフローは間に合っております。

それで車両の移動方向ですが、上の図の青矢印の通り4画面分のマルチ映像では8方向に移動します。
本来であれば「移動する車両と直行するように2本のラインを設置する」のがベターですが、8方向(下手をすると15車線で個別に)それぞれに2本ずつラインを設定するのは嫌な気持ちになります。

そこでこのシステムでは「ラインを超える順番」を指定できるようにしました。
「車線1はLine2⇒Line1の順」「車線5はLine1⇒Line2の順」とかですね。こうすることで、例えば左下の映像では車線が4本、方向が[5][6]の2つあるにもかかわらず、ライン設定はLine5,6の2本で済んでます。「素晴らしい設計でしょ！？」と自慢したいからこんなこと書いてるんですが、実際には何でもかんでもライン設定を省力化できるわけではありません
。例えば右下の映像では、LIne7,8で上下車線とも解析したいところでしたが、それが無理なのでLIne9,10を増やしました。

他にも例えば左下の映像では[6]の方向の車両は、ラインを越えてから車両が画面外に消えるまであまり時間がありません。要するにLine6の位置が低すぎるのですね。ここは[6]用に新規でラインを設定した方が良い結果が出たかも？他にも[2]はまったく速度が取れませんね。ただ元々撮影時から捨てている(検出対象として期待していない)車線なので、勇気を出して除外領域としても良かったかもしれません。
これを考えると、4画面で設定すべきLineの上限は16本くらい必要かもしれません。

ところでムービー上は一瞬しか表示されないものでも、解析結果のログにはちゃんと速度や車間距離の数値は入ってる場合もあります。
ライン設定を省力化するvsライン配置を車線ごとに最適化する・ムービーの見た目を優先するvs解析結果ログを重視する…など、判断するポイントが色々あります。
ちなみに私の場合はエビデンスとしてムービーを提出することがあり、それの見栄えが悪いとクレームがつく(解析結果のログはあまり見てくれない。見ても判断がつかない？)ので、見た目優先になることが多いです。

#処理速度とか解析精度とか雑感

![車線とライン説明2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/35d0e8b5-1d3c-de97-a1fa-598d071e83fd.jpeg)

最後に処理速度の話をしたいと思います。期待したいのは**「4画面マルチ映像でも、単独映像でも物体検出時間も精度もは変わらない！」**という結果になれば最高ですね。

この話をするには、「そもそもGPUの処理能力は何に費やされるか？」という問題に帰結します。このシステムでの処理は
**・Yolo V3による静止画単位での物体検知
・検知した車両のトラッキング
・多重検出の抑制
・速度算出
・車間距離算出
・ムービー出力**
に分かれます。このうち、GPUを必要とするのは「Yolo V3による静止画単位での物体検知」だけ（正確にはトラッキングも物体検知と合体しているので、GPU処理から分離できない)です。あとはすべてCPU処理。
また通常、GPU処理は物体検知する静止画の縦横サイズに大きく影響を受けます。大きな静止画の方が時間がかかるわけですね(解析対象が映像でもYolo V3は静止画単位でしか処理しません)。静止画サイズについては今回、4画面のマルチ映像も単体の映像も同じくFHD(1920x1080pix)なので差異はありません。
加えて1画面あたりの検出結果が多い・少ないでもGPUの処理時間は影響を受けます。つまり車両が全く通らない暇な4映像マルチムービーの解析時間は、渋滞気味の単独映像より処理時間がかかる…ということですね。

結果は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140663/c2084c00-e8d5-11a9-8e09-00253e9a9d96.png)

上記は1フレームあたりのGPUでの処理時間(単位=秒)で、左上映像～右下映像までは単独映像(FHD)での処理時間、丸い映像(FHD)は今回の左上映像～右下映像を合体させたもの(FHD)。いずれも1～500フレームまでの処理時間で平均をとっています。これを見ると単独映像が1フレームあたり約0.12秒なのに対し、マルチ映像は0.14秒となっています。**約22%**の増加ですね。ただし単独映像を1個のGPUで4本処理するには4倍の時間がかかるため、22%増加程度に短縮できるなら(マルチ映像の作成時間やコストにもよりますが)やってみる価値はあるかな？と思います。

あ、CPU処理時間と精度について書いてないな…。後で追記します。
あと「いいね！」が20以上ついたら自分でも解析してみたい方向けに、今回解析に使った4画面マルチ映像のオリジナルファイル(解析前)とマスク画像をダウンロードできるようにします。「いいね！」が少なければ、GPU節約なんかに興味ある人が少なくて、みんなTeslaを普通に買ってるという事ですね。羨ましい…。

**⇒(2019/10/2追記)**
記事を投稿してその日のうちに20いいね！を頂きました。ありがとうございます！
GPU費用の節約に興味を持っていただきホッとしました。
データは[こちら](Qiita_computervision191002.zip)にアップロードしております。処理前のムービー5本とマスク画像5枚で、約754MBあります。ご自由にご利用ください。

また今回はFHDの映像をフルフレームで(馬鹿正直に)処理しましたが、リアルタイム処理に近づけるよう高速化のテクニックもあれこれ試し済みなので、「ディープラーニングで映像解析を高速化するのに苦労した」とかの別記事を書きます。

#まとめ
・GPUの節約には、4画面マルチ映像化が有効
・マルチ映像化しても各映像ごとに解析結果を取り出せる工夫が必要(今回は車線の特定で対応)
・マルチ映像化すると、マスク画像の色や速度算出用のラインが単独映像より多く設定できる必要がある。
・マルチ映像化するとGPU処理速度は22%遅くなる
・Teslaとか早く安くなるといいな…


#関連記事
・[Teslaが買えないのでGeForceで映像解析を3並列処理させてみた](https://qiita.com/ComputerVision/items/dd20292a8b4aaab3e34f)
・[ディープラーニングで故障車両を発見するのに苦労した]
(https://qiita.com/ComputerVision/items/4f377bc3eb5e601676ac)
・[ディープラーニングで映像から速度を正確に算出するのに苦労した]
(https://qiita.com/ComputerVision/items/d5358632209c67dab325)
・[ディープラーニングによる映像解析で車両をトラッキングするのに苦労した](https://qiita.com/ComputerVision/items/d865f084c98a59349910)
・[ディープラーニングで交通量調査の映像解析精度を上げるのに苦労した](https://qiita.com/ComputerVision/items/2b5e8ed97610085a20c2)
・[SSD_KerasをWindowsで使って交通量調査できるか試してみた](https://qiita.com/ComputerVision/items/0f87b35f5941b7c3c06b)
・[YOLO V3を使った交通量調査ソフトを作って苦労した](https://qiita.com/ComputerVision/items/bdbf5c237004195a4fbc)