見出し画像

AI高位合成ツール「AIRTIPS」で生成した独自AIアクセラレータ(4DTC)をKV260で動かす方法~AIRTIPS実践編②~

研究開発本部 中村 龍昇(なかむら たつのり)

はじめに

本稿では、独自AIアクセラレータ(4DTC)を用いて、AI超解像モデルをFPGA基板であるKV260上で動作させる方法について解説します。
本システムの紹介動画をYoutubeに公開しておりますので、ぜひご覧ください。

紹介動画にあるように、4DTCを活用することで、映像を高速に超解像処理することが可能になります。本稿では、その方法について詳しく解説します。

AI高位合成ツール「AIRTIPS」は、以下のリンクからダウンロードすることができます。
https://corporate.jp.sharp/8k5g/8klab/ai-edge_report_202505.html

本稿を読む前に、是非、AIRTIPS導入編実践編①を見てください。

まず、動作させるAI超解像モデルについて説明します。
次に、4DTCを用いて、AI超解像モデルをKV260で動かす方法について説明します。
さらに、4DTCの特長機能であるレイヤ統合により、最適化したモデルへ変更する方法を説明します。最適化モデルへの変更は手動で行います。
最後に、Webカメラ等からUSB伝送される映像をAI超解像するサンプルプログラムについて説明します。

AI超解像モデル

本稿では、1 層 16 チャンネルの独自AI超解像モデル(sr_evalmodel)を動かします。FSRCNNをベースに、チャンネル数等を調整したもので、レイヤ構成は以下の通りです。

画像
レイヤ構成(1層16チャンネル、RGBの場合)

パラメータ数は、7779個で、内訳は以下の通りです。

=================================================================
Layer (type:depth-idx)                   Param #
=================================================================
FSRCNN                                   --
├─Sequential: 1-1                        --
│    └─Conv2d: 2-1                       448
│    └─ClipBLK: 2-2                      --
├─Sequential: 1-2                        --
│    └─ResBlock: 2-3                     --
│    │    └─Sequential: 3-1              4,640
│    └─ReLU: 2-4                         --
│    └─Conv2d: 2-5                       2,320
├─Sequential: 1-3                        --
│    └─ConvTranspose2d: 2-6              260
│    └─ClipBLK: 2-7                      --
│    └─Conv2d: 2-8                       111
│    └─ClipBLK: 2-9                      --
=================================================================
Total params: 7,779
Trainable params: 7,779
Non-trainable params: 0
=================================================================

本AI超解像モデルの先頭のレイヤは、ichannel=3、ochannel=16、kernel=3のConv2d(2-1)です。次に、ichannel=ochannel=16、kernel=3のConv2dが3層(2-3、2-5)つづきます。その次のレイヤは、ichannel=16、ochannel=4、kernel=2のConvTranspose2d(2-6)です。最後のレイヤは、ichannel=4、ochannel=3、kernel=3のConv2d(2-8)です。
ReLUの代わりにClipBLKを使用している部分があります。ClipBLKではMin値(0)とともに、Max値(255)でも値をクリップします。

AIRTIPSによる4DTC用Cプログラムの作成

AIRTIPSの実行

AI高位合成ツール(AIRTIPS_v1.0.zip)の sample/sr/sr_evalmodelフォルダにあるreadme.mdを参考に、4DTCのエミュレータの実行までの動作を確認して下さい。KV260でAIRTIPSの動作確認を行うと時間がかかるため、実践編①に記載するVivado合成用PC等で行うことを推奨します。

~/DEVREL_AIRTIPS/sample/sr/sr_evalmodel/readme.md

動作を確認した結果、/sample/sr/sr_evalmodel/4dtcフォルダにmodels.cppがあることを確認して下さい。

KV260でのAI超解像の確認

KV260で、4DTCのROMロード

AIRTIPS実践編①と同様に、まず、4DTCのROMロードを実行します。
sudo xmutil listappsで、ロードされているROMファイルを確認します。起動時はk26-starter-kitsがロードされています。

ubuntu@kria:~$ sudo xmutil listapps
Accelerator          Accel_type Base             Base_type      #slots(PL+AIE)  Active_slot
k26-starter-kits     XRT_FLAT    k26-starter-kits   XRT_FLAT        (0+0)            0,
project_1            XRT_FLAT    project_1          XRT_FLAT        (0+0)           -1

