裁剪预测库方法
裁剪预测库方法
Paddle-Lite支持根据模型裁剪预测库功能。Paddle-Lite的一般编译会将所有已注册的operator打包到预测库中,造成库文件体积膨胀;裁剪预测库能针对具体的模型,只打包优化后该模型需要的operator,有效降低预测库文件大小。
效果展示(Tiny_publish Android动态预测库体积)
测试模型 | 裁剪开关 | libpaddle_lite_jni.so | 转化后模型中的OP |
---|---|---|---|
mobilenetv1(armv8) | 裁剪前–build_tailor=OFF | 1.5M | feed,etch,conv2d,depthwise_conv2d,fc,fpool2d,softmax |
mobilenetv1(armv8) | 裁剪后–build_tailor=ON | 788K | feed,etch,conv2d,depthwise_conv2d,fc,fpool2d,softmax |
mobilenetv2(armv8) | 裁剪前–build_tailor=OFF | 1.5M | feed,fetch,conv2d,depthwise_conv2d,elementwise_add,fc,pool2d,relu6,softmax |
mobilenetv2(armv8) | 裁剪后–build_tailor=ON | 912K | feed,fetch,conv2d,depthwise_conv2d,elementwise_add,fc,pool2d,relu6,softmax |
inceptionv4(armv7) | 裁剪前–build_tailor=OFF | 938K | feed,fetch,concat,conv2d,dropout,fc,pool2d,softmax |
inceptionv4(armv7) | 裁剪后–build_tailor=ON | 512K | feed,fetch,concat,conv2d,dropout,fc,pool2d,softmax |
yolov3(armv7) | 裁剪前–build_tailor=OFF | 938K | feed,fetch,concat,conv2d,depthwise_conv2d,multiclass_nms,nearest_interp,transpose2,yolo_box |
yolov3(armv7) | 裁剪后–build_tailor=ON | 516K | feed,fetch,concat,conv2d,depthwise_conv2d,multiclass_nms,nearest_interp,transpose2,yolo_box |
实现过程:
1、转化模型时记录优化后模型信息
说明:使用model_optimize_tool转化模型时,选择 --record_tailoring_info =true
会将优化后模型的OP和kernel信息保存到输出文件夹,这些信息将用于编译裁剪后的动态库。
注意:需要使用Paddle-Lite 最新版本(release/v2.0.0之后)代码编译出的model_optimize_tool
例如:
./model_optimize_tool --model_dir=./mobilenet_v1 --optimize_out_type=naive_buffer --optimize_out=mobilenet_v1NB --record_tailoring_info =true --valid_targets=arm
效果:优化后模型使用的OP和kernel信息被保存在 mobilenet_v1NB
文件夹中的隐藏文件里了
2、根据模型信息编译裁剪后的预测库
说明:编译Paddle-Lite时选择--build_tailor=ON
,并且用 –-opt_model_dir=
指定优化后的模型的地址
例如:
./lite/tools/build.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_static --build_extra=ON --build_tailor=ON --opt_model_dir=../mobilenet_v1NB full_publish
注意:上面命令中的../mobilenet_v1NB
是第1步得到的转化模型的输出路径
效果:编译出来的动态库文件变小,且可以运行优化后的模型。
编译出的C++预测库文件位于 :
build.lite.android.armv7.gcc/inference_lite_lib.android.armv7/cxx/lib/
编译出的Java预测库文件位于:
build.lite.android.armv7.gcc/inference_lite_lib.android.armv7/java/so/
3、运行裁剪后的预测库文件
注意:基于某一模型裁剪出的预测库只能支持优化工具转化后的该模型,例如根据mobilenetV1裁剪出的 full_api预测库只能运行以protobuf格式转化出的模型mobilenetV1_opt_nb, 裁剪出的light_api预测库只能运行以naive_buffer格式转化出的模型mobilenetV1_opt_nb, 运行其他模型可能会出现segementation fault:undifined op or kernel
。 模型转化方法参考:使用model_optimize_tool转化模型)。
示例1:使用裁剪后的light_api预测库运行mobilenetv1
1、执行第二步编译后,light_api的C++ 示例位于
/Paddle-Lite/build.lite.android.armv7.gcc/inference_lite_lib.android.armv7/demo/cxx/mobile_light
输入make
命令执行编译可编译出可执行文件mobilenetv1_light_api
2、使用adb将mobilenetV1_NB模型和mobilenetv1_light_api传到手机后执行demo:
./mobilenetv1_light_api --model_dir=./mobilenetV1_NB
注意:mobilenetV1_NB
是用mobilenetV1
模型转化的naive_buffer格式模型(不需要设置 --record_tailoring_info =true
,转化流程参考:使用model_optimize_tool转化模型)。
示例2:使用裁剪后的full_api预测库运行mobilenetv1
1、执行第二步编译后,full_api的C++ 示例位于
/Paddle-Lite/build.lite.android.armv7.gcc/inference_lite_lib.android.armv7/demo/cxx/mobile_light
替换mobilenetv1_full_api.cc代码内容:
#include <gflags/gflags.h>
#include <stdio.h>
#include <vector>
#include "paddle_api.h" // NOLINT
#include "paddle_use_kernels.h" // NOLINT
#include "paddle_use_ops.h" // NOLINT
#include "paddle_use_passes.h" // NOLINT
using namespace paddle::lite_api; // NOLINT
DEFINE_string(model_dir, "", "Model dir path.");
int64_t ShapeProduction(const shape_t& shape) {
int64_t res = 1;
for (auto i : shape) res *= i;
return res;
}
void RunModel() {
// 1. Set CxxConfig
CxxConfig config;
config.set_model_file(FLAGS_model_dir + "model");
config.set_param_file(FLAGS_model_dir + "params");
std::vector<Place> valid_places{Place{TARGET(kARM), PRECISION(kFloat)}};
config.set_valid_places(valid_places);
// 2. Create PaddlePredictor by CxxConfig
std::shared_ptr<PaddlePredictor> predictor =
CreatePaddlePredictor<CxxConfig>(config);
// 3. Prepare input data
std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0)));
input_tensor->Resize(shape_t({1, 3, 224, 224}));
auto* data = input_tensor->mutable_data<float>();
for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) {
data[i] = 1;
}
// 4. Run predictor
predictor->Run();
// 5. Get output
std::unique_ptr<const Tensor> output_tensor(
std::move(predictor->GetOutput(0)));
printf("Output dim: %d\n", output_tensor->shape()[1]);
for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) {
printf("Output[%d]: %f\n", i, output_tensor->data<float>()[i]);
}
}
int main(int argc, char** argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
RunModel();
return 0;
}
2、使用adb将mobilenetV1_PB模型和mobilenetv1_full_api传到手机后执行demo:
./mobilenetv1_full_api --model_dir=./mobilenetV1_PB
注意:mobilenetV1_PB
是用mobilenetV1
模型转化的protobuf格式模型(不需要设置 --record_tailoring_info =true
,转化流程参考:使用model_optimize_tool转化模型)。