Python ラッパーの利用 - DigitalMediaProfessionals/dv-sdk GitHub Wiki

この節ではネットワークのPython ラッパの使い方を、MobileNet を例にして説明します。

この例では、ネットワーク変換ツールに与えられた.ini ファイルで python_module == gnet_wrap と指定されているとします。

必要なもの

  • Boost.Python(libboost-python-dev), Boost.Numpy(libboost-numpy-dev)
  • libpython3.6-dev (お使いのPython のバージョンに合わせてご変更ください)
  • jinja2

ビルド方法

ネットワークのPython ラッパーモジュールを作成するには次のステップに従ってください。 (なお、サンプルコードはAI FPGA モジュール上で実行されるものとします。)

  1. python_module オプションを指定して、DMP ツールからPython ラッパーのC++ ソースコードを生成してください。
  2. 位置独立コード(PIC)のオプション(gcc であれば -fPIC)とともに、ネットワークのソースコードをコンパイルしてください。コンパイル方法についてはアプリケーションのビルドをご覧ください。
  3. Python ラッパーのソースコードをPIC オプションとともにコンパイルしてください。そのソースコードではPython ライブラリを用いているので、Python のインクルードディレクトリを適切にコンパイラに渡してください。
# AI FPGA モジュール上にて
$ g++ -std=c++11 -O3 -fPIC -c -I/usr/include/python3.6 -o gnet_wrap.o gnet_wrap.cpp
  1. コンパイルしてできたオブジェクトファイルを-ldmpdv -lboost_python3 -lboost_numpy3 オプションとともにリンクして、Python ラッパーとなる動的共有ライブラリを作成してください。 そのファイル名はgnet_wrap.so でなくてはなりません。 ほかのネットワークについては、gnet_wrap の部分をDMP ツール使用時に python_module で指定した名前に置き換えてください。
# AI FPGA モジュール上にて
$ g++ -std=c++11 -shared -fPIC gnet_wrap.o CaffeMobileNet_gen.o dmp_network.o -o gnet_wrap.so -L/path/to/dv-user-driver -ldmpdv -lboost_python3 -lboost_numpy3

この共有ライブラリがPython モジュールとして扱われます。

シンプルサンプル

ここでは作成したPython モジュールを用いてネットワークの利用方法を、サンプルコードを用いて紹介します。 なお簡便のためエラーチェックはしません。

注: Python は作成した共有ライブラリを、通常のPython モジュールのように名前を指定してimport できます。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2
import numpy as np

import gnet_wrap as gnw


net = gnw.create()
try:
	# initialize
	gnw.initialize(net)
	gnw.load_weights(net, "path/to/network_weight.bin/")
	gnw.commit(net)

	# get image
	img = cv2.imread("path/to/image_file")
	## Manipulate image according to network rule
	...
	## Be sure to call np.ascontiguousarray() before put_input()
	img = np.ascontiguousarray(img)

	# run network
	gnw.put_input(net, img)
	gnw.run_network(net)
	output = gnw.get_final_output(net)

	# after processing	
	...

finally:
	gnw.destroy(net)

API リファレンス

ここではgnet_wrap Python モジュールのAPI を紹介します。 これらのAPI はほかのネットワークにおいても同様です。

create()

def create() -> int:

対象のネットワークのオブジェクトを作成します。

返値はそのオブジェクトのID 番号です。

destroy()

def destroy(id: int) -> None:

ネットワークオブジェクトを破棄します。

  • id ネットワークオブジェクトのID 番号です。

initialize()

def initialize(id: int) -> bool:

ネットワークオブジェクトを初期化します。

  • id ネットワークオブジェクトのID 番号です。

関数の成功時にはTrue が、そうでなければFalse が返されます。

load_weights()

def load_weights(id: int, weight_file: str) -> bool:

ネットワークの重みを読み込みます。

  • id ネットワークオブジェクトのID 番号です。
  • weight_file 重みファイルへのパスです。

関数の成功時にはTrue が、そうでなければFalse が返されます。

commit()

def commit(id: int) -> bool:

ネットワークオブジェクトをコミットします。

  • id ネットワークオブジェクトのID 番号です。

関数の成功時にはTrue が、そうでなければFalse が返されます。

run_network()

def run_network(id: int) -> bool:

ネットワークを実行します。

  • id ネットワークオブジェクトのID 番号です。

関数の成功時にはTrue が、そうでなければFalse が返されます。

put_input()

def put_input(id: int, input: numpy.ndarray) -> None:

ネットワークに入力を与えます。

  • id ID number of a network object

  • input Input to the network. input.dtype must be numpy.float16. Please be sure to call np.ascontiguousarray(input) just before calling this function.

  • id ネットワークオブジェクトのID 番号です。

  • input ネットワークへの入力です。input.dtypenumpy.float16 でなくてはなりません。 またこの関数の前にnp.ascontiguousarray(input) を必ず呼び出してください。

get_final_output()

def put_input(id: int, index: int) -> numpy.ndarray:
  • id ネットワークオブジェクトのID 番号です。
  • index ネットワークのオブジェクトのインデックスです。

ネットワークの出力を返します。

get_conv_usec()

def get_conv_usec(id: int) -> int:
  • id ネットワークオブジェクトのID 番号です。

最後に畳み込み層の実行にかけた時間をマイクロ秒単位で返します。

get_fc_usec()

def get_fc_usec(id: int) -> int:
  • id ネットワークオブジェクトのID 番号です。

最後に全結合層の実行にかけた時間をマイクロ秒単位で返します。

get_cpu_usec()

def get_cpu_usec(id: int) -> int:
  • id ネットワークオブジェクトのID 番号です。

最後にCPU 層の実行にかけた時間をマイクロ秒単位で返します。