LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

ncnn(2) 変換ツールのビルドと、Keras->ONNX->NCNNへのモデル形式変換

Posted at

この記事について

前回は、既に用意したncnn用モデル(.param, .bin) を使用しました。
今回はこのncnn用モデルを作ります。

ncnnの方で有名どころのフレームワークからの変換ツールは用意してくれています。ただし、ソースコード形式なのでまずはビルドをします。
その後、Keras -> ONNX -> ncnn と変換してみます。

変換ツールは https://github.com/Tencent/ncnn/tree/master/tools

  • 今の時点で用意されているのは以下:
    • caffe
    • mxnet
    • onnx
    • tensorflow (2日前(2019/05/03)に消えてた。開発者さんが諦めた模様)
  • 以下のフレームワークは、有志の作っているツールを使うか一度ONNX形式に変換する方法が提示されている
    • pytorch
    • darknet

ビルド済みツールバイナリ

ビルドするのが面倒な方は以下をご利用ください。
https://github.com/take-iwiw/NcnnMultiPlatformProject/tree/master/ExternalLibs/ncnn_prebuilt/tools

ncnnモデル変換ツールのビルド

ソースコードの取得

変換ツールをビルドするためにはprotobufが必要なので、まずはそちらのビルド、(場合によってはインストール)を行います。
変換ツールのソースコードは前回取得済みのncnnリポジトリ内にあるのですが、一応再取得するところからやります。
以下、Windows, Linux共通のソース取得とバージョン指定(2019/05/05現在で最新のリリースバージョン)です。

ソースコード取得
cd ~/   # Windowsの場合は適当なところで実施。以後の説明では'C:\work\protobuf'とする
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git checkout  v3.7.1

cd ~/   # Windowsの場合は適当なところで実施。以後の説明では'C:\work\ncnn'とする
git clone https://github.com/Tencent/ncnn.git
cd ncnn
git checkout 20190320

Windows

Protobufのビルド

cmake-guiを起動し、以下のように設定します。(パスはどこでもいいです)(設定項目を出すために、パス設定後に一度Configureをクリックしてください。その時のワーニングは無視して大丈夫です)

  • Where is the source code: : C:/work/protobuf/cmake
  • Where to build the binaries: : C:/work/build_protobuf
  • CMAKE_INSTALL_PREFIX: : ./install
  • protobuf_BUILD_TEST: : チェックを外す

その後、Configure, Generateします。

生成されたprotobuf.slnをVisual Studioで開き、ALL_BUILD->右クリック->ビルド、と、INSTALL->右クリック->ビルド をします。念のためReleaseとDebugの両方でやります。

C:\work\build_protobuf\install に必要なファイルが生成されました。

image.png

ncnnモデル変換ツールのビルド

cmake-guiを起動し、以下のように設定します。(パスはどこでもいいです)(設定項目を出すために、パス設定後に一度Configureをクリックしてください。その時のワーニングは無視して大丈夫です)

Protobuf用の設定をするために、cmake-gui上のAdvancedをチェックしてください。

  • Where is the source code: : C:/work/ncnn
  • Where to build the binaries: : C:/work/build_ncnn
  • Protobuf_LITE_LIBRARY_DEBUG: : C:/work/build_protobuf/install/lib/libprotobuf-lited.lib
  • Protobuf_INCLUDE_DIR: : C:\work\build_protobuf\install\include
  • Protobuf_LITE_LIBRARY_RELEASE: : C:/work/build_protobuf/install/lib/libprotobuf-lite.lib
  • Protobuf_LIBRARY_RELEASE: : C:\work\build_protobuf\install\lib\libprotobuf.lib
  • Protobuf_PROTOC_EXECUTABLE: : C:/work/build_protobuf/install/bin/protoc.exe
  • Protobuf_PROTOC_LIBRARY_DEBUG: : C:/work/build_protobuf/install/lib/libprotocd.lib
  • Protobuf_PROTOC_LIBRARY_RELEASE: : C:/work/build_protobuf/install/lib/libprotoc.lib
  • Protobuf_LIBRARY_DEBUG: : C:\work\build_protobuf\install\lib\libprotobufd.lib

その後、Configure, Generateします。

生成されたncnn.slnをVisual Studioで開き、caffe2ncnnmxnet2ncnnonnx2ncnnncnn2memで右クリック->ビルドします。バイナリ実行形式でツールとして確保しておきたい場合は、Releaseビルドで良いと思います。

onnx2ncnnのビルドで、LNK2038エラー(RuntimeLibraryの不一致)が発生するかもしれません。その時は、onnx2ncnn->右クリック->C/C++->コード生成->ランタイムライブラリの設定を/MT(Releaseの場合)、/MTd(Debugの場合)に変更してください。

build_ncnn\tools 下にそれぞれフォルダが作られて、バイナリが生成されます。

image.png

Debugバージョンは必要?

「ツール」なのだからReleaseバージョンだけで良いと思っていたのですが、結構デバッグします。変換がうまくいかないときなど、何が悪いのかを探す必要が出てきます。

とりあえずReleaseビルドしたバイナリツール群をどこかにまとめて、普段はそっちを使えばいいと思います。デバッグが出来るVSプロジェクトも用意しておいて、いざというときにデバッグ出来ればいいと思います。

Linux

続いて、Linux(Ubuntu)でのビルド方法です。
上述のコード取得とバージョン指定が完了しているものとします。
Protobufは/usr/libにインストールしてしまいました。そのためncnnビルド時のprotobufディレクトリの指定は不要です。(最初cmake時に指定する方法でやろうとしたが、うまくいかなかった)
なお、VirtualBoxの場合だと、Windowsとの共有フォルダで作業するとうまくいかないかもしれません。

