Jetson Nanoでリアルタイムに物体検出をする方法（TensorFlow Object Detection API/NVIDIA TensorRT）

![jetson_detection.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/9106f198-3521-0246-6150-72b8b763d76e.gif)

# Jetson Nanoでの物体検出
　[Jetson Nanoでディープラーニングでの画像認識を試した](https://karaage.hatenadiary.jp/entry/2019/04/29/073000)ので、次は物体検出にチャレンジしてみました。そこで、本記事では、TensorFlowの「Object Detection API」と「Object Detection API」を簡単に使うための自作ツール「Object Detection Tools」を活用します。

　これらに関して詳細は、以下ブログ記事を参照下さい。Jetson Nanoでの物体検出自体は、本記事で完結するのでブログ記事は読まなくても大丈夫です。

[TensorFlowの物体検出用ライブラリ「Object Detection API」を手軽に使えるソフト「Object Detection Tools」を作ってみた](https://karaage.hatenadiary.jp/entry/2019/05/27/073000)

　これ以降の本記事の作業は、全部Jetson Nanoで行います（Jetson Nano自体のセットアップ作業を除く）。

# Jetson Nanoで最も簡単に物体検出する方法
　まずは、以下記事をもとにJetson NanoのTensorFlowのセットアップまでを実施します。

[Jetson Nanoをセットアップしてディープラーニングで画像認識試してみた](https://karaage.hatenadiary.jp/entry/2019/04/29/073000)

　具体的には、Jetson Nanoが起動するところまでできたら、以下4行のスクリプト実行するだけです。TensorFlowやOpenCV、Matplotlibなどの必要なライブラリがインストールされます。

```sh
$ git clone https://github.com/karaage0703/jetson-nano-tools
$ cd jetson-nano-tools
$ ./install-tensorflow.sh
$ ./install-tools.sh
```

　また、以下記事のSwapファイルの設定も実施しておいて下さい。これを実施しないと思い処理（モデルの変換等）を実施したとき、プログラムが落ちる可能性があります。
[Jetson Nano関係のTIPSまとめ](https://qiita.com/karaage0703/items/b14c249aa33112669ee4)


　あとは、SSD Lite Mobilenet V2という軽いモデルを使えば、そのまま物体検出のデモを動かすことができます。具体的には以下5行のコマンドを実行するだけです。

　使用しているプログラムは「Object Detection API」のサンプルプログラムをベースに、私が作成したものです。

```
$ cd && git clone https://github.com/karaage0703/object_detection_tools
$ cd ~/object_detection_tools/models
$ ./get_ssdlite_mobilenet_v2_coco_model.sh
$ cd ~/object_detection_tools
$ python3 scripts/object_detection.py -l='models/coco-labels-paper.txt' -m='models/ssdlite_mobilenet_v2_coco_2018_05_09/frozen_inference_graph.pb' -d='jetson_nano_raspi_cam'
```

　`-l`でラベルファイルの指定。`-m`でモデルファイルの指定。`-d`で使用するカメラの指定をしています。今回は、Jetson NanoにRaspberry Piカメラモジュールv2を繋いで使用していますが、`-d`で`jetson_nano_web_cam`を指定すれば、USBのWebカメラでも使用可能です。

　実行結果は、以下のようになります（ソフトのバージョンによって、若干表示は異なります）

![jetson_detection.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/9106f198-3521-0246-6150-72b8b763d76e.gif)

　ラズパイカメラモジュールを使用して物体検出したとき、起動時にフリーズしてしまう場合は、一度カメラの画像を表示してから起動するとうまくいく場合があります。

　画像の表示に関しては、私がテストプログラムを用意したので活用下さい。具体的には、以下2行のコマンドでプログラムのダウンロードと実行ができます。実行すると、カメラ画像がウィンドウ上に表示されます。終了したい場合は、画面上でESCキーを押して下さい。

```sh
$ wget https://raw.githubusercontent.com/karaage0703/jetson-nano-tools/master/scripts/raspi_cam_test.py
$ python3 raspi_cam_test.py
```

# NVIDIA TensorRTを使ったモデルの最適化
　物体検出を更に高速化したい場合や、もう少し大きいSSD Mobilenet V1を使いたい場合は、NVIDIA TensorRTという仕組みを使って、モデルを最適化することで高速化することが可能です。この場合、Jetson NanoでObject Detection APIの環境構築とモデル変換が必要になるため、少し手順が複雑になります。

　順に説明していきます。

## Jetson Nanoへの「Object Detection API」環境構築
　環境構築は、[「Object Detection API」の公式のセットアップ情報](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/tf1.md)を参考に、Jetson Nano用に修正したものとなります（Jetson NanoはArmコアなので公式情報そのままではセットアップできません）。あくまで非公式情報ですのでご了承下さい。

　次に、TensorFlowの「Object Detection API」を含むリポジトリをホームディレクトリにクローンします。ファイルサイズ大きいので結構時間かかります。

```sh
$ cd && git clone https://github.com/tensorflow/models
```

　Protocol Bufferをインストールしてセットアップします。

```sh
$ cd ~/models/research
$ wget -O protobuf.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.7.0/protoc-3.7.0-linux-aarch_64.zip
$ unzip protobuf.zip
$ ./bin/protoc object_detection/protos/*.proto --python_out=.
```

　以下でObject Detection APIの動作テストをします。

```sh
$ cd ~/models/research
$ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
$ python3 object_detection/builders/model_builder_test.py
```

　OKという表示が出たら準備は完了です。

## NVIDIA TensorRTを使ってモデルファイルを最適化する
　次に、学習モデルを最適化します。先ほど普通のPCではサクサク動くような学習モデルも、Jetson Nanoでそのまま動かそうとするともの凄い遅く、使い物になりません。Jetson Nanoでリアルタイムに動かすには、モデルを[NVIDIA TensorRT](https://developer.nvidia.com/tensorrt)というNVIDIAの環境を用いて、モデルファイルを最適化する必要があります。NVIDIA TensorRTに関して詳しくは公式サイトを参照下さい（私も詳細理解できていません…）


　まずは、最適化する学習モデルをダウンロードしましょう。ちなみにJetson Nanoで最適化できるモデルは、私の環境ではmobilenet等の小さいモデルのみでした（ssd_inception_v2等のモデルで試したら、GPUが`nvinfer1::OutofMemory`エラーになりました）。


　あらかじめ、「Object Detection API」のパスを通しておきます。

```sh
$ cd ~/models/research
$ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
```

　続いて、Object Detection Tools（自作のツール）と学習モデルをダウンロードします。以下3行でOKです。最初の物体検出のところで、既にObject Detection Toolsをダウンロード済みの場合は、最初の1行は省略して下さい。

```sh
$ cd && git clone https://github.com/karaage0703/object_detection_tools
$ cd ~/object_detection_tools/models
$ ./get_ssd_mobilenet_v1_coco_model.sh
```


　続いて「NVIDIA TensorRT」をダウンロードします。

```sh
$ cd && git clone https://github.com/NVIDIA-AI-IOT/tf_trt_models
$ cd tf_trt_models
```

　自作の変換ツールを用いて、学習モデルをJetson Nanoに最適化したモデルに変換します。

```sh
$ cp ../object_detection_tools/scripts/convert_rt_model.py .
$ python3 convert_rt_model.py -c='../models/research/object_detection/samples/configs/ssd_mobilenet_v1_coco.config' -m='../object_detection_tools/models/ssd_mobilenet_v1_coco_2018_01_28/model.ckpt' -o='./frozen_inference_graph_trt.pb'
```

　`-c`オプションが使用するコンフィグファイル、`-m`が最適化する対象の学習モデル `-o`が最適化した後の学習モデルのファイル名となります。


## Jetson Nanoでの最適化したモデルでのリアルタイム物体検出
　最適化したモデルで物体検出を行います。

```sh
$ cd ~/object_detection_tools
$ python3 scripts/object_detection.py -l='models/coco-labels-paper.txt' -m='../tf_trt_models/frozen_inference_graph_trt.pb' -d='jetson_nano_raspi_cam'
```


　もし、ここで以下のようなエラーがでたら

```
NotFoundError: Op type not registered 'TRTEngineOp' in binary running on your-jetson. ...
```

　以下のように、`object_detection.py`に1行追記をして下さい。

```python
import tensorflow as tf
import tensorflow.contrib.tensorrt as trt # <-- add
```

　このエラー対処は　@brownbro さんにコメントで指摘いただいたものです。感謝です。

# まとめ
　Jetson Nanoでリアルタイムの物体検出をしました。簡単にできるかと思ったのですが、TensorFlowの「Object Detection API」が思ったより難しく大変で、結局ツールを自作することになってしまいました。

　PCでもJetson Nanoのようなモバイルデバイスでも、モデルファイルを変換するだけで、同じプログラムで学習から推論までできるというのは素晴らしいですね。これって、意外に今まではできそうで出来ていなかったことと思います（大体、デバイスに特化したプログラムを学習でも推論でも用意する必要があるので）。NVIDIAのデファクトの強さを感じますね。

　次は、自前データの学習方法に関しても、まとめる予定です。

# 参考リンク
　今回も何度も絶望したのですが、その度に多くの先人の知恵に助けられました。感謝です。参考にした情報にリンクいたします。

　特に @PINTO さんと @tsutof さんの情報なければ、実現できなかったと思います感謝です。

- https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/index.html
- https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/installation.md
- https://qiita.com/tsutof/items/0328ede42d509eb247ad
- https://qiita.com/PINTO/items/8a91d79abe6e939ef01c
- https://devtalk.nvidia.com/default/topic/1049646/jetson-nano/jupyter-notebook-in-jetson-nano/
- https://nextremer-nbo.blogspot.com/2019/11/jetson-nanotf-trtobject-detection.html

# 関連記事
[Jetson Nano関係のTIPSまとめ](https://qiita.com/karaage0703/items/b14c249aa33112669ee4)
Jetson Nano関係の情報はこちらにまとめています

[TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました](https://qiita.com/karaage0703/items/8c3197d11f61812546a9)