Skip to content

Commit 0a0a2d2

Browse files
[M1 cherry-pick]fix M1-arm64 build_optimize_tool and benchmark tool bug (#8925)
1 parent 7abb898 commit 0a0a2d2

File tree

9 files changed

+191
-47
lines changed

9 files changed

+191
-47
lines changed

cmake/configure.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ if (LITE_WITH_ARM82_FP16)
297297
add_definitions("-DLITE_WITH_ARM82_FP16")
298298
endif(LITE_WITH_ARM82_FP16)
299299

300+
if (LITE_WITH_M1)
301+
add_definitions("-DLITE_WITH_M1")
302+
endif(LITE_WITH_M1)
303+
300304
if (WITH_CONVERT_TO_SSA STREQUAL ON)
301305
add_definitions("-DWITH_CONVERT_TO_SSA")
302306
endif(WITH_CONVERT_TO_SSA)

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Welcome to Paddle-Lite's documentation!
6060
user_guides/quant_aware
6161
user_guides/model_visualization
6262
user_guides/profiler
63+
user_guides/sparse
6364

6465
.. toctree::
6566
:maxdepth: 1

docs/user_guides/model_optimize_tool.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,22 @@ pip install x2paddle
2828
./lite/tools/build.sh build_optimize_tool
2929
```
3030

31-
如果在 arm64 架构的 MacOS 下编译 opt 工具失败,试着删除 third-party 目录并重新`git checkout third-party`,然后将上一条指令改为
31+
如果在 arm64 架构的 MacOS 下编译 opt 工具失败
32+
33+
- 方法1: 试着删除 third-party 目录并重新`git checkout third-party`,然后将上一条指令改为:
34+
3235
```shell
3336
arch -x86_64 ./lite/tools/build.sh build_optimize_tool
3437
```
35-
该命令会编译 x86 格式的 opt 工具,但是不会影响工具的正常使用,编译成功后,在./build.opt/lite/api目录下,生成了可执行文件 opt
38+
该命令会编译 x86 格式的 opt 工具,但是不会影响工具的正常使用,编译成功后,在./build.opt/lite/api目录下,生成了可执行文件 opt
39+
- 方法2: 使用 `build_macos.sh` 脚本进行编译
40+
41+
```shell
42+
./lite/tools/build_macos.sh build_optimize_tool
43+
```
44+
45+
[使用可执行文件 opt 工具](./opt/opt_bin)
3646

37-
[使用可执行文件 opt 工具](./opt/opt_bin)
3847
## 使用 X2paddle 导出 Padde Lite 支持格式
3948

4049
**背景**:如果想用 Paddle Lite 运行第三方来源(TensorFlow、Caffe、ONNX、PyTorch)模型,一般需要经过两次转化。即使用 X2paddle 工具将第三方模型转化为 PaddlePaddle 格式,再使用 opt 将 PaddlePaddle 模型转化为Padde Lite 可支持格式。

docs/user_guides/sparse.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# 模型的非结构化稀疏
2+
3+
常见的稀疏方式可分为结构化稀疏和非结构化稀疏。前者在某个特定维度(特征通道、卷积核等等)上对卷积、矩阵乘法做剪枝操作,然后生成一个更小的模型结构,这样可以复用已有的卷积、矩阵乘计算,无需特殊实现推理算子;后者以每一个参数为单元稀疏化,然而并不会改变参数矩阵的形状,只是变成了含有大量零值的稀疏矩阵,所以更依赖于推理库、硬件对于稀疏后矩阵运算的加速能力。更多介绍请参照[这篇技术文章](https://mp.weixin.qq.com/s/l__C5IOu3z7uQdcWKnViOw)
4+
5+
本文从推理的视角,介绍如何基于 Paddle Lite 的系列工具,在稀疏模型上获得更优性能。
6+
7+
## 非结构化稀疏训练
8+
9+
### 1 简介
10+
11+
稀疏化训练是使用全量训练数据,对训练好的稠密模型进行稀疏。在训练过程中,该方法只优化部分重要参数,对不重要的参数置零,达到保证稀疏模型精度的效果。
12+
13+
使用条件:
14+
15+
- 有预训练模型
16+
- 有全量的训练数据
17+
18+
使用步骤:
19+
20+
- 产出稀疏模型:使用 PaddleSlim 调用稀疏训练接口,产出稀疏模型
21+
- 稀疏模型预测:使用 Paddle Lite 加载稀疏模型进行预测推理
22+
23+
优点:
24+
25+
- 减小计算量、降低计算内存、减小 FP32 模型大小
26+
- 模型精度受稀疏影响小
27+
28+
缺点:
29+
30+
- 需要全量数据,训练时间较长
31+
32+
建议首先使用 [虚拟稀疏](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/auto_compression/utils/prune_model.py#L12) 的接口对稠密推理模型进行快速稀疏(只保证稀疏度,不保证精度);然后使用稀疏模型进行预测。如果该稀疏模型的性能达不到要求或超出要求,再调大或者调小稀疏度;最后使用适合的稀疏度开始稀疏训练。
33+
34+
### 2 产出稀疏模型
35+
36+
目前,PaddleSlim 的稀疏训练主要针对 1x1卷积,对应算子是 conv2d。Paddle Lite 支持运行 PaddleSlim 稀疏训练产出的模型,可以加快模型在移动端的执行速度。
37+
38+
温馨提示:如果您是初次接触 PaddlePaddle 框架,建议首先学习[使用文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/beginners_guide/index_cn.html)
39+
40+
使用 PaddleSlim 模型压缩工具训练稀疏模型,请参考文档:
41+
* 稀疏训练接口 [动态图](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/api_cn/dygraph/pruners/unstructured_pruner.rst)|[静态图](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/api_cn/static/prune/unstructured_prune_api.rst)
42+
* 稀疏训练Demo [动态图](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/dygraph/unstructured_pruning)| [静态图](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/unstructured_prune)
43+
44+
45+
### 3 使用 Paddle Lite 运行稀疏模型推理
46+
47+
首先,使用 Paddle Lite 提供的模型转换工具(model_optimize_tool)将稀疏模型转换成移动端预测的模型,然后加载转换后的模型进行预测部署。
48+
49+
#### 3.1 模型转换
50+
51+
参考[模型转换](../user_guides/model_optimize_tool.md)准备模型转换工具,建议从 Release 页面下载。
52+
53+
参考[模型转换](../user_guides/model_optimize_tool.md)使用模型转换工具,参数按照实际情况设置。比如在安卓手机ARM端进行预测,模型转换的命令为:
54+
55+
```bash
56+
./OPT --model_dir=./mobilenet_v1_quant \
57+
--optimize_out_type=naive_buffer \
58+
--optimize_out=mobilenet_v1_quant_opt \
59+
--valid_targets=arm \
60+
--sparse_model=true --sparse_theshold=0.5
61+
```
62+
63+
注意,我们通过上述的 sparse_model 和 sparse_threshold 两个参数控制是否对模型进行稀疏优化:
64+
65+
- 当 sparse_model=false时,稀疏优化关闭,所有的参数都不会被稀疏
66+
- 当 sparse_model=true时,稀疏优化打开
67+
- 当前参数矩阵稀疏度大于 sparse_threshold 时,会被稀疏
68+
- 当前参数矩阵稀疏度小于 sparse_threshold 时,不会被稀疏
69+
70+
#### 3.2 稀疏模型预测
71+
72+
和 FP32 模型一样,转换后的稀疏模型可以在 Android APP 中加载预测,建议参考[C++ Demo](./cpp_demo.md)
73+
74+
75+
### FAQ
76+
77+
**问题**:为什么模型优化(*.nb文件)后,稀疏 FP32 模型的体积比稠密 FP32 小了,但是稀疏 INT8 模型的体积反而比稠密 INT8 模型体积大了?
78+
79+
**解答**:这是可能出现的现象,因为稀疏格式中,我们虽然节省了部分 INT8 参数的存储空间,但是引入了 INT32 类型的 index,所以理论上75%稀疏度以下时,INT8 模型体积是会有些增大的。
80+
81+
**问题**:当前非结构化稀疏的适用范围是什么
82+
83+
**解答**:在推理上, PaddleLite-2.11 支持 1x1卷积的非结构化和半结构化稀疏(2x1 的block为一个单元进行稀疏);全连接层的稀疏正在开发中。同时,暂时只支持 ARM CPU (例如高通系列,瑞芯微系列)上的稀疏推理。

lite/api/tools/benchmark/benchmark.cc

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,23 +90,16 @@ void RunImpl(std::shared_ptr<PaddlePredictor> predictor,
9090
const int cnt,
9191
const bool repeat_flag) {
9292
lite::Timer timer;
93-
bool has_validation_set = FLAGS_validation_set.empty();
94-
if (!has_validation_set) {
95-
timer.Start();
96-
task->PreProcess(predictor, config, image_files, cnt);
97-
perf_data->set_pre_process_time(timer.Stop());
98-
}
99-
93+
timer.Start();
94+
task->PreProcess(predictor, config, image_files, cnt);
95+
perf_data->set_pre_process_time(timer.Stop());
10096
timer.Start();
10197
predictor->Run();
10298
perf_data->set_run_time(timer.Stop());
103-
104-
if (!has_validation_set) {
105-
timer.Start();
106-
task->PostProcess(
107-
predictor, config, image_files, word_labels, cnt, repeat_flag);
108-
perf_data->set_post_process_time(timer.Stop());
109-
}
99+
timer.Start();
100+
task->PostProcess(
101+
predictor, config, image_files, word_labels, cnt, repeat_flag);
102+
perf_data->set_post_process_time(timer.Stop());
110103
}
111104
#endif
112105

@@ -171,6 +164,7 @@ void Run(const std::string& model_file,
171164
#endif
172165
}
173166

167+
bool has_validation_set = !(FLAGS_validation_set.empty());
174168
// Warmup
175169
for (int i = 0; i < FLAGS_warmup; ++i) {
176170
#ifdef __ANDROID__
@@ -188,21 +182,27 @@ void Run(const std::string& model_file,
188182
timer.SleepInMs(FLAGS_run_delay);
189183
}
190184

191-
// Run
192-
for (int i = 0; i < FLAGS_repeats; ++i) {
185+
if (has_validation_set) {
186+
for (int i = 0; i < FLAGS_repeats; ++i) {
193187
#ifdef __ANDROID__
194-
RunImpl(predictor,
195-
&perf_data,
196-
task.get(),
197-
config,
198-
image_files,
199-
word_labels,
200-
i,
201-
true);
188+
RunImpl(predictor,
189+
&perf_data,
190+
task.get(),
191+
config,
192+
image_files,
193+
word_labels,
194+
i,
195+
true);
202196
#else
203-
RunImpl(predictor, &perf_data);
197+
RunImpl(predictor, &perf_data);
204198
#endif
205-
timer.SleepInMs(FLAGS_run_delay);
199+
timer.SleepInMs(FLAGS_run_delay);
200+
}
201+
} else {
202+
for (int i = 0; i < FLAGS_repeats; ++i) {
203+
RunImpl(predictor, &perf_data);
204+
timer.SleepInMs(FLAGS_run_delay);
205+
}
206206
}
207207

208208
// Get output

lite/api/tools/benchmark/benchmark.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -358,15 +358,6 @@ const std::string OutputOptModel(const std::string& opt_model_file) {
358358
opt.SetValidPlaces(FLAGS_backend);
359359
}
360360
}
361-
362-
auto npos = opt_model_file.find(".nb");
363-
std::string out_name = opt_model_file.substr(0, npos);
364-
#ifdef __ANDROID__
365-
if (out_name.empty()) {
366-
out_name = "/data/local/tmp/";
367-
}
368-
#endif
369-
opt.SetOptimizeOut(out_name);
370361
bool is_opt_model =
371362
(FLAGS_uncombined_model_dir.empty() && FLAGS_model_file.empty() &&
372363
FLAGS_param_file.empty() && !FLAGS_optimized_model_file.empty());
@@ -380,15 +371,23 @@ const std::string OutputOptModel(const std::string& opt_model_file) {
380371
return FLAGS_optimized_model_file;
381372
}
382373

374+
std::string model_dir = FLAGS_uncombined_model_dir;
383375
if (!FLAGS_uncombined_model_dir.empty()) {
384376
opt.SetModelDir(FLAGS_uncombined_model_dir);
385377
} else {
378+
model_dir = FLAGS_model_file.substr(0, FLAGS_model_file.rfind("/"));
386379
opt.SetModelFile(FLAGS_model_file);
387380
opt.SetParamFile(FLAGS_param_file);
388381
}
382+
auto npos = opt_model_file.find(".nb");
383+
std::string out_name = opt_model_file.substr(0, npos);
384+
if (out_name.empty()) {
385+
out_name = model_dir + "/opt";
386+
}
387+
opt.SetOptimizeOut(out_name);
389388

390389
std::string saved_opt_model_file =
391-
opt_model_file.empty() ? "/data/local/tmp/.nb" : opt_model_file;
390+
opt_model_file.empty() ? out_name + ".nb" : opt_model_file;
392391
if (paddle::lite::IsFileExists(saved_opt_model_file)) {
393392
int err = system(
394393
lite::string_format("rm -rf %s", saved_opt_model_file.c_str()).c_str());

lite/core/device_info.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ LITE_THREAD_LOCAL int64_t DeviceInfo::count_ = 0;
9292
const int DEFAULT_L1_CACHE_SIZE = 64 * 1024;
9393
const int DEFAULT_L2_CACHE_SIZE = 2048 * 1024;
9494
const int DEFAULT_L3_CACHE_SIZE = 0;
95+
#elif defined(LITE_WITH_M1)
96+
const int DEFAULT_L1_CACHE_SIZE = 128 * 1024;
97+
const int DEFAULT_L2_CACHE_SIZE = 4096 * 1024;
98+
const int DEFAULT_L3_CACHE_SIZE = 0;
9599
#else
96100
const int DEFAULT_L1_CACHE_SIZE = 32 * 1024;
97101
const int DEFAULT_L2_CACHE_SIZE = 512 * 1024;
@@ -117,7 +121,7 @@ int get_cpu_num() {
117121
cpu_num = 1;
118122
}
119123
return cpu_num;
120-
#elif defined(TARGET_IOS)
124+
#elif defined(TARGET_IOS) || defined(LITE_WITH_M1)
121125
int cpu_num = 0;
122126
size_t len = sizeof(cpu_num);
123127
sysctlbyname("hw.ncpu", &cpu_num, &len, NULL, 0);
@@ -148,7 +152,7 @@ size_t get_mem_size() {
148152
}
149153
fclose(fp);
150154
return memsize;
151-
#elif defined(TARGET_IOS)
155+
#elif defined(TARGET_IOS) || defined(LITE_WITH_M1)
152156
// to be implemented
153157
printf("not implemented, set to default 4GB\n");
154158
return 4096 * 1024;
@@ -236,6 +240,10 @@ void get_cpu_arch(std::vector<ARMArch>* archs, const int cpu_num) {
236240
for (int i = 0; i < cpu_num; ++i) {
237241
archs->at(i) = kAPPLE;
238242
}
243+
#elif defined(LITE_WITH_M1)
244+
for (int i = 0; i < cpu_num; ++i) {
245+
archs->at(i) = kX1;
246+
}
239247
#endif
240248
}
241249

@@ -1133,6 +1141,10 @@ int DeviceInfo::Setup() {
11331141
#else
11341142
#ifdef TARGET_IOS
11351143
dev_name_ = "Apple";
1144+
#elif defined(LITE_WITH_M1)
1145+
dev_name_ = "M1";
1146+
SetDotInfo(1, 1);
1147+
SetFP16Info(1, 1);
11361148
#else
11371149
dev_name_ = "Unknown";
11381150
#endif

lite/demo/cxx/test_cv/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@ example:
1717
wget http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz
1818
tar zxvf mobilenet_v1.tar.gz
1919
./lite/tools/build.sh build_optimize_tool
20-
# 如果在arm64架构的MacOS下编译Opt工具失败,试着将上一条指令改为
21-
#"arch -x86_64 ./lite/tools/build.sh build_optimize_tool"
20+
# 如果在 arm64 架构的 MacOS 下编译 opt 工具失败
21+
# - 方法1: 试着删除 third-party 目录并重新`git # checkout third-party`,然后将上一条指令改为:
22+
# ```shell
23+
# arch -x86_64 ./lite/tools/build.sh # build_optimize_tool
24+
# ```
25+
# 该命令会编译 x86 格式的 opt 工具,但是不会影响工具的正常使用,编译成功后,在./build.opt/lite/api目录下,生成了可执行文件 opt
26+
#- 方法2: 使用 `build_macos.sh` 脚本进行编译
27+
#```shell
28+
#./lite/tools/build_macos.sh build_optimize_tool
29+
#```
30+
2231
./build.opt/lite/api/opt
2332
--optimize_out_type=naive_buffer
2433
--optimize_out=model_dir

lite/tools/build_macos.sh

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ function prepare_thirdparty {
104104
function set_benchmark_options {
105105
BUILD_EXTRA=ON
106106
WITH_EXCEPTION=ON
107-
WITH_OPENCL=ON
108107
LITE_ON_TINY_PUBLISH=OFF
109108

110109
if [ ${WITH_PROFILE} == "ON" ] || [ ${WITH_PRECISION_PROFILE} == "ON" ]; then
@@ -114,9 +113,30 @@ function set_benchmark_options {
114113
fi
115114
}
116115

116+
function build_opt {
117+
cd $workspace
118+
prepare_thirdparty
119+
mkdir -p build.opt
120+
cd build.opt
121+
opt_arch=$(echo `uname -a` | awk -F " " '{print $15}')
122+
with_x86=OFF
123+
if [ $opt_arch == "arm64" ]; then
124+
with_x86=OFF
125+
else
126+
with_x86=ON
127+
fi
128+
cmake .. -DWITH_LITE=ON \
129+
-DLITE_ON_MODEL_OPTIMIZE_TOOL=ON \
130+
-DWITH_TESTING=OFF \
131+
-DLITE_BUILD_EXTRA=ON \
132+
-DLITE_WITH_X86=${with_x86} \
133+
-DWITH_MKL=OFF
134+
make opt -j$NUM_PROC
135+
}
136+
117137
function make_armosx {
138+
prepare_thirdparty
118139
if [ "${BUILD_PYTHON}" == "ON" ]; then
119-
prepare_thirdparty
120140
BUILD_EXTRA=ON
121141
LITE_ON_TINY_PUBLISH=OFF
122142
fi
@@ -176,8 +196,9 @@ function make_armosx {
176196
-DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \
177197
-DLITE_WITH_PRECISION_PROFILE=${WITH_PRECISION_PROFILE} \
178198
-DLITE_WITH_OPENMP=OFF \
179-
-DWITH_ARM_DOTPROD=OFF \
199+
-DWITH_ARM_DOTPROD=ON \
180200
-DLITE_WITH_X86=OFF \
201+
-DLITE_WITH_M1=ON \
181202
-DLITE_WITH_PYTHON=${BUILD_PYTHON} \
182203
-DPY_VERSION=$PY_VERSION \
183204
-DLITE_WITH_LOG=$WITH_LOG \
@@ -292,7 +313,7 @@ function print_usage {
292313
echo -e "| |"
293314
echo -e "| for arm macos: |"
294315
echo -e "| optional argument: |"
295-
echo -e "| --with_metal: (OFF|ON); controls whether to build with Metal, default is OFF |"
316+
echo -e "| --with_metal: (OFF|ON); controls whether to build with Metal, default is OFF |"
296317
echo -e "| --with_cv: (OFF|ON); controls whether to compile cv functions into lib, default is OFF |"
297318
echo -e "| --with_log: (OFF|ON); controls whether to print log information, default is ON |"
298319
echo -e "| --with_exception: (OFF|ON); controls whether to throw the exception when error occurs, default is OFF |"
@@ -302,6 +323,8 @@ function print_usage {
302323
echo -e "| --with_arm82_fp16: (OFF|ON); controls whether to include FP16 kernels, default is OFF |"
303324
echo -e "| warning: when --with_arm82_fp16=ON, toolchain will be set as clang, arch will be set as armv8. |"
304325
echo -e "| |"
326+
echo -e "| compiling for macos OPT tool: |"
327+
echo -e "| ./lite/tools/build_macos.sh build_optimize_tool |"
305328
echo -e "| arguments of benchmark binary compiling for macos x86: |"
306329
echo -e "| ./lite/tools/build_macos.sh --with_benchmark=ON x86 |"
307330
echo -e "| |"
@@ -431,6 +454,10 @@ function main {
431454
make_x86
432455
shift
433456
;;
457+
build_optimize_tool)
458+
build_opt
459+
shift
460+
;;
434461
help)
435462
print_usage
436463
exit 0

0 commit comments

Comments
 (0)