diff --git a/docs/advanced_user_guides/npu.md b/docs/advanced_user_guides/npu.md new file mode 100644 index 0000000000000000000000000000000000000000..c84a3c3bd151dbc1574a0d874bacfbcd0af330a3 --- /dev/null +++ b/docs/advanced_user_guides/npu.md @@ -0,0 +1,129 @@ +# 使用华为NPU + +Paddle Lite是首款支持华为自研达芬奇架构NPU(Kirin 810/990 SoC搭载的NPU)的预测框架。 +原理是在线分析Paddle模型,将Paddle算子转成HiAI IR后,调用HiAI IR/Builder/Runtime APIs生成并执行HiAI模型。 + +## 已支持的设备 + +- 华为nova5、nova5i pro、mate30、mate30 pro、mate30 5G、荣耀v30,以及即将推出的mate40、p40。据华为透露,今后上市的大部分手机都会搭载其自研达芬奇架构NPU。 + +## 已支持的模型 + +- MobileNetV1 +- MobileNetV2 +- ResNet-18/50 +- ShuffleNetV2 +- CycleGAN (暂时需要华为内部rom的支持) +- 百度内部业务模型(由于涉密,不方便透露具体细节) + +## 已支持(或部分支持)的Paddle算子 + +- sigmoid +- relu +- tanh +- relu_clipped +- leaky_relu +- softsign +- hard_sigmoid +- batch_norm +- concat +- conv2d +- depthwise_conv2d +- conv2d_transpose +- dropout +- elementwise_add +- elementwise_sub +- elementwise_mul +- elementwise_div +- fusion_elementwise_add_activation +- fusion_elementwise_sub_activation +- fusion_elementwise_mul_activation +- fusion_elementwise_div_activation +- fc +- bilinear_interp +- nearest_interp +- matmul +- mul +- pad2d +- pool2d +- reduce_mean +- reshape +- reshape2 +- scale +- shuffle_channel +- softmax +- split +- sqrt +- square +- transpose +- transpose2 +- unsqueeze +- unsqueeze2 +- instance_norm (暂时需要华为内部rom的支持) +- layer_norm (暂时需要华为内部rom的支持) + +## 编译支持NPU的Paddle Lite库 + +- 从https://developer.huawei.com/consumer/cn/hiai/下载华为HiAI DDK后解压到任意路径(注意:华为提供了多个版本的DDK,我们需要下载针对麒麟810/990芯片HiAI Foundation开发套件,例如最新的[DDK V310版本](https://obs.cn-north-2.myhwclouds.com/hms-ds-wf/sdk/hwhiai-ddk-100.310.011.010.zip))。 +- 将HiAI DDK中的ai_ddk_lib目录拷贝至Paddle Lite源码根目录后,使用[NPU编译脚本](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/tools/build_npu.sh)编译full_publish和tiny_publish。 + +注意:以下是HiAI DDK V310版解压后的目录结构,需要将ai_ddk_lib目录拷贝至Paddle Lite源码根目录。 +```shell +- app_sample +- ddk + - ai_ddk_lib + - include + - lib # for armv7 + - lib64 # for armv8 +- document +- tools +``` + +- full_publish and tiny_publish for armv8,由于HiAI DDK的armv7和armv8的so库均基于c++_shared构建,因此,建议使用c++_shared编译Paddle Lite。 +```shell +$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_shared full_publish +$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_shared tiny_publish +``` + +- full_publish and tiny_publish for armv7 +```shell +$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_shared full_publish +$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_shared tiny_publish +``` + +注意:为了保证编译环境一致,建议参考[源码编译](../installation/source_compile)中的Docker开发环境进行配置,然后再执行上述命令。 + +## 优化生成NPU模型 + +- model_optimize_tool工具已经支持生成NPU模型,仅需要将valid_targets设置为npu,arm即可,具体参考[模型转化方法](../user_guides/model_optimize_tool)。 +```shell +./model_optimize_tool --model_dir= \ + --model_file= \ + --param_file= \ + --optimize_out_type=(protobuf|naive_buffer) \ + --optimize_out= \ + --valid_targets=npu,arm \ + --prefer_int8_kernel=(true|false) \ + --record_tailoring_info =(true|false) +``` +- model_optimize_tool生成的模型只是标记了NPU支持的Paddle算子,并没有真正生成NPU HiAI模型,只有在执行时才会将标记的Paddle算子转成HiAI IR,最终生成并执行HiAI模型,具体实现参考PR[2576](https://github.com/PaddlePaddle/Paddle-Lite/pull/2576)。 +- 不同模型,不同型号(ROM版本)的华为手机,在执行阶段,由于某些Paddle算子无法完全转成HiAI IR,或目标手机的HiAI版本过低等原因,可能导致HiAI模型无法成功生成,在这种情况下,Paddle Lite会调用CPU版算子进行运算完成整个预测任务。 + +## 通过JAVA接口加载并执行NPU模型 + +- 使用方法和[Java实例](../user_guides/java_demo)一致,无需额外设置任何参数,只需将模型换成NPU模型即可。[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)中的Image Classification Demo for Android是同时支持CPU和NPU两种模型的图像分类Demo。 + +注意:在拷贝libpaddle_lite_jni.so的时候,由于依赖HiAI DDK so和libc++_shared.so库,需要将HiAI DDK中ai_ddk_lib/lib或ai_ddk_lib/lib64目录下的所有so和libc++_shared.so,拷到libpaddle_lite_jni.so同级目录下。 + +## 通过C++接口加载并执行NPU模型 + +- 使用方法和[C++实例](../user_guides/cpp_demo)一致,同样无需额外设置任何参数,只需将模型换成NPU模型即可。 + +注意:1)不能使用安卓模拟器,需要使用真实设备,且必须是支持NPU的华为手机。2)在使用adb push命令向手机推送目标程序时,需要将HiAI DDK中ai_ddk_lib/lib或ai_ddk_lib/lib64目录下的所有so和libc++_shared.so,推送到目标程序同级目录下。 + + +## 其它说明 + +- 华为达芬奇架构的NPU内部大量采用float16进行运算,因此,预测结果会存在偏差,但大部分情况下精度不会有较大损失,可参考[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)中Image Classification Demo for Android对同一张图片CPU与NPU的预测结果。 +- 华为Kirin 810/990 Soc搭载的自研达芬奇架构的NPU,与Kirin 970/980 Soc搭载的寒武纪NPU不一样,同样的,与Hi3559A、Hi3519A使用的NNIE也不一样,Paddle Lite只支持华为自研达芬奇架构NPU。 +- 我们正在持续增加能够适配HiAI IR的Paddle算子bridge/converter,以便适配更多Paddle模型,同时华为研发同学也在持续对HiAI IR性能进行优化。 diff --git a/docs/advanced_user_guides/support_operation_list.md b/docs/advanced_user_guides/support_operation_list.md index 7c2ceb0ff819f7f1676308a33ec88f5eab820e57..c0acb02b9d7fb71f8abf79a651e07f2d78c1d2c1 100644 --- a/docs/advanced_user_guides/support_operation_list.md +++ b/docs/advanced_user_guides/support_operation_list.md @@ -39,6 +39,7 @@ - expand - fake_channel_wise_dequantize_max_abs - fake_dequantize_max_abs +- fake_quantize_abs_max - fake_quantize_dequantize_moving_average_abs_max - fake_quantize_moving_average_abs_max - fake_quantize_range_abs_max @@ -56,10 +57,11 @@ - fusion_elementwise_mul_activation - fusion_elementwise_sub_activation - gather +- gelu - generate_proposals -- graph_op - greater_equal - greater_than +- grid_sampler - gru - gru_unit - hard_sigmoid @@ -93,7 +95,7 @@ - nearest_interp - negative - norm -- notequal +- not_equal - pad2d - pool2d - power @@ -127,6 +129,7 @@ - sequence_expand - sequence_expand_as - sequence_pool +- sequence_pool_concat - sequence_reshape - sequence_reverse - sequence_softmax @@ -144,6 +147,7 @@ - squeeze - squeeze2 - stack +- subgraph - swish - tanh - top_k @@ -216,6 +220,7 @@ - generate_proposals - greater_equal - greater_than +- grid_sampler - gru - gru_unit - hard_sigmoid @@ -301,6 +306,9 @@ - gelu - gru - layer_norm +- leaky_relu +- lookup_table +- lookup_table_v2 - match_matrix_tensor - matmul - mul @@ -378,9 +386,11 @@ - yolo_box ### OpenCL kernels +- concat - conv2d - depthwise_conv2d - elementwise_add +- elementwise_mul - fc - fusion_elementwise_add_activation - layout @@ -388,5 +398,10 @@ - io_copy - io_copy_once - mul +- nearest_interp - pool2d - relu +- reshape +- reshape2 +- scale +- sigmoid diff --git a/docs/index.rst b/docs/index.rst index d7359f1d0508f8e85824f450ca07f095d047f90c..9f9a2be8c9a34901cabc9f69d21de4fa57cc9057 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,6 +13,7 @@ Welcome to Paddle-Lite's documentation! introduction/tech_highlights introduction/architecture + introduction/support_hardware .. toctree:: :maxdepth: 1 @@ -37,7 +38,10 @@ Welcome to Paddle-Lite's documentation! user_guides/model_optimize_tool user_guides/library_tailoring user_guides/cuda + user_guides/fpga user_guides/opencl + user_guides/cpp_demo + user_guides/java_demo .. toctree:: :maxdepth: 1 @@ -48,7 +52,9 @@ Welcome to Paddle-Lite's documentation! advanced_user_guides/add_layout advanced_user_guides/model_quantization advanced_user_guides/add_new_pass + advanced_user_guides/npu advanced_user_guides/x86 + advanced_user_guides/cv .. toctree:: :maxdepth: 1 diff --git a/docs/introduction/support_hardware.md b/docs/introduction/support_hardware.md new file mode 100644 index 0000000000000000000000000000000000000000..b4f76577bc9a0b80b188aedfc2c5cf33f786033a --- /dev/null +++ b/docs/introduction/support_hardware.md @@ -0,0 +1,32 @@ + +# 支持硬件列表 + + +## ARM CPU +Paddle Lite支持[ARM Cortex-A系列处理器](https://en.wikipedia.org/wiki/ARM_Cortex-A),支持列表如下: +### 32bit(ARMv7a) +- Cortex-A5 +- Cortex-A7 +- Cortex-A8 +- Cortex-A9 +- Cortex-A12 +- Cortex-A15 +- Cortex-A17(RK3288) +- Cortex-A32 +### 64bit(ARMv7a, ARMv8a) +- Cortex-A35 +- Cortex-A53(树莓派3) +- Cortex-A55 +- Cortex-A57(Nvidia tx1,Nvidia tx2, 高通810等) +- Cortex-A72(麒麟95X,高通820, RK3399,树莓派4等) +- Cortex-A73(麒麟960,麒麟970,高通835, 联发科X30等) +- Cortex-A75(高通845等) +- Cortex-A76(麒麟980,麒麟990,高通855,高通730,联发科G90等) +- Cortex-A77 +- ARMv8-A compatible(Apple A系列处理器, Nvidia tegra, Qualcomm Kryo, Falkor, Samsung Mongoose) + +## 移动端GPU +Paddle Lite支持移动端GPU和Nvidia端上GPU设备,支持列表如下: +- ARM Mali G 系列 +- Qualcomm Adreno 系列 +- Nvida tegra系列: tx1, tx2, nano, xavier diff --git a/docs/user_guides/cpp_demo.md b/docs/user_guides/cpp_demo.md new file mode 100644 index 0000000000000000000000000000000000000000..a915a3f05ef133988db10a77584b565352a1a8f6 --- /dev/null +++ b/docs/user_guides/cpp_demo.md @@ -0,0 +1,343 @@ +# C++ Demo + +## 编译 + +首先按照[PaddleLite 源码编译](https://github.com/PaddlePaddle/Paddle-Lite/wiki/source_compile)准备交叉编译环境,之后拉取最新[PaddleLite release发布版代码](https://github.com/PaddlePaddle/Paddle-Lite)。下面以Android-ARMv8架构为例,介绍编译过程,并最终在手机上跑通MobilNetv1模型。 + +进入 Paddle-Lite 目录,运行以下命令编译代码(**需加编译选项`--build_extra=ON`确保完整编译**): + +``` +./lite/tools/build.sh \ + --arm_os=android \ + --arm_abi=armv8 \ + --arm_lang=gcc \ + --android_stl=c++_static \ + --build_extra=ON \ + full_publish +``` + +编译完成后 `./build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/` 文件夹下包含: + +- cxx + - include (头文件文件夹) + - lib (库文件文件夹) + - libpaddle_api_full_bundled.a + - libpaddle_api_light_bundled.a + - libpaddle_light_api_shared.so + - libpaddle_full_api_shared.so +- demo + - cxx (C++ demo) + - mobile_light (light api demo) + - mobile_full (full api demo) + - mobile_detection (detection model api demo) + - mobile_classify (classify model api demo) + - Makefile.def + - include +- third_party (第三方库文件夹) + - gflags + +## 准备执行环境 + +执行环境有两种:使用安卓手机;若没安卓手机,也可在安卓模拟器中执行。 + +### 环境一:使用安卓手机 + +将手机连上电脑,在手机上打开选项 -> 开启-开发者模式 -> 开启-USB调试模式。确保 `adb devices` 能够看到相应的设备。 + +### 环境二:使用安卓模拟器 + +运行下面命令,分别创建安卓armv8、armv7架构的模拟器。若需在真机测试,将模拟器换成相应架构的真机环境即可。 + +``` +*android-armv8* +adb kill-server +adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done +echo n | avdmanager create avd -f -n paddle-armv8 -k "system-images;android-24;google_apis;arm64-v8a" +echo -ne '\n' | ${ANDROID_HOME}/emulator/emulator -avd paddle-armv8 -noaudio -no-window -gpu off -port 5554 & +sleep 1m +``` + +``` +*android-armv7* +adb kill-server +adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done +echo n | avdmanager create avd -f -n paddle-armv7 -k "system-images;android-24;google_apis;armeabi-v7a" +echo -ne '\n' | ${ANDROID_HOME}/emulator/emulator -avd paddle-armv7 -noaudio -no-window -gpu off -port 5554 & +sleep 1m +``` + +## 下载模型并运行示例 + +``` +cd inference_lite_lib.android.armv8/demo/cxx/mobile_full +wget http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz +tar zxvf mobilenet_v1.tar.gz + +make + +adb push mobilenet_v1 /data/local/tmp/ +adb push mobilenetv1_full_api /data/local/tmp/ +adb shell chmod +x /data/local/tmp/mobilenetv1_full_api +adb shell "/data/local/tmp/mobilenetv1_full_api --model_dir=/data/local/tmp/mobilenet_v1 --optimized_model_dir=/data/local/tmp/mobilenet_v1.opt" +``` + +注:我们也提供了轻量级 API 的 demo、图像分类demo和目标检测demo,支持图像输入; + +### Light API Demo + +``` +cd ../mobile_light +make +adb push mobilenetv1_light_api /data/local/tmp/ +adb shell chmod +x /data/local/tmp/mobilenetv1_light_api +adb shell "/data/local/tmp/mobilenetv1_light_api --model_dir=/data/local/tmp/mobilenet_v1.opt " +``` + + +### 图像分类 Demo + +``` +cd ../mobile_classify +wget http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz +tar zxvf mobilenet_v1.tar.gz +make +adb push mobile_classify /data/local/tmp/ +adb push test.jpg /data/local/tmp/ +adb push labels.txt /data/local/tmp/ +adb push ../../../cxx/lib/libpaddle_light_api_shared.so /data/local/tmp/ +adb shell chmod +x /data/local/tmp/mobile_classify +adb shell "export LD_LIBRARY_PATH=/data/local/tmp/:$LD_LIBRARY_PATH && /data/local/tmp/mobile_classify /data/local/tmp/mobilenet_v1.opt /data/local/tmp/test.jpg /data/local/tmp/labels.txt" +``` + +### 目标检测 Demo + +``` +cd ../mobile_detection +wget https://paddle-inference-dist.bj.bcebos.com/mobilenetv1-ssd.tar.gz +tar zxvf mobilenetv1-ssd.tar.gz +make +adb push mobile_detection /data/local/tmp/ +adb push test.jpg /data/local/tmp/ +adb push ../../../cxx/lib/libpaddle_light_api_shared.so /data/local/tmp/ +adb shell chmod +x /data/local/tmp/mobile_detection +adb shell "export LD_LIBRARY_PATH=/data/local/tmp/:$LD_LIBRARY_PATH && /data/local/tmp/mobile_detection /data/local/tmp/mobilenetv1-ssd /data/local/tmp/test.jpg" +adb pull /data/local/tmp/test_detection_result.jpg ./ +``` + +## Demo 程序运行结果 + +### light API Demo 运行结果 + +运行成功后 ,将在控制台输出预测结果的前10个类别的预测概率: + +``` +Output dim: 1000 +Output[0]: 0.000191 +Output[100]: 0.000160 +Output[200]: 0.000264 +Output[300]: 0.000211 +Output[400]: 0.001032 +Output[500]: 0.000110 +Output[600]: 0.004829 +Output[700]: 0.001845 +Output[800]: 0.000202 +Output[900]: 0.000586 +``` + +### 图像分类 Demo 运行结果 + +运行成功后 ,将在控制台输出预测结果的前5个类别的类型索引、名字和预测概率: + +``` +parameter: model_dir, image_path and label_file are necessary +parameter: topk, input_width, input_height, are optional +i: 0, index: 285, name: Egyptian cat, score: 0.482870 +i: 1, index: 281, name: tabby, tabby cat, score: 0.471593 +i: 2, index: 282, name: tiger cat, score: 0.039779 +i: 3, index: 287, name: lynx, catamount, score: 0.002430 +i: 4, index: 722, name: ping-pong ball, score: 0.000508 +``` + +### 目标检测 Demo 运行结果 + +运行成功后 ,将在控制台输出检测目标的类型、预测概率和坐标: + +``` +running result: +detection image size: 935, 1241, detect object: person, score: 0.996098, location: x=187, y=43, width=540, height=592 +detection image size: 935, 1241, detect object: person, score: 0.935293, location: x=123, y=639, width=579, height=597 +``` + +## 如何在代码中使用 API + +在C++中使用PaddleLite API非常简单,不需要添加太多额外代码,具体步骤如下: + +- 加入头文件引用 + +``` + #include + #include + #include "paddle_api.h" + #include "paddle_use_kernels.h" + #include "paddle_use_ops.h" + #include "paddle_use_passes.h" +``` + +- 通过MobileConfig设置:模型文件位置(model_dir)、线程数(thread)和能耗模式( power mode )。输入数据(input),从 MobileConfig 创建 PaddlePredictor 并执行预测。 (注:Lite还支持从memory直接加载模型,可以通过MobileConfig::set_model_buffer方法实现) + +代码示例: + +``` +// 1. Create MobileConfig +MobileConfig config; + +// 2. Load model +config.set_model_dir("path to your model directory"); // model dir +/*load model: Lite supports loading model from file or from memory (naive buffer from optimized model) +//Method One: Load model from memory: +void set_model_buffer(const char* model_buffer, + size_t model_buffer_size, + const char* param_buffer, + size_t param_buffer_size) +//Method Two: Load model from file: +void set_model_dir(const std::string& model_dir) */ + +// 3. Set MobileConfig (or you can skip this step to use default value): +config.set_power_mode(LITE_POWER_HIGH); // power mode +/*power modes: Lite supports the following power modes + LITE_POWER_HIGH + LITE_POWER_LOW + LITE_POWER_FULL + LITE_POWER_NO_BIND + LITE_POWER_RAND_HIGH + LITE_POWER_RAND_LOW */ +config.set_threads("num of threads"); // threads + +// 4. Create PaddlePredictor by MobileConfig +std::shared_ptr predictor = + CreatePaddlePredictor(config); + +// 5. Prepare input data +std::unique_ptr input_tensor(std::move(predictor->GetInput(0))); +input_tensor->Resize({1, 3, 224, 224}); +auto *data = input_tensor -> mutable_data(); +for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) { + data[i] = 1; +} + +// 6. Run predictor +predictor->Run(); + +// 7. Get output +std::unique_ptr output_tensor(std::move(predictor->GetOutput(0))); +``` + +## CxxConfig案例: OCR_model的运行 + +1. OCR 模型文件: + - 我们提供Pb格式的[ocr_attention_mode](https://paddle-inference-dist.cdn.bcebos.com/ocr_attention.tar.gz)l下载 + - 也可以从[Paddle/model项目](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/ocr_recognition)中训练出模型 +2. 示例代码: + + +``` +#include "paddle_api.h" // NOLINT +#include "paddle_use_passes.h" // NOLINT +#include +#include +#include +using namespace paddle::lite_api; // NOLINT + +DEFINE_string(model_dir, "", "Model dir path."); +DEFINE_bool(prefer_int8_kernel, false, "Prefer to run model with int8 kernels"); + +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_dir(FLAGS_model_dir); + std::vector valid_places({Place{TARGET(kARM), PRECISION(kFloat)}}); + if (FLAGS_prefer_int8_kernel) { + valid_places.insert(valid_places.begin(), + Place{TARGET(kARM), PRECISION(kInt8)}); + } + config.set_valid_places(valid_places); + + // 2. Create PaddlePredictor by CxxConfig + std::shared_ptr predictor = + CreatePaddlePredictor(config); + + // 3. Prepare input data + // input 0 + std::unique_ptr input_tensor(std::move(predictor->GetInput(0))); + input_tensor->Resize(shape_t({1, 1, 48, 512})); + auto *data = input_tensor->mutable_data(); + for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) { + data[i] = 1; + } + // input1 + std::unique_ptr init_ids(std::move(predictor->GetInput(1))); + init_ids->Resize(shape_t({1, 1})); + auto *data_ids = init_ids->mutable_data(); + for (int i = 0; i < ShapeProduction(init_ids->shape()); ++i) { + data_ids[i] = 0; + } + + lod_t lod_i; + lod_i.push_back({0, 1}); + lod_i.push_back({0, 1}); + init_ids->SetLoD(lod_i); + // input2 + std::unique_ptr init_scores(std::move(predictor->GetInput(2))); + init_scores->Resize(shape_t({1, 1})); + auto *data_scores = init_scores->mutable_data(); + for (int i = 0; i < ShapeProduction(init_scores->shape()); ++i) { + data_scores[i] = 0; + } + lod_t lod_s; + lod_s.push_back({0, 1}); + lod_s.push_back({0, 1}); + init_scores->SetLoD(lod_s); + + // 4. Run predictor + predictor->Run(); + + // 5. Get output + std::unique_ptr output_tensor( + std::move(predictor->GetOutput(0))); + for (int i = 0; i < ShapeProduction(output_tensor->shape()); i++) { + printf("Output[%d]: %f\n", i, output_tensor->data()[i]); + } +} + +int main(int argc, char **argv) { + google::ParseCommandLineFlags(&argc, &argv, true); + RunModel(); + return 0; +} +``` + +3. 运行方法: + 参考以上代码编译出可执行文件`OCR_DEMO`,模型文件夹为`ocr_attention`。手机以USB调试、文件传输模式连接电脑。 +``` +简单编译出`OCR_DEMO`的方法:用以上示例代码替换编译结果中`build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_full/mobilenetv1_full_api.cc`文件的内容,终端进入该路径(`demo/cxx/mobile_full/`),终端中执行`make && mv mobilenetv1_full_api OCR_DEMO`即编译出了OCR模型的可执行文件`OCR_DEMO` +``` + 在终端中输入以下命令执行OCR model测试: + +``` +#OCR_DEMO为编译出的可执行文件名称;ocr_attention为ocr_attention模型的文件夹名称;libpaddle_full_api_shared.so是编译出的动态库文件,位于`build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/cxx/lib` +adb push OCR_DEMO /data/local/tmp +adb push ocr_attention /data/local/tmp +adb push libpaddle_full_api_shared.so /data/local/tmp/ +adb shell 'export LD_LIBRARY_PATH=/data/local/tmp/:$LD_LIBRARY_PATH && cd /data/local/tmp && ./OCR_DEMO --model_dir=./OCR_DEMO' +``` + +4. 运行结果 + + diff --git a/docs/user_guides/fpga.md b/docs/user_guides/fpga.md new file mode 100644 index 0000000000000000000000000000000000000000..a7c398af2036cab7d914a692ce4f8fdbae13d45c --- /dev/null +++ b/docs/user_guides/fpga.md @@ -0,0 +1,106 @@ +# Lite基于FPGA的模型预测 + +Paddle Lite支持基于arm的FPGA zu3/zu5/zu9的模型预测,提供armv8的交叉编译 + +Lite基于FPGA运行模型需要相应的FPGA驱动,目前只支持百度[Edgeboard开发板](https://ai.baidu.com/tech/hardware/deepkit) + +## Lite实现FPGA简介 + +Lite支持FPGA作为后端硬件进行模型推理,其主要特性如下: + +- Lite中FPGA的kernel(feed、fetch除外)均以FP16、NHWC的格式作为输入输出格式,所有的weights和bias仍为FP32、NCHW的格式,feed的输入和fetch的输出均为FP32、NCHW格式的数据,在提升计算速度的同时能做到用户对数据格式无感知 + +- 对于FPGA暂不支持的kernel,均会切回arm端运行,实现arm+FPGA混合布署运行 + +- 目前FPGA成本功耗都较低,Lite基于FPGA的模型性能远远好于arm端,可作为边缘设备首选硬件 + +## 编译 + +需要提前准备带有FPGAdrv.ko的FPGA开发板(如edgeboard开发板)和Lite代码 + +CMAKE编译选项: + +- 设置`LITE_WITH_FPGA=ON`和`LITE_WITH_ARM=ON` + +其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”](../source_compile)。 +示例如下: +```shell + cmake .. \ + -DWITH_GPU=OFF \ + -DWITH_MKL=OFF \ + -DWITH_LITE=ON \ + -DLITE_WITH_CUDA=OFF \ + -DLITE_WITH_X86=OFF \ + -DLITE_WITH_ARM=ON \ + -DLITE_WITH_OPENMP=ON \ + -DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \ + -DWITH_TESTING=OFF \ + -DLITE_WITH_FPGA=ON \ + -DARM_TARGET_OS=armlinux + make publish_inference -j2 +``` +Lite提供FPGA编译脚本,位于lite/tools/build_FPGA.sh,在Lite根目录执行该脚本即可编译 + +## 运行示例 + +- **运行文件准备** + +下面以Resnet50模型为例,介绍如何使用edgeboard开发板实现模型运行 + +```bash +#连接开发板,并利用screen命令启动 [本机执行] +screen /dev/cu.SLAB_USBtoUART 115200 +#查看开发板ip并ssh登录到开发板,假设开发板ip为192.0.1.1 [本机执行] +ssh root@192.0.1.1 + +#在开发板上建立目录workspace,拷贝FPGA驱动FPGAdrv.ko到workspace目录 [开发板执行] +mkdir workspace && scp $DRIVER_PATH/FPGAdrv.ko workspace + +#将Lite中编译好的测试程序拷贝到开发板workspace目录 [本机执行] +scp $LITE_ROOT/build_FPGA/lite/api/test_resnet50_FPGA root@$EDGEBOARD_IP:workspace/ +#把Resnet50的模型和参数scp到开发板workspace目录 [本机执行] +scp -r $LITE_ROOT/build_FPGA/lite/third_party/install/resnet50/ root@$EDGEBOARD_IP:workspace/ + +#在运行模型前需要加载FPGA驱动 [开发板执行] +insmod FPGAdrv.ko +#给测试程序添加可运行权限 [开发板执行] +chmod +x test_resnet50_FPGA +``` + +- **使用FPGA进行模型预测** + +```bash +#以下命令均在开发板上运行 +#直接运行单测程序 +./test_resnet50_FPGA --model_dir=resnet50 +#如果需要测试性能,可以用repeats参数设置模型运行次数(如1000),同时可以设置预热次数(如10)来让硬件事先运行到稳定水平 +./test_resnet50_FPGA --model_dir=resnet50 --repeats=1000 --warmup=10 +``` + +## 如何在Code中使用 + +在Lite中使用FPGA与ARM相似,具体的区别如下: + +- 由于fpga运行模式为fp16精度、nhwc布局,所以需要修改相应的`valid_place` +- fpga不需要device的初始化和运行模式设置 + +代码示例: +```cpp +lite::Predictor predictor; +std::vector valid_places( + {Place{TARGET(kFPGA), PRECISION(kFP16), DATALAYOUT(kNHWC)},Place{TARGET(kARM)}); + +predictor.Build(model_dir, "", "", valid_places); + +auto* input_tensor = predictor.GetInput(0); +input_tensor->Resize(DDim(std::vector({1, 3, 224, 224}))); +auto* data = input_tensor->mutable_data(); +auto item_size = input_tensor->dims().production(); +//假设设置输入数据全为1 +for (int i = 0; i < item_size; i++) { + data[i] = 1; +} + +predictor.Run(); +auto* out = predictor.GetOutput(0); +``` diff --git a/docs/user_guides/index.rst b/docs/user_guides/index.rst deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/docs/user_guides/java_demo.md b/docs/user_guides/java_demo.md new file mode 100644 index 0000000000000000000000000000000000000000..4a09826cd45f6ae1b8c46331d54d2f61af32fb14 --- /dev/null +++ b/docs/user_guides/java_demo.md @@ -0,0 +1,99 @@ +# Java Demo + +本节中,Java demo 完整代码位于 [demo/java](https://github.com/PaddlePaddle/Paddle-Lite/tree/develop/lite/demo/java) 。 + +要编译和跑起Android demo 程序 PaddlePredictor,你需要准备: + +1. 一台能运行安卓程序的安卓手机 +2. 一台带有AndroidStudio的开发机 + +## 编译 + +首先在PaddleLite的开发 [Docker镜像](../source_compile) 中,拉取最新PaddleLite代码,编译对应你手机架构的预测库, +下面我们以arm8 架构举例。进入paddlelite 目录,运行以下命令: + +```shell +./lite/tools/build.sh \ + --arm_os=android \ + --arm_abi=armv8 \ + --arm_lang=gcc \ + --android_stl=c++_static \ + tiny_publish +``` + +命令完成后查看要存在 + +``` +./build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/java/so/libpaddle_lite_jni.so +./build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/java/jar/PaddlePredictor.jar +./build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/java/android +``` + +libpaddle_lite_jni.so为 PaddleLite c++ 动态链接库,PaddlePredictor.jar为 Java jar 包,两者包含 PaddleLite Java API,接下来 Android Java 代码会使用这些api。android文件夹中则是Android demo。 + +## 准备 demo 需要的其他文件 + +Demo 除了代码,还需要准备在Android工程目录下配置好JNI .so 库(上节提到的`libpaddle_lite_jni.so`),Java .jar 包(上文提到的`PaddlePredictor.jar` ),和模型文件。我们提供了自动化的脚本和手动拷贝两种方法,用户可以根据自己需要选择: + +### 脚本方法 + +进入 `build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/java/android`,我们准备了一个脚本`prepare_demo.bash`,脚本输入一个参数,为你要拷贝的.so 对应的架构文件夹名。 + +例如运行 + +``` +bash prepare_demo.bash arm8 +``` + +该脚本自动下载并解压缩模型文件,拷贝了 .jar 包进demo,还有生成的.so包进`PaddlePredictor/app/src/main/jinLibs/架构文件夹下`, +在我们这个例子里,armv8 就是架构文件夹。备注:这种方式构建的 demo 在 armv8 手机运行正常。如果要demo 程序在别的手机架构(如 armv7)上也运行正常,需要添加别的架构。 + +### 手动拷贝方法 + +接下来我们介绍手动拷贝,如果使用了脚本,那么可以跳过以下手动方法的介绍。 + +### 把 .so 动态库和 .jar 拷贝进安卓demo程序: + +1. 将PaddlePredictor 载入到AndroidStudio。 +2. 将`libpaddle_lite_jni.so`拷贝进 `PaddlePredictor/app/src/main/jinLibs/架构文件夹下` ,比如文件夹arm8里要包含该 .so文件。 +3. 将 `PaddlePredictor.jar` 拷贝进 `PaddlePredictor/app/libs` 下 + +### 把demo使用到的模型文件拷贝进安卓程序: + +下载我们的5个模型文件,并解压缩到 `PaddlePredictor/app/src/main/assets` 这个文件夹中 +需要拷贝的模型文件和下载地址: + +``` +inception_v4_simple_opt.nb http://paddle-inference-dist.bj.bcebos.com/inception_v4_simple_opt.nb.tar.gz +lite_naive_model_opt.nb http://paddle-inference-dist.bj.bcebos.com/lite_naive_model_opt.nb.tar.gz +mobilenet_v1_opt.nb http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1_opt.nb.tar.gz +mobilenet_v2_relu_opt.nb http://paddle-inference-dist.bj.bcebos.com/mobilenet_v2_relu_opt.nb.tar.gz +resnet50_opt.nb http://paddle-inference-dist.bj.bcebos.com/resnet50_opt.nb.tar.gz +``` + +下载完后,assets文件夹里要包含解压后的上面五个模型文件夹,但demo里不需要保存原压缩.tar.gz 文件。 + +注意:输入的模型要求为naive buffer存储格式,您可以通过 [**Model Optimize Tool**](../model_optimize_tool) 将fluid模型转为naive buffer存储格式。 + +## 运行 Android 程序结果 + +以上准备工作完成,就可以开始Build 、安装、和运行安卓demo程序。当你运行PaddlePredictor 程序时,大概会等10秒,然后看到类似以下字样: + +``` +lite_naive_model output: 50.213173, -28.872887 +expected: 50.2132, -28.8729 + +inception_v4_simple test:true +time: xxx ms + +resnet50 test:true +time: xxx ms + +mobilenet_v1 test:true +time: xxx ms + +mobilenet_v2 test:true +time: xxx ms +``` + +该 demo 程序跑我们的 5 个模型,第一个模型结果将真正的头两个数字输出,并在第二行附上期望的正确值。你应该要看到他们的误差小于0.001。后面四个模型如果你看到 `test:true` 字样,说明模型输出通过了我们在 demo 程序里对其输出的测试。time 代表该测试花费的时间。 diff --git a/lite/api/light_api.cc b/lite/api/light_api.cc index 29d8f4f29ab822f8c9601bbd63a3626abbbf1818..d517383d2773a02f9edba46c6df0df131c746876 100644 --- a/lite/api/light_api.cc +++ b/lite/api/light_api.cc @@ -25,6 +25,8 @@ void LightPredictor::Build(const std::string& lite_model_file, } else { LoadModelNaiveFromFile(lite_model_file, scope_.get(), &cpp_program_desc_); } + + DequantizeWeight(); BuildRuntimeProgram(cpp_program_desc_); PrepareFeedFetch(); } diff --git a/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc b/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc index 9d923cb87da5244e4550be3fb6936a650ec9b53a..1f7c4522f159dd080b5965fb383ab6624df3db4e 100644 --- a/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc +++ b/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc @@ -27,10 +27,10 @@ int64_t ShapeProduction(const shape_t& shape) { void RunModel(std::string model_dir) { // 1. Set MobileConfig MobileConfig config; - config.set_model_dir(model_dir); - // To load model transformed by opt after release/v2.3.0, plese use - // `set_model_from_file` listed below. - // config.set_model_from_file(model_dir); + config.set_model_from_file(model_dir); + // NOTE: To load model transformed by model_optimize_tool before + // release/v2.3.0, plese use `set_model_dir` API as listed below. + // config.set_model_dir(model_dir); // 2. Create PaddlePredictor by MobileConfig std::shared_ptr predictor = diff --git a/lite/operators/conv_op.cc b/lite/operators/conv_op.cc index d9c0ecb4fd8457782ac90850b8b6a002c7dfcffe..9ae52d1cb6a406dc8d1059ad97f3757dbc0a31fa 100644 --- a/lite/operators/conv_op.cc +++ b/lite/operators/conv_op.cc @@ -52,12 +52,12 @@ inline int ConvOutputSize(int input_size, return output_size; } -inline void UpdatePaddingAndDilation(std::vector* paddings, - std::vector* dilations, - const std::vector& strides, - const std::string padding_algorithm, - const lite::DDim data_dims, - const lite::DDim& ksize) { +void UpdatePaddingAndDilation(std::vector* paddings, + std::vector* dilations, + const std::vector& strides, + const std::string padding_algorithm, + const lite::DDim data_dims, + const lite::DDim& ksize) { // when padding_desc is "VALID" or "SAME" if (padding_algorithm == "SAME") { for (size_t i = 0; i < strides.size(); ++i) {