sudo xmutil unloadappで、ROMファイルをアンロードします。

ubuntu@kria:~$ sudo xmutil unloadapp
Accelerator successfully removed.

project_1のROMファイルをロードします。

ubuntu@kria:~$ sudo xmutil loadapp project_1
Accelerator loaded to slot 0

4DTCを動かすためのファイルを、KV260へコピー

KV260上で、AI高位合成ツール(AIRTIPS_v1.0.zip)を展開して下さい。展開したフォルダをAIRTIPSとして説明します。
「AIRTIPSの実行」の節で確認した/sample/sr/sr_evalmodel/4dtcフォルダのmodels.cppを、KV260の同じフォルダへコピーします。KV260でのフォルダ内のファイルを以下に示します。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ ls
4dtc.h         4dtc_emu.cpp  main_sr_models.cpp  make_emu.sh  pams.cpp
4dtc_dmac.cpp  kiyomizu.bmp  make.sh             models.cpp   pams.h

4DTCの動作確認

make.shを実行します。modelsという名前の実行ファイルができていることを確認して下さい。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sh make.sh

./modelsを実行します。sudoコマンドをつけて実行して下さい。sudoコマンドをつけない場合、Segmentation fault (core dumped)になります。./modelsを実行した結果の一例を以下に示します。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sudo ./models racehorses.bmp
bo0.size()   :0xc000000
bo0.address():0x37300000
bo0.map()    :0xffffa9670000
O.K.
AI     FFFFB571D000
       A1000000
AI RAM FFFFA9670000
       37300000
Load racehorses.bmp !
*** AI Super Resolution(4DTC) ***
Time : 144.918ms
Save out_4dtc.bmp !

入力画像は別途準備したracehorses.bmp(解像度 160x120)を使いました。もともとフォルダにあるkiyomizu.bmpを使用しても問題ありません。
AI超解像により2倍に拡大された画像はout_4dtc.bmp(解像度 320x240)です。


入力画像
画像
AI超解像後の画像

参考として、エミュレータ(4DTCを使用せず、CPUのみで計算)を実行した結果を以下に示します。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ ./models_emu racehorses.bmp
Load racehorses.bmp !
*** AI Super Resolution(4DTC) ***
Time : 8991.181ms
Save out_4dtc.bmp !

レイヤ統合による最適化モデル

レイヤ統合による最適化とは

AIアクセラレータの高速化および低消費電力化を実現するためには、DDRなどの外部メモリへのアクセスを削減し、内部メモリ(オンチップメモリ)へのアクセスを増加させる手法が有効です。
我々が開発したAIアクセラレータである4DTCは、多数のラインバッファを用い、複数のレイヤの演算をライン単位でパイプライン処理することで、フレームメモリであるDDRメモリへのアクセスを削減することができます。
複数のレイヤの演算を統合し、フレームメモリへのアクセスを削減することを、レイヤ統合による最適化とよんでいます。

レイヤ統合前の処理ブロック図を以下に示します。AI高位合成ツールであるAIRTIPSを用いると、Pythonプログラム(models.py)から、以下のような処理のCプログラム(models.cpp)を自動で生成することができます。

画像
レイヤ統合前の処理ブロック図

今回は、レイヤ統合により以下のような処理ブロックへ手動で変更し、動作を確認します。

画像
レイヤ統合後の処理ブロック図

レイヤ統合前は、加算処理とReLU(Clip)とをそれぞれ単独でCPU処理しています。レイヤ統合後は、Conv2dと同様に、加算処理やReLUを4DTCでHW処理するため、処理時間を短縮することができます。

models.cppの変更

models.cppのvoid make_param()の後段を以下のように修正してください。make_conv2d_param、及びmake_convtranspose2d_paramの引数の値は参考値です。引数の値については、以下で説明しますので、作成したmodels.cppの各パラメータを考慮して変更してください。


