Ultra96 PYNQ Darknet Google-Colabo

#Memo#

フレームワークやDNNを使ったことがなく、いろんなことを試す中で解った事柄をメモしています。日を追うごとに、PYNQと関係なくなってきてますが。

#PYNQ-DNN#
OpenVINOは、Python記述から中間言語に変換し、HLSすることで実現しているらしい。OpenVINOについては[こちら](https://qiita.com/yka2ki/items/cc3f8903238d80742114)で。

PYNQの場合は？

[**PYNQ**](https://github.com/Xilinx/PYNQ)

[**PYNQ sdbuild**](https://github.com/Xilinx/PYNQ/tree/master/sdbuild)

[**Board files to build Ultra96 PYNQ image**](https://github.com/Avnet/Ultra96-PYNQ)

[**Petalinux2018.2 BSP for Ultra96**](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/embedded-design-tools/2018-2.html)

[**BNN-PYNQ pip install package**](https://github.com/Xilinx/BNN-PYNQ)

```shell-session:BNN-PYNQ
$ sudo pip3 install git+https://github.com/Xilinx/BNN-PYNQ.git (on PYNQ v2.3)
```

[**QNN on PYNQ using a MO architecture**](https://github.com/Xilinx/QNN-MO-PYNQ)

```shell-session:QNN-MO-PYNQ
$ sudo pip3 install git+https://github.com/Xilinx/QNN-MO-PYNQ.git
```

[**In Shimaharu's mind**](http://shimaharu.blogspot.com/search/label/PYNQ)　から勝手に引用。

恐らくだが、CNNやらPoolingやらの層はあらかじめHLSで生成したハードを使って、
層数とか特徴量のチャネル数はパラメータ（**JSON**に記述されている？）により
ネットワークが決まるようである。

確かにそんな感じがする。

```json:tinier-yolo-layers.json
{
    "network": "tinier-yolo",
    "input_image": "../../tests/Test_image/tinier-yolo/input.bin",
    "verification_image": "../../tests/Test_image/tinier-yolo/verification.bin",
    "binparam": "binparam-tinier-yolo-nopool",
    "use_binparams" : true,
    "binparam_skip": 1,
    "layer_skip": 0,
    "layers": [{
            "name": "conv1",
            "func": "conv_layer",
            "input_bits": 3,
            "output_bits": 3,
            "weight_bits": 1,
            "threshold_bits": 16,
            "kernel_shape": 3,
            "kernel_stride": 1,
            "input_channels": 16,
            "input": [16, 208, 208],
            "output_channels": 64,
            "output": [64, 208, 208],
            "padding": 1
        },
        {
            "name": "pool1",
            "func": "maxpool_layer",
            "input_bits": 3,
            "output_bits": 3,
            "kernel_shape": 2,
            "kernel_stride": 2,
            "input_channels": 64,
            "input": [64, 208, 208],
            "output_channels": 64,
            "output": [64, 104, 104],
            "padding": 0
        },

        途中割愛

        {
            "name": "end",
            "func": "none"
        }
    ]
}
```

詳しくは、よくわからない・・・

#[Ultra96-PYNQを自分でビルドする](https://qiita.com/okuhata/items/44b279d266191273885d)#
@okuhata さんの記事です。

#[ZCU102向けPYNQビルド備忘録](https://qiita.com/jin0g/items/42d53fd1eca42ec17c0f)#
@jin0g さんの記事です。

#PYNQ LinuxイメージのSDカードへの書き込み#

```shell-session:SDカード
$ sudo mkfs -t vfat -F 32 /dev/sdb1
$ sudo mkfs -t ext4       /dev/sdb2

$ sudo mlabel  -i /dev/sdb1 ::BOOT
$ sudo e2label    /dev/sdb2 ROOTFS 

$ sudo mount /dev/sdb1 /mnt
$ sudo cp BOOT.BIN image.ub /mnt
$ sudo sync
$ sudo umount /mnt

$ sudo dd if=rootfs.ext4 of=/dev/sdb2 bs=1M status=progress

$ sudo e2fsck -f /dev/sdb2
$ sudo resize2fs -p /dev/sdb2 {7G}
```

#Darknet#

FPGA Magazineを参考にして、Darknetを試してみる。

##Pjreddie（本家？）Yolo v3##

```shell-session:Pjreddie
$ git clone https://github.com/pjreddie/darknet

$ cd darknet

$ vi Makefile
  OPENCV=1
  CFLAGS = ... -pg

$ make
```

```shell-session:Pjreddie
$ wget https://pjreddie.com/media/files/yolov3.weights
$ ./darknet detect cfg/yolov3.cfg yolov3.weights data/people_dog.jpg
```
Input JPEG
<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/287eaeb5-fa2b-182b-07ba-ff65df19f0a4.jpeg" width="320">

Predictions JPG
<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/6cb8e882-1afe-c920-5be8-fb8404d0bcbb.jpeg" width="320">

##Pjreddie（本家？）Yolo v3 Tiny##

```shell-session:Pjreddie
$ wget https://pjreddie.com/media/files/yolov3-tiny.weights
$ ./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/people_dog.jpg
```

Predictions JPG
<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/0f50ef4c-a096-7474-a7bb-c503535d368c.jpeg" width="320">
靴先を野球ボールとだと認識してる。

##Giuliogamba（forked from Pjreddie）Yolo v2##

```shell-session:Giuliogamba
$ git clone https://github.com/giuliogamba/darknet.git
$ wget https://pjreddie.com/media/files/yolov2-voc.weights
$ wget https://pjreddie.com/media/files/yolo-voc.weights
```
##AlexeyAB（forked from Pjreddie）Yolo v3##

このForkは、動画ファイル（mp4）やWebカメラでも動作した。

```shell-session:AlexeyAB
$ git clone https://github.com/AlexeyAB/darknet.git
```

GPU、cuDNNを有効にして

```shell-session:AlexeyAB
$ vi Makefile
  OPENCV=1
  GPU=1
  CUDNN=1

$ make
$ ./darknet detect cfg/yolov3.cfg yolov3.weights data/people_dog.jpg
```
Predictions JPG
<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/15cc4562-86ba-b208-237e-44f138feb954.jpeg" width="320">
後ろの人やベンチも認識している。
CPUだけ、GPUを有効、cuDNNも有効にした場合の処理時間の違いを。
NVidiaボードは古~いQuadro。

```shell-session:AlexeyAB
$ ./darknetCPU detect cfg/yolov3.cfg yolov3.weights data/People_Dog.jpg 
data/People_Dog.jpg: Predicted in 19813.975000 milli-seconds.

$ ./darknetGPU detect cfg/yolov3.cfg yolov3.weights data/People_Dog.jpg 
data/People_Dog.jpg: Predicted in 505.077000 milli-seconds.

$ ./darknetCUDNN detect cfg/yolov3.cfg yolov3.weights data/People_Dog.jpg 
data/People_Dog.jpg: Predicted in 299.481000 milli-seconds.
 
```
40倍以上、高速になった。
澁谷のゾンビ行進の画像で試してみると、皆Personです、当然といえば当然。:wink:
<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/0127695d-8b54-de17-7b16-dd3a2daf572d.jpeg" width="320">

```shell-session:動画ファイルを使うなら
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights -dont_show data/hoge.mp4 -i 0 -out_filename res.avi
```

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">AlexeyABのYolo v3で、動画ファイルを試してみた。 <a href="https://t.co/TRUPr6ugyi">pic.twitter.com/TRUPr6ugyi</a></p>&mdash; yka2ki (@yka2ki) <a href="https://twitter.com/yka2ki/status/1099324782242234368?ref_src=twsrc%5Etfw">2019年2月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

3fpsぐらいだったので、それならWebカメラでカクカク映像が見れるかも。



```shell-session:Webカメラを使うなら
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights
```

**準備中**



#Jupyter Notebook Viewer#
GitのJupyter Notebookを手っ取り早く見るためには便利

[**Jupyter Notebook Viewer**](https://nbviewer.jupyter.org/)

#Linux上で画像ファイルの表示#
apt updateしてなかったからか、Ubuntuに入っていなかったので。

```shell-session:ImageMagick
$ sudo apt install imagemagick
$ display predictions.jpg
```
#Ubuntu16.04にUSB Webカメラを繋ぐ#

Webカメラからの映像を表示するアプリCheeseを起動しても、Webカメラにアクセスできませんでした。デバイスファイル/dev/video0へのアクセスにはroot権限が要るらしく、setfaclコマンドでアクセス制御を設定することで、表示できるようになりました。

```shell-session:Webカメラ
sudo chmod 660 /dev/video0
sudo chgrp video /dev/video0
sudo setfacl -m u:自分のアカウント:rw /dev/video0
```
setfaclコマンドなるものを、初めて知った・・・

#Ubuntu16.04にNVidiaドライバとCUDA9.0をインストール#

[こちら](https://qiita.com/yka2ki/items/ec3c3d3e0656d8a2c557)

#Google Colaboratoryで試してみる#

**作成中**

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/48105457-e902-48cf-2e68-d8146d03d52c.png" width="480">


<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/84cf56f1-1e0e-5186-744f-77125c748e5d.png" width="480">


<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/60c4ec96-8a86-5951-21e7-545a506d71cf.png" width="480">


<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/704c6145-d361-bfe9-b4f4-5a7f40068502.png" width="480">

```shell-session:Time
./People_Dog.jpg: Predicted in 281.701000 milli-seconds.
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/50bd74e9-28f3-d531-9e54-7517c79ea6f4.png" width="480">

```shell-session:FPS_on_Google-Colabo
cvWriteFrame 
1;1H
FPS:16.4
Objects:

person: 100% 
person: 100% 
person: 99% Stream closed.

person: 99% 
person: 98% 
person: 96% 
person: 75% 
person: 74% 
person: 69% 
person: 68% 
person: 45% 
```

#Darknetの処理時間の可視化#
Interfaceの記事をたよりに、Darknetの処理時間のプロファイルを取ってみた。

```shell-session:Profile_on_Ubuntu_using_GPU
$ vi Makefile
  OPENCV=1
  GPU=1
  CUDNN=1
  CFLAGS = ... -pg

$ make
$ ./darknet detect cfg/yolov3.cfg yolov3.weights data/people_dog.jpg
$ gprof darknet | ./gprof2dot.py | dot -Tpng -o profile.png
```

gprof2dot.pyは以下からゲットする。

```shell-session:gprof2dot
$ git clone https://github.com/jrfonseca/gprof2dot
```

###Ubuntu上でGPUを使った場合のプロファイルは###

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/4e83c96d-fe6b-d319-5abc-032eaa7a08b6.png">

###Google Colabo上でGPUを使った場合のプロファイルは###

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/b3b1b625-6e47-7d36-6767-cb5fa76c4767.png">

###Ubuntu上でCPUを使った場合のプロファイルは###

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/d9cfe93f-2b6f-cd9b-aeb3-c7308dbf41f8.png">

###Ultra96のPSだけで処理した場合のプロファイルは###

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/702d910b-daca-c30a-0d70-60aa367d004b.png">


処理時間は、

```shell-session
$ ./darknet detect cfg/yolov3.cfg yolov3.weights data/People_Dog.jpg 
data/People_Dog.jpg: Predicted in 120869.165000 milli-seconds.

```
dotが入ってなかったのでインストールする。Ubuntuであれば、以下のようなaptでインストールできますが

```shell-session
$ sudo apt install graphviz
```
Ultra96のPetalinux BSPで作ったLinuxは、Ubuntuではないのでaptできず、ソースをダウンロードしてコンパイル、インストールする。

```shell-session
$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz
$ tar zxvf graphviz.tar.gz
$ cd graphviz-2.40.1
$ ./configure
$ make
$ sudo make install
```

わざわざUltra96上でdot変換する必要はないけど、Memoとして。

#Ultra96のXwindowをPC上に表示#
処理結果の画像を表示して確認するために、
わざわざディスプレイを繋ぐのが場所もとるし面倒なので、
SSHでloginし、XwindowアプリをPC上に表示できるようにした。

PC上ではCygwinを使っているので、
[CygwinによるXWindowsの利用](https://itcweb.cc.affrc.go.jp/affrit/documents/guide/x-window/x-win-cygwin)等を参考にしてXサーバーをインストールし、

```shell-session:まずCygwin上でDISPLAY変数を設定する
  $ echo $DISPLAY
  localhost:0.0
  $ export DISPLAY=:0.0
  $ echo $DISPLAY
  :0.0
```

```shell-session:Ultra96にsshするときのオプション-Yが重要
  $ ssh -l root -Y 192.168.3.11
```

```shell-session:Ultra96上のDISPLAY変数は
  root@ultra96:~ # echo $DISPLAY
  localhost:10.0
```

```shell-session:xtermを起動すると、PCに表示される
  root@ultra96:~ # xterm
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/75262/2d242f40-4e09-031e-aebc-586cbfa5949d.png" width="680">


取り敢えずここまで。