aoirint's note

メモ帳(古い記事はkanomiya blogから移行)

Jetson Nano セットアップとおためし

メモ。

TPLink Wireless Driver

開発ボード(これ)にはWi-Fiモジュールが乗ってないので、USBドングルで無線LANにつなぐ(セットアップは有線で)。

TPLink Archer T2U Nano(これ)を使う。

tp-link Archer T2U Nano AC600をLinuxで使う方法 | Shizuka's Style (Duo)

Jetson Nano で TP-LINK Archer T2U Nano を使う - Qiita

https://devtalk.nvidia.com/default/topic/1051503/jetson-nano/make-usb-wifi-dongle-rtl8812au-works-on-nano/

NVIDIA Developer Forumsのつい最近(11/27)のポストで、新しいcommitで動かなくなっちゃったからCommit IDd277c36がいいよ、っていってる人がいる。でもT2U NanoのIDが登録されたのは2つ後の4235b0eなので、これを使ってみたけど、これで動いた(OSはr32.2.3)。この1つ後(現在masterの最新commit)のfa68771は接続が確立しなかった(パスワードの入力を何度でも求められる)。警告回避のためにリファクタリングしたらバグったっぽい(コミットコメントプルリク)。

sudo apt install dkms

git clone https://github.com/abperiasamy/rtl8812AU_8821AU_linux.git
git checkout 4235b0ec7d7220a6364586d8e25b1e8cb99c36f1

Edit Makefile
CONFIG_PLATFORM_I386_PC = n
CONFIG_PLATFORM_ARM_JET_NANO = y

sudo make -f Makefile.dkms install
reboot

ibus-mozc

sudo apt install ibus-mozc
killall ibus-daemon
ibus-daemon -x &

Python

PyTorch使うならシステムのPython 3.6.9を使うのがよさそうだったので、そのまま

sudo apt install python3-pip

jetson-stats

Jetson NanoのGPUモニタリング - Qiita

いい感じに状態を確認できるやつ。

# pip3 install jetson-stats
# jtop
NVIDIA Jetson NANO/TX1 - Jetpack UNKNOWN [L4T 32.2.3]
CPU1 [|||||    Schedutil -  21%] 614MHz
CPU2 [|||      Schedutil -  15%] 614MHz
CPU3 [|||||    Schedutil -  20%] 614MHz
CPU4 [||||     Schedutil -  18%] 614MHz

Mem [|||||||||||||||||||||||||||||||                   2.1G/4.0GB] (lfb 95x4MB)
Imm [                                                    0kB/252kB] (lfb 252kB)
Swp [                                                 0.0GB/2.0GB] (cached 0MB)
EMC [||                                                              4%] 1.6GHz