629 /*
630 make_conv2d_param(parameter_0_0, para_0_0, 3, 3, 16, 0x40, 0x0, 127, -128);
631 para_a_0_0_0[0]=(int8_t *)parameter_a_0_0_0;
632 make_conv2d_param(parameter_1_0_0_0, para_1_0_0_0, 3, 16, 16, 0x40, 0x0, 127, -128);
633 para_a_0_0_1[0]=(int8_t *)parameter_a_0_0_1;
634 make_conv2d_param(parameter_1_0_0_2, para_1_0_0_2, 3, 16, 16, 0x40, 0x0, 127, -128);
635 para_a_0_0_2[0]=(int8_t *)parameter_a_0_0_2;
636 para_a_0_0_3[0]=(int8_t *)parameter_a_0_0_3;
637 make_add_param(parameter_a_0_0_4, para_a_0_0_4, 127, -128);
638 para_1_1[0]=(int8_t *)parameter_1_1;
639 make_conv2d_param(parameter_1_2, para_1_2, 3, 16, 16, 0x40, 0x0, 127, -128);
640 make_add_param(parameter_a_0_0_5, para_a_0_0_5, 127, -128);
641 make_convtranspose2d_param(parameter_2_0, para_2_0, 2, 16, 4, 0x40, 0x0, 127, -128);
642 para_a_0_0_6[0]=(int8_t *)parameter_a_0_0_6;
643 make_conv2d_param(parameter_2_2, para_2_2, 3, 4, 3, 0x40, 0x0, 127, -128);
644 para_a_0_0_7[0]=(int8_t *)parameter_a_0_0_7;
645 para_a_0_0_8[0]=(int8_t *)parameter_a_0_0_8;
646 */
647 make_conv2d_param(parameter_0_0, para_0_0, 3, 3, 16, 0x40, 0x0, 127, 0);
648 make_conv2d_param(parameter_1_0_0_0, para_1_0_0_0, 3, 16, 16, 0x40, 0x0, 127, 0);
649 make_conv2d_param(parameter_1_0_0_2, para_1_0_0_2, 3, 16, 16, 0x4, 0x20, 127, 0);
650 make_conv2d_param(parameter_1_2, para_1_2, 3, 16, 16, 0x20, 0x8, 127, -128);
651 make_convtranspose2d_param(parameter_2_0, para_2_0, 2, 16, 4, 0x40, 0x0, 127, 0);
652 make_conv2d_param(parameter_2_2, para_2_2, 3, 4, 3, 0x40, 0x0, 127, 0);
653 }

次に、models.cppのvoid modelsを変更します。変更前と変更後とを以下に記載します。

//変更前
647 void models( int8_t *x, int in_sizex, int in_sizey, int8_t *y, int iwidth, int owidth)
648 {
649 ai_sizex=in_sizex;
650 ai_sizey=in_sizey;
651 pams_conv2d(dd_0_, x, &ai_sizex, &ai_sizey, para_0_0, 3, 3, 16, 1, 1, iwidth, SizeX*8*1);
652 pams_clip(dd_1_, dd_0_, &ai_sizex, &ai_sizey, 0.0, 255.0, para_a_0_0_0, 16, SizeX*8*1);
653 pams_conv2d(dd_2_, dd_1_, &ai_sizex, &ai_sizey, para_1_0_0_0, 3, 16, 16, 1, 1, SizeX*8*1, SizeX*8*1);
654 pams_clip(dd_3_, dd_2_, &ai_sizex, &ai_sizey, 0.0, 255.0, para_a_0_0_1, 16, SizeX*8*1);
655 pams_conv2d(dd_4_, dd_3_, &ai_sizex, &ai_sizey, para_1_0_0_2, 3, 16, 16, 1, 1, SizeX*8*1, SizeX*8*1);
656 pams_clip(dd_5_, dd_4_, &ai_sizex, &ai_sizey, -255.0, 255.0, para_a_0_0_2, 16, SizeX*8*1);
657 float tmp0[1]={0.125};
658 pams_init(init_0, &ai_sizex, &ai_sizey, 16, 1, tmp0, SizeX*8*1);
659 pams_mul(dd_6_, dd_5_, init_0, &ai_sizex, &ai_sizey, para_a_0_0_3, 16, SizeX*8*1);
660 pams_add(dd_7_, dd_6_, dd_1_, &ai_sizex, &ai_sizey, para_a_0_0_4, 16, SizeX*8*1);
661 pams_relu(dd_8_, dd_7_, &ai_sizex, &ai_sizey, para_1_1, 16, SizeX*8*1);
662 pams_conv2d(dd_9_, dd_8_, &ai_sizex, &ai_sizey, para_1_2, 3, 16, 16, 1, 1, SizeX*8*1, SizeX*8*1);
663 pams_add(dd_10_, dd_9_, dd_1_, &ai_sizex, &ai_sizey, para_a_0_0_5, 16, SizeX*8*1);
664 pams_convtranspose2d(dd_11_, dd_10_, &ai_sizex, &ai_sizey, para_2_0, 2, 16, 4, 2, 0, 0, SizeX*8*1, SizeX*8*2);
665 pams_clip(dd_12_, dd_11_, &ai_sizex, &ai_sizey, 0.0, 255.0, para_a_0_0_6, 4, SizeX*8*2);
666 pams_conv2d(dd_13_, dd_12_, &ai_sizex, &ai_sizey, para_2_2, 3, 4, 3, 1, 1, SizeX*8*2, owidth);
667 pams_clip(dd_14_, dd_13_, &ai_sizex, &ai_sizey, 0.0, 255.0, para_a_0_0_7, 3, owidth);
668 pams_shift(y, dd_14_, &ai_sizex, &ai_sizey, para_a_0_0_8, 3, owidth);
669 }
//変更後
655 void models( int8_t *x, int in_sizex, int in_sizey, int8_t *y, int iwidth, int owidth)
656 {
657 ai_sizex=in_sizex;
658 ai_sizey=in_sizey;
659
660 pams_conv2d(dd_1_, x, &ai_sizex, &ai_sizey,
661     para_0_0, 3, 3, 16, 1, 1, iwidth, SizeX*8);
662
663 pams_conv2dx2_add(dd_8_, dd_1_, dd_1_, &ai_sizex, &ai_sizey,
664     para_1_0_0_0, 3,
665     para_1_0_0_2, 3, 16, 16, 16, SizeX*8, SizeX*8);
666
667 pams_conv2d_add(dd_10_, dd_8_, dd_1_, &ai_sizex, &ai_sizey,
668     para_1_2, 3, 16, 16, 1, 1, SizeX*8, SizeX*8);
669
670 pams_convtranspose2d_conv2d(y, dd_10_, &ai_sizex, &ai_sizey,
671     para_2_0, 2,
672     para_2_2, 3, 16, 4, 3, 2, SizeX*8, owidth);
673
674 }

