Jetson Nano で EdgeTPU を使う

## 【目的】
Jetson NanoでCoral USB TPU Accelerator(EdgeTPU)を動かせるようにします。

## 【はじめに】
本手順は公式に則ったものではありません。
動作させるために一部無理やり対応している部分がありますのでご注意ください。

## 【EdgeTPU用モジュールのインストール】
下記コマンドを実行して、最新のモジュールの取得とインストールを行います。

```bash:EdgeTPU用モジュールのインストール
wget https://dl.google.com/coral/edgetpu_api/edgetpu_api_latest.tar.gz -O edgetpu_api.tar.gz --trust-server-names
tar xzf edgetpu_api.tar.gz
cd edgetpu_api
sudo ./install.sh
```

```bash:インストール結果
Warning: During normal operation, the Edge TPU Accelerator may heat up, depending
on the computation workloads and operating frequency. Touching the metal part of the
device after it has been operating for an extended period of time may lead to discomfort
and/or skin burns. As such, when running at the default operating frequency, the device is
intended to safely operate at an ambient temperature of 35C or less. Or when running at
the maximum operating frequency, it should be operated at an ambient temperature of
25C or less.

Google does not accept any responsibility for any loss or damage if the device is operated
outside of the recommended ambient temperature range.
.............................................................
Would you like to enable the maximum operating frequency? Y/N
y
Using maximum operating frequency.
Installing library dependencies...
Reading package lists... Done
Building dependency tree
Reading state information... Done
libunwind8 is already the newest version (1.2.1-8).
libusb-1.0-0 is already the newest version (2:1.0.21-2).
libusb-1.0-0 set to manually installed.
python3-numpy is already the newest version (1:1.13.3-2ubuntu1).
python3-numpy set to manually installed.
python3-pil is already the newest version (5.1.0-1).
libgcc1 is already the newest version (1:8.3.0-6ubuntu1~18.04.1).
python3-pip is already the newest version (9.0.1-2.3~ubuntu1.18.04.1).
Suggested packages:
  clang
The following NEW packages will be installed:
  libc++1 libc++abi1
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 204 kB of archives.
After this operation, 1,005 kB of additional disk space will be used.
Get:1 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 libc++abi1 arm64 6.0-2 [48.7 kB]
Get:2 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 libc++1 arm64 6.0-2 [155 kB]
Fetched 204 kB in 4s (46.6 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libc++abi1:arm64.
(Reading database ... 137234 files and directories currently installed.)
Preparing to unpack .../libc++abi1_6.0-2_arm64.deb ...
Unpacking libc++abi1:arm64 (6.0-2) ...
Selecting previously unselected package libc++1:arm64.
Preparing to unpack .../libc++1_6.0-2_arm64.deb ...
Unpacking libc++1:arm64 (6.0-2) ...
Setting up libc++abi1:arm64 (6.0-2) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Setting up libc++1:arm64 (6.0-2) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Done.
Installing device rule file [/etc/udev/rules.d/99-edgetpu-accelerator.rules]...
Done.
Installing Edge TPU runtime library [/usr/lib/aarch64-linux-gnu/libedgetpu.so.1.0]...
Done.
Installing Edge TPU Python API...
Processing ./edgetpu-2.11.1-py3-none-any.whl
Installing collected packages: edgetpu
Successfully installed edgetpu-2.11.1
Done.
```
特に問題なくインストールが完了しました。


## 【EdgeTPUの動作確認】
サンプルプログラムを実行して動作確認を行います。
まずはサンプルプログラムに必要なモデルファイルと、推論に使う画像ファイルをダウンロードします。

```bash:モデルおよび画像データのダウンロード
cd ~/Downloads/

wget https://dl.google.com/coral/canned_models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite \
https://dl.google.com/coral/canned_models/inat_bird_labels.txt \
https://coral.withgoogle.com/static/docs/images/parrot.jpg
```

サンプルプログラムを実行します。

```bash:サンプルプログラムの実行
cd /usr/local/lib/python3.6/dist-packages/edgetpu/demo
python3 classify_image.py \
 --model ~/Downloads/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite \
 --label ~/Downloads/inat_bird_labels.txt \
 --image ~/Downloads/parrot.jpg
```
```bash:実行結果(エラー)
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/edgetpu/swig/edgetpu_cpp_wrapper.py", line 18, in swig_import_helper
    fp, pathname, description = imp.find_module('_edgetpu_cpp_wrapper', [dirname(__file__)])
  File "/usr/lib/python3.6/imp.py", line 297, in find_module
    raise ImportError(_ERR_MSG.format(name), name=name)
ImportError: No module named '_edgetpu_cpp_wrapper'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "classify_image.py", line 17, in <module>
    from edgetpu.classification.engine import ClassificationEngine
  File "/usr/local/lib/python3.6/dist-packages/edgetpu/classification/engine.py", line 17, in <module>
    from edgetpu.basic.basic_engine import BasicEngine
  File "/usr/local/lib/python3.6/dist-packages/edgetpu/basic/basic_engine.py", line 17, in <module>
    from edgetpu.swig.edgetpu_cpp_wrapper import BasicEnginePythonWrapper
  File "/usr/local/lib/python3.6/dist-packages/edgetpu/swig/edgetpu_cpp_wrapper.py", line 28, in <module>
    _edgetpu_cpp_wrapper = swig_import_helper()
  File "/usr/local/lib/python3.6/dist-packages/edgetpu/swig/edgetpu_cpp_wrapper.py", line 20, in swig_import_helper
    import _edgetpu_cpp_wrapper
ModuleNotFoundError: No module named '_edgetpu_cpp_wrapper'
```

残念ながらエラーで実行できませんでした。
`/usr/local/lib/python3.6/dist-packages/edgetpu/swig/` 内でエラーになっているので中身を確認してみます。


```bash:モジュール確認
ls /usr/local/lib/python3.6/dist-packages/edgetpu/swig/
_edgetpu_cpp_wrapper.cpython-35m-aarch64-linux-gnu.so    _edgetpu_cpp_wrapper.cpython-35m-x86_64-linux-gnu.so  edgetpu_cpp_wrapper.py  __pycache__
_edgetpu_cpp_wrapper.cpython-35m-arm-linux-gnueabihf.so  _edgetpu_cpp_wrapper.cpython-36m-x86_64-linux-gnu.so  __init__.py
```
arm系、aarch系にはPython3.5用のモジュールしか存在しないようです。
ラズパイはPython3.5でしたし、ubuntuを使ったときはPython3.6でしたがIntel系でしたので気が付きませんでした。

少し無理矢理になりますが、3.5用のモジュールを3.6用としてシンボリックリンクを切ります。[^1]
[^1]: 予期せぬ動作をする可能性がありますので、ご注意ください。
本来はPython3.5をインストールして、そちらにモジュールをインストールするのが正しい手順だと思います。



```bash:3.6用にシンボリックリンクの作成(要注意)
sudo ln -s /usr/local/lib/python3.6/dist-packages/edgetpu/swig/_edgetpu_cpp_wrapper.cpython-35m-aarch64-linux-gnu.so /usr/local/lib/python3.6/dist-packages/edgetpu/swig/_edgetpu_cpp_wrapper.cpython-36m-aarch64-linux-gnu.so
```

サンプルプログラムを再度実行します。

```bash:サンプルプログラムの再実行
cd /usr/local/lib/python3.6/dist-packages/edgetpu/demo
python3 classify_image.py \
 --model ~/Downloads/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite \
 --label ~/Downloads/inat_bird_labels.txt \
 --image ~/Downloads/parrot.jpg
```
```bash:結果
INFO: Initialized TensorFlow Lite runtime.
---------------------------
Ara macao (Scarlet Macaw)
Score :  0.76171875
```

今度はきちんと結果が表示されました。

## 【最後に】
少し無理やりでしたがJetson NanoでEdgeTPUが動くようにはなりました。
このあと、別のプログラムも動かしましたが、現時点では特に問題は出ていませんので、まずはこれで作業完了とします。
ただし、予期せぬ動作をする可能性がありますので、くれぐれもご注意ください。