チュートリアル:AI FPGA モジュールへのネットワークのポーティング - DigitalMediaProfessionals/dv-sdk GitHub Wiki

本チュートリアルは弊社のこちらのリポジトリを使います。以下の手順でダウンロードできます。

$ git clone https://github.com/DigitalMediaProfessionals/dv-tutorial

本チュートリアルではこちらのリポジトリのネットワーク定義ファイルmobilenet_deploy.prototxt と重みファイルmobilenet.caffemodel を使って、Caffeの ネットワークをAI FPGA モジュール上に移植する方法を見ていきます。 ネットワークをアプリケーションから使う際の注意点などもみていきます。 実際に手を動かしてみて実感してみてください。

なお、始める前にクイックスタート でAI FPGA モジュールを用意してください。 これ以降ではPC とAI FPGA モジュールの両方で、SDK が~/dv-sdk/ にインストールされているとして説明します。 また、特筆がなければ~/dv-tutorial/ にいるとします。

ネットワークをエクスポートする

ご自身のネットワークをエクスポートしてください。 エクスポート方法についてはこちらをご覧ください。 ここでは代わりにmobilenet_deploy.prototxtmobilenet.caffemodel を使います。

ネットワークを変換する

ネットワークを変換するにはネットワーク変換ツール を使います。 AI FPGA モジュール上の計算資源は限られているので、サーバーやPC 上で変換を推奨しています。 変換ツールのための環境設定についてはこちら をご覧ください。

まずは元のネットワークのファイルを用意します。 mobilenet_deploy.prototxtmobilenet.caffemodel~/dv-tutorial/ の下においてください。

ネットワーク変換ツールにはネットワークを定義したファイルのほかに、ツールの設定ファイルが必要です。 次のようにツールの設定ファイルtool.ini を作成してください。 (tool.ini での設定は最小限の設定です。さらなる機能を使いたい場合はネットワーク変換ツールへの入力ファイル をご覧ください。)

; tool.ini
; This file is configuration for network convertor

[INPUT]
name = CaffeModileNet                     ; 
origin = CAFFE                            ; original deep learning framework
definition = mobilenet_deploy.prototxt    ; network definition file
data = mobilenet.caffemodel               ; network weight file

[OUTPUT]
output_folder = ./     ; Output folder is under a directory where this .ini file exists
generate_source = 1

設定ファイルを作成したのち、次のコマンドによりネットワークを変換してください。

$ python3 ~/dv-sdk/tool/convertor.py tool.ini

こうして、ネットワークのソースコードCaffeModileNet_gen.cppCaffeModileNet_gen.h と、ネットワークの重みファイルCaffeModileNet_weights.binCaffeModileNet 以下に生成されます。 現在のディレクトリ構成は次のようになっているはずです。 なお、生成されたファイルの先頭にはtool.ininame で指定した文字列が付与されます。

$ tree
.
|-- CaffeModileNet                    # generated directory
|   |-- CaffeModileNet_gen.cpp        # source code of the network
|   |-- CaffeModileNet_gen.h          # source code of the network
|   |-- CaffeModileNet_weights.bin    # weight file of the network
|-- mobilenet.caffemodel
|-- mobilenet_deploy.prototxt 
|-- tool.ini

アプリケーションコードを書く

次にネットワークを利用したアプリケーションを作成します。 ここでは簡便のために作成済みのサンプルコードを参考に、ネットワークの利用方法を説明します。 サンプルプログラムは、コマンドライン引数で指定された画像ファイルの物体クラスを出力する簡単なプログラムです。 サンプルコード をご覧になりながら以降をお読みください。 またここで、チュートリアルのリポジトリ のファイルを~/dv-tutorial/ の下に置いてください。

全体の流れ

サンプルコードの流れは次の通りです。

  1. ネットワークを初期化する
  2. 指定された画像ファイルごとに次の操作をする
    1. 画像を読み込み、前処理をする
    2. ネットワークに前処理済みのデータを渡し、ネットワークを実行する
    3. ネットワークの出力を取得し、結果を出力する

ネットワークの初期化

ネットワークの初期化はinit_net() 内で行われています。 ここではネットワークオブジェクトの初期化・重みの読み込み・ネットワークのコミットをしています。 またこの時点でネットワークへの入力となるメモリ領域のアドレスを取得しています。