参考のため行数を記載しています。
一旦、本修正を行った後、models.cppをコンパイルして出力画像を確認してみてください。出力画像の色などがおかしい場合、以下の記載を参照し、make_conv2d_paramや、make_convtranspose2d_paramの引数の値を調整し、再度、コンパイルし出力画像を確認して下さい。

models.cppの修正内容について説明します。
まずは一番先頭のConv2D処理(660行目、661行目のpams_conv2d)について説明します。
pams.hでの関数宣言は、以下の通りです。

void pams_conv2d(int8_t *output, int8_t *input, int *sizex, int *sizey,
    int8_t *param[], int kernel, int ichannel, int ochannel, int stride, int padding,
    int iwidth, int owidth);

入力画像はinput(x)です。出力画像はoutput(dd_1_)です。weightやbiasやReLU(Clip)の設定値等は、para_0_0に格納されています。

para_0_0は、make_conv2d_param関数で作ります。元の値は、parameter_0_0に格納されています。
make_conv2d_paramの関数宣言は、以下の通りです。

void make_conv2d_param(uint8_t *param, int8_t *buf[], int kernel, int ichannel, int ochannel,
     int conv, int add, int imax, int imin);

ReLU相当の処理をするために、imaxとiminとを設定します。映像データの型は符号付8bitのため、imaxは127と設定します。また、ReLU相当の処理をするためiminは0と設定します。変更前後の設定を以下に示します。

//変更前
630 make_conv2d_param(parameter_0_0, para_0_0, 3, 3, 16, 0x40, 0x0, 127, -128);

//変更後
647 make_conv2d_param(parameter_0_0, para_0_0, 3, 3, 16, 0x40, 0x0, 127, 0);

次のレイヤであるpams_conv2dx2_addについて説明します。
本レイヤのブロック図を以下に示します。

画像
pams_conv2dx2_addのブロック図

models.cppのvoid modelsでは、以下のように記述しています。

663 pams_conv2dx2_add(dd_8_, dd_1_, dd_1_, &ai_sizex, &ai_sizey,
664     para_1_0_0_0, 3,
665     para_1_0_0_2, 3, 16, 16, 16, SizeX*8, SizeX*8);

pams.hでの関数宣言は、以下の通りです。

