はじめに
先日 書いたWindows向けTensorflow liteのビルドではMinGW向けでVisualStudioを用いたアプリ開発ができませんでした
Makefile(CMake)をゴリゴリ駆使して開発しても良かったのですがデバッグ効率が悪いことからVisualStudio向けのビルドに挑戦し、うまくいったのでまとめておきます
この記事のモチベーション
- Bazelを用いてTensorflow liteのビルドを行いたい
- 手軽にmasterを追いかける環境を用意しておきたい
ビルド環境
- Windows10
- Bazel1.2.1
- ./configure.pyで求められるバージョンを使用
- MSYS2 + VisualStudio2017(version15.9.19)
- 古いVisula Studio2017ではリンカの問題があるとのことで必ず新しいものを使用
- https://github.com/bazelbuild/bazel/issues/3949
- Python3.6
- tensorflow master: f285ba1aab3223279131db7168f23884fa79812c
- origin/r2.xブランチにはまだtensorflowliteのビルドルールが無いためmasterを使います
ビルド手順
$ cd tensorflow
$ python ./configure.py #全部Noにすれば最小限
$ VSPATH="$(cygpath -u "$(reg query 'HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7' -v 15.0 | tail -n+3 | head -n1 | awk '{for (i=3;i<=NF;i++) {printf "%s ",$i;};}' | sed 's/ *$//')")"
$ export BAZEL_VS="$VSPATH" #VS2017を使用
$ bazel build -c opt --cxxopt=--std=c++11 tensorflow/lite:tensorflowlite
※BAZEL_VSを解決するためにこちらを参考にしています
※ビルドが成功すると tensorflow\bazel-out\x64_windows-opt\bin
以下にバイナリがあります
ビルドしたライブラリの利用
注意: tensorflowlite.dllのビルドに成功したと思っていたのですが、実はdllはすっからかんで.libの方を使用することになります
tensorflow/lite/examples/minimal/minimal.cc
を元に最小限コードをコンパイル&実行してみます
includeパスに
tensorflow
tensorflow\bazel-tensorflow\external\com_google_absl
tensorflow\bazel-tensorflow\external\flatbuffers\include
を追加、libraryパスに
tensorflow\bazel-out\x64_windows-opt\bin\tensorflow\lite
tensorflow\bazel-out\x64_windows-opt\bin\external
を追加しておきます。
※mobilenet_v1_1.0_224.tfliteは任意の.tfliteファイルに置き換え可能です
Minimal.cpp
#include <iostream>
#pragma comment(lib, "c\\common.lo.lib")
#pragma comment(lib, "core\\api\\api.lib")
#pragma comment(lib, "delegates\\nnapi\\nnapi_delegate.lib")
#pragma comment(lib, "kernels\\builtin_op_kernels.lo.lib")
#pragma comment(lib, "kernels\\builtin_ops.lo.lib")
#pragma comment(lib, "kernels\\cpu_backend_context.lib")
#pragma comment(lib, "kernels\\cpu_backend_gemm.lib")
#pragma comment(lib, "kernels\\eigen_support.lib")
#pragma comment(lib, "kernels\\kernel_util.lib")
#pragma comment(lib, "kernels\\lstm_eval.lib")
#pragma comment(lib, "kernels\\internal\\audio_utils.lib")
#pragma comment(lib, "kernels\\internal\\kernel_utils.lib")
#pragma comment(lib, "kernels\\internal\\neon_tensor_utils.lib")
#pragma comment(lib, "kernels\\internal\\portable_tensor_utils.lib")
#pragma comment(lib, "kernels\\internal\\quantization_util.lib")
#pragma comment(lib, "kernels\\internal\\sse_tensor_utils.lib")
#pragma comment(lib, "kernels\\internal\\tensor_utils.lib")
#pragma comment(lib, "kernels\\internal\\transpose_utils.lib")
#pragma comment(lib, "experimental\\ruy\\allocator.lib")
#pragma comment(lib, "experimental\\ruy\\block_map.lib")
#pragma comment(lib, "experimental\\ruy\\blocking_counter.lib")
#pragma comment(lib, "experimental\\ruy\\context.lib")
#pragma comment(lib, "experimental\\ruy\\detect_arm.lib")
#pragma comment(lib, "experimental\\ruy\\detect_x86.lib")
#pragma comment(lib, "experimental\\ruy\\have_built_path_for_avx2.lib")
#pragma comment(lib, "experimental\\ruy\\have_built_path_for_avx512.lib")
#pragma comment(lib, "experimental\\ruy\\have_built_path_for_avxvnni.lib")
#pragma comment(lib, "experimental\\ruy\\have_built_path_for_sse42.lib")
#pragma comment(lib, "experimental\\ruy\\kernel_arm.lib")
#pragma comment(lib, "experimental\\ruy\\kernel_avx2.lib")
#pragma comment(lib, "experimental\\ruy\\kernel_avx512.lib")
#pragma comment(lib, "experimental\\ruy\\kernel_avxvnni.lib")
#pragma comment(lib, "experimental\\ruy\\kernel_sse42.lib")
#pragma comment(lib, "experimental\\ruy\\pack_arm.lib")
#pragma comment(lib, "experimental\\ruy\\pack_avx2.lib")
#pragma comment(lib, "experimental\\ruy\\pack_avx512.lib")
#pragma comment(lib, "experimental\\ruy\\pack_avxvnni.lib")
#pragma comment(lib, "experimental\\ruy\\pack_sse42.lib")
#pragma comment(lib, "experimental\\ruy\\prepacked_cache.lib")
#pragma comment(lib, "experimental\\ruy\\thread_pool.lib")
#pragma comment(lib, "experimental\\ruy\\trace.lib")
#pragma comment(lib, "experimental\\ruy\\trmul.lib")
#pragma comment(lib, "experimental\\ruy\\tune.lib")
#pragma comment(lib, "experimental\\ruy\\wait.lib")
#pragma comment(lib, "tools\\optimize\\sparsity\\format_converter.lib")
#pragma comment(lib, "farmhash_archive\\farmhash.lib")
#pragma comment(lib, "flatbuffers\\src\\flatbuffers.lib")
#pragma comment(lib, "flatbuffers\\src\\flatc.lib")
#pragma comment(lib, "fft2d\\fft2d.lib")
#pragma comment(lib, "allocation.lib")
#pragma comment(lib, "arena_planner.lib")
#pragma comment(lib, "external_cpu_backend_context.lib")
#pragma comment(lib, "framework.lo.lib")
#pragma comment(lib, "minimal_logging.lib")
#pragma comment(lib, "simple_memory_arena.lib")
#pragma comment(lib, "string_util.lib")
#pragma comment(lib, "tensorflowlite.dll.if.lib") # たぶん不要
#pragma comment(lib, "util.lib")
#include <cstdio>
#include <tensorflow/lite/interpreter.h>
#include <tensorflow/lite/kernels/register.h>
#include <tensorflow/lite/model.h>
#include <tensorflow/lite/optional_debug_tools.h>
int main()
{
auto model = tflite::FlatBufferModel::BuildFromFile("mobilenet_v1_1.0_224.tflite");
// Build the interpreter
tflite::ops::builtin::BuiltinOpResolver resolver;
tflite::InterpreterBuilder builder(*model, resolver);
std::unique_ptr<tflite::Interpreter> interpreter;
builder(&interpreter);
// Allocate tensor buffers.
printf("=== Pre-invoke Interpreter State ===\n");
tflite::PrintInterpreterState(interpreter.get());
// Run inference
printf("\n\n=== Post-invoke Interpreter State ===\n");
tflite::PrintInterpreterState(interpreter.get());
}
こんな感じの実行結果が出れば成功です
output.txt
=== Pre-invoke Interpreter State ===
Interpreter has 88 tensors and 31 nodes
Inputs: 87
Outputs: 86
Tensor 0 MobilenetV1/Conv2d_0/weights kTfLiteFloat32 kTfLiteMmapRo 3456 bytes ( 0.0 MB) 32 3 3 3
Tensor 1 MobilenetV1/Conv2d_10_depthwise/depthwise_weights kTfLiteFloat32 kTfLiteMmapRo 18432 bytes ( 0.0 MB) 1 3 3 512
Tensor 2 MobilenetV1/Conv2d_10_pointwise/weights kTfLiteFloat32 kTfLiteMmapRo 1048576 bytes ( 1.0 MB) 512 1 1 512
Tensor 3 MobilenetV1/Conv2d_11_depthwise/depthwise_weights kTfLiteFloat32 kTfLiteMmapRo 18432 bytes ( 0.0 MB) 1 3 3 512
・・・
Inputs: 49
Outputs: 27
Node 28 Operator Builtin Code 3 CONV_2D
Inputs: 27 30 29
Outputs: 28
Node 29 Operator Builtin Code 43 SQUEEZE
Inputs: 28
Outputs: 31
Node 30 Operator Builtin Code 25 SOFTMAX
Inputs: 31
Outputs: 86