Glow Compilerの環境を構築する(CPU Backend)

# この記事について
この記事では、[Facebook Glow Compiler](https://facebook.ai/developers/tools/glow)の環境導入について記載します。


# この記事の目標
- Glowのビルド環境をUbuntu(x86)上に構築します
- Glowをビルドします
- 提供されているサンプルを実行します

[公式ドキュメント](https://github.com/pytorch/glow)を参考にして進めていきます。

Ubuntu 16.04、g++ 5.4.0、python 2.7.12の環境で構築します。

# Glowについて

Glow CompilerはNNVM(Relay)/TVM等と同様に、Deep learningの推論用コンパイラの一つで、Facebookによりサポートされています。Glowの詳細については[ホワイトペーパー](https://arxiv.org/pdf/1805.00907.pdf)が公開されています。また、[2018年9月の記事](https://venturebeat.com/2018/09/13/intel-marvell-qualcomm-and-others-will-support-facebooks-glow-compiler/)でCadence、Esperanto、Intel、Marvell、Qualcomm等が将来的なサポートを表明するなどビジネス的な活動も行われている推論コンパイラとなっています。

- Deep Learning推論用のコンパイラです
- CPU、OpenCL、Interpreterのバックエンドがサポートされています
    - [Backendsのソースコード](https://github.com/pytorch/glow/tree/master/lib/Backends)
- コンパイルによりhigh-levelとlower-levelの二段階の最適化が実施されます
    - [Optimizerのソースコード](https://github.com/pytorch/glow/tree/master/lib/Optimizer)
- ONNXとCaffe2のモデルのインポートに対応しています
- Facebookによって開発、メンテナンスされています

# Glowの導入

## 必要環境の準備

[公式ドキュメント](https://github.com/pytorch/glow)によると、Ubuntuでは以下の環境が必要とされています。一度実行します。

```bash
$sudo apt-get install graphviz clang cmake wget ninja-build llvm-5.0 \
    libprotobuf-dev protobuf-compiler libpng-dev
```

### LLVMの準備
公式ではLLVM-5.0となっていますが、ここではLLVM-7を導入します。初期状態のapt-getでは古いバージョンしか取得できないため、プリビルドモジュールの取得準備を行います。プリビルドモジュールの取得方法は[ここ](https://apt.llvm.org/)に記載されています。準備ができたらapt-getによりインストールします。

```bash
$sudo apt-get update
$sudo apt-get install llvm-7
```

### cmakeの準備

glowではcmake 3.7以上を要求されますが、初期状態で取得できるcmakeは3.5となっています。そのため、最新版のcmakeを[公式サイト](https://cmake.org/download/)より取得します。Linux x86_64に記載のあるcmake-3.XX.0-rc1-Linux-x86_64.shをダウンロードして、任意のディレクトリに展開します。


## Glowのビルド

Glowのソースを取得します。/path/to/workの直下にglowディレクトリが作成されます。

```bash
$cd /path/to/work
$git clone https://github.com/pytorch/glow.git
$cd glow
$git submodule update --init --recursive
```

CPU Backendのみのモードでビルドするため、CMakeLists.txtを編集し、OpenCLをOFFにします。

```cmake:/path/to/work/glow/CMakeLists.txt
...
option(GLOW_WITH_OPENCL "Build the OpenCL backend" OFF)
...
```

ビルドディレクトリを作成します。

```bash
$cd /path/to/work/glow
$mkdir build_Debug
$cd build_Debug
```

cmakeを実行します。/path/to/latest/cmakeに最新のcmakeをインストールしたと仮定しています。llvm-7は通常は/usr/lib/llvm-7にインストールされています。また、ここではビルドモードをDebugに指定していますが、リリース版を作成する際は、Releaseを指定します。

```bash
/path/to/latest/cmake -G Ninja ..\
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_PREFIX_PATH=/usr/lib/llvm-7
```

cmakeに成功すると、以下のような表示が出力されます。

```bash
-- ******** Summary ********
--   CMake version         : 3.12.1
--   CMake command         : /path/to/latest/cmake
--   System                : Linux
--   C++ compiler          : /usr/bin/c++
--   C++ compiler version  : 5.4.0
--   CXX flags             :  -Wall -Wnon-virtual-dtor -fno-exceptions -fno-rtti
--   Build type            : Debug
--   Compile definitions   : GLOW_WITH_CPU=1;GOOGLE_PROTOBUF_NO_RTTI;ONNX_NAMESPACE=glow_onnx
--   CMAKE_PREFIX_PATH     : /usr/lib/llvm-7
--   CMAKE_INSTALL_PREFIX  : /usr/local
--   CMAKE_MODULE_PATH     : /path/to/work/glow/cmake/modules
-- 
--   ONNX version          : 1.3.0
--   ONNX NAMESPACE        : glow_onnx
--   ONNX_BUILD_TESTS      : OFF
--   ONNX_BUILD_BENCHMARKS : OFF
--   ONNX_USE_LITE_PROTO   : OFF
--   ONNXIFI_DUMMY_BACKEND : OFF
-- 
--   Protobuf compiler     : /usr/bin/protoc
--   Protobuf includes     : /usr/include
--   Protobuf libraries    : /usr/lib/libprotobuf.so;-lpthread
--   BUILD_ONNX_PYTHON     : OFF
-- Found PythonInterp: /usr/bin/python (found version "2.7.12") 
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Configuring done
-- Generating done
-- Build files have been written to:/path/to/work/glow/build_Debug
```

完了したらビルドを実行します。

```
$cd /path/to/work/glow/build_Debug
$ninja all
```

## サンプルの実行

### Ahead-of-time Compilation

[Creating standalone executable bundles](https://github.com/pytorch/glow/blob/master/docs/AOT.md)にResNet50の推論をスタンドアロンで実行するサンプルの説明が記載されています。サンプルのディレクトリに移動します。

```bash
$cd /path/to/work/glow/example/bundles/resnet50
```

MakeFileにglowを導入したディレクトリ位置を指定する項目があるため修正します。

```makefile:/path/to/work/glow/example/bundles/resnet50/MakeFile
# The path to the image-classifier executable.
LOADER?=/path/to/work/glow/build_Debug/bin/image-classifier

# The root directory of the Glow repo.
GLOW_SRC?=~/path/to/work/glow
```

量子化に関する設定がありますので任意に変更します。[ドキュメント](https://github.com/pytorch/glow/blob/master/docs/Quantization.md)によると、Glowではprofile-guided quantizationによる量子化を採用しているということで、実行しながらレンジを算出しているようです。そのため、ONにするとプロファイリングのための時間がかかります。

```makefile:/path/to/work/glow/example/bundles/resnet50/MakeFile
# Should quantize the network (YES/NO)?
QUANTIZE?=YES
```

makeします

```
$make
```

成功すると、以下の内容が生成されます。

```
$ls build
resnet50
```


# 関連情報
- ドキュメント・ニュース
    - [公式HP](https://facebook.ai/developers/tools/glow)
    - [ホワイトペーパー](https://arxiv.org/pdf/1805.00907.pdf)
    - [Glow: A community-driven approach to AI infrastructure](https://code.fb.com/ml-applications/glow-a-community-driven-approach-to-ai-infrastructure/)
    - [2018 @Scale Conference recap](https://code.fb.com/android/2018-scale-conference-recap/)

- ソースコード (GitHub)
    - https://github.com/pytorch/glow