int init_net(CCaffeMobileNet &net, void **input_addr)
{
	if(!net.Initialize()){
		cerr << "fail to initialize network" << endl;
		return -1;
	}
	if(!net.LoadWeights("CaffeMobileNet/CaffeMobileNet_weights.bin")){
		cerr << "fail to load weight" << endl;
		return -1;
	}
	if(!net.Commit()){
		cerr << "fail to commit network" << endl;
		return -1;
	}
	*input_addr = net.get_network_input_addr_cpu();
	return 0;
}

画像の読み込みと前処理

画像の読み込みと前処理はread_and_preprocess_image() で行っています。 画像の前処理について次のことを注意してください。

  • 入力画像を転置(縦と横の入れ替え)してください。理由についてはこちら をご覧ください。
  • ネットワークの入力データはFP16 型なので、FP16 型へと変換してください。
  • ネットワークに合わせて適切に画像を正規化してください。
// 前処理
void preproc_image(const uint8_t *src, __fp16 *dst, size_t width, size_t height)
{
	for(size_t c = 0; c < width; c++){
		for(size_t r = 0; r < height; r++){
			dst[(c * height + r) * 3 + 0] = (__fp16)(src[(r * width + c) * 3 + 0] - 128);
			dst[(c * height + r) * 3 + 1] = (__fp16)(src[(r * width + c) * 3 + 1] - 128);
			dst[(c * height + r) * 3 + 2] = (__fp16)(src[(r * width + c) * 3 + 2] - 128);
		}
	}
}

ネットワークの実行

ネットワークを実行するにはRunNetwork() を呼びます。 ネットワークに入力データを渡すには、初期化の際に取得した入力データ用の領域に入力データをmemcpy() などで書き込みます。

                // input image and run network
		memcpy(net_input_addr, input_buf, width * height * 6);
		if(!net.RunNetwork()){
			cerr << "fail to run network" << endl;
			ret = -1;
			goto fin_loop;
                }

ネットワークの出力を取得する

get_final_output() によりネットワークの出力を取得してください。 最後に出力を適宜加工してアプリケーションにご利用ください。

		// get and output result
		net.get_final_output(output);
         cout << img_path << "," << categories[argmax(output)] << endl

アプリケーションをビルドして実行する

ついにアプリケーションをビルドして実行します。

まずビルドに必要なファイルを用意します。 ネットワーク変換ツールで生成されたソースコードが依存しているファイルをsrc/ 以下に置いてください。 またmain.cpp が依存しているファイルもsrc/ 以下に置いてください。

$ # copy files the network source depends on 
$ cp ~/dv-sdk/application/common/src/dmp_network.cpp \
  ~/dv-sdk/application/common/include/dmp_network.h \
  ~/dv-sdk/application/common/include/stats.h \
  ~/dv-tutorial/src/
$ # copy file main.cpp depends on
$ cp ~/dv-sdk/application/CaffeMobileNet/imagenet_1000_categories.h ~/dv-tutorial/src/

次に~/dv-tutorial/ をAI FPGA モジュール上に移して、AI FPGA モジュール上でmake -j4 によりアプリケーションをビルドしてmain 実行ファイルを作成してください。

$ # on AI FPGA module
$ make -j4

あとはAI FPGA モジュール上でこのプログラムをsudo bash run.sh により実行してください。run.sh~/dv-sdk/application/ で使われる画像ファイルのクラスを推論します。次のような出力が出れば成功です。

$ # on AI FPGA module
$ sudo bash run.sh
/home/ubuntu/dv-sdk/application/bin/images/img01.jpg , notebook, notebook computer
/home/ubuntu/dv-sdk/application/bin/images/img02.jpg , cup
/home/ubuntu/dv-sdk/application/bin/images/img03.jpg , airliner
/home/ubuntu/dv-sdk/application/bin/images/img04.jpg , Granny Smith
/home/ubuntu/dv-sdk/application/bin/images/img05.jpg , bald eagle, American eagle, Haliaeetus leucocephalus
/home/ubuntu/dv-sdk/application/bin/images/img06.jpg , coil, spiral, volute, whorl, helix
/home/ubuntu/dv-sdk/application/bin/images/img07.jpg , baseball
/home/ubuntu/dv-sdk/application/bin/images/img08.jpg , baseball
/home/ubuntu/dv-sdk/application/bin/images/img09.jpg , basketball
/home/ubuntu/dv-sdk/application/bin/images/img10.jpg , folding chair
...