void pams_conv2dx2_add(int8_t *output, int8_t *input, int8_t *add, int *sizex, int *sizey,
    int8_t *param0[], int kernel0, int8_t *param1[], int kernel1,
    int ichannel0, int ichannel1, int ochannel, int iwidth, int owidth);

前段のConv2dのパラメータはparam0(para_1_0_0_0)、後段のConv2dのパラメータはparam1(para_1_0_0_2)です。
まず、para_1_0_0_0の作り方について説明します。前段のConv2dの後にReLUがあるため、make_conv2d_paramのiminの値を0に変更します。

//変更前
make_conv2d_param(parameter_1_0_0_0, para_1_0_0_0, 3, 16, 16, 0x40, 0x0, 127, -128);

//変更後
make_conv2d_param(parameter_1_0_0_0, para_1_0_0_0, 3, 16, 16, 0x40, 0x0, 127, 0);

次に、para_1_0_0_2の作り方について説明します。本パラメータを作る場合、make_conv2d_paramの、int conv、int addを調整する必要があります。convはConv2dの出力データをビットシフトするための引数で、addは加算データをビットシフトするため引数です。

//変更前
make_conv2d_param(parameter_1_0_0_2, para_1_0_0_2, 3, 16, 16, 0x40, 0x0, 127, -128);

//変更後
make_conv2d_param(parameter_1_0_0_2, para_1_0_0_2, 3, 16, 16, 0x4, 0x20, 127, 0);

変更前は、scaleによる乗算(x0.125)と加算処理とは、pams_init、pams_mul、pams_addで行っています。
変更前のmake_conv2d_paramは、Conv2dの出力データを変更する必要はありません。0x40(64)を基準にしているため、conv=0x40となります。また、加算データを考慮する必要がないため、add=0x0となります。
以下が対応するmodels.cppのvoid models()の記述です。

657 float tmp0[1]={0.125};
658 pams_init(init_0, &ai_sizex, &ai_sizey, 16, 1, tmp0, SizeX*8*1);
659 pams_mul(dd_6_, dd_5_, init_0, &ai_sizex, &ai_sizey, para_a_0_0_3, 16, SizeX*8*1);
660 pams_add(dd_7_, dd_6_, dd_1_, &ai_sizex, &ai_sizey, para_a_0_0_4, 16, SizeX*8*1);
661 pams_relu(dd_8_, dd_7_, &ai_sizex, &ai_sizey, para_1_1, 16, SizeX*8*1);

pams_initで、scale=0.125のデータであるinit_0を作ります。pams_mulは、init_0と、para_a_0_0_3(parameter_a_0_0_3)とで入力データ(dd_5_)を処理し、出力データ(dd_6_)を返します。
scale=0.125のため、入力データを右に3ビットシフトします。
models.cppでは、parameter_a_0_0_3[0]=0x7です。int8_tとint8_tとの掛け算の結果を、右に7ビットシフトするという意味で、変更後のmake_conv2d_paramで考慮する必要はありません。

pams_addは、para_a_0_0_4(parameter_a_0_0_4)で、dd_6_と加算データ(dd_1_)とを加算処理し、出力データ(dd_7_)を返します。
models.cppでは、parameter_a_0_0_4 = {0x0,0x0,0x8}です。入力データに対応するパラメータは、parameter_a_0_0_4[0] = 0x0で、ビットシフト不要です。また、加算データに対応するパラメータは、parameter_a_0_0_4[1] = 0x0で、同様にビットシフト不要です。出力データに対応するパラメータは、parameter_a_0_0_4[2] = 0x8です。0x7が基準のため、右に1ビットシフトする必要があります。

pams_reluでは、入力データ(dd_7_)の最小値を0にクリップし、出力データ(dd_8_)を返します。

よって、変更後のmake_conv2d_paramは、以下を考慮する必要があります。

  • Conv2dの出力側のパラメータであるconv

    • scale=0.125のため、右に3bitシフト

    • parameter_a_0_0_4より、右に1ビットシフト

    • →0x40を右に4ビットシフトするため、0x4

  • 加算データのパラメータであるadd

    • parameter_a_0_0_4より、右に1ビットシフト

    • →0x40を右に1ビットシフトするため、0x20

  • ReLUのため、iminを0に設定

次に、pams_conv2d_addについて説明します。
本レイヤのブロック図を以下に示します。

画像
pams_conv2d_addのブロック図