Protobufのビルド
cd ~/protobuf
mkdir build && cd build
cmake ../cmake -Dprotobuf_BUILD_TESTS=OFF
make -j2
sudo make install
sudo ldconfig
ncnnモデル変換ツールのビルド
cd ~/ncnn
mkdir build && cd build
cmake ..  -DCMAKE_BUILD_TYPE=Release
make -j2
ls tools

生成物

  • onnx2ncnn.exe : ONNX形式モデル(.onnx)をNCNN形式モデル(.param, .bin)に変換する
  • caffe2ncnn.exe : Caffe形式モデルをNCNN形式モデル(.param, .bin)に変換する
  • mxnet2ncnn.exe : MXNet形式モデルをNCNN形式モデル(.param, .bin)に変換する
  • tensorflow2ncnn.exe : TensorFlow形式モデル(.pb)をNCNN形式モデル(.param, .bin)に変換する
  • ncnn2mem.exe : NCNN形式モデル(.param, .bin)をC言語の配列形式に変換する(コード埋め込み用)

使い方はいずれも、ツールの引数に変換元のモデル名を設定するだけです。
例: onnx2ncnn.exe mobilenetv2.onnx

Keras->ONNX->NCNNへの変換

ONNXの理想に基づけば、ONNX->NCNNへの変換が出来ればどのようなフレームワークのモデルもNCNN形式へ変換が可能となります。そのため、ONNX->NCNNへの変換をやります。
ただし、元になるONNXモデルが必要なので、まずはKeras->ONNXへの変換をします。
(ちなみに、Keras2NCNN というツールも存在はしましたが、あまり開発はされていないようです。)

以後、Keras形式のMobilenetモデルを変換していきます。

変換する

keras2onnx.convert_keras や、nnxmltools.convert_keras 、一度Tensorflow形式にしてからのtf2onnx.convert など色々試しましたが、MMdnn を使うのが一番うまくいきました。
これ以外の方法だと変換自体は出来ても、余計なレイヤが残ってしまい、onnx2ncnnするときに「xxx not supported yet!」エラーが出まくります。

Keras->ONNX->NCNNへの変換
pip install mmdnn   # mmdnnインストール
mmdownload -f keras -n mobilenet    # Keras形式のMobilenet取得
mmconvert -sf keras -iw imagenet_mobilenet.h5 -df onnx -om imagenet_mobilenet.onnx  # Keras -> ONNX
onnx2ncnn.exe imagenet_mobilenet.onnx   # ONNX -> NCNN
# ncnn.bin と ncnn.paramが出来るので適当にRenameする

備考

  • ncnnのwikiにはpython -m onnxsim 元モデル.onnx スリム化モデル.onnx でstrip的なことをした方が良いと書いてましたが、MMdnnの場合には不要でした
    • onnx.utils.polish_modelonnx.optimizer.optimizer もなくて大丈夫でした。
  • Mobilenetだと問題なく変換できましたが、MobilenetV2やVGG16など、Dense層(Gemm)があるモデルはonnx2ncnnでうまく変換できませんでした(エラーは出ないが、.paramファイルで一部情報が欠ける)。
  • MMdnnで変換する場合には、元モデルはfrom tensorflow.python.keras.xxx で生成したものは使えませんでした。変換時にValueError: Unknown initializer: GlorotUniform エラーが出ました。from keras.xxx を使う必要があります。

変換したモデルを使う

ダウンロードしたimagenet_mobilenet.h5のmodel.summary()
>>> model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         (None, 224, 224, 3)       0
_________________________________________________________________
conv1_pad (ZeroPadding2D)    (None, 225, 225, 3)       0
_________________________________________________________________
conv1 (Conv2D)               (None, 112, 112, 32)      864
_________________________________________________________________
~略~
dropout (Dropout)            (None, 1, 1, 1024)        0
_________________________________________________________________
conv_preds (Conv2D)          (None, 1, 1, 1000)        1025000
_________________________________________________________________
act_softmax (Activation)     (None, 1, 1, 1000)        0
_________________________________________________________________
reshape_2 (Reshape)          (None, 1000)              0
=================================================================
ncnn.param
7767517
95 95
Input            input_1_orig             0 1 input_1_orig
Permute          input_1                  1 1 input_1_orig input_1 0=4
Padding          conv1_pad                1 1 input_1 conv1_pad 0=0 1=0 2=0 3=0 4=0 5=0.000000
Convolution      conv1                    1 1 conv1_pad conv1 0=32 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=0 6=864
BatchNorm        conv1_bn                 1 1 conv1 conv1_bn 0=32
~ 略 ~
Flatten          global_average_pooling2d_1_flatten 1 1 global_average_pooling2d_1 global_average_pooling2d_1_flatten
Reshape          reshape_1                1 1 global_average_pooling2d_1_flatten reshape_1 0=1 1=1 2=1024
Dropout          dropout                  1 1 reshape_1 dropout
Convolution      conv_preds               1 1 dropout conv_preds 0=1000 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=1024000
Softmax          act_softmax              1 1 conv_preds act_softmax 0=0 1=1
Reshape          reshape_2                1 1 act_softmax reshape_2 0=1000

ncnn.paramから、入出力名を探します。Keras形式のmodel.summary()の名前とほとんど一致しています。
出力はreshape_2 だと分かります。
入力はinput_1_orig ではなく、input_1 でした。input_1_orig が何なのかは謎。ONNXに変換した時点で付いているっぽい。

前回のプロジェクト(https://github.com/take-iwiw/NcnnMultiPlatformProject/tree/master/NcnnSimpleProject )にモデルと入出力名を差し替えるだけで動きます。今回もちゃんとオウムを識別してくれました。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up