owned this note
owned this note
Published
Linked with GitHub
# How to Build MACE on Mac
###### tags: `mace` `deep learning` `framework`
* This guide is based on the official document, please refer to their latest document - [MACE](https://mace.readthedocs.io/en/latest/introduction.html).
* This guide is only for caffe to mace (no tensorflow).
## Environment
* This guide is based on the below environment
* Hardware :
* MacBook Pro (15-inch, 2017)
* Processor 2.8 GHz Intel Core i7
* Memory 16 GB 2133 MHz LPDDR3
* Startup Disk Macintosh HD
* Graphics Radeon Pro 555 2048 MB, Intel HD Graphics 630 1536 MB
* Software :
* OS High Sierra 10.13.4
* Python 3.6.4
* Homebrew 1.6.9
* Cmake 3.11.1
## Install Dependencies
### Required Dependencies
| Software | Installation Command | Tested Version |
|:--------:|:--------------------:|:--------------:|
| Python | | 2.7 |
| Bazel | [bazel install guide](https://docs.bazel.build/versions/master/install.html) | 0.13.0 |
| CMake | apt-get install cmake | 2.7 |
| Jinja2 | pip install -I jinja2==2.10 | 2.10 |
| PyYaml | pip install -I pyyaml==3.12 | 3.12.0 |
| sh | pip install -I sh==1.12.14 | 1.12.14 |
| Numpy | pip install -I numpy==1.14.0| Required by model validation |
### Optional Dependencies
| Software | Installation Command | Remark |
|:--------:|:--------------------:|:--------------:|
| Android NDK | [NDK installation guide](https://developer.android.com/ndk/guides/setup#install) | Required by Android build, r15b, r15c, r16b |
| ADB | apt-get install android-tools-adb | Required by Android run, >= 1.0.32 |
| TensorFlow | pip install -I tensorflow==1.6.0 | Required by TensorFlow model |
| Docker | [docker installation guide](https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository) | Required by docker mode for Caffe model |
| Scipy | pip install -I scipy==1.0.0 | Required by model validation |
| FileLock | pip install -I filelock==3.0.0 | Required by run on Android |
:::danger
**Note:**
* python 2.7 instead of python 3
* if python need enum package , do ```pip install Enum34```, Enum34 is the right package
* for android build, *ANDROID_NDK_HOME* must be configured by using
```export ANDROID_NDK_HOME=/path/to/ndk```
:::
## Build MACE from Source
* clone the git repository of MACE
```
> git clone https://github.com/XiaoMi/mace.git
> git fetch --all --tags --prune
```
* build MACE library
```
> cd path/to/mace
# Build library
# output lib path: builds/lib
> bash tools/build-standalone-lib.sh
```
* after building, it would generate a folder called 'builds'.
```
builds
├── include
│ └── mace
| └── public
| ├── mace.h
| └── mace_runtime.h
└── lib
├── arm64-v8a
│ ├── libmace.a
│ └── libmace.so
├── armeabi-v7a
│ ├── libhexagon_controller.so
│ ├── libmace.a
│ └── libmace.so
└── linux-x86-64
├── libmace.a
└── libmace.so
```
## Caffe to MACE
* If your caffe model is from old version caffe, you need to convert it into new Caffe format first. (see [How to Build Caffe on Mac](https://hackmd.io/8ljOZQVOQ3qVG1SJIERF3g?both))
* Create yaml file for your model
* example
```yaml=
library_name: model_0_48
target_abis: [armeabi-v7a,arm64-v8a]
embed_model_data: 0
model_graph_format: code
model_data_format: code
models:
model_0_48:
platform: caffe
model_file_path: ./models/model_0-48/model_0-48.prototxt
weight_file_path: ./models/model_0-48/model_0-48.caffemodel
model_sha256_checksum: 9d17635684a3d430d3e52c84f79fb73e8da62269472c08da24da29ba9965b56e
weight_sha256_checksum: 1df2f73bcc8d9ed8f7479ec244a6884aaf39dd8ecf4e07b02566bab2b9812326
subgraphs:
- input_tensors:
- data
output_tensors:
- prob
input_shapes:
- 1,480,480,3
output_shapes:
- 1,60,60,2
runtime: cpu+gpu
winograd: 0
```
* for each attribute, refer to [Deployment file](https://mace.readthedocs.io/en/latest/user_guide/advanced_usage.html#deployment-file)
:::info
runtime : build your library as cpu or gpu or cpu+gpu version.
:::
* sha256_checksum
* install sha256sum
```
> brew install coreutils
# Once it completes, simply link the binaries as follows so that macOS can see them.
> sudo ln -s /usr/local/bin/gsha256sum /usr/local/bin/sha256sum
> sudo ln -s /usr/local/bin/gsha512sum /usr/local/bin/sha512sum
```
* generate checksum
```
> sha256sum path/to/file
```
* Convert the model
```
> python tools/converter.py convert --config=/path/to/your/model.yaml
```
* after converting, your model is generated in builds folder
```
builds
├── include
│ └── mace
| └── public
| ├── mace.h
| └── mace_runtime.h
├── lib
| ├── arm64-v8a
| │ ├── libmace.a
| │ └── libmace.so
| ├── armeabi-v7a
| │ ├── libhexagon_controller.so
| │ ├── libmace.a
| │ └── libmace.so
| └── linux-x86-64
| ├── libmace.a
| └── libmace.so
└── model_0_48
├── include
│ └── mace
| └── public
| ├── model_0_48.h
| └── mace_engine_factory.h
└── model
├── arm64-v8a
│ └── model_0_48.a
└── armeabi-v7a
└── model_0_48.a
```
## Tansfer for Specific Caffe Layer
Sometimes we will use specific (or non-official) caffe layers which cannot be transformed to MACE layer. They may have different layer name in MACE. Therefore, we have to modify some code to make MACE understand these layers. The below is an example of transfering Caffe **Interp** layer to **ResizeBilinear** layer in MACE.
### modify caffe.proto
* in order to let mace know the Interp layer, we have to define the layer in mace/third_party/caffe/caffe.proto
* add InterpParameter into LayerParameter message
```
optional InterpParameter interp_param = 205;
```
* define InterpParameter with the parameter corresponding to ResizeBilinear layer
```
message InterpParameter {
// currently, only support width and height
optional int32 height = 1 [default = 0]; // Height of output
optional int32 width = 2 [default = 0]; // Width of output
}
```
### modify caffe_converter.py
* mace/mace/python/tools/converter_tool/caffe_converter.py
* we now need to implement the translation from caffe layer to mace layer.
* add layer name as a keyword while parsing the layers.
```python=
self._op_converters = {
'Input': self.convert_nop,
'Convolution': self.convert_conv2d,
'Eltwise': self.convert_elementwise,
'Add': self.convert_add,
'ReLU': self.convert_activation,
'TanH': self.convert_activation,
'Sigmoid': self.convert_activation,
'PReLU': self.convert_activation,
'Pooling': self.convert_pooling,
'Concat': self.convert_concat,
'Slice': self.convert_slice,
'Softmax': self.convert_softmax,
'InnerProduct': self.convert_fully_connected,
'BatchNorm': self.convert_folded_batchnorm,
'Interp': self.convert_interp, # new line
}
```
* the above code means keyword 'Interp' relates to function self.convert_interp, which is the main function doing the transformation from Interp to ResizeBilinear layer.
* see the line in convert_op()
```python=
self._op_converters[layer.type](caffe_op)
```
* if layer.type = 'Interp', it would execute self.convert_interp(caffe_op), caffe_op is the original caffe layer parsed from caffe.pb.h.
* define convert_interp function
```python=
def convert_interp(self, caffe_op):
op = self.convert_general_op(caffe_op) # new Mace operator, convert_general_op 做了一些基本的轉換 (ex: layer name, input, output shape)
param = caffe_op.layer.interp_param # 拿到我們原本 caffe operator 中的 param, 定義如同 caffe.proto 中我們定義的
op.type = MaceOp.ResizeBilinear.name # 給予這個 Mace operator 一個 type, 必須存在於 mace/mace/python/tools/converter_tool/base_converter.py : MaceSupportedOps 中, 在此我們的 caffe Interp layer 對應到 Mace ResizeBilinear
interp_arg = op.arg.add() # new param
interp_arg.name = MaceKeyword.mace_resize_size_str # 指定 param 為 ResizeBilinear 的 size, mace_resize_size_str 是定義在 mace/mace/python/tools/converter_tool/base_converter.py : MaceKeyword 中
interp_arg.ints.extend([param.width, param.height]) # 將 caffe 讀到的 param 傳給 mace 的 operator
```
### modify shape_inference.py
* mace/mace/python/tools/converter_tool/shape_inference.py
* shape_inference would check the output shape is correct or not. we need to tell MACE the output shape of our ResizeBilinear layer.
* similarly, add layer name as a key and function as a value
```python=
self._op_shape_inference = {
MaceOp.Conv2D.name: self.infer_shape_conv_pool_shape,
MaceOp.DepthwiseConv2d.name: self.infer_shape_conv_pool_shape,
MaceOp.Eltwise.name: self.infer_shape_general,
MaceOp.FoldedBatchNorm.name: self.infer_shape_general,
MaceOp.AddN.name: self.infer_shape_general,
MaceOp.Activation.name: self.infer_shape_general,
MaceOp.Pooling.name: self.infer_shape_conv_pool_shape,
MaceOp.Concat.name: self.infer_shape_concat,
MaceOp.Slice.name: self.infer_shape_slice,
MaceOp.Softmax.name: self.infer_shape_general,
MaceOp.FullyConnected.name: self.infer_shape_fully_connected,
MaceOp.ResizeBilinear.name: self.infer_shape_resize_bilinear, # new line
}
```
* implement infer_shape_resize_bilinear function
```python=
def infer_shape_resize_bilinear(self, op):
size = ConverterUtil.get_arg(op, MaceKeyword.mace_resize_size_str).ints # 拿取我們在 caffe_converter:convert_interp 中所傳入的參數
self.add_output_shape(op, [[1,2,size[0],size[1]]]) # 用 NCHW 的格式給予 ResizeBilinear output shape
```
## MACE GPU Build for specific SoC (Optional)
* get your phone's SoC
```
> adb shell getprop | grep platform
msm8998
```
* add SoC target in yaml file
```yml=
target_socs: [msm8998]
```
* build model
```
> python tools/converter.py convert --config=/path/to/your/model.yaml
```
* tuning the library for your phone, connect the phone through usb cable.
```
> python tools/converter.py run --config=/path/to/your/model.yaml
```
* you will get opencl binary file
![](https://i.imgur.com/Qey6yCA.png)
## Build Android Example (Optional)
```
> cd mace/mace/examples/android
> sh build.sh
```
* if you meet any problem, see problem shooting
## Problem Shooting
### ImportError: No module named tensorflow while converting Caffe
* Errror Message
```
ImportError: No module named tensorflow
Traceback (most recent call last):
File "tools/converter.py", line 1348, in <module>
flags.func(flags)
File "tools/converter.py", line 885, in build_library
convert_model(configs)
File "tools/converter.py", line 660, in convert_model
",".join(model_config.get(YAMLKeyword.transformers, [])))
File "/Users/yilinchen/Projects/mace/tools/sh_commands.py", line 521, in gen_model_code
_fg=True)
File "/anaconda3/envs/mace/lib/python2.7/site-packages/sh.py", line 1413, in __call__
raise exc
sh.ErrorReturnCode_1:
```
* Solution : Release Version below 0.8.1 bug, clone the latest code or download the release version above 0.8.1
### Model Converting Error
* Error Message
```
INFO: Elapsed time: 3.338s, Critical Path: 0.21s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
Traceback (most recent call last):
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/mace/mace/python/tools/converter.py", line 300, in <module>
main(unused_args=[sys.argv[0]] + unparsed)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/mace/mace/python/tools/converter.py", line 140, in main
FLAGS.weight_file)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/mace/mace/python/tools/converter_tool/caffe_converter.py", line 193, in __init__
str(f.read()), self._caffe_layers)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 525, in Merge
descriptor_pool=descriptor_pool)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 579, in MergeLines
return parser.MergeLines(lines, message)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 612, in MergeLines
self._ParseOrMerge(lines, message)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 627, in _ParseOrMerge
self._MergeField(tokenizer, message)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 727, in _MergeField
merger(tokenizer, message, field)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 815, in _MergeMessageField
self._MergeField(tokenizer, sub_message)
File "/Users/yilinchen/Projects/mace/bazel-bin/mace/python/tools/converter.runfiles/com_google_protobuf/python/google/protobuf/text_format.py", line 695, in _MergeField
(message_descriptor.full_name, name))
google.protobuf.text_format.ParseError: 1332:3 : Message type "caffe.LayerParameter" has no field named "interp_param".
Traceback (most recent call last):
File "tools/converter.py", line 1376, in <module>
flags.func(flags)
File "tools/converter.py", line 890, in build_library
convert_model(configs)
File "tools/converter.py", line 655, in convert_model
",".join(model_config.get(YAMLKeyword.graph_optimize_options, [])))
File "/Users/yilinchen/Projects/mace/tools/sh_commands.py", line 527, in gen_model_code
_fg=True)
File "/anaconda3/envs/mace/lib/python2.7/site-packages/sh.py", line 1413, in __call__
raise exc
sh.ErrorReturnCode_1:
RAN: /anaconda3/envs/mace/bin/python bazel-bin/mace/python/tools/converter -u --platform=caffe --model_file=./models/model_0-48/model_0-48.prototxt --weight_file=./models/model_0-48/model_0-48.caffemodel --model_checksum=9d8fb0edaddc52fb8b32a711a154a06815cd35381da37cd7629cc5116c368140 --weight_checksum=1df2f73bcc8d9ed8f7479ec244a6884aaf39dd8ecf4e07b02566bab2b9812326 --input_node=data --output_node=prob --runtime=cpu+gpu --template=mace/python/tools --model_tag=MOBILENET_Dilated --input_shape=1,473,473,3 --dsp_mode=0 --embed_model_data=0 --winograd=0 --obfuscate=0 --output_dir=mace/codegen/models/MOBILENET_Dilated --model_build_type=proto --data_type=fp16_fp32 --graph_optimize_options=
STDOUT:
STDERR:
```
* Solution : your network might have some problem, check your caffe model and yaml file.
### (Building Library) error: no member named 'accumulate' in namespace 'std'
* Error Message
```
ERROR: /Users/xxxx/Projects/mace/mace/utils/BUILD:12:1: C++ compilation of rule '//mace/utils:utils' failed (Exit 1): wrapped_clang failed: error executing command
(cd /private/var/tmp/_bazel_xxxx/36445054cdf415abf2459eeb034b1bff/execroot/mace && \
exec env - \
APPLE_SDK_PLATFORM='' \
APPLE_SDK_VERSION_OVERRIDE='' \
PATH=/anaconda3/envs/mace/bin:/anaconda3/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/usr/local/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Users/xxxx/Library/Android/sdk/tools:/Users/xxxx/Library/Android/sdk/platform-tools:/Users/xxxx/Library/Android/sdk/ndk-bundle \
XCODE_VERSION_OVERRIDE=9.3.1 \
external/local_config_cc/wrapped_clang '-D_FORTIFY_SOURCE=1' -fstack-protector -fcolor-diagnostics -Wall -Wthread-safety -Wself-assign -fno-omit-frame-pointer -g0 -O2 '-D_FORTIFY_SOURCE=1' -DNDEBUG -ffunction-sections -fdata-sections '-std=c++11' -iquote . -iquote bazel-out/darwin-opt/genfiles -iquote external/bazel_tools -iquote bazel-out/darwin-opt/genfiles/external/bazel_tools -MD -MF bazel-out/darwin-opt/bin/mace/utils/_objs/utils/mace/utils/string_util.d '-frandom-seed=bazel-out/darwin-opt/bin/mace/utils/_objs/utils/mace/utils/string_util.o' '-isysroot __BAZEL_XCODE_SDKROOT__' '-std=c++11' -D_GLIBCXX_USE_C99_MATH_TR1 -DMACE_OBFUSCATE_LITERALS -O3 -ffunction-sections -fdata-sections '-fvisibility=hidden' -Werror -Wextra -Wno-missing-field-initializers -no-canonical-prefixes -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -c mace/utils/string_util.cc -o bazel-out/darwin-opt/bin/mace/utils/_objs/utils/mace/utils/string_util.o)
Use --sandbox_debug to see verbose messages from the sandbox
mace/utils/string_util.cc:53:12: error: no member named 'accumulate' in namespace 'std'
std::accumulate(max_column_len.begin(), max_column_len.end(),
~~~~~^
1 error generated.
Target //mace:libmace failed to build
INFO: Elapsed time: 2.122s, Critical Path: 1.38s
INFO: 0 processes.
FAILED: Build did NOT complete successfully
```
* Solution : comment all the line that relate to x86-64 in tools/build-standalone-lib.sh
```python=
#rm -rf $LIB_DIR/linux-x86-64
#mkdir -p $LIB_DIR/linux-x86-64
#echo "build shared lib for linux-x86-64"
#bazel build mace:libmace --config optimization --define openmp=true
#cp bazel-bin/mace/libmace.so $LIB_DIR/linux-x86-64/
#echo "build static lib for linux-x86-64"
#bazel build mace:libmace_static --config optimization --define openmp=true
#cp bazel-genfiles/mace/libmace.a $LIB_DIR/linux-x86-64/
```
### (Android example building error) Could not determine java version from '10.0.1'.
* Solution : updgrade gradle to the latest version
### (Android example building error)libmace_mobile_jni.so', missing and no known rule to make it
* Error Message
```
> Task :macelibrary:externalNativeBuildRelease FAILED
Build mace_mobile_jni arm64-v8a
ninja: error: '../../../../src/main/cpp/model/mobilenet.a', needed by '../../../../build/intermediates/cmake/release/obj/arm64-v8a/libmace_mobile_jni.so', missing and no known rule to make it
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':macelibrary:externalNativeBuildRelease'.
> Build command failed.
Error while executing process /Users/xxxxxx/Library/Android/sdk/cmake/3.6.4111459/bin/cmake with arguments {--build /Users/yilinchen/Projects/mace/mace/examples/android/macelibrary/.externalNativeBuild/cmake/release/arm64-v8a --target mace_mobile_jni}
ninja: error: '../../../../src/main/cpp/model/mobilenet.a', needed by '../../../../build/intermediates/cmake/release/obj/arm64-v8a/libmace_mobile_jni.so', missing and no known rule to make it
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 10s
41 actionable tasks: 3 executed, 38 up-to-date
```
* Solution : modify mace/examples/android/macelibrary/CMakeLists.txt (solved from source code 07/16/2018)
```
set(mobilenet_file ${CMAKE_SOURCE_DIR}/src/main/cpp/model/mobilenet.a)
```
to
```
set(mobilenet_file ${CMAKE_SOURCE_DIR}/src/main/cpp/model/arm64-v8a/mobilenet.a
```
## Reference
* [Mobile AI Compute Engine Documentation](https://mace.readthedocs.io/en/latest/index.html)
* [git XiaoMi/mace](https://github.com/XiaoMi/mace/issues)