models.cppのvoid modelsでは、以下のように記述しています。

667 pams_conv2d_add(dd_10_, dd_8_, dd_1_, &ai_sizex, &ai_sizey,
668     para_1_2, 3, 16, 16, 1, 1, SizeX*8, SizeX*8);

pams.hでの関数宣言は、以下の通りです。

void pams_conv2d_add(int8_t *output, int8_t *input, int8_t *add, int *sizex, int *sizey,
    int8_t *param[], int kernel, int ichannel, int ochannel, int stride, int padding,
    int iwidth, int owidth);

para_1_2の作り方について説明します。本パラメータを作る場合も、make_conv2d_paramの、int conv、int addを調整する必要があります。

//変更前
make_conv2d_param(parameter_1_2, para_1_2, 3, 16, 16, 0x40, 0x0, 127, -128);

//変更後
make_conv2d_param(parameter_1_2, para_1_2, 3, 16, 16, 0x20, 0x8, 127, -128);

変更前は、Conv2dの出力データは変更しません。0x40(64)を基準にしているため、conv=0x40となります。また、加算処理は、pams_addで行います。
以下が対応するmodels.cppのvoid models()の記述です。

663 pams_add(dd_10_, dd_9_, dd_1_, &ai_sizex, &ai_sizey, para_a_0_0_5, 16, SizeX*8*1);

pams_addは、para_a_0_0_5(parameter_a_0_0_5)で、dd_9_と加算データ(dd_1_)とを加算処理し、出力データ(dd_10_)を返します。
models.cppでは、parameter_a_0_0_5 = {0x0,0x2,0x8}です。入力データに対応するパラメータは、parameter_a_0_0_5[0]=0x0で、ビットシフト不要です。加算データに対応するパラメータは、parameter_a_0_0_5[1]=0x2のため、右に2ビットシフトが必要です。出力データに対応するパラメータは、parameter_a_0_0_5[2] = 0x8です。0x7基準のため、右に1ビットシフトする必要があります。

よって、変更後のmake_conv2d_paramは、以下を考慮する必要があります。

  • Conv2dの出力側のパラメータであるconv

    • parameter_a_0_0_5[2] = 0x8です。0x7基準のため、右に1ビットシフト

    • →0x40を右に1ビットシフトするため、0x20

  • 加算データのパラメータであるadd

    • parameter_a_0_0_5[1]=0x2のため、右に2ビットシフト

    • parameter_a_0_0_5[2] = 0x8です。0x7基準のため、右に1ビットシフト

    • →0x40を右に3ビットシフトするため、0x8

  • ReLUはないので、iminは-128のまま

最後に、pams_convtranspose2d_conv2dについて説明します。
本レイヤのブロック図を以下に示します。

画像
pams_convtranspose2d_conv2dのブロック図

models.cppのvoid modelsでは、以下のように記述しています。

670 pams_convtranspose2d_conv2d(y, dd_10_, &ai_sizex, &ai_sizey,
671     para_2_0, 2,
672     para_2_2, 3, 16, 4, 3, 2, SizeX*8, owidth);

pams.hでの関数宣言は、以下の通りです。

void pams_convtranspose2d_conv2d(int8_t *output, int8_t *input, int *sizex, int *sizey,
    int8_t *param0[], int kernel0, int8_t *param1[], int kernel1,
    int ichannel, int mchannel, int ochannel, int stride, int iwidth, int owidth);

前段のConvTranspose2dのパラメータはparam0(para_2_0)、後段のConv2dのパラメータはparam1(para_2_2)です。

para_2_0の作り方について説明します。前段のConvTranspose2dの後にReLUがあるため、make_convtranspose2d_paramのiminの値を0に変更します。
para_2_2の作り方について、後段のConv2dの後にReLUがあるため、make_conv2d_paramのiminの値を0に変更します。

//変更前
make_convtranspose2d_param(parameter_2_0, para_2_0, 2, 16, 4, 0x40, 0x0, 127, -128);
make_conv2d_param(parameter_2_2, para_2_2, 3, 4, 3, 0x40, 0x0, 127, -128);

//変更後
make_convtranspose2d_param(parameter_2_0, para_2_0, 2, 16, 4, 0x40, 0x0, 127, 0);
make_conv2d_param(parameter_2_2, para_2_2, 3, 4, 3, 0x40, 0x0, 127, 0);

