Windows向けtensorflowliteのビルド(for Visual Studio 2017)

# はじめに

[先日](https://qiita.com/na0ki_ikeda/items/7b1436ff87751b30622b) 書いた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を解決するために[こちら](https://blog.vucica.net/2020/01/detecting-location-of-visual-studio-2017-and-2019.html)を参考にしています
※ビルドが成功すると ```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ファイルに置き換え可能です

```C++: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());
}
```

こんな感じの実行結果が出れば成功です

```txt: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

```