今回はultra96v2上で学習済みモデルを動かしてみる。
この作業がすんなりできれば、論理回路の高位合成とか組み込み部分を除けば、学習済みモデルを作れればドローン制御、自動運転の制御とかいろんなことの礎になる。
本家サイト「Ultra96V2向けVitis AI(2019.2)の組み立て方」通りに進めたけど情報が古かったのでかなり苦労した。
目次
1.動作環境「vitis AI」の構築
2.Deep Learning Processor Unit (DPU) IP の作成
3.学習済みデータと画像の用意
4.pbファイルの量子化(quantization)
5.量子化したファイルからFPGA用アプリケーションの作成
6.Ultra96v2ボードでの動作確認
1.動作環境「vitis AI」の構築
dockerのインストール
dockerが必要なのでdockerをインストール。
$ sudo apt-get update && sudo apt-get upgrade $ sudo apt install -y apt-transport-https ca-certificates curl software-properties-common $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - >>> OK $ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" # Uninstall Old Versions of Docker & Install Docker $ sudo apt-get remove docker docker-engine docker.io && sudo apt install docker.io # Start and Automate Docker $ sudo systemctl start docker && sudo systemctl enable docker # コンテナ確認 $ sudo docker ps >>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
sudo なしで実行できるようにする。
# dockerグループ作成 & 現行ユーザをdockerグループに所属させる $ sudo groupadd docker && sudo gpasswd -a $USER docker # dockerデーモンを再起動する (CentOS7の場合) $ sudo systemctl restart docker # exitして再ログインすると反映される。 $ sudo reboot # コンテナ確認 $ docker ps >>> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
参考:Ubuntu 18.04にDockerをインストールする(+docker-composeも)
vitis-Aiのインストール
「tesnsorflow_q_val」コマンドがvirtualbocxだとCPUの関係で使えないので、EC2インスタンスで作業した。
次にvitis AIのインストール。
XilinxのVitis-AIがupgradeされてた。ブランチのv1.1をgit clone。
$ git clone -b v1.1 https://github.com/Xilinx/Vitis-AI # Dockerの設定 $ cd Vitis-AI/docker $ ./docker_build_cpu.sh $ cd Vitis-AI $ ./docker_run.sh xilinx/vitis-ai-cpu:latest
今回はCPU環境で試してみて、動いた!
# 抜ける $ exit
# GPUの時はこちら
$ sudo ./docker_build_gpu.sh
$ sudo ./docker_run.sh xilinx/vitis-ai-gpu:latest
BitStreamのためにメモリの増設
VirtualBoxで作業してるので、DPUは死ぬほどメモリを食うので
・メインメモリを11800くらいに変更
して計算リソースを増やした。
計算リソースが足りないとBitStream時に「強制終了エラー」が出る。
2.Deep Learning Processor Unit (DPU) IP の作成
DPU IPは「DPU for Convolutional Neural Network v1.1」によるとFPGAでCNNとかを動かすリソース(レジスタ設定、データ コントローラー、たたみ込み演算の各モジュールとか)が組み込まれてる。DPU IPはvivadoで作成しなきゃならないけど、ここは本家サイトからresnet50用のDPUをdownloadした。
DPU(AI)IP作成パート
download後にultra96v2ボードにetcherでコピー。
コピー後のボード内ファイル一覧
$ ls ultra96_oob
BOOT.BIN image.ub system.dtb
README.txt init.sh ultra96v2_oob.hwh
dpu.xclbin platform_desc.tx
これはSDCARDのboot領域(/media/user/${SDCARD}/boot)にコピーされる
3.学習済みネットワークと画像の用意
学習済みネットワークと画像の用意のパート
1.学習済みネットワークを用意
まず、作業環境のDocker起動(これ以降はほとんどdocker上で動かす)
$ cd Vitis-AI $ sudo ./docker_run.sh xilinx/vitis-ai-cpu:latest # 作業ディレクトリ作成 $ mkdir workspace $ cd workspace
“vitis-ai-tensorflow”(または”vitis-ai-caffe”)をcondaで実行。
$ conda activate vitis-ai-caffe
# tensorflowの場合
$ conda activate vitis-ai-tensorflow
今回はtensorflowの「unet」を自分で学習して、kerasの重みファイル(hdf5, ckptファイル)からultra96v2で動くアプリケーションを作る。
2.評価用画像の用意
評価用として学習用に使った画像をprepare_dataset.pyで100枚用意した。
量子化に使う「graph_input_fn.py」を少し書き換えた。
graph_input_fn.py
calib_batch_size = 10 def calib_input(iter): images = [] line = open(calib_image_list).readlines() #print(line) for index in range(0, calib_batch_size): curline = line[iter*calib_batch_size + index] #print("iter= ", iter, "index= ", index, "sum= ", int(iter*calib_batch_size + index), "curline= ", curline) calib_image_name = curline.strip() image_path = os.path.join(calib_image_dir, calib_image_name) image2 = NormalizeImageArr(image_path) #image2 = image2.reshape((image2.shape[0], image2.shape[1], 3)) images.append(image2) return {"input_1": images} def main(): calib_input() if __name__ == "__main__": main()
4.pbファイルの量子化(quantization)
kerasの訓練済の重みファイルを変換して、freezeしたpbファイル(frozen_graph.pb)を量子化する。
quantize.shで量子化。
#!/bin/sh FREEZE_DIR=freeze_tfpb FROZEN_GRAPH_FILENAME=frozen_graph.pb QUANT_DIR=quantized_model INPUT_NODE="input_1" Q_OUTPUT_NODE="conv2d_23/Sigmoid" # output node of quantized CNN vai_q_tensorflow quantize \ --input_frozen_graph ${FREEZE_DIR}/${FROZEN_GRAPH_FILENAME} \ --input_nodes ${INPUT_NODE} \ --input_shapes ?,224,224,3 \ --output_nodes ${Q_OUTPUT_NODE} \ --output_dir ${QUANT_DIR}/ \ --method 1 \ --input_fn graph_input_fn.calib_input \ --calib_iter 10 \ --gpu 0
4.量子化データから、FPGA用アプリケーションの作成
アプリケーション作成のパート
1.dcfファイルの作成
次に、etcherでイメージをSDカードにコピーしたときできた、”ultra96v2_oob.hwh”のhwhファイル(ハードウェア情報ファイル)を使って、dcfファイルを作る。
$ dlet -f ultra96v2_oob.hwh >>> [DLet]Generate DPU DCF file dpu-11-18-2019-18-45.dcf successfully. # rename $ mv dpu-11-18-2019-18-45.dcf resnet50.dcf
dletコマンドは“vitis-ai-caffe”(“vitis-ai-tensorflow”)内でのみ使える。
dcfファイルは後で使う。
2.compileを実行
compile.sh
#! /bin/sh CNN=unet COMPILE_DIR=output_compile QUANT_DIR=quantized_model TARGET=custom ARCH=${TARGET}.json vai_c_tensorflow \ --frozen_pb ${QUANT_DIR}/deploy_model.pb \ --arch ${ARCH} \ --output_dir ${COMPILE_DIR}/${CNN}2 \ --options "{'mode':'normal'}" \ --net_name ${CNN}2
dcfを入れたcustom.jsonの中身。
$cat custom.json >>> {"target": "dpuv2", "dcf": "dpu-11-18-2019-18-45.dcf", "cpu_arch": "arm64"}
compileを実行。
$ ./compile.sh >>>> ************************************************** * VITIS_AI Compilation - Xilinx Inc. ************************************************** [VAI_C][Warning] layer [conv2d_23_Sigmoid] (type: Sigmoid) is not supported in DPU, deploy it in CPU instead. Kernel topology "unet2_kernel_graph.jpg" for network "unet2" kernel list info for network "unet2" Kernel ID : Name 0 : unet2_0 1 : unet2_1 Kernel Name : unet2_0 -------------------------------------------------------------------------------- Kernel Type : DPUKernel Code Size : 1.16MB Param Size : 29.63MB Workload MACs : 83685.54MOPS IO Memory Space : 17.04MB Mean Value : 0, 0, 0, Total Tensor Count : 40 Boundary Input Tensor(s) (H*W*C) input_1:0(0) : 224*224*3 Boundary Output Tensor(s) (H*W*C) conv2d_23_convolution:0(0) : 224*224*11 Total Node Count : 35 Input Node(s) (H*W*C) conv2d_1_convolution(0) : 224*224*3 Output Node(s) (H*W*C) conv2d_23_convolution(0) : 224*224*11 Kernel Name : unet2_1 -------------------------------------------------------------------------------- Kernel Type : CPUKernel Boundary Input Tensor(s) (H*W*C) conv2d_23_Sigmoid:0(0) : 224*224*11 Boundary Output Tensor(s) (H*W*C) conv2d_23_Sigmoid:0(0) : 224*224*11 Input Node(s) (H*W*C) conv2d_23_Sigmoid : 224*224*11 Output Node(s) (H*W*C) conv2d_23_Sigmoid : 224*224*11
終わったあとのファルダ構造。
$ tree
>>>
compile
├── compile.sh
├── custom.json
├── dpu-11-18-2019-18-45.dcf
├── output_compile
│ └── unet2
│ └── unet2_kernel_graph.gv
| └── dpu_unet2_0.elf
├── quantized_model
│ ├── deploy_model.pb
│ └── quantize_eval_model.pb
└── ultra96v2_oob.hwh
3.アプリケーションの作成(sigmoidを使う
)
まずdocker。Xilinx提供のVitis AI runtimeを実行。
$ ./docker_run.sh xilinx/vitis-ai:runtime-1.0.0-cpu
今回unetにsigmoidを使った。
sigmoidはDPUで対応してないため、DPUKernelとCPUKernelが分割されるので、dpu_unet2_0.elf(unet2_0)が作成される。
なのでアプリケーション作成時に使う
「src/fpc_main.cc」のコードで
#define KERNEL_CONV "unet2"
から
#define KERNEL_CONV "unet2_0"
に置き換えないとultra96v2上で動かない。
5.量子化したファイルからFPGA用アプリケーションの作成
1.開発環境構築・ライブラリをSDカードへコピー
Vitis AIをUltra96上で動かすには、xilinxのライブラリーが必要なので、runtime パッケージをSDカード(rootのsdcardフォルダ)にコピー
# パッケージのinstall(開発環境構築) $ sudo cp -r /opt/vitis_ai/xilinx_vai_board_package Vitis-AI/workspace/ $ cd Vitis-AI/workspace/xilinx_vai_board_package/ $ sudo ./install.sh # パッケージをSDカードにコピー $ sudo cp -r /opt/vitis_ai/xilinx_vai_board_package /media/user/${SDCARD}/root/home/root/
2.FPGA用アプリケーションの作成
さっき作った「dpu_unet2_0.elf」をのmodelファルダの中に移動。
「$make」コマンドでアプリケーション作成実行。
コードはXilinxのsegmentationチュートリアルのコードを少し改造して使った。
# アプリケーションの作成実行
$ sudo make
アプリケーション完成後のディレクトリ構造
$ tree
>>>
├── common
│ ├── dputils.cpp
│ ├── dputils.h
│ └── dputils.py
└── unet2
├── Makefile
├── build
│ ├── dputils.o
│ └── fps_main.o
├── model
│ ├── dpu_unet2_0.elf
│ └── libdpumodelunet2.so
├── src
│ └── fps_main.cc
└── unet2
src/fps_main.ccの一部を変更。
// constants for segmentation network #define KERNEL_CONV "unet2_0" #define CONV_INPUT_NODE "conv2d_1_convolution" #define CONV_OUTPUT_NODE "conv2d_23_convolution"
アプリケーションとして「unet2」と「libdpumodelunet2.so」ができるので、それをSDカード(rootのsdcardフォルダ)にコピー。
$ cp resnet50 /media/user/${SDCARD}/root/home/root/
6.Ultra96v2ボードでの動作確認
いつもみたいにultra96v2の実機を起動後に、gtktermで接続してログイン
$ gtkterm -p /dev/ttyUSB1 -s 115200
# ライブラリのinstall $ cd xilinx_vai_board_package $ ./install.sh >>> Begin to install Xilinx DNNDK ... Requirement already satisfied: Edge-Vitis-AI==1.0 from file:///sdcard/pkgs/python/Edge_Vitis_AI-1.0-py2.py3-none-any.whl in /usr/lib/python3.5/site-packages (1.0) Complete installation successfully.
判別用画像をroot/home/rootの「worksapace/dataset1/」の中に入れておく。
$ cd unet2/ $ sudo chmod 755 * $ ./unet2
中身は適当なので出力結果は気にしないけど、とりあえず動いた。
ここでこの部分の作業が終わって、AIを動かす過程が一通り終了。
ここまででようやくultra96v2上で学習済みモデルを動かせた。
参考サイト
・Ultra96V2向けVitis AI(2019.2)の組み立て方
・Ubuntu 18.04にDockerをインストールする(+docker-composeも)
・ザイリンクス社「Vitis AI開発環境」を評価キット ZCU102 で動かしてみた