GPU [||||                                                            7%] 153MHz
Dsk [########################                                    10.1GB/29.2GB]
          [info]          [Sensor]   [Temp]         [Power/mW]   [Cur]   [Avr]
UpT: 0 days 0:30:1        AO         39.50C         POM_5V_CPU   288     672
FAN [         0%] Ta=  0% CPU        32.00C         POM_5V_GPU   82      85
Jetson Clocks: [inactive] GPU        28.00C         POM_5V_IN    1895    2511
NV Power[0]: MAXN         PLL        30.00C
APE: 25MHz                PMIC      100.00C
HW engine:                thermal    29.75C
 ENC: NOT RUNNING
 DEC: NOT RUNNING

いちおうデフォルトでもtegrastatsで状態をwatchできる。

パフォーマンス最大化(発熱注意)

5V4AのDC電源を用意して、J48にジャンパーピンを挿す(電源不足で落ちるかも)。

コマンドjetson_clocksはオプションなしで呼び出すとCPU、GPU、EMC(メモリ?)のクロックを最大化する。熱暴走するかもなので熱対策してない場合はやらない方がいいかも。

ヘルプ
# jetson_clocks -h

デフォルトの設定
# jetson_clocks --show
SOC family:tegra210  Machine:NVIDIA Jetson Nano Developer Kit
Online CPUs: 0-3
CPU Cluster Switching: Disabled
cpu0: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1036800 IdleStates: WFI=1 c7=1 
cpu1: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=921600 IdleStates: WFI=1 c7=1 
cpu2: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1132800 IdleStates: WFI=1 c7=1 
cpu3: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=1 c7=1 
GPU MinFreq=76800000 MaxFreq=921600000 CurrentFreq=230400000
EMC MinFreq=204000000 MaxFreq=1600000000 CurrentFreq=1600000000 FreqOverride=0
Fan: speed=0
NV Power Mode: MAXN

# jetson_clocks --store ~/default_clocks.data

# jetson_clocks

# jetson_clocks --show
SOC family:tegra210  Machine:NVIDIA Jetson Nano Developer Kit
Online CPUs: 0-3
CPU Cluster Switching: Disabled
cpu0: Online=1 Governor=schedutil MinFreq=1428000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=0 c7=0 
cpu1: Online=1 Governor=schedutil MinFreq=1428000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=0 c7=0 
cpu2: Online=1 Governor=schedutil MinFreq=1428000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=0 c7=0 
cpu3: Online=1 Governor=schedutil MinFreq=1428000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=0 c7=0 
GPU MinFreq=921600000 MaxFreq=921600000 CurrentFreq=921600000
EMC MinFreq=204000000 MaxFreq=1600000000 CurrentFreq=1600000000 FreqOverride=1
Fan: speed=255
NV Power Mode: MAXN

# jetson_clocks --restore ~/default_clocks.data
# jetson_clocks --show
SOC family:tegra210  Machine:NVIDIA Jetson Nano Developer Kit
Online CPUs: 0-3
CPU Cluster Switching: Disabled
cpu0: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1428000 IdleStates: WFI=1 c7=1 
cpu1: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=921600 IdleStates: WFI=1 c7=1 
cpu2: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1132800 IdleStates: WFI=1 c7=1 
cpu3: Online=1 Governor=schedutil MinFreq=102000 MaxFreq=1428000 CurrentFreq=1326000 IdleStates: WFI=1 c7=1 
GPU MinFreq=76800000 MaxFreq=921600000 CurrentFreq=230400000
EMC MinFreq=204000000 MaxFreq=1600000000 CurrentFreq=1600000000 FreqOverride=0
Fan: speed=0
NV Power Mode: MAXN

PyTorch

https://devtalk.nvidia.com/default/topic/1049071/jetson-nano/pytorch-for-jetson-nano-version-1-3-0-now-available/

pip3 install numpy # takes long..
pip3 install torch-1.3.0-cp36-cp36m-linux_aarch64.whl

TorchVision

setup.pyからinstallの途中でPillowが自動でビルドされるけど、ライブラリがないと失敗するので事前インストール。

必須はlibjpegzlib。あと使いそうなlibfreetypeも(zliblibfreetypeはデフォルトで入ってる)。

Installation — Pillow (PIL Fork) 6.2.1 documentation

sudo apt install libjpeg-turbo8-dev zlib1g-dev
sudo apt install libfreetype6-dev

pip3 install Pillow
git clone https://github.com/pytorch/vision.git
cd vision
python3 setup.py install --user # takes long..

動作テスト

(Clock:デフォルト)

pip3 install ipython
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
In [1]: import torch                                                            

In [2]: torch.cuda.is_available()
Out[2]: True

In [3]: torch.cuda.device_count()
Out[3]: 1

In [4]: device = torch.device('cuda:0')

In [5]: x = torch.randn(1, 3, 40, 40)

In [6]: x = x.to(device)

In [7]: x.shape
Out[7]: torch.Size([1, 3, 40, 40])

In [8]: x
Out[8]: 
tensor([[[[-0.0362, -0.6796,  0.6484,  ..., -0.5588,  0.3949, -0.8214],
          [-0.5975,  0.6352,  0.9712,  ..., -0.4434,  0.4439, -0.2363],
          [ 0.2326,  0.1052,  0.5346,  ..., -0.7047, -0.0173, -1.1312],
          ...,
          [-0.0730, -0.7666,  0.7147,  ...,  0.8821, -0.0262, -0.6976],
          [ 0.9593,  1.0495,  0.6041,  ...,  0.2833,  0.5237, -0.5829],
          [-0.4293, -1.9287,  0.6741,  ..., -1.0791, -0.5570, -0.3463]],

         [[-0.5106, -0.3363,  0.2770,  ..., -1.6835,  2.2409,  0.5745],
          [-0.9233,  0.7389,  0.6966,  ..., -0.5657, -0.4024, -0.5671],
          [-1.7160, -1.3546,  0.4675,  ...,  1.8385, -0.9948,  1.0485],
          ...,
          [ 0.8693,  0.2434,  0.7501,  ..., -0.9752,  2.3783, -0.4887],
          [-0.2279, -1.1861, -1.2003,  ..., -0.7934,  0.3169, -2.3324],
          [-1.1039, -1.6662, -0.0719,  ...,  0.6115,  2.2238, -0.8375]],

         [[-1.2368,  0.3786, -0.7985,  ...,  0.0504,  0.3354, -0.3505],
          [ 0.3309,  0.8257,  0.4800,  ..., -1.6101, -0.4429,  0.3643],
          [ 0.5604,  1.6997, -0.5299,  ..., -0.4896,  1.0926,  0.0423],
          ...,
          [ 1.8049, -1.0500, -1.3723,  ..., -0.4516,  0.5884,  1.3404],
          [ 0.3622,  0.6343, -0.0500,  ..., -0.0991,  0.9009,  0.7298],
          [ 2.3776, -0.1111,  0.2054,  ..., -1.4465, -2.2340, -1.0085]]]],
       device='cuda:0')

動いたけど、toがめっちゃ遅かった気がする..

toが遅い。なんぞこれ

In [1]: import time
In [2]: import torch

In [3]: x = torch.randn(1, 3, 40, 40)

In [4]: ts = time.time(); x = x.cuda(); elapsed = time.time() - ts;

In [5]: elapsed
Out[5]: 8.121735572814941

8秒...

In [6]: z = torch.randn(1, 3, 40, 40)

In [7]: ts = time.time(); z = z.cuda(); elapsed = time.time() - ts;

In [8]: elapsed
Out[8]: 0.0011272430419921875

In [9]: y = torch.randn(1, 3, 512, 512)

In [10]: ts = time.time(); y = y.cuda(); elapsed = time.time() - ts;

In [11]: elapsed
Out[11]: 0.02282571792602539

初回だけ遅い。初期化でも走ってるんだろうか..

ipythonプロセスのMemを見てみると、初回のtoGPUの前後で600MiBくらいMem使用量が増えたが、2回目以降は0.1MiBくらいの増加だった。初回になにかしらの初期化処理が入ってるっぽい..

メモリ

デスクトップ環境あり、ブラウザ付きでMem 2.2/4.0GB、Swap 1.3/2.0GB。

import torch

x = torch.randn(1, 3, 512, 512)
x = x.cuda()

z = torch.randn(1, 3, 512, 512)
z = z.cuda()

ipythonプロセスをみると、起動直後33.6MiB、import torchで69.0MiB、x = torch.randn(1, 3, 512, 512)で72.4MiB、x = x.cuda()で726MiB、z = torch.randn(1, 3, 512, 512)で729MiB、z = z.cuda()で729Mib変化なし。

速度

(Clock:デフォルト)

In [1]: import time

In [2]: import torch

In [3]: import torchvision.models as M

In [4]: x = torch.randn(1, 3, 224, 224)

In [5]: x = x.cuda()

In [6]: model = M.resnet50(pretrained=False)

In [7]: model = model.cuda()

In [8]: model.eval();

In [9]: with torch.no_grad():
   ...:     ts = time.time()
   ...:     y = model(x)
   ...:     elapsed = time.time() - ts
   ...:                                                                         

In [10]: elapsed                                                                
Out[10]: 20.638437747955322

In [11]: y.device                                                               
Out[11]: device(type='cuda', index=0)

あれ? とても遅い。

In [12]: z = torch.randn(1, 3, 224, 224)                                        

In [13]: z = z.cuda()                                                           

In [14]: with torch.no_grad(): 
    ...:     ts = time.time() 
    ...:     w = model(z) 
    ...:     elapsed = time.time() - ts 
    ...:                                                                        

In [15]: elapsed                                                                
Out[15]: 0.5333945751190186

うーん?

In [16]: s = torch.randn(1, 3, 224, 224)

In [17]: s = s.cuda()

In [18]: with torch.no_grad():
    ...:     ts = time.time()
    ...:     t = model(s)
    ...:     elapsed = time.time() - ts
    ...:     

In [19]: elapsed
Out[19]: 0.04768824577331543

In [20]: u = torch.randn(1, 3, 224, 224).cuda()

In [21]: with torch.no_grad():
    ...:     ts = time.time()
    ...:     v = model(u)
    ...:     elapsed = time.time() - ts
    ...:     

In [22]: elapsed
Out[22]: 0.045920610427856445

2回くらい実行しないといいパフォーマンスがでないみたいですね..

仕切り直しでもう一回。

In [1]: import time

In [2]: import torch

In [3]: import torchvision.models as M

In [4]: model = M.resnet50(pretrained=False)

In [5]: model = model.cuda()

In [6]: model.eval();

In [7]: x = torch.randn(1, 3, 224, 224)

In [8]: x = x.cuda()

In [9]: with torch.no_grad():
   ...:     ts = time.time()
   ...:     y = model(x)
   ...:     elapsed = time.time() - ts
   ...:     

In [10]: elapsed                                                                
Out[10]: 7.917057514190674

スワップ作成

AWS Amazon Linux スワップファイル作成によりSwap領域のサイズを増やす - Qiita

このあとの節でメモリ不足に陥ったのでswapfileを追加する(Default Mem: 4GB、Swap: 2GB)。2GB追加することにする。Swapに乗るとパフォーマンス低下するはずなので注意。

次の節で変換をJetson Nanoでゴリ押さなければ必要ないかもしれない。

# check storage capacity
df -h

dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile

mkswap /swapfile
swapon /swapfile

# Append to /etc/fstab
/swapfile            swap                     swap           defaults                                     0 0

# check swap size
jtop

高速化(TensorRT)

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

高速化のためにはNVIDIAのTensorRTなるプログラムでモデルを最適化する必要があるらしい。1回目2回目のオーバーヘッドがなくなることを期待。

NVIDIA TensorRT | NVIDIA Developer

You can import trained models from every deep learning framework into TensorRT.

GitHub - NVIDIA-AI-IOT/torch2trt: An easy to use PyTorch to TensorRT converter

PyTorch用の変換スクリプトはこれっぽい。Pythonコード上でパラメータ読み込み済みのモデルインスタンスを渡して変換、戻ってくるオブジェクト(torch2trt.TRTModule)はPyTorchのnn.Moduleを継承してて、ふつうのModule(Model)と同じようにtorch.loadMODULE.load_state_dicttorch.saveMODULE.state_dict()を使ってパラメータ読み書きできるみたい。

変換まではふつうのGPUマシンでやらないと重い(いちおう変換はできる)。

git clone https://github.com/NVIDIA-AI-IOT/torch2trt.git
cd torch2trt
python3 setup.py install --user
import torch
import torchvision.models as M
from torch2trt import torch2trt
from torch2trt import TRTModule

# On GPU Machine
torch_model = M.resnet50(pretrained=False).cuda()
dummy = torch.zeros(1, 3, 224, 224).cuda()

trt_model = torch2trt(torch_model, [ dummy ])
torch.save(trt_model.state_dict(), 'trt_model.pth')

# On Jetson Nano
trt_model = TRTModule()
trt_model.load_state_dict(torch.load('trt_model.pth'))
In [5]: ts = time.time(); model.load_state_dict(torch.load('trt_model.pth')); el
   ...: apsed = time.time() - ts

In [6]: elapsed
Out[6]: 38.654945611953735

In [7]: ts = time.time(); model.load_state_dict(torch.load('trt_model.pth')); el
   ...: apsed = time.time() - ts

In [8]: elapsed
Out[8]: 5.191670894622803

In [9]: ts = time.time(); model.load_state_dict(torch.load('trt_model.pth')); el
    ...: apsed = time.time() - ts

In [10]: elapsed
Out[10]: 7.234739542007446
In [18]: ts = time.time(); x = torch.randn(1, 3, 224, 224).cuda(); elapsed = tim
    ...: e.time() - ts                                                          

In [19]: elapsed                                                                
Out[19]: 0.3353462219238281

In [20]: ts = time.time(); x = torch.randn(1, 3, 224, 224).cuda(); elapsed = tim
    ...: e.time() - ts                                                          

In [21]: elapsed                                                                
Out[21]: 0.016706228256225586

In [22]: ts = time.time(); x = torch.randn(1, 3, 224, 224).cuda(); elapsed = tim
    ...: e.time() - ts                                                          

In [23]: elapsed                                                                
Out[23]: 0.015973806381225586
In [24]: ts = time.time(); y = model(x); elapsed = time.time() - ts             

In [25]: elapsed                                                                
Out[25]: 0.659074068069458

In [26]: ts = time.time(); y = model(x); elapsed = time.time() - ts             

In [27]: elapsed                                                                
Out[27]: 0.0033349990844726562

In [28]: ts = time.time(); y = model(x); elapsed = time.time() - ts             

In [29]: elapsed                                                                
Out[29]: 0.0031561851501464844

inferenceはだいぶ速い。ただモデルロードがとても遅い...。それに、初回実行の遅延は軽減してるとはいえ残ってる。

SDカード

これまでの速度にも関わっていそうなので、SDカードについて調べてみる。

UHS(Ultra-High Speed)とは - IT用語辞典 e-Words

安物を選んだので、UHS-I Class1 32GBのSamsung製Micro SDカード(これ)を使っている。UHS Class3の場合最低アクセス速度30MB/sだが、UHS Class1では最低アクセス速度10MB/sらしい。SDカードを変えれば(読み書きのかかるところでは)見込みで3倍以上速くなる可能性はあるのかなぁ?