pams_shiftで出力値を調整すためにbitシフトを行う必要がありますが、pams_shiftに対応するパラメータは、parameter_a_0_0_8[1] = {0x7}で、0x7基準のため、変更はありません。

レイヤ統合した場合の実行時間

レイヤ統合したmodels.cppを再度コンパイルしてください。
レイヤ統合後に、AI超解像した場合の処理結果を以下に示します。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sudo ./models racehorses.bmp
...
Load racehorses.bmp !
*** AI Super Resolution(4DTC) ***
Time : 8.357ms
Save out_4dtc.bmp !

レイヤ統合前の処理時間が約145msecに対し、レイヤ統合後の処理時間は約8msecと処理時間が短くなっていることが分かります。
レイヤ統合後の処理画像について、左端と右端とが変になる不具合がありますが、今後、修正していきたいと思います。

画像
レイヤ統合後にAI超解像した画像

(補足)コンパイルの際の最適化オプション

g++でコンパイルする際に、コンパイルオプション(-O3)をつけることで、コンパイル時間は長くなりますが、より高速な処理が可能です。変更後のmake.shを以下に示します。

#!/bin/sh

g++ -O3 -o models main_sr_models.cpp models.cpp 4dtc_dmac.cpp pams.cpp \
-D XRT_BO \
-I/usr/include/xrt \
-L/usr/lib \
-lxrt_coreutil -pthread

実行後のログを以下に示します。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sudo ./models racehorses.bmp
...
Load racehorses.bmp !
*** AI Super Resolution(4DTC) ***
Time : 5.751ms
Save out_4dtc.bmp !

映像をAI超解像

映像をAI超解像するためのシステム構成図

AI超解像した映像を確認するためのシステムの構成図を以下に示します。

画像
AI超解像の映像を確認するためのシステム構成図

Webカメラや映像源のデータをUSBでKV260へ入力します。AI超解像した映像をHDMIで出力し、モニタで確認します。

USBの映像データの確認

v4l2コマンドでUSBカメラからの情報を確認します。私が確認した場合のログは以下の通りです。解像度は320x240でフォーマットはYUYVです。

ubuntu@kria:~$ v4l2-ctl --all
...
Format Video Capture:
        Width/Height      : 320/240
        Pixel Format      : 'YUYV' (YUYV 4:2:2)
...

以下の説明は、入力映像の解像度が320x240の場合についてです。

AI超解像の映像の確認

USBカメラ映像をOpenCVで受信し、ウィンドウ表示するプログラムは、以下に添付します。sample/sr/sr_evalmodel/4dtcのフォルダに入れてください。

入力解像度は320x240です。AI超解像により、出力解像度は640x480になります。サンプル画像(160x120)より入力解像度が大きいため、一部のパラメータを変更する必要があります。
4dtc.hのP_AI_LINE_BUFを512から1024へ変更してください。

//変更前
#define P_AI_LINE_BUF 512

//変更後
#define P_AI_LINE_BUF 1024

以下のコマンドでopencvをダウンロードしてください。

sudo apt update
sudo apt install libopencv-dev

以下のコマンドでコンパイルすることができます。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sh make_sr_cam.sh

実行時のログは、以下の通りです。Warningがでますが、特に問題ありません。処理速度は26~27fpsぐらいです。

ubuntu@kria:~/AIRTIPS/sample/sr/sr_evalmodel/4dtc$ sudo ./sr_cam
[ WARN:0] global ./modules/videoio/src/cap_gstreamer.cpp (1100) open OpenCV | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1
bo0.size()   :0xc000000
bo0.address():0x38c00000
bo0.map()    :0xffff54000000
O.K.
AI     FFFF6EBB0000
       A1000000
AI RAM FFFF54000000
       38C00000
diff:0.036914sec, 27.089993frame/sec
diff:0.037524sec, 26.649611frame/sec
diff:0.037438sec, 26.710829frame/sec
...

4DTCでAI超解像を動作させる方法の説明は、以上です。

参考文献

最後まで読んでいただき、ありがとうございました。

いいなと思ったら応援しよう!

コメント

コメントするには、 ログイン または 会員登録 をお願いします。
AI高位合成ツール「AIRTIPS」で生成した独自AIアクセラレータ(4DTC)をKV260で動かす方法~AIRTIPS実践編②~|sharp_engineer
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1