Jetson NanoのNode-REDでTensorFlowモデルを利用する際にGPUリソースを使用するメモ (※TensorFlow 1.x, JetPack 4.3)

# はじめに

Jetson Nano の Node-RED で TensorFlow モデルを試した際に GPU リソースを使用する手順をまとめておきます。(TensorFlow 1.x, JetPack 4.3)

![sample_flow_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/08f4a063-ecc4-5a53-4059-f5c582099271.jpeg)

# 環境

TensorFlow.js を Node.js で利用する場合、Jetson Nano の GPU リソースを使用するためには環境が重要です。

- @tensorflow/tfjs-node の最新バージョン(2021年5月3日時点)は v1.7.4
- TensorFlow v1.15.0 が指定されている
- TensorFlow shared libraries が必要だが、arm64 でビルドされたものを custom-binary.json で指定する必要がある
- arm64 でビルドされた TensorFlow shared libraries は CUDA 10.0 と cuDNN 7 ライブラリを使用している

Jetson Nano の環境は JetPack 4.3 を使用する必要があります。
(最新の JetPack 4.5.1 を使用するとエラーが出て使用できませんでした。)

|リリース時期 |JetPack |CUDA |cuDNN | 対象 |
|---|---|---|---|---|
|2019/12 |4.3 | 10.0.326 |7.6.3 | o |
|2020/7 |4.4 |10.2.89 |8.0.0 DP | - |
|2020/7 |4.4.1 |10.2.89 |8.0.0 DP | - |
|2021/1 |4.5 |10.2.89 |8.0.0.180 | - |
|2021/2 |4.5.1 |10.2.89 |8.0.0.180 | - |

# 手順

簡単に試したい場合は、後ろの手順(簡単に試す場合の手順)を参照してください。


## 1. Node-REDのインストール

以下のコマンドを実行して、Jetson Nano に Node-RED をインストールします。

```bash
$ bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```

質問を聞かれた場合は、y を入力します。(2回)

```bash
Are you really sure you want to do this ? [y/N] ? y
Would you like to install the Pi-specific nodes ? [y/N] ? y
```

## 2. @tensorflow/tfjs-node のインストール

TensorFlow.js を Node-RED(Node.js) で使用するために、@tensorflow/tfjs-node モジュールをインストールします。

```bash
$ cd ~/.node-red
$ npm i @tensorflow/tfjs-node@1.7.4
```

エラーが表示されるので、以下の手順を実施します。

```bash
$ cd node_modules/@tensorflow/tfjs-node
```

custom-binary.json ファイルを作成します。

```bash
$ vi scripts/custom-binary.json
```

```json:custom-binary.json
{
  "tf-lib": "https://s3.us.cloud-object-storage.appdomain.cloud/tfjs-cos/libtensorflow-gpu-linux-arm64-1.15.0.tar.gz"
}
```

再度インストールします。

```bash
$ npm i
```

## 3. node-red-contrib-tfjs-coco-ssd のインストール

COCO モデルを使用した SSD によるオブジェクト検出を試すために、 <a href="https://flows.nodered.org/node/node-red-contrib-tfjs-coco-ssd">node-red-contrib-tfjs-coco-ssd</a> モジュールをインストールします。
node-red-contrib-tfjs-coco-ssd は 依存関係に @tensorflow/tfjs-node モジュールのバーション 1.4.0 が指定されているため、最新バージョン (1.7.4) へ変更する必要があります。

```bash
$ cd ~/.node-red
$ npm i node-red-contrib-tfjs-coco-ssd
```

エラーが表示されるので、以下の手順を実施します。

```bash
$ cd node_modules/node-red-contrib-tfjs-coco-ssd
```

package.json の依存関係で、@tensorflow/tfjs-node に指定されているバージョンを 1.4.0 から 1.7.4 へ変更します。

```json:package.json
        "@tensorflow/tfjs-node": "1.4.0",
↓
        "@tensorflow/tfjs-node": "1.7.4",
```

エラーが表示されるので、2. @tensorflow/tfjs-node のインストールと同様に、以下の手順を実施します。

```bash
$ cd node_modules/@tensorflow/tfjs-node
```

custom-binary.json ファイルを作成します。

```bash
$ vi scripts/custom-binary.json
```

```json:custom-binary.json
{
  "tf-lib": "https://s3.us.cloud-object-storage.appdomain.cloud/tfjs-cos/libtensorflow-gpu-linux-arm64-1.15.0.tar.gz"
}
```

再度インストールします。

```bash
$ npm i
```

package-lock.json を削除します。
(@tensorflow/tfjs-node モジュールのバーション 1.4.0 をインストールした情報が残っているため)

```
$ cd ~/.node-red
$ rm package-lock.json
```

## 4. Node-RED を起動します。

```bash
$ node-red-start
```

Node-RED の起動ログが表示されますので、起動が完了したら Ctrl + C で抜けます。
停止する場合は、以下のコマンドを実行します。

```bash
$ node-red-stop
```

# 簡単に試す場合の手順

node-red-contrib-tfjs-coco-ssd モジュールを fork して導入手順を簡略化しています。

## 1. Node-REDのインストール

以下のコマンドを実行して、Jetson Nano に Node-RED をインストールします。

```bash
$ bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```

質問を聞かれた場合は、y を入力します。(2回)

```bash
Are you really sure you want to do this ? [y/N] ? y
Would you like to install the Pi-specific nodes ? [y/N] ? y
```

## 2. @kitazaki/node-red-contrib-tfjs-coco-ssd のインストール

```bash
$ cd ~/.node-red
$ npm i @kitazaki/node-red-contrib-tfjs-coco-ssd@0.0.3
```

エラーが表示されるので、以下の手順を実施します。
(インストールの中で @tensorflow/tfjs-node の custom-binary.json を作成しているので、2回目のインストールで成功します)

```bash
$ cd node_modules/@tensorflow/tfjs-node/
$ npm i
```

## 3. Node-RED を起動します。

```bash
$ node-red-start
```

Node-RED の起動ログが表示されますので、起動が完了したら Ctrl + C で抜けます。
停止する場合は、以下のコマンドを実行します。

```bash
$ node-red-stop
```

# サンプルのフローを動かす

USB カメラで撮影した画像を使用してオブジェクト検出し、結果を Node-RED のフロー上に表示するため、以下の2つのモジュールをインストールします。

- node-red-contrib-image-output
- node-red-contrib-usbcamera

node-red-contrib-usbcamera モジュールを使用するためには、fswebcam コマンドをインストールする必要があります。

```bash
$ sudo apt update
$ sudo apt install fswebcam
```

```bash
$ cd ~/.node-red
$ npm i node-red-contrib-image-output 
$ npm i node-red-contrib-usbcamera
```

モジュールをインストールした後は Node-RED の停止・起動を行います。

```bash
$ node-red-stop
$ node-red-start
```

サンプルのフローをインポートします。

```json:flows.json
[{"id":"7b70c5ee.6f8b54","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"536b8b06.e08124","type":"tensorflowCoco","z":"7b70c5ee.6f8b54","name":"","modelUrl":"http://localhost:1880/coco/model.json","scoreThreshold":0.5,"passthru":"bbox","lineColour":"magenta","x":530,"y":340,"wires":[["322a680c.2a6458","91d145e.e45deb8"]]},{"id":"974b536b.811538","type":"image","z":"7b70c5ee.6f8b54","name":"","width":160,"data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":540,"y":160,"wires":[]},{"id":"6bc3a717.18fcd","type":"http request","z":"7b70c5ee.6f8b54","name":"","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://upload.wikimedia.org/wikipedia/commons/b/b3/Team_Queerala.jpg","tls":"","persist":false,"proxy":"","authType":"","x":310,"y":280,"wires":[["974b536b.811538","536b8b06.e08124","8f34f7cf.94bfe8"]]},{"id":"71825deb.2c1e34","type":"inject","z":"7b70c5ee.6f8b54","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":280,"wires":[["6bc3a717.18fcd"]]},{"id":"322a680c.2a6458","type":"debug","z":"7b70c5ee.6f8b54","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":300,"wires":[]},{"id":"91d145e.e45deb8","type":"image","z":"7b70c5ee.6f8b54","name":"","width":"320","data":"image","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":740,"y":340,"wires":[]},{"id":"8f34f7cf.94bfe8","type":"debug","z":"7b70c5ee.6f8b54","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":510,"y":100,"wires":[]},{"id":"20417db3.6bb88a","type":"usbcamera","z":"7b70c5ee.6f8b54","filemode":"0","filename":"image01.jpg","filedefpath":"1","filepath":"","fileformat":"jpeg","resolution":"2","name":"","x":310,"y":340,"wires":[["974b536b.811538","8f34f7cf.94bfe8","536b8b06.e08124"]]},{"id":"e39ca5b2.147f48","type":"inject","z":"7b70c5ee.6f8b54","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":340,"wires":[["20417db3.6bb88a"]]}]
```

サンプルのフローはGithubにも置いておきます。

https://github.com/kitazaki/tfjs-coco-ssd/blob/master/flows.json

# 動作確認

Node-RED を実行し、サンプルフローを読み込んだ後、以下のようなログが出力されれば正常です。

```bash
5 May 12:30:23 - [info] Starting flows
2021-05-05 12:30:24.866596: W tensorflow/core/platform/profile_utils/cpu_utils.cc:98] Failed to find bogomips in /proc/cpuinfo; cannot determine CPU frequency
2021-05-05 12:30:24.867601: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7f3dbf7290 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2021-05-05 12:30:24.867990: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2021-05-05 12:30:24.895666: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcuda.so.1
2021-05-05 12:30:24.916967: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:24.917130: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1618] Found device 0 with properties:
name: NVIDIA Tegra X1 major: 5 minor: 3 memoryClockRate(GHz): 0.9216
pciBusID: 0000:00:00.0
2021-05-05 12:30:24.923907: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.0
2021-05-05 12:30:24.937424: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10.0
2021-05-05 12:30:24.953026: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcufft.so.10.0
2021-05-05 12:30:24.958246: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcurand.so.10.0
2021-05-05 12:30:24.974519: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusolver.so.10.0
2021-05-05 12:30:24.983350: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusparse.so.10.0
2021-05-05 12:30:25.032299: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2021-05-05 12:30:25.032490: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:25.032660: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:25.032749: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1746] Adding visible gpu devices: 0
2021-05-05 12:30:26.638460: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1159] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-05-05 12:30:26.638579: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1165]      0
2021-05-05 12:30:26.638612: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1178] 0:   N
2021-05-05 12:30:26.638878: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:26.639051: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:26.639201: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:950] ARM64 does not support NUMA - returning NUMA node zero
2021-05-05 12:30:26.639567: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1304] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 212 MB memory) -> physical GPU (device: 0, name: NVIDIA Tegra X1, pci bus id: 0000:00:00.0, compute capability: 5.3)
2021-05-05 12:30:26.648679: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7eacbb15e0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:
2021-05-05 12:30:26.648767: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): NVIDIA Tegra X1, Compute Capability 5.3
cpu backend was already registered. Reusing existing backend factory.
Platform node has already been set. Overwriting the platform with [object Object].
5 May 12:30:27 - [info] Started flows
2021-05-05 12:30:28.221079: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2021-05-05 12:30:32.507124: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10.0
```

実際に GPU リソースが使用されているか確認する場合、jtop コマンドを実行するのが簡単です。
初回にインストールした場合、OSの再起動が必要です。既にインストールされている場合、最新の jtop コマンドがインストールされます。

以下の手順でインストールします。

```bash
$ sudo apt install python-pip
$ sudo -H pip install -U jetson-stats

# 初回の場合のみ
$ sudo reboot
```

以下の手順で実行します。

```bash
$ jtop
```

![GPU.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/be3d5a95-917f-613f-967b-4cd8158f5e38.jpeg)

# まとめ

みなさま、良き Jetson Nano & Node-RED ライフを！

### @kitazaki/node-red-contrib-tfjs-coco-ssd モジュールの変更内容

### 1. package.json 変更

https://github.com/kitazaki/tfjs-coco-ssd/blob/master/package.json

### 2. fixarm64.js 追加

https://github.com/kitazaki/tfjs-coco-ssd/blob/master/fixarm64.js

### 3. custom-binary.json 追加

https://github.com/kitazaki/tfjs-coco-ssd/blob/master/custom-binary.json

### 参考

https://developer.ibm.com/technologies/artificial-intelligence/tutorials/building-a-machine-learning-node-for-node-red-using-tensorflowjs/

https://github.com/yhwang/node-red-contrib-tf-model#note

https://flows.nodered.org/node/node-red-contrib-tfjs-coco-ssd