提交 cc3972aa 编写于 作者: J juncaipeng 提交者: huzhiqiang

Modify pages (#2068)

上级 2010fb55
无法预览此类型文件
文件已添加
......@@ -3,7 +3,7 @@ layout: post
title: Benchmark 数据
---
可以参考[benchmark_tools]({{ site.baseurl }}/benchmark_tools),推荐**一键benchmark**
可以参考[benchmark_tools](../benchmark_tools),推荐**一键benchmark**
## 测试环境
......
......@@ -71,7 +71,7 @@ wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_bin_v8
#### 方式二:由源码编译benchmark_bin文件
根据[源码编译]({{ site.baseurl }}/source_compile)准备编译环境,拉取PaddleLite最新release发布版代码,并在仓库根目录下,执行:
根据[源码编译](../source_compile)准备编译环境,拉取PaddleLite最新release发布版代码,并在仓库根目录下,执行:
```shell
###########################################
......@@ -120,7 +120,7 @@ tar zxvf benchmark_models.tar.gz
> 注:若要使用测试脚本,**对单个模型测试**,请把单个模型放入 `benchmark_models` 文件夹,并确保测试脚本、`benchmark_models`文件夹在同一级的目录。
注:上述模型都已经使用`model_optimize_tool`进行转化,而且Lite移动端只支持加载转化后的模型。如果需要测试其他模型,请先参考[模型转化方法]({{ site.baseurl }}/model_optimize_tool)。
注:上述模型都已经使用`model_optimize_tool`进行转化,而且Lite移动端只支持加载转化后的模型。如果需要测试其他模型,请先参考[模型转化方法](../model_optimize_tool)
### 3. benchmark.sh脚本
......
......@@ -5,7 +5,7 @@ title: C++ API接口使用指南
# C++ API接口使用指南
请参考[源码编译]({{ site.baseurl }}/source_compile)确保 Lite 可以正确编译,下面用Lite的c++接口加载并执行 MobileNetV1 模型为例,详细说明使用方法。
请参考[源码编译](../source_compile)确保 Lite 可以正确编译,下面用Lite的c++接口加载并执行 MobileNetV1 模型为例,详细说明使用方法。
## 准备模型
......@@ -13,11 +13,11 @@ Lite支持PaddlePaddle训练好的模型,MobileNetV1模型可以由以下三
- 直接下载训练好的[MobileNetV1模型](https://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz)
- 使用[PaddlePaddle](https://paddlepaddle.org.cn/)构建MobileNetV1网络并训练
- 使用[X2Paddle]({{ site.baseurl }}/x2paddle)对caffe或者tensorflow的MobileNetV1模型进行转换得到
- 使用[X2Paddle](../x2paddle)对caffe或者tensorflow的MobileNetV1模型进行转换得到
## 模型优化
使用Model Optimize Tool优化模型,使得模型预测过程表现出优异的性能。Model Optimize Tool的具体使用方法请参考[文档]({{ site.baseurl }}/model_optimize_tool)。
使用Model Optimize Tool优化模型,使得模型预测过程表现出优异的性能。Model Optimize Tool的具体使用方法请参考[文档](../model_optimize_tool)
- 准备model_optimize_tool
- 使用model_optimize_tool优化模型
......
---
layout: post
title: 基础须知
---
可以参考 [Paddle 开发者文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/advanced_usage/development/contribute_to_paddle/local_dev_guide.html)
# 提交PR
需要在 commit message 里加上 `test=develop` 才能触发 CI
# 版本发布检查清单
1. 所有 feature 梳理,确认状态
2. 所有 QA 测试结果梳理,确认版本可靠
3. Release note 确认 review 通过
4. 确认需要 release 的 binary 编译完毕
......@@ -24,7 +24,7 @@ CMAKE编译选项:
- 设置`LITE_WITH_FPGA=ON``LITE_WITH_ARM=ON`
其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”]({{ site.baseurl }}/source_compile)。
其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”](../source_compile)
示例如下:
```shell
cmake .. \
......
---
layout: post
title: Paddle-Lite文档
---
Paddle-Lite 框架是 PaddleMobile 新一代架构,重点支持移动端推理预测,特点**高性能、多硬件、轻量级** 。支持PaddleFluid/TensorFlow/Caffe/ONNX模型的推理部署,目前已经支持 ARM CPU, Mali GPU, Adreno GPU, Huawei NPU 等>多种硬件,正在逐步增加 X86 CPU, Nvidia GPU 等多款硬件,相关硬件性能业内领先。
## 简介
- [技术特点](../tech_highlights)
- [架构设计](../architecture)
- [Road Map](../roadmap)
## Benchmark
- [最新性能](../benchmark)
- [测试方法](../benchmark_tools)
## 安装
- [源码编译](../source_compile)
## 使用
- [使用流程](../tutorial)
- [C++实例](../cpp_demo)
- [Java实例](../java_demo)
- [Android/IOS APP demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)
- [模型转化方法](../model_optimize_tool)
## 进阶
- [通过 X2Paddle 支持 Caffe, TensorFlow 模型](../x2paddle)
- [模型量化](../model_quantization)
- [支持Op列表](../support_operation_list)
- [新增Op方法](../add_new_operation)
- [测试工具](../debug_tools)
- [调试方法](../debug_tools)
- [使用华为NPU](../npu)
- [使用Android GPU](../opencl)
- [使用FPGA](../fpga)
## 开发者文档
- [开发基础须知](../for-developer)
- [架构详解](../architecture-intro)
## FAQ
- 问题或建议可以[发Issue](https://github.com/PaddlePaddle/Paddle-Lite/issues),为加快问题解决效率,可先检索是否有类似问题,我们也会及时解答!
- 欢迎加入Paddle-Lite百度官方QQ群:696965088
## paddle-mobile
- [paddle-mobile 编译](../mobile)
......@@ -26,7 +26,7 @@ title: Java Android Demo
## 编译
首先在PaddleLite的开发 [Docker镜像]({{ site.baseurl }}/source_compile) 中,拉取最新PaddleLite代码,编译对应你手机架构的预测库,
首先在PaddleLite的开发 [Docker镜像](../source_compile) 中,拉取最新PaddleLite代码,编译对应你手机架构的预测库,
下面我们以arm8 架构举例。进入paddlelite 目录,运行以下命令:
```shell
......@@ -90,7 +90,7 @@ resnet50_opt.nb http://paddle-inference-dist.bj.bcebos.com/resnet50_o
下载完后,assets文件夹里要包含解压后的上面五个模型文件夹,但demo里不需要保存原压缩.tar.gz 文件。
注意:输入的模型要求为naive buffer存储格式,您可以通过 [**Model Optimize Tool**]({{ site.baseurl }}/model_optimize_tool) 将fluid模型转为naive buffer存储格式。
注意:输入的模型要求为naive buffer存储格式,您可以通过 [**Model Optimize Tool**](../model_optimize_tool) 将fluid模型转为naive buffer存储格式。
## 运行 Android 程序结果
......
......@@ -18,7 +18,7 @@ chmod 777 model_optimize_tool
### 编译model_optimize_tool
1、参照 [编译安装]({{ site.baseurl }}/source_compile) 进行环境配置和编译
1、参照 [编译安装](../source_compile) 进行环境配置和编译
2、进入docker中PaddleLite根目录,```git checkout develop```切换到develop分支
......
......@@ -26,7 +26,7 @@ CMAKE编译选项:
- 设置`LITE_WITH_NPU=ON``LITE_WITH_ARM=ON`
- 设置DDK根目录路径 `NPU_DDK_ROOT`
其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”]({{ site.baseurl }}/source_compile)。
其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”](../source_compile)
示例如下:
```shell
......
......@@ -12,9 +12,9 @@ Lite框架目前支持的模型结构为[PaddlePaddle](https://github.com/Paddle
# 二. 模型优化
Lite框架拥有强大的加速、优化策略及实现,其中包含诸如量化、子图融合、Kernel优选等等优化手段,为了方便您使用这些优化策略,我们提供了[Model Optimize Tool]({{ site.baseurl }}/model_optimize_tool)帮助您轻松进行模型优化。优化后的模型更轻量级,耗费资源更少,并且执行速度也更快。
Lite框架拥有强大的加速、优化策略及实现,其中包含诸如量化、子图融合、Kernel优选等等优化手段,为了方便您使用这些优化策略,我们提供了[Model Optimize Tool](../model_optimize_tool)帮助您轻松进行模型优化。优化后的模型更轻量级,耗费资源更少,并且执行速度也更快。
Model Optimize Tool的详细介绍,请您参考 [模型优化方法]({{ site.baseurl }}/model_optimize_tool) 。
Model Optimize Tool的详细介绍,请您参考 [模型优化方法](../model_optimize_tool)
使用Model Optimize Tool,您只需执行以下代码:
## 1. Android
......@@ -72,8 +72,8 @@ $ adb shell
# 四. Lite API
为了方便您的使用,我们提供了C++与Java两种API,并且提供了相应的api使用的[完整示例]({{ site.baseurl }}/demos),您可以参考示例中的说明快速了解C++/Java的API使用方法,并集成到您自己的项目中去。需要说明的是,为了减少第三方库的依赖、提高Lite预测框架的通用性,在移动端使用Lite API您需要准备Naive Buffer存储格式的模型,具体方法可参考第2节`模型优化`
为了方便您的使用,我们提供了C++与Java两种API,并且提供了相应的api使用的[完整示例](../demos),您可以参考示例中的说明快速了解C++/Java的API使用方法,并集成到您自己的项目中去。需要说明的是,为了减少第三方库的依赖、提高Lite预测框架的通用性,在移动端使用Lite API您需要准备Naive Buffer存储格式的模型,具体方法可参考第2节`模型优化`
# 五. 测试工具
为了使您更好的了解并使用Lite框架,我们向有进一步使用需求的用户开放了 [Lite Model Debug Tool]({{ site.baseurl }}/debug_tools) 和 [Profile Monitor Tool]({{ site.baseurl }}/debug_tools)。Lite Model Debug Tool可以用来查找Lite框架与PaddlePaddle框架在执行预测时模型中的对应变量值是否有差异,进一步快速定位问题Op,方便复现与排查问题。Profile Monitor Tool可以帮助您了解每个Op的执行时间消耗,其会自动统计Op执行的次数,最长、最短、平均执行时间等等信息,为性能调优做一个基础参考。您可以通过 [相关专题]({{ site.baseurl }}/debug_tools) 了解更多内容。
为了使您更好的了解并使用Lite框架,我们向有进一步使用需求的用户开放了 [Lite Model Debug Tool](../debug_tools)[Profile Monitor Tool](../debug_tools)。Lite Model Debug Tool可以用来查找Lite框架与PaddlePaddle框架在执行预测时模型中的对应变量值是否有差异,进一步快速定位问题Op,方便复现与排查问题。Profile Monitor Tool可以帮助您了解每个Op的执行时间消耗,其会自动统计Op执行的次数,最长、最短、平均执行时间等等信息,为性能调优做一个基础参考。您可以通过 [相关专题](../debug_tools) 了解更多内容。
---
layout: post
title: 新增op的方法
---
以下以添加argmax为例,详细说明新增op的方法步骤。
## 1. 添加OpParam 结构体以传导 Op 的输入和输出
- 这里命名为 `ArgmaxParam`
-`paddlelite/lite/operators/op_params.h` 中添加 `ArgmaxParam` 结构体,代码如下:
```c++
struct ArgmaxParam {
lite::Tensor* X{};
lite::Tensor* Out{};
int Axis{0};
};
```
## 2. 添加 Argmax Op 并注册
- 在paddlelite/lite/operators/目录下新建argmax_op.h文件,主要代码如下:
```c++
class ArgmaxOpLite : public OpLite {
public:
ArgmaxOpLite() {}
explicit ArgmaxOpLite(const std::string &op_type) : OpLite(op_type) {}
bool CheckShape() const override;
bool InferShape() const override;
bool AttachImpl(const cpp::OpDesc &opdesc, lite::Scope *scope) override;
void AttachKernel(KernelBase *kernel) override { kernel->SetParam(param_); }
std::string DebugString() const override { return "argmax"; }
private:
mutable ArgmaxParam param_;
};
```
`ArgmaxOpLite` 继承 `OpLite` ,成员变量包括 `ArgmaxParam` 结构体,需要实现的接口包括 `CheckShape()``InferShape()``AttachImp()``AttachKernel()``DebugString()` 函数。`AttachKernel()``DebugString() `函数较为简单,此处直接实现;
-`paddlelite/lite/operators/` 目录下新建argmax_op.cc文件,需要具体实现`CheckShape()``InferShape()``AttachImp()`函数。`CheckShape()`函数检查输入是否符合要求,`InferShape()`函数基于输入推断得到输出的维度,`AttachImp()`函数绑定Op的输入输出。然后在argmax_op.cc文件中注册argmax,核心代码如下:
```c++
bool ArgmaxOpLite::CheckShape() const {
CHECK_OR_FALSE(param_.X);
CHECK_OR_FALSE(param_.Out);
CHECK_OR_FALSE(param_.Axis < (param_.X)->dims().size());
return true;
}
bool ArgmaxOpLite::InferShape() const {
auto x_dims = param_.X->dims();
int x_rank = x_dims.size();
int axis = param_.Axis;
if (axis < 0) axis += x_rank;
std::vector<int64_t> out_dims;
for (int64_t i = 0; i < axis; i++) {
out_dims.push_back(x_dims[i]);
}
for (int64_t i = axis + 1; i < x_rank; i++) {
out_dims.push_back(x_dims[i]);
}
// Set output dims
param_.Out->Resize(lite::DDim(out_dims));
return true;
}
bool ArgmaxOpLite::AttachImpl(const cpp::OpDesc &op_desc, lite::Scope *scope) {
auto x = op_desc.Input("X").front();
auto out = op_desc.Output("Out").front();
param_.X = scope->FindVar(x)->GetMutable<lite::Tensor>();
param_.Out = scope->FindVar(out)->GetMutable<lite::Tensor>();
param_.Axis = op_desc.GetAttr<int>("Axis");
return true;
}
REGISTER_LITE_OP(argmax, paddle::lite::operators::ArgmaxOpLite);
```
- 在paddlelite/lite/operators/CMakeLists.txt中添加```lite_cc_library(argmax_op SRCS argmax_op.cc DEPS ${op_DEPS})```,并且在set ops lite 中添加argmax_op;
- 在paddlelite/lite/api/paddle_use_ops.h中添加```USE_LITE_OP(argmax)```
## 3. 添加Argmax Kernel并绑定
以下以arm端argmax实现为例说明
- 在paddlelite/lite/kernels/arm/目录下新建argmax_compute.h文件,声明ArgmaxCompute类,并继承KernelLite,主要代码如下:
```c++
class ArgmaxCompute : public KernelLite<TARGET(kARM), PRECISION(kFloat)> {
public:
using param_t = operators::ArgmaxParam;
void Run() override;
virtual ~ArgmaxCompute() = default;
};
```
- 在paddlelite/lite/kernels/arm/目录下新建argmax_compute.cc文件,主要实现Run函数。`Run()`函数调用paddlelite/lite/arm/math/argmax.h中的`argmax_func()`函数,根据输入计算输出。最后在argmax_compute.cc文件中,我们绑定argmax的输入输出(为tensor的输入参数都需要绑定),代码如下:
```c++
void ArgmaxCompute::Run() {
auto& param = Param<operators::ArgmaxParam>();
lite::Tensor* input = param.X;
lite::Tensor* output = param.Out;
int axis = param.Axis;
lite::arm::math::argmax_func(input, axis, output);
return;
}
REGISTER_LITE_KERNEL(
argmax, kARM, kFloat, kNCHW, paddle::lite::kernels::arm::ArgmaxCompute, def)
.BindInput("X", {LiteType::GetTensorTy(TARGET(kARM))})
.BindOutput("Out", {LiteType::GetTensorTy(TARGET(kARM))})
.Finalize();
```
- 在paddlelite/lite/kernels/arm/CMakeLists.txt中添加
```cmake
lite_cc_library(argmax_compute_arm SRCS argmax_compute.cc DEPS ${lite_kernel_deps} math_arm)
```
CMakeLists.txt中set arm_kernels需要添加argmax_compute_arm;
- 在paddlelite/lite/api/paddle_use_kernels.h中添加```USE_LITE_KERNEL(argmax, kARM, kFloat, kNCHW, def)```
## 4. 添加Argmax实现
- 在paddlelite/lite/arm/math/目录下新建argmax.h文件,声明`argmax_func()`函数,代码如下:
```c++
void argmax_func(const lite::Tensor* input, const int axis, lite::Tensor* output);
```
- 在paddlelite/lite/arm/math/目录下新建argmax.cc文件,具体实现`argmax_func()`函数,代码如下:
```c++
void argmax_func(const lite::Tensor *input,
const int axis,
lite::Tensor *output) {
auto input_ddim = input->dims();
auto output_ddim = output->dims();
const int size = input_ddim[axis];
const int in_channel = input_ddim.count(axis, input_ddim.size());
const int out_channel = output_ddim.count(axis, output_ddim.size());
const int in_stride = input_ddim.count(axis + 1, input_ddim.size());
const int out_stride = input_ddim.count(0, axis);
for (int n = 0; n < out_stride; n++) {
for (int k = 0; k < in_stride; k++) {
const float *in_ptr = input->data<float>() + n * in_channel + k;
std::vector<std::pair<float, int>> vec;
vec.resize(size);
for (int i = 0; i < size; i++) {
vec[i] = std::make_pair(in_ptr[i * in_stride], i);
}
// sort
std::partial_sort(vec.begin(),
vec.begin() + 1,
vec.end(),
std::greater<std::pair<float, int>>());
// out
float *out_ptr = output->mutable_data<float>() + n * out_channel + k;
*out_ptr = vec[0].second;
}
}
}
```
- 在paddlelite/lite/arm/math/CMakeFile.txt中的```math_arm library```中添加argmax.cc,在paddlelite/lite/arm/math/funcs.h中添加```#include "lite/arm/math/argmax.h"```
## 5. 添加Argmax单测
- 在paddlelite/lite/tests/kernels目录下新建argmax_compute_test.cc文件,声明并实现ArgmaxComputeTester类;
- ArgmaxComputeTester类中主要包括PrepareOpDesc、PrepareData和RunBaseline函数。PrepareOpDesc函数设定单测op的类型和输入输出参数,PrepareData函数对输入tensor进行初始化,RunBaseline是基于输入计算得到输出,用于和框架计算的输出进行对比;
- 使用gtest添加单测,代码如下:
```c++
TEST(Argmax, precision) {
#ifdef LITE_WITH_ARM
LOG(INFO) << "test argmax arm";
Place place(TARGET(kARM));
for (int axis : {0, 1, 2, 3}) {
for (int n : {1, 3}) {
for (int c : {3, 6}) {
for (int h : {9, 18}) {
for (int w : {9, 18}) {
std::unique_ptr<arena::TestCase> tester(
new ArgmaxComputeTester(place, "def", axis, n, c, h, w));
arena::Arena arena(std::move(tester), place, 2e-5);
arena.TestPrecision();
}
}
}
}
}
#endif
}
```
- 在paddlelite/lite/tests/kernels/CMakeLists.txt中添加
```cmake
lite_cc_test(test_kernel_argmax_compute SRCS argmax_compute_test.cc DEPS arena_framework ${x86_kernels} ${arm_kernels} ${lite_ops} ${host_kernels})
```
# 6. 编译运行
- 在paddlelite目录中,执行```./lite/tools/ci_build.sh build_test_arm```,该脚本会创建手机模拟器,并编译运行所有单测(花费时间较久)。如果运行无误,则表明添加argmax成功。
---
layout: post
title: Paddle-Lite 开发者文档
---
这篇文档会从开发者角度详细介绍开发 Paddle-Lite 需要的相关信息。
## 设计及思考
近年来,各种深度学习预估硬件称出不穷,从手机APP到车载设备,再到音箱,均需要部署深度学习预测,且有如下共性需求:
1. 高性能
2. 硬件支持和扩展容易
3. 轻量级部署
Paddle-Lite 的架构方面便是定向参考如上需求设计实现的,具体地
- 高性能方面
- 通过 MIR(Machine IR) 实现精细复杂的计算图的分析和优化
- 执行期 Kernel 的简单设计,几乎没有额外调度开销
- 适当的硬件层抽象,框架支持各个硬件后端中做特定的调度实现
- 轻量级部署方面
- 拆分分析和执行两个阶段,执行阶段轻量级实现,可以单独部署
- 轻量级 Op 和 Kernel 设计
- 硬件支持和扩展方面
- 通过 MIR 支撑带硬件和执行信息的宏观分析优化
- TypeSystem 抽象带硬件的不同计算模式的表示,实现整个计算图的强类型推导,以及执行状态机的静态分析
Paddle-Lite 的架构尝试从强类型推导的角度建模支持多硬件,多种计算模式(不同量化精度、不同的 data layout等)的混合计算,从而实现宏观上的各异硬件和计算模式的混合。
框架部分已经经过 FPGA,GPU,NPU 等异构硬件的打磨,各项能力也在完善中。
## 重要模块介绍
### OpLite
[OpLite](https://github.com/PaddlePaddle/Paddle-Lite/blob/v2.0.0-beta1-prerel/lite/core/op_lite.h#L52) 是 Paddle-Lite 中的 Operator,用户扩展单个硬件时,最多的就是扩展 Op 和 Kernel。
重要方法如下:
```c++
class OpLite : public Registry {
public:
// Check the shape.
virtual bool CheckShape() const { return true; }
// Inference the outputs' shape.
virtual bool InferShape() const { return true; }
// Link the external execution environ to internal context.
bool AttachImpl(const cpp::OpDesc &opdesc, lite::Scope *scope);
};
```
其中,分析期执行
- `AttachImpl`
执行期执行
- `CheckShape`
- `InferShape`
扩展须知:
1. `CheckShape` 只在第一个 batch 执行,所以耗时不敏感
2. `InferShape` 需要在每个 batch 执行,应该严格耗时
1. 可以通过添加 member variable 的方式,对其中一部分信息增加 cache,比如
```c++
class XXOp : public OpLite {
void InferShape() {
int batch_size = param().input.shape[0];
if (!shape_cache_.empty()) {
shape_cache_[0] = batch_size;
param().output->Resize(shape_cache_);
}
}
private:
shape_t shape_cache_;
}
```
### OpParam
[OpParam](https://github.com/PaddlePaddle/Paddle-Lite/blob/v2.0.0-beta1-prerel/lite/operators/op_params.h) 用于存储执行期 Kernel 需要的各项参数。 所有字段可以直接存储(比如指针或者 `int`),以避免执行中获取参数的延迟。
因为没有需求,OpParam 暂时没有设置基类。
实际例子:
```c++
// For Softmax op
struct SoftmaxParam {
lite::Tensor* x{};
lite::Tensor* output{};
int axis{-1};
};
```
OpLite 的 `AttachImpl` 方法就用于构建 `OpParam` ,复制传递给 `Kernel` 用于执行。
OpParam 是执行期的重要模块,需要严格保证性能,相应的扩展要求:
1. 字段的获取必须是低延迟的,可以直接用指针,或者直接复制值
2. 避免执行无关信息混入,包括 debug 信息
3. 命名需要与 Paddle OpDesc 中的信息严格一致,以降低功能对齐和理解的难度
### Kernel
```c++
template <TargetType Target,
PrecisionType Precision,
DataLayoutType DataLayout = DataLayoutType::kNCHW>
class KernelLite : public KernelBase {
public:
// Run the kernel.
virtual void Run() { CHECK(false) << "Not Implemented"; }
TargetType target() const override { return Target; }
PrecisionType precision() const override { return Precision; }
DataLayoutType layout() const override { return DataLayout; }
Place place() const override { return Place{Target, Precision, DataLayout}; }
std::string name() const override;
};
```
由于是执行期的重要概念,因此 Kernel 设计地非常简单高效。
其中,执行期的 `Run` 是其唯一重要的接口,其中包含具体的计算逻辑。
模板中的参数主要用于方便多硬件编译,以及自解释:
- Target: 执行硬件
- Precision: 主要的计算精度
- DataLayout:主要计算的 data layout
这部分信息用于帮助挑选 kernel,具体的值并不严格。
Kernel 的注册需要用到 TypeSystem,不光对 Kernel 本身的特性进行描述,对其输入和输出均进行详尽的定义。
例如 FullyConnected 的注册
```c++
REGISTER_LITE_KERNEL(
fc, kARM, kFloat, kNCHW, paddle::lite::kernels::arm::FcCompute, def)
.BindInput("Input", {LiteType::GetTensorTy(TARGET(kARM), PRECISION(kFloat), LAYOUT(kNCHW))})
.BindInput("Bias", {LiteType::GetTensorTy(TARGET(kARM))})
.BindInput("W", {LiteType::GetTensorTy(TARGET(kARM))})
.BindOutput("Out", {LiteType::GetTensorTy(TARGET(kARM))})
.Finalize();
```
Kernel自身定义是 `kARM` 的,也就是ARM上的kernel,主要的计算精度是 `kFloat`,主要的 Data layout 是 `kNCHW`
接着会对其所有的输入和输出做详细定义,比如看 `Input` 输入的定义是 `LiteType::GetTensorTy(TARGET(kARM), PRECISION(kFloat), LAYOUT(kNCHW))`,也就是声明其 Target 是 `kARM`, PRECISION 是 `kFloat`,Data Layout 是 `kNCHW`
这里的设计思想是类似C++中的函数重载,同一个 Kernel(的名字),在重载了其输入输出的类型之后可以是不同的kernel。
#### 扩展须知
1. 模板参数选用计算中主要的来表示
1. 比如,scale kernel,同时能接受 `float``int` 的输入,但其不算量化 kernel,那应该设置为 `Precision=float`,代表常规的计算精度中使用
2. Kernel 输入输出的定义需要足够精确,是什么类型就是什么类型;框架会根据其输入输出的定义来动态构建状态机,否则会出现分析期和执行期的状态机不一致,造成未定义行为
### MIR
MIR 类似于 LLVM 里的 IR,只是加上了硬件和执行期的信息参与分析优化。
Pass 是MIR中的模块化策略,其输入和输出都是 SSA Graph.
框架会自动基于模型的Program 构建 SSA Graph,之后按 [Optimizer](https://github.com/PaddlePaddle/Paddle-Lite/blob/v2.0.0-beta1-prerel/lite/core/optimizer.h) 中定义的pass的顺序调用一系列 Pass。
#### Op Fusion
MIR 中的 [PatternMacher](https://github.com/PaddlePaddle/Paddle-Lite/blob/v2.0.0-beta1-prerel/lite/core/mir/pattern_matcher.h) 实现了简单有效的基于图的模板识别的算法,相关的 op fusion 的图操作可以基于此实现。
实际的例子可以参考 [fc_fuse_pass.h](https://github.com/PaddlePaddle/Paddle-Lite/blob/v2.0.0-beta1-prerel/lite/core/mir/fusion/fc_fuse_pass.h)
### TypeSystem
TypeSystem 是 Paddle-Lite 中构建复杂计算图的基础模块,核心思想是协助 SSA Graph 构建一个状态机,表示其中不同的状态。
这里的 Type 主要包含下面四组信息,更多的信息可以按需扩展:
- TargetType
- Precision
- DataLayout
- device id,用于表示卡号
状态机的表示:
```python
Tensor0(kARM, kFloat, kNCHW) --pass--> Tensor1(kOpenCL, kFloat, kNCHW)
```
MIR 会识别出,Tensor0 和 Tensor1 的硬件位置不同,因此触发相依的 Pass 插入对应的 cast op 来进行 type cast,比如
```
Tensor0(kARM, kFloat, kNCHW) --pass-> IoCopyOp(kARM, kOpenCL) --pass-> Tensor1(kOpenCL, kFloat, kNCHW)
```
### KernelContext
KernelContext 是硬件支持的核心封装,主要用于为 Kernel 提供执行期的硬件上下文。
KernelContext 的设计类似于 OpParam,两者均没有基类;对于 KernelContext,其假定是,不同的硬件间的接口和逻辑可能完全不同,比如 kARM 和 kCUDA,因此不设定基类,也不需要提供统一的接口来封装不同硬件行为。
不同硬件的 KernelContext 直接与该硬件对应的 Kernel 对接。
KernelContext 的行为可以被 MIR 在分析期确定和调度。
注意事项:
1. 由于是执行期概念,KernelContext 也需要注意性能和轻量化
2. 移动端部署时只会部署执行期,因此 MIR 和 KernelContext 会拆开,因此 KernelContext 相应的设置需要能够序列化到 ProgramDesc 中,以便执行期载入和执行
## 扩展硬件后端
### 扩展现有的硬件后端
主要是扩充 Op 和 Kernel 的工作,如果需要 fuse,则参考 MIR 章节,增加相应的fuse pass便可,具体地,可以参考
- [fc_op](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/operators/fc_op.h) 实现类似的 Op
- [fc_compute](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/kernels/arm/fc_compute.h) 实现类似的 Kernel
- [fc_fuse_pass](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/mir/fusion/fc_fuse_pass.h) 实现fuse逻辑,并注册到 [optimizer](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/optimizer.h)
### 扩展全新硬件后端
需要额外扩充如下模块,让框架能够支撑硬件执行:
- TypeSystem,需要扩充其中相关的 type
- 相关 [enum](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/api/paddle_place.h#L44)
- MIR,需要扩展其中的 type cast 相关的 pass
- [TargetType cast pass](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/mir/type_target_cast_pass.cc) 用于拷贝不同硬件上的tensor
- [Data layout cast pass](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/mir/type_target_cast_pass.h) 用于转化不同的 data layout
- [Precision cast pass](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/mir/type_precision_cast_pass.h) 用于转化不同 tensor 的量化精度
- KernelContext,具体地可以参考
- [ARM context](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.0.0-beta1/lite/core/context.h#L91)
- 需要注意的是,硬件 context 的接口只服务于该硬件的 kernel
- context 有分析期和执行期两个阶段,如果分析期没有特殊的优化,则无需考虑;否则,需要注意将分析期的信息整理并序列化到离线模型中,用于执行期直接加载。
\ No newline at end of file
---
layout: post
title: 架构设计
---
Mobile 在这次升级为 Lite 架构, 侧重多硬件、高性能的支持,其主要设计思想如下
- 引入 Type system,强化多硬件、量化方法、data layout 的混合调度能力
- 硬件细节隔离,通过不同编译开关,对支持的任何硬件可以自由插拔
- 引入 MIR(Machine IR) 的概念,强化带执行环境下的优化支持
- 优化期和执行期严格隔离,保证预测时轻量和高效率
架构图如下
![Paddle Inference Refactor1.0](https://user-images.githubusercontent.com/52520497/64949619-26e49580-d8ac-11e9-855a-514feb9b75af.png)
## 编译期和执行期严格隔离设计
- compile time 优化完毕可以将优化信息存储到模型中;execution time 载入并执行
- 两套 API 及对应的预测lib,满足不同场景
- `CxxPredictor` 打包了 `Compile Time``Execution Time`,可以 runtime 在具体硬件上做分析和优化,得到最优效果
- `MobilePredictor` 只打包 `Execution Time`,保持部署和执行的轻量
## `Execution Time` 轻量级设计和实现
- 每个 batch 实际执行只包含两个步骤执行
- `Op.InferShape`
- `Kernel.Run`,Kernel 相关参数均使用指针提前确定,后续无查找或传参消耗
- 设计目标,执行时,只有 kernel 计算本身消耗
- 轻量级 `Op``Kernel` 设计,避免框架额外消耗
- `Op` 只有 `CreateKernels``InferShape` 两个重要职能
- `Kernel` 只有 `Run` 职能
## 多硬件后端支持
- 硬件通用行为,使用 `TargetWrapper` 模块做适配器适配,对上层框架提供一致界面
- 框架上层策略保持硬件无关,如存储优化 (Memory optimize),计算剪枝 (Computation prune) 等,任何硬件接入均可直接复用
- 框架支持了硬件通用行为,特定硬件细节不做过多约束,各硬件可以自行实现并接入框架
- 计算模式上目前支持两种主流模型,一种是类似 X86, ARM CPU 等非异构设备;一种是 GPU,或 FPGA 等异构设备(支持 stream, event异步执行模式以及跨设备拷贝)
---
## 多硬件及算法混合调度支持
`TensorTy` 用来表示 Tensor 类型
```c++
struct TensorTy {
TargetType target;
PrecisionType precision;
DataLayout layout;
int deviceid;
};
```
```c++
enum class TargetType { kARM, kX86, kCUDA, kOpenCL };
enum class PrecisionType { kFP32, kFP16, kInt8, kInt16 };
enum class DataLayout { kNCHW, kNHWC };
```
---
注册 Kernel,确定特定 Kernel 的输入输出特征
```c++
REGISTER_LITE_KERNEL(
mul, kARM, kFloat, kNCHW, arm::MulCompute, def)
.BindInput("X", {LiteType::GetTensorTy(kARM, kFloat, kNCHW)})
.BindInput("Y", {LiteType::GetTensorTy(kARM, kFloat, kNCHW))})
.BindOutput("Out", {LiteType::GetTensorTy(kARM, kFloat, kNCHW)})
.Finalize();
```
---
同一个 Op 的不同 Kernel 类似函数重载
用于支持任意的混合调度:
1. 标记模型中所有 tensor 的 Type
2. 标记 Kernel 的 硬件、执行精度、data layout 等信息
全局做类型推断,当发现 tensor 传递中有类型冲突,采用 type cast 操作,通过插入特定功能 Op 来实现正确的传导
![lite-7](https://user-images.githubusercontent.com/52520497/64949642-395ecf00-d8ac-11e9-8b69-ced1996abc3b.png)
---
## MIR 用于图分析优化
基于 Type System 的 SSA,通过 IR Pass 对计算图进行分析和优化:
- 支持对整个 graph 进行类型推断,发现类型冲突并加入 type cast op,来支持通用混合调度
- 计算剪枝 (Compute prune),比如去掉 scale(1), assign op 等
- 存储优化 (Memory optimize)
- 操作熔合 (Operator fuse)(已经支持 fc, conv_bn, ele_add+act 等6种 fuse 策略)
- 支持量化处理(已支持 Int8预测)
\ No newline at end of file
---
layout: post
title: Benchmark 数据
---
可以参考[benchmark_tools](../benchmark_tools),推荐**一键benchmark**
## 测试环境
* 测试模型
* fp32模型
* mobilenet_v1
* mobilenet_v2
* squeezenet_v1.1
* mnasnet
* shufflenet_v2
* int8模型
* mobilenet_v1
* mobilenet_v2
* resnet50
* 测试机器(android ndk ndk-r17c)
* 骁龙855
* xiaomi mi9, snapdragon 855
* 4xA76(1@2.84GHz + 3@2.4GHz) + 4xA55@1.78GHz
* 骁龙845
* xiaomi mi8, 845
* 2.8GHz(大四核),1.7GHz(小四核)
* 骁龙835
* xiaomi mix2, snapdragon 835
* 2.45GHz(大四核),1.9GHz(小四核)
* 骁龙625
* oppo R9s, snapdragon625
* A53 x 8, big core@2.0GHz
* 骁龙653
* 360 N5, snapdragon 653
* 4 x A73@2.0GHz + 4 x A53@1.4GHz
* 麒麟970
* HUAWEI Mate10
* 测试说明
* commit id: 12c129affaacd476e27a0a82b235a9d547d33f0f
* warmup=10, repeats=30,统计平均时间,单位是ms
* 当线程数为1时,```DeviceInfo::Global().SetRunMode```设置LITE_POWER_HIGH,否者设置LITE_POWER_NO_BIND
* 模型的输入图像的维度是{1, 3, 224, 224},输入图像的每一位数值是1
## 测试数据
### fp32 模型测试数据
## 测试数据
### fp32 模型测试数据
骁龙855 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 31.64 | 18.98 | 10.67 | 33.17 | 19.55 | 11.43
mobilenet_v2 | 25.54 | 13.80 | 8.75 | 29.25 | 15.19 | 9.65
squeezenet_v1.1 | 26.81 | 14.39 | 8.92 | 28.63 | 15.37 | 9.53
mnasnet | 25.39 | 13.89 | 9.63 | 28.97 | 15.54 | 10.10
shufflenet_v2 | 13.85 | 7.81 | 5.87 | 14.64 | 8.35 | 6.14
骁龙845 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 62.04 | 33.63 | 18.63 | 66.23 | 35.78 | 20.14
mobilenet_v2 | 40.41 | 22.94 | 13.33 | 44.22 | 24.58 | 14.50
squeezenet_v1.1 | 49.92 | 23.78 | 13.86 | 52.00 | 24.85 | 15.87
mnasnet | 40.14 | 23.36 | 14.46 | 43.77 | 24.78 | 14.76
shufflenet_v2 | 22.27 | 13.69 | 8.96 | 26.11 | 14.95 | 9.02
骁龙835 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 89.57 | 50.88 | 27.62 | 96.11 | 53.18 | 31.99
mobilenet_v2 | 59.92 | 33.93 | 20.91 | 64.04 | 36.85 | 23.10
squeezenet_v1.1 | 65.25 | 37.92 | 23.40 | 74.87 | 40.96 | 23.69
mnasnet | 60.97 | 35.04 | 22.40 | 64.88 | 37.90 | 24.53
shufflenet_v2 | 30.87 | 19.33 | 12.78 | 31.71 | 19.52 | 13.25
骁龙625 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 180.98 | 92.27 | 51.51 | 216.12 | 110.33 | 61.68
mobilenet_v2 | 132.46 | 68.38 | 43.54 | 146.18 | 76.62 | 46.21
squeezenet_v1.1 | 124.49 | 66.84 | 41.53 | 153.28 | 82.42 | 47.14
mnasnet | 122.50 | 67.46 | 43.04 | 146.20 | 79.64 | 48.56
shufflenet_v2 | 68.70 | 40.77 | 26.53 | 75.38 | 42.40 | 28.36
骁龙653 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 121.27 | 59.36 | 34.06 | 126.55 | 64.96 | 39.23
mobilenet_v2 | 79.48 | 46.17 | 27.81 | 87.93 | 48.28 | 31.87
squeezenet_v1.1 | 81.10 | 42.66 | 42.07 | 82.29 | 45.88 | 28.84
mnasnet | 75.60 | 44.22 | 30.16 | 82.99 | 49.07 | 32.34
shufflenet_v2 | 39.18 | 23.54 | 16.73 | 40.12 | 24.76 | 17.68
麒麟970 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1 | 99.58 | 56.91 | 29.02 | 102.42 | 57.81 | 35.36
mobilenet_v2 | 69.22 | 42.41 | 23.55 | 69.49 | 43.38 | 25.26
squeezenet_v1.1 | 67.48 | 41.06 | 24.47 | 75.03 | 43.57 | 26.35
mnasnet | 74.55 | 43.06 | 24.22 | 75.48 | 44.43 | 26.69
shufflenet_v2 | 39.20 | 24.54 | 16.34 | 37.40 | 24.32 | 16.66
### int8 模型测试数据
骁龙855 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 16.77 | 8.38 | 4.59 | 43.42 | 20.80 | 10.89
mobilenet_v2_int8 | 22.81 | 13.71 | 10.43 | 29.65 | 20.09 | 13.99
resnet50_int8 | 258.83 | 157.22 | 85.83 | 424.99 | 209.37 | 112.32
骁龙845 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 44.08 | 23.75 | 12.52 | 49.19 | 26.77 | 13.82
mobilenet_v2_int8 | 36.61 | 22.70 | 15.29 | 40.51 | 25.84 | 17.89
resnet50_int8 | 399.64 | 217.74 | 112.86 | 408.80 | 224.72 | 122.15
骁龙835 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 59.99 | 31.59 | 16.55 | 62.92 | 33.33 | 17.38
mobilenet_v2_int8 | 50.68 | 31.25 | 21.62 | 52.56 | 33.88 | 24.31
resnet50_int8 | 498.85 | 267.65 | 146.03 | 510.54 | 278.77 | 155.05
骁龙625 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 122.86 | 63.52 | 33.91 | 125.77 | 64.78 | 34.25
mobilenet_v2_int8 | 110.71 | 67.76 | 49.85 | 114.63 | 71.74 | 51.73
resnet50_int8 | 954.67 | 505.78 | 286.64 | 1016.64 | 532.84 | 305.20
骁龙653 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 81.46 | 42.99 | 31.69 | 81.20 | 42.46 | 23.47
mobilenet_v2_int8 | 68.39 | 43.47 | 32.03 | 69.40 | 44.47 | 33.46
resnet50_int8 | 687.59 | 369.70 | 208.99 | 684.55 | 369.04 | 208.42
麒麟970 | armv8 | | |armv7 |||
---- | ---- | ---- | ---- |---- |----| ----|
num_threads | 1 | 2 | 4 |1 |2| 4
mobilenet_v1_int8 | 64.27 | 35.48 | 18.76 | 64.63 | 37.67 | 20.70
mobilenet_v2_int8 | 64.54 | 36.76 | 22.17 | 68.80 | 38.85 | 24.30
resnet50_int8 | 509.94 | 268.95 | 276.13 | 520.57 | 281.92 | 157.82
---
layout: post
title: Benchmark
---
<!--ts-->
* [Benchmark](#Benchmark)
* [环境准备](#环境准备)
* [1. 一键Benchmark](#一-一键benchmark)
* [2. 逐步Benchmark](#二-逐步Benchmark)
* [1. 获取benchmark可执行文件](#1-获取benchmark可执行文件)
* [2. 下载模型](#2-下载模型)
* [3. benchmark.sh脚本](#3-benchmark-sh脚本)
* [4. 测试](#4-测试)
<!--te-->
本文将会介绍,在**Ubuntu:16.04交叉编译环境**下,用安卓手机在终端测试Paddle-Lite的性能,并介绍两种Benchmark方法:
1. **一键Benchmark**:适用于想快速获得常见模型性能的用户,下载预编译好的benchmark可执行文件;
2. **逐步Benchmark**:将**一键Benchmark**流程拆解讲解。
# 环境准备
1. 准备[adb](https://developer.android.com/studio/command-line/adb)等必备软件:
```shell
sudo apt update
sudo apt install -y wget adb
```
2. 检查手机与电脑连接。安卓手机USB连上电脑,打开设置 -> 开启开发者模式 -> 开启USB调试 -> 允许(授权)当前电脑调试手机;
3. 在电脑终端输入`adb devices`命令,查看当前连接到的设备:
```shell
adb devices
```
命令成功执行,显示结果类似下面(序列码略有不同):
```shell
List of devices attached
712QSDSEMMS7C device
```
## 一. 一键Benchmark
执行以下命令,完成Benchmark:
```shell
wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/run_benchmark.sh
sh run_benchmark.sh
```
`run_benchmark.sh`脚本会:
1. 下载模型,并上传手机:包含mobilenetv1/v2、shufflenetv2、squeezenetv1.1、mnasnet;
2. 下载pre-built android-armv7和android-armv8的可执行文件,并上传手机:`benchmark_bin_v7``benchmark_bin_v8`
3. 自动执行另一个脚本`benchmark.sh`(多台手机连接USB,请在`benchmark.sh`脚本中对`adb`命令后加上测试手机的`serial number`);
4. 从手机下载benchmark结果`result_armv7.txt``result_armv8.txt`,到当前目录,并显示Benchmark结果。
## 二. 逐步Benchmark
### 1. 获取benchmark可执行文件
benchmark_bin文件可以测试PaddleLite的性能,有下面两种方式获得。
#### 方式一:下载benchmark_bin可执行文件
```shell
# Download benchmark_bin for android-armv7
wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_bin_v7
# Download benchmark_bin for android-armv8
wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_bin_v8
```
#### 方式二:由源码编译benchmark_bin文件
根据[源码编译](../source_compile)准备编译环境,拉取PaddleLite最新release发布版代码,并在仓库根目录下,执行:
```shell
###########################################
# Build benchmark_bin for android-armv7 #
###########################################
./lite/tools/ci_build.sh \
--arm_os="android" \
--arm_abi="armv7" \
--arm_lang="gcc " \
build_arm
# build result see: <paddle-lite-repo>/build.lite.android.armv7.gcc/lite/api/benchmark_bin
###########################################
# Build benchmark_bin for android-armv8 #
###########################################
./lite/tools/ci_build.sh \
--arm_os="android" \
--arm_abi="armv8" \
--arm_lang="gcc " \
build_arm
# build result see: <paddle-lite-repo>/build.lite.android.armv8.gcc/lite/api/benchmark_bin
```
> **注意**:为了避免在docker内部访问不到手机的问题,建议编译得到benchmark_bin后退出到docker外面,并且将benchmark_bin文件拷贝到一个临时目录。然后在该临时目录下,按照下面步骤下载模型、拷贝脚本、测试。
### 2. 下载模型
PaddleLite为Benchmark准备好了[常见Benchmark模型](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_models.tar.gz)
执行以下命令,下载常见Benchmark模型并解压:
```shell
wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_models.tar.gz
tar zxvf benchmark_models.tar.gz
```
| 模型 | 下载地址 |
| --------------- | ------------------------------------------------------------ |
| MobilenetV1 | [下载](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/mobilenet_v1.tar.gz) |
| MobilenetV2 | [下载](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/mobilenet_v2.tar.gz) |
| ShufflenetV2 | [下载](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/shufflenet_v2.tar.gz) |
| Squeezenet_V1.1 | [下载](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/squeezenet_v11.tar.gz) |
| Mnasnet | [下载](https://paddle-inference-dist.bj.bcebos.com/PaddleLite/mnasnet.tar.gz) |
> 注:若要使用测试脚本,**对单个模型测试**,请把单个模型放入 `benchmark_models` 文件夹,并确保测试脚本、`benchmark_models`文件夹在同一级的目录。
注:上述模型都已经使用`model_optimize_tool`进行转化,而且Lite移动端只支持加载转化后的模型。如果需要测试其他模型,请先参考[模型转化方法](../model_optimize_tool)
### 3. benchmark.sh脚本
benchmark测试的执行脚本`benchmark.sh` 位于源码中的`/PaddleLite/lite/tools/benchmark.sh`位置,测试时需要将`benchmark.sh``benchmark_bin``benchmark_models` 文件复制到同一目录下。
### 4. 测试
从终端进入benchmark.sh、可执行文件(benchmark_bin_v7、benchmark_bin_v8)和模型文件(benchmark_models)所在文件夹。
运行 benchmark.sh 脚本执行测试
```shell
# Benchmark for android-armv7
sh benchmark.sh ./benchmark_bin_v7 ./benchmark_models result_armv7.txt
# Benchmark for android-armv8
sh benchmark.sh ./benchmark_bin_v8 ./benchmark_models result_armv8.txt
```
测试结束后,armv7和armv8的结果,分别保存在当前目录下的`result_armv7.txt``result_armv8.txt`文件中。
**查看测试结果**
在当前目录的`result_armv7.txt``result_armv8.txt`文件,查看测试结果。
```shell
run benchmark armv7
--------------------------------------
PaddleLite Benchmark
Threads=1 Warmup=10 Repeats=30
-- mnasnet avg = 159.8427 ms
-- mobilenet_v1 avg = 235.0072 ms
-- mobilenet_v2 avg = 173.0387 ms
-- shufflenet_v2 avg = 76.0040 ms
-- squeezenet_v11 avg = 164.2957 ms
Threads=2 Warmup=10 Repeats=30
-- mnasnet avg = 83.1287 ms
-- mobilenet_v1 avg = 121.6029 ms
-- mobilenet_v2 avg = 86.6175 ms
-- shufflenet_v2 avg = 41.5761 ms
-- squeezenet_v11 avg = 87.8678 ms
Threads=4 Warmup=10 Repeats=30
-- mnasnet avg = 73.3880 ms
-- mobilenet_v1 avg = 119.0739 ms
-- mobilenet_v2 avg = 85.3050 ms
-- shufflenet_v2 avg = 38.0762 ms
-- squeezenet_v11 avg = 64.2201 ms
--------------------------------------
run benchmark armv8
--------------------------------------
PaddleLite Benchmark
Threads=1 Warmup=10 Repeats=30
-- mnasnet avg = 165.3073 ms
-- mobilenet_v1 avg = 306.0188 ms
-- mobilenet_v2 avg = 195.1884 ms
-- shufflenet_v2 avg = 99.3692 ms
-- squeezenet_v11 avg = 156.6971 ms
Threads=2 Warmup=10 Repeats=30
-- mnasnet avg = 90.2290 ms
-- mobilenet_v1 avg = 157.0007 ms
-- mobilenet_v2 avg = 118.1607 ms
-- shufflenet_v2 avg = 68.6804 ms
-- squeezenet_v11 avg = 91.3090 ms
Threads=4 Warmup=10 Repeats=30
-- mnasnet avg = 179.9730 ms
-- mobilenet_v1 avg = 204.0684 ms
-- mobilenet_v2 avg = 181.6486 ms
-- shufflenet_v2 avg = 123.2728 ms
-- squeezenet_v11 avg = 412.9046 ms
--------------------------------------
```
---
layout: post
title: C++ Demo
---
<!--ts-->
- [C++ Demo](#c-demo)
- [编译](#编译-1)
- [准备执行环境](#准备执行环境)
- [使用安卓手机](#使用安卓手机)
- [使用安卓模拟器](#使用安卓模拟器)
- [下载模型并运行示例](#下载模型并运行示例)
- [Demo 程序运行结果](#demo-程序运行结果)
- [如何在代码中使用 API](#如何在代码中使用-api)
<!-- Added by: yanchunwei, at: Mon Aug 26 22:23:07 CST 2019 -->
<!--te-->
## 编译
首先按照[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`确保完整编译**):
{% highlight shell %}
./lite/tools/build.sh \
--arm_os=android \
--arm_abi=armv8 \
--arm_lang=gcc \
--android_stl=c++_static \
--build_extra=ON \
full_publish
{% endhighlight %}
编译完成后 `./build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/` 文件夹下包含:
{% highlight shell %}
cxx/include/
cxx/lib/libpaddle_api_full_bundled.a
cxx/lib/libpaddle_api_light_bundled.a
demo/cxx/ #其中包括{include Makefile.def mobile_light}
third_party/gflags/
{% endhighlight %}
## 准备执行环境
执行环境有两种:使用安卓手机;若没安卓手机,也可在安卓模拟器中执行。
### 环境一:使用安卓手机
将手机连上电脑,在手机上打开选项 -> 开启-开发者模式 -> 开启-USB调试模式。确保 `adb devices` 能够看到相应的设备。
### 环境二:使用安卓模拟器
运行下面命令,分别创建安卓armv8、armv7架构的模拟器。若需在真机测试,将模拟器换成相应架构的真机环境即可。
{% highlight shell %}
# 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
{% endhighlight %}
{% highlight shell %}
# 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
{% endhighlight %}
## 下载模型并运行示例
{% highlight bash %}
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 -s emulator-5554 push mobilenet_v1 /data/local/tmp/
adb -s emulator-5554 push mobilenetv1_full_api /data/local/tmp/
adb -s emulator-5554 shell chmod +x /data/local/tmp/mobilenetv1_full_api
adb -s emulator-5554 shell "/data/local/tmp/mobilenetv1_full_api --model_dir=/data/local/tmp/mobilenet_v1 --optimized_model_dir=/data/local/tmp/mobilenet_v1.opt"
{% endhighlight %}
注:我们也提供了轻量级 API 的 demo,可以执行以下代码运行轻量级 API 示例。
{% highlight bash %}
cd ../mobile_light
make
adb -s emulator-5554 push mobilenetv1_light_api /data/local/tmp/
adb -s emulator-5554 shell chmod +x /data/local/tmp/mobilenetv1_light_api
adb -s emulator-5554 shell "/data/local/tmp/mobilenetv1_light_api --model_dir=/data/local/tmp/mobilenet_v1.opt --threads=1 "
{% endhighlight %}
## Demo 程序运行结果
Demo 运行成功后 ,将在控制台输出预测结果的前10个类别的预测概率:
{% highlight bash %}
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
{% endhighlight %}
## 如何在代码中使用 API
在C++中使用PaddleLite API非常简单,不需要添加太多额外代码,具体步骤如下:
- 加入头文件引用
{% highlight cpp %}
#include <iostream>
#include <vector>
#include "paddle_api.h"
#include "paddle_use_kernels.h"
#include "paddle_use_ops.h"
#include "paddle_use_passes.h"
{% endhighlight %}
- 通过MobileConfig设置:模型文件位置(model_dir)、线程数(thread)和能耗模式( power mode )。输入数据(input),从 MobileConfig 创建 PaddlePredictor 并执行预测。 (注:Lite还支持从memory直接加载模型,可以通过MobileConfig::set_model_buffer方法实现)
代码示例:
{% highlight cpp %}
// 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<PaddlePredictor> predictor =
CreatePaddlePredictor<MobileConfig>(config);
// 5. Prepare input data
std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0)));
input_tensor->Resize({1, 3, 224, 224});
auto *data = input_tensor -> mutable_data<float>();
for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) {
data[i] = 1;
}
// 6. Run predictor
predictor->Run();
// 7. Get output
std::unique_ptr<const Tensor> output_tensor(std::move(predictor->GetOutput(0)));
{% endhighlight %}
## 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. 示例代码:
{% highlight cpp %}
#include "paddle_api.h" // NOLINT
#include "paddle_use_kernels.h" // NOLINT
#include "paddle_use_ops.h" // NOLINT
#include "paddle_use_passes.h" // NOLINT
#include <gflags/gflags.h>
#include <stdio.h>
#include <vector>
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<Place> valid_places{Place{TARGET(kARM), PRECISION(kFloat)},
Place{TARGET(kHost), PRECISION(kFloat)}};
config.set_preferred_place(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
// input 0
std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0)));
input_tensor->Resize(shape_t({1, 1, 48, 512}));
auto *data = input_tensor->mutable_data<float>();
for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) {
data[i] = 1;
}
// input1
std::unique_ptr<Tensor> init_ids(std::move(predictor->GetInput(1)));
init_ids->Resize(shape_t({1, 1}));
auto *data_ids = init_ids->mutable_data<float>();
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<Tensor> init_scores(std::move(predictor->GetInput(2)));
init_scores->Resize(shape_t({1, 1}));
auto *data_scores = init_scores->mutable_data<float>();
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<const Tensor> 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<float>()[i]);
}
}
int main(int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
RunModel();
return 0;
}
{% endhighlight %}
3. 运行方法:
参考以上代码编译出可执行文件`OCR_DEMO`,模型文件夹为`ocr_attention`。手机以USB调试、文件传输模式连接电脑
在终端中输入以下命令执行OCR model测试:
{% highlight shell %}
#OCR_DEMO为编译出的可执行文件名称,ocr_attention为ocr_attention模型的文件夹名称
adb push OCR_DEMO data/local/tmp
adb push ocr_attention data/local/tmp
adb shell 'cd data/local/tmp && ./OCR_DEMO --model_dir=./OCR_DEMO'
{% endhighlight %}
4. 运行结果
<img src='https://user-images.githubusercontent.com/45189361/64398400-46531580-d097-11e9-9f1c-5aba1dfbc24f.png' align='left' width="150" height="200"/>
---
layout: post
title: C++ API接口使用指南
---
# C++ API接口使用指南
请参考[源码编译](../source_compile)确保 Lite 可以正确编译,下面用Lite的c++接口加载并执行 MobileNetV1 模型为例,详细说明使用方法。
## 准备模型
Lite支持PaddlePaddle训练好的模型,MobileNetV1模型可以由以下三种方式得到:
- 直接下载训练好的[MobileNetV1模型](https://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz)
- 使用[PaddlePaddle](https://paddlepaddle.org.cn/)构建MobileNetV1网络并训练
- 使用[X2Paddle](../x2paddle)对caffe或者tensorflow的MobileNetV1模型进行转换得到
## 模型优化
使用Model Optimize Tool优化模型,使得模型预测过程表现出优异的性能。Model Optimize Tool的具体使用方法请参考[文档](../model_optimize_tool)
- 准备model_optimize_tool
- 使用model_optimize_tool优化模型
- 得到优化后的模型,包括__model__.nb文件和param.nb文件
## 加载模型
加载MobileNetV1网络模型,创建predictor,具体可以参考```paddlelite/lite/api/model_test.cc```文件。
```c++
lite::DeviceInfo::Init();
lite::DeviceInfo::Global().SetRunMode(lite::LITE_POWER_HIGH, thread_num);
lite_api::MobileConfig config;
config.set_model_dir(model_dir);
auto predictor = lite_api::CreatePaddlePredictor(config);
```
## 设定输入
得到input_tensor,设置输入值,此处我们设定为全1
```cpp
// 获取第 j 个 tensor 的句柄
auto input_tensor = predictor->GetInput(j);
input_tensor->Resize(input_shapes[j]);
// 获取数据指针,以塞入数据
auto input_data = input_tensor->mutable_data<float>();
int input_num = 1;
for (int i = 0; i < input_shapes[j].size(); ++i) {
input_num *= input_shapes[j][i];
}
for (int i = 0; i < input_num; ++i) {
input_data[i] = 1.f;
}
```
## 执行并输出
```cpp
predictor.Run()
auto* out = predictor.GetOutput(0);
LOG(INFO) << "dims " << out->dims();
LOG(INFO) << "out data size: " << out->data_size();
```
输出为```dims dims{1000,}, out data size: 1000```
---
layout: post
title: Debug tools
---
**Lite Model Debug Tool** 是用来检查Paddle-Lite框架与Paddle-Fluid框架运行时tensor(包括variable与weight)之间diff信息的基础工具。
## 工作流程:
1. 运行 `/bin/bash check_model.sh --model_dir=<your_model_path> --build_root_dir=<your_cmake_root_dir> debug_cpp_stage` 获得模型在Paddle-Lite框架下的运行拓扑信息、varibles信息和weights信息。运行后拓扑信息将会存储在默认名为 `topo_file.txt` 的文件中,variables和weights信息将会存储在默认名为 `tensor_cpp.txt` 的文件中。
2. 运行 `/bin/bash check_model.sh --model_dir=<your_model_path> --build_root_dir=<your_cmake_root_dir> debug_py_stage`执行fluid框架预测以获取相同模型在fluid框架下的variable与weight信息(注意:我们使用fluid的python api运行fluid模型,因此您在运行此步之前应确保已正确安装fluid的python api)。然后debug tool将会自动比较Paddle-Lite框架输出的信息和Paddle-Fluid框架输出的信息来检查是否存在运行时diff。 执行Paddle-Fluid框架,输出的信息将会存储在默认名为 `tensor_py.txt` 的文件中,相应的diff信息将会存储在默认名为 `diff.txt`的文件中(默认情况下,只会输出执行拓扑序中第一个有diff的variable相关的信息)。
## 注意事项:
1. 输出的结果是在**执行完一次预测后**输出的相应变量/权重的最终值,因此如果您在预测过程进行过诸如变量复用/子图融合等优化方法,则相应的输出可能会出现偏差。
2. 默认情况下debug tools将以全1作为输入进行比对。
3. 默认情况下,为了保证与Paddle-Fluid框架的结果可比对,debug tool将会禁用掉所有的Paddle-Lite的优化策略。
4. Paddle-Lite框架的执行环境由与您的编译选项有关,比如您开启了LITE_WITH_ARM编译选项,那debug tool的`debug_cpp_stage`也需要在ARM平台下运行。
## Diff信息输出:
如果debug tool检测到diff信息,那么在`diff.txt`中将会输出类似以下结构信息
```c++
>>>>>>>>>>>>>>>>>>DIFF VARIABLE: dropout_0.tmp_0<<<<<<<<<<<<<<<<<<<
dropout (X:pool2d_7.tmp_0) (Mask:dropout_0.tmp_1 Out:dropout_0.tmp_0)
--------------- Tensor File info ---------------
pool2d_7.tmp_0 {1,1536,1,1} 0.749892 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0150336 0.621641 0.147099 0.636727 0.0 0.0 0.00410917 0.784708 0.0 0.0704846 0.233599 0.840123 0.239201 0.112878 0.0 0.155352 0.306906 0.0 0.0 0.860938 0.221037 0.787316 0.256585 ...
dropout_0.tmp_0 {1,1536,1,1} 0.749892 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0150336 0.621641 0.147099 0.636727 0.0 0.0 0.00410917 0.784708 0.0 0.0704846 0.233599 0.840123 0.239201 0.112878 0.0 0.155352 0.306906 0.0 0.0 0.860938 0.221037 0.787316 0.256585 ...
--------------- Fluid Tensor info ---------------
pool2d_7.tmp_0 {1,1536,1,1} 0.7498912 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.015033395 0.6216395 0.14709876 0.63672537 0.0 0.0 0.0041093696 0.7847073 0.0 0.07048465 0.23359808 0.8401219 0.23919891 0.1128789 0.0 0.1553514 0.3069055 0.0 0.0 0.8609365 0.22103554 ...
dropout_0.tmp_0 {1,1536,1,1} 0.599913 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.012026716 0.4973116 0.117679015 0.5093803 0.0 0.0 0.0032874958 0.62776583 0.0 0.056387722 0.18687847 0.67209756 0.19135913 0.090303116 0.0 0.12428112 0.2455244 0.0 0.0 0.68874925 ...
```
其中第二行为op相关信息,标明了执行哪个op出现了diff及其对应的输入输出变量名。Tensor File info为Paddle-Lite框架的输出信息,而Fluid Tensor info为Paddle-Fluid框架的相应输出信息。
示例中的`dropout_0.tmp_1`没有相应的tensor信息是因为工具检测到其在预测的后序流程中未被使用,因此不会对预测结果造成影响,从而将其自动屏蔽掉以保证输出尽量简洁。
## 其他选项:
| Option | Description |
| --------------------------- | ------------------------------------------------------------ |
| --input_file | 输入文件名,不同field以逗号分隔,相同field内以空格分隔, 只有文件中的第一行输入信息会被使用. 如果您不指定input_file,那么所有输入将会被置为1。注意:`debug_py_stage`目前不支持多field输入。 |
| --cpp_topo_file | 存储运行时拓扑信息,由`debug_cpp_stage`写入并且由`debug_py_stage`读取使用。 默认为`topo_file.txt` 。 |
| --cpp_tensor_file | 存储`debug_cpp_stage` 在运行拓扑序下的输出信息,默认为 `tensor_cpp.txt` 。 |
| --tensor_names | 如果此选项不为空,那么只输出由此选项中指定名字的variable/weight信息,名字间用逗号分隔。 |
| --tensor_output_length | 输出数据的长度,默认为全部输出。 |
| --py_threshold | 判断diff发生的阈值,默认为 `1e-5` 。 |
| --py_tensor_file | 存储`debug_py_stage` 在运行拓扑序下的输出信息,默认为`tensor_py.txt`. |
| --py_output_file | diff信息的存储文件,默认为`diff.txt`。 |
| --py_only_output_first_diff | 是否只输出运行时拓扑序中第一个有diff的var/op信息,默认为true |
您可以参考 `check_model.sh` 脚本中的代码以获得更多细节.
## Basic Profiler
Basic profiler 用于 CPU 上kernel 耗时的统计,在 cmake 时添加 `-DLITE_WITH_PROFILER=ON` ,就可以开启相应支持。
在模型执行完毕后,会自动打印类似如下 profiler 的日志
```
kernel average min max count
feed/def/1/4/2 0 0 0 1
conv2d/def/4/1/1 1175 1175 1175 1
conv2d/def/4/1/1 1253 1253 1253 1
depthwise_conv2d/def/4/1/1 519 519 519 1
conv2d/def/4/1/1 721 721 721 1
elementwise_add/def/4/1/1 18 18 18 1
conv2d/def/4/1/1 2174 2174 2174 1
depthwise_conv2d/def/4/1/1 380 380 380 1
conv2d/def/4/1/1 773 773 773 1
elementwise_add/def/4/1/1 2 2 2 1
conv2d/def/4/1/1 1248 1248 1248 1
depthwise_conv2d/def/4/1/1 492 492 492 1
conv2d/def/4/1/1 1150 1150 1150 1
elementwise_add/def/4/1/1 33 33 33 1
elementwise_add/def/4/1/1 3 3 3 1
conv2d/def/4/1/1 1254 1254 1254 1
depthwise_conv2d/def/4/1/1 126 126 126 1
```
---
layout: post
title: 基础须知
---
可以参考 [Paddle 开发者文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/advanced_usage/development/contribute_to_paddle/local_dev_guide.html)
# 提交PR
需要在 commit message 里加上 `test=develop` 才能触发 CI
# 版本发布检查清单
1. 所有 feature 梳理,确认状态
2. 所有 QA 测试结果梳理,确认版本可靠
3. Release note 确认 review 通过
4. 确认需要 release 的 binary 编译完毕
---
layout: post
title: 基础须知
---
可以参考 [Paddle 开发者文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/advanced_usage/development/contribute_to_paddle/local_dev_guide.html)
# 提交PR
需要在 commit message 里加上 `test=develop` 才能触发 CI
# 版本发布检查清单
1. 所有 feature 梳理,确认状态
2. 所有 QA 测试结果梳理,确认版本可靠
3. Release note 确认 review 通过
4. 确认需要 release 的 binary 编译完毕
---
layout: post
title: Lite基于fpga的模型预测
---
Paddle Lite支持基于arm的fpga zu3/zu5/zu9的模型预测,提供armv8的交叉编译
Lite基于fpga运行模型需要相应的fpga驱动,目前只支持百度edgeboard开发板
**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=ON \
-DLITE_WITH_FPGA=ON \
-DARM_TARGET_OS=armlinux
make -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``preferred_place`
- fpga不需要device的初始化和运行模式设置
代码示例:
```cpp
lite::Predictor predictor;
std::vector<Place> valid_places(
{Place{TARGET(kFPGA), PRECISION(kFP16), DATALAYOUT(kNHWC)},
Place{TARGET(kHost), PRECISION(kFloat), DATALAYOUT(kNHWC)}});
Place preferred_place = Place{TARGET(kFPGA), PRECISION(kFP16), DATALAYOUT(kNHWC)};
predictor.Build(model_dir, preferred_place, valid_places);
auto* input_tensor = predictor.GetInput(0);
input_tensor->Resize(DDim(std::vector<DDim::value_type>({1, 3, 224, 224})));
auto* data = input_tensor->mutable_data<float>();
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);
```
---
layout: post
title: Paddle-Lite文档 (v2.0.0-beta1)
---
Paddle-Lite 框架是 PaddleMobile 新一代架构,重点支持移动端推理预测,特点**高性能、多硬件、轻量级** 。支持PaddleFluid/TensorFlow/Caffe/ONNX模型的推理部署,目前已经支持 ARM CPU, Mali GPU, Adreno GPU, Huawei NPU 等>多种硬件,正在逐步增加 X86 CPU, Nvidia GPU 等多款硬件,相关硬件性能业内领先。
## 简介
- [技术特点](../tech_highlights)
- [架构设计](../architecture)
- [Road Map](../roadmap)
## Benchmark
- [最新性能](../benchmark)
- [测试方法](../benchmark_tools)
## 安装
- [源码编译](../source_compile)
## 使用
- [使用流程](../tutorial)
- [C++实例](../cpp_demo)
- [Java实例](../java_demo)
- [Android/IOS APP demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)
- [模型转化方法](../model_optimize_tool)
## 进阶
- [通过 X2Paddle 支持 Caffe, TensorFlow 模型](../x2paddle)
- [模型量化](../model_quantization)
- [支持Op列表](../support_operation_list)
- [新增Op方法](../add_new_operation)
- [测试工具](../debug_tools)
- [调试方法](../debug_tools)
- [使用华为NPU](../npu)
- [使用Android GPU](../opencl)
- [使用FPGA](../fpga)
## 开发者文档
- [开发基础须知](../for-developer)
- [架构详解](../architecture-intro)
## FAQ
- 问题或建议可以[发Issue](https://github.com/PaddlePaddle/Paddle-Lite/issues),为加快问题解决效率,可先检索是否有类似问题,我们也会及时解答!
- 欢迎加入Paddle-Lite百度官方QQ群:696965088
## paddle-mobile
- [paddle-mobile 编译](../mobile)
---
layout: post
title: Java Android Demo
---
<!--ts-->
* [Java Android Demo](#java-android-demo)
* [编译](#编译)
* [准备 demo 需要的其他文件](#准备-demo-需要的其他文件)
* [脚本方法](#脚本方法)
* [手动拷贝方法](#手动拷贝方法)
* [把 .so 动态库和 .jar 拷贝进安卓demo程序:](#把-so-动态库和-jar-拷贝进安卓demo程序)
* [把demo使用到的模型文件拷贝进安卓程序:](#把demo使用到的模型文件拷贝进安卓程序)
* [运行 Android 程序结果](#运行-android-程序结果)
<!-- Added by: yanchunwei, at: Mon Aug 26 22:23:07 CST 2019 -->
<!--te-->
本节中,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 代表该测试花费的时间。
---
layout: post
title: paddle mobile 代码编译
---
详情可以参考 [mobile/README](https://github.com/PaddlePaddle/Paddle-Lite/tree/develop/mobile)
要切换 paddle-mobile 编译,cmake 需要加上 **-DWITH_PADDLE_MOBILE=ON** 开关,其余 flag 请参考上面文档添加到后面
所有其他选项跟 paddle-mobile 原始操作完全一致
\ No newline at end of file
---
layout: post
title: 模型转化方法
---
Lite架构在预测过程中表现出来的高性能得益于其丰富的优化组件,其中包括量化、子图融合、混合调度、Kernel优选等等策略。为了使优化过程更加方便易用,我们提供了**Model Optimize Tool**来自动完成优化步骤,输出一个轻量的、最优的可执行模型。具体使用方法介绍如下:
## 准备model_optimize_tool
可以选择下载或者手动编译model_optimize_tool可执行文件。
### 下载model_optimize_tool
```sh
wget https://paddle-inference-dist.bj.bcebos.com/PaddleLite/model_optimize_tool
chmod 777 model_optimize_tool
```
### 编译model_optimize_tool
1、参照 [编译安装](../source_compile) 进行环境配置和编译
2、进入docker中PaddleLite根目录,```git checkout develop```切换到develop分支
3、使用cmake构建目标,执行如下命令编译model_optimize_tool
```bash
./lite/tools/build.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_static full_publish
```
4、编译完成,优化工具在```Paddle-Lite/build.lite.android.armv8.gcc/lite/api/model_optimize_tool```
## 使用方法
1、准备需要优化的fluid模型
fluid模型有两种形式,combined形式(权重保存为一个param文件)和非combined形式(权重保存为一个一个单独的文件),model_optimize_tool支持对这两种形式的fluid模型进行直接优化。
2、将model_optimize_tool和需要优化的模型文件push到手机端
3、使用model_optimize_tool对模型进行优化
```shell
./model_optimize_tool \
--model_dir=<model_param_dir> \
--model_file=<model_path> \
--param_file=<param_path> \
--optimize_out_type=(protobuf|naive_buffer) \
--optimize_out=<output_optimize_model_dir> \
--valid_targets=(arm|opencl|x86) \
--prefer_int8_kernel=(true|false)
```
| 选项 | 说明 |
| ------------------- | ------------------------------------------------------------ |
| --model_dir | 待优化的fluid模型(非combined形式)的路径,其中包括网络结构文件和一个一个单独保存的权重文件。|
| --model_file | 待优化的fluid模型(combined形式)的网络结构路径。 |
| --param_file | 待优化的fluid模型(combined形式)的权重文件路径。 |
| --optimize_out_type | 输出模型类型,目前支持两种类型:protobuf和naive_buffer,其中naive_buffer是一种更轻量级的序列化/反序列化实现。若您需要在mobile端执行模型预测,请将此选项设置为naive_buffer。默认为protobuf。 |
| --optimize_out | 优化模型的输出路径。 |
| --valid_targets | 指定模型可执行的backend,目前可支持x86、arm、opencl,您可以同时指定多个backend(以空格分隔),Model Optimize Tool将会自动选择最佳方式。默认为arm。 |
| --prefer_int8_kernel | 是否启用int8量化模型,默认为false。 |
* 如果待优化的fluid模型是非combined形式,请设置`--model_dir`,忽略`--model_file``--param_file`
* 如果待优化的fluid模型是combined形式,请设置`--model_file``--param_file`,忽略`--model_dir`
* 优化后的模型包括__model__.nb和param.nb文件。
---
layout: post
title: 模型量化
---
<!--ts-->
* [模型量化](#模型量化)
* [一、使用PaddleSlim模型压缩工具获取量化模型](#一使用PaddleSlim模型压缩工具获取量化模型)
* [1. 安装PaddlePaddle版本](#1-安装PaddlePaddle版本)
* [2. 克隆量化训练所需的代码库](#2-克隆量化训练所需的代码库)
* [3. 数据准备](#3-数据准备)
* [4. 压缩脚本介绍](#4-压缩脚本介绍)
* [5. 执行int8量化训练](#5-执行int8量化训练)
* [二、使用Paddle-Lite运行量化模型推理](#二使用Paddle-Lite运行量化模型推理)
* [1. 在手机端准备量化模型文件](#1-在手机端准备量化模型文件)
* [2. 使用模型优化工具对量化模型进行优化](#2-使用模型优化工具对量化模型进行优化)
* [3. 使用mobilenetv1_light_api运行优化后的量化模型](#3-使用mobilenetv1_light_api运行优化后的量化模型)
* [三、FAQ](#三FAQ)
<!-- Added by: , at: Thu Aug 29 16:00:45 CST 2019 -->
<!--te-->
Paddle-Lite支持加载运行[PaddlePaddle框架](https://github.com/PaddlePaddle/Paddle)量化训练产出的模型。本文主要介绍如何基于PaddlePaddle和Paddle-Lite对模型进行端到端的量化训练和推理执行。PaddlePaddle框架中所使用的量化训练原理请猛戳[此处](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/docs/tutorial.md#1-quantization-aware-training%E9%87%8F%E5%8C%96%E4%BB%8B%E7%BB%8D)。如果您是初次接触PaddlePaddle框架,建议首先学习[新人入门](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/beginners_guide/index_cn.html)[使用指南](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.5/user_guides/index_cn.html)
> 备注:本文中所使用的模型量化示例均为MobileNetV1。
### 一、使用PaddleSlim模型压缩工具获取量化模型
**用户须知**: 现阶段的量化训练主要针对卷积层(包括二维卷积和Depthwise卷积)以及全连接层进行量化。卷积层和全连接层在PaddlePaddle框架中对应算子包括conv2d、depthwise_conv2d和mul等。量化训练会对conv2d、depthwise_conv2d和mul进行量化操作,且要求它们的输入中必须包括激活和参数两部分。
#### 1. 安装PaddlePaddle
根据操作系统、安装方式、Python版本和CUDA版本,按照[官方说明](https://paddlepaddle.org.cn/start)安装PaddlePaddle1.5.1版本。例如:
Ubuntu 16.04.4 LTS操作系统,CUDA9,cuDNN7,GPU版本安装:
```bash
pip install paddlepaddle-gpu==1.5.1.post97 -i https://mirrors.aliyun.com/pypi/simple/
```
Ubuntu 16.04.4 LTS操作系统,CPU版本安装:
```bash
pip install paddlepaddle==1.5.1 -i https://mirrors.aliyun.com/pypi/simple/
```
#### 2. 克隆量化训练所需的代码库
克隆[PaddlePaddle/models](https://github.com/PaddlePaddle/models)到本地,并进入models/PaddleSlim路径。执行如下命令:
```bash
git clone https://github.com/PaddlePaddle/models.git
cd models/PaddleSlim
```
#### 3. 数据准备
##### 3.1 训练数据准备
参考[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#data-preparation)下的数据准备教程准备训练数据,并放入PaddleSlim/data路径下。
##### 3.2 预训练模型准备
脚本run.sh会自动从[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/image_classification#supported-models-and-performances)下载MobileNetV1的预训练模型,并放入PaddleSlim/pretrain路径下。
经过以上三步,PaddleSlim目录下的文件结构如下所示:
```bash
.
├── compress.py # 模型压缩任务主脚本,定义了压缩任务需要的模型相关信息
├── configs # 压缩任务的配置文件,包括:蒸馏、int8量化量化、filter剪切和组合策略的配置文件
├── data # 存放训练数据(需要用户自己创建)
│   └── ILSVRC2012
├── pretrain # 存放预训练模型参数,执行run.sh自动生成
│   ├── MobileNetV1_pretrained
│   ├── MobileNetV1_pretrained.tar
│   ├── ResNet50_pretrained
│   └── ResNet50_pretrained.tar
├── docs # 文档目录
├── light_nas
├── models # 模型网络结构的定义,如MobileNetV1
├── quant_low_level_api # 量化训练的底层API, 用于灵活定制量化训练的过程,适用于高阶用户
├── reader.py # 定义数据处理逻辑
├── README.md
├── run.sh # 模型压缩任务启动脚本
└── utility.py # 定义了常用的工具方法
```
#### 4. 压缩脚本介绍
`compress.py`中定义了执行压缩任务需要的所有模型相关的信息,这里对几个关键的步骤进行简要介绍:
##### 4.1 目标网络的定义
compress.py的以下代码片段定义了train program, 这里train program只有前向计算操作。
```python
out = model.net(input=image, class_dim=args.class_dim)
cost = fluid.layers.cross_entropy(input=out, label=label)
avg_cost = fluid.layers.mean(x=cost)
acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1)
acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5)
```
然后,通过clone方法得到eval_program, 用来在压缩过程中评估模型精度,如下:
```python
val_program = fluid.default_main_program().clone()
```
定义完目标网络结构,需要对其初始化,并根据需要加载预训练模型。
##### 4.2 定义feed_list和fetch_list
对于train program, 定义train_feed_list用于指定从train data reader中取的数据feed给哪些variable。定义train_fetch_list用于指定在训练时,需要在log中展示的结果。如果需要在训练过程中在log中打印accuracy信心,则将('acc_top1', acc_top1.name)添加到train_fetch_list中即可。
```python
train_feed_list = [('image', image.name), ('label', label.name)]
train_fetch_list = [('loss', avg_cost.name)]
```
> 注意: 在train_fetch_list里必须有loss这一项。
对于eval program. 同上定义eval_feed_list和train_fetch_list:
```python
val_feed_list = [('image', image.name), ('label', label.name)]
val_fetch_list = [('acc_top1', acc_top1.name), ('acc_top5', acc_top5.name)]
```
##### 4.3 Compressor和量化配置文件
I. `compress.py`主要使用Compressor和yaml文件完成对模型的量化训练工作。Compressor类的定义如下:
```python
class Compressor(object):
def __init__(self,
place,
scope,
train_program,
train_reader=None,
train_feed_list=None,
train_fetch_list=None,
eval_program=None,
eval_reader=None,
eval_feed_list=None,
eval_fetch_list=None,
teacher_programs=[],
checkpoint_path='./checkpoints',
train_optimizer=None,
distiller_optimizer=None):
```
在定义Compressor对象时,需要注意以下问题:
* train program如果带反向operators和优化更新相关的operators, 参数train_optimizer需要设置为None.
* eval_program中parameter的名称需要与train_program中的parameter的名称完全一致。
* 最终保存的量化模型是在eval_program网络基础上进行剪枝保存的。所以,如果用户希望最终保存的模型可以用于inference, 则eval program需要包含推理阶段需要的各种operators.
* checkpoint保存的是float数据类型的模型。
II. `configs/quantization.yaml`量化配置文件示例如下:
```python
version: 1.0
strategies:
quantization_strategy:
class: 'QuantizationStrategy'
start_epoch: 0
end_epoch: 9
float_model_save_path: './output/float'
mobile_model_save_path: './output/mobile'
int8_model_save_path: './output/int8'
weight_bits: 8
activation_bits: 8
weight_quantize_type: 'abs_max'
activation_quantize_type: 'moving_average_abs_max'
save_in_nodes: ['image']
save_out_nodes: ['fc_0.tmp_2']
compressor:
epoch: 10
checkpoint_path: './checkpoints_quan/'
strategies:
- quantization_strategy
```
其中,可配置参数包括:
- **class:** 量化策略的类名称,目前仅支持`QuantizationStrategy`
- **start_epoch:** 在start_epoch开始之前,量化训练策略会往train_program和eval_program插入量化operators和反量化operators。 从start_epoch开始,进入量化训练阶段。
- **end_epoch:** 在end_epoch结束之后,会保存用户指定格式的模型。注意:end_epoch之后并不会停止量化训练,而是继续训练直到epoch数等于compressor.epoch值为止。举例来说,当start_epoch=0,end_epoch=0,compressor.epoch=2时,量化训练开始于epoch0,结束于epoch1,但保存的模型是epoch0结束时的参数状态。
- **float_model_save_path:** 保存float数据格式的模型路径,即该路径下的模型参数范围为int8范围但参数数据类型为float32。如果设置为None, 则不存储float格式的模型,默认为None。**注意:Paddle-Lite即使用该目录下的模型进行量化模型推理优化,详见本文[使用Paddle-Lite运行量化模型推理](#二使用Paddle-Lite运行量化模型推理)部分。**
- **int8_model_save_path:** 保存int8数据格式的模型路径,即该路径下的模型参数范围为int8范围且参数数据类型为int8。如果设置为None, 则不存储int8格式的模型,默认为None.
- **mobile_model_save_path:** 保存兼容paddle-mobile框架的模型路径。如果设置为None, 则不存储paddle-mobile格式的模型,默认为None。目前paddle-mobile已升级为Paddle-Lite。
- **weight_bits:** 量化weight的bit数,注意偏置(bias)参数不会被量化。
- **activation_bits:** 量化activation的bit数。
- **weight_quantize_type:** weight量化方式,目前量化训练支持`abs_max``channel_wise_abs_max`
- **activation_quantize_type:** activation量化方式,目前量化训练支持`abs_max``range_abs_max``moving_average_abs_max`
- **save_in_nodes:** variable名称列表。在保存量化后模型的时候,需要根据save_in_nodes对eval programg 网络进行前向遍历剪枝。默认为eval_feed_list内指定的variable的名称列表。
- **save_out_nodes:** varibale名称列表。在保存量化后模型的时候,需要根据save_out_nodes对eval programg 网络进行回溯剪枝。默认为eval_fetch_list内指定的variable的名称列表。
> **备注:**
>
> 1)`abs_max`意为在训练的每个step及inference阶段均动态计算量化scale值。`channel_wise_abs_max`与`abs_max`类似,不同点在于它会对卷积权重进行分channel求取量化scale。换言之,`abs_max`属于tensor-wise量化,而`channel_wise_abs_max`属于channel-wise量化,详细说明请猛戳[此处](https://github.com/PaddlePaddle/FluidDoc/blob/develop/doc/fluid/design/quantization/training_quantization_model_format.md)。
>
> 2)`moving_average_abs_max`和`range_abs_max`意为在训练阶段计算出一个静态的量化scale值,并将其用于inference阶段。`moving_average_abs_max`使用窗口滑动平均的方法计算量化scale,而`range_abs_max`则使用窗口绝对值最大值的方式。
>
> 3)**目前,Paddle-Lite仅支持运行weight量化方式使用`abs_max`且activation量化方式使用`moving_average_abs_max`或`range_abs_max`产出的量化模型**。
#### 5. 执行int8量化训练
修改run.sh,即注释掉`# enable GC strategy``# for sensitivity filter pruning`之间的内容并打开`#for quantization`相关的脚本命令(所需打开注释的命令如下所示)。
```bash
# for quantization
#---------------------------
export CUDA_VISIBLE_DEVICES=0
python compress.py \
--batch_size 64 \
--model "MobileNet" \
--pretrained_model ./pretrain/MobileNetV1_pretrained \
--compress_config ./configs/quantization.yaml \
--quant_only True
```
最后,运行`sh run.sh`命令开始int8量化训练。
### 二、使用Paddle-Lite运行量化模型推理
上述量化训练过程完成后,若用户按照本文中所述`configs/quantization.yaml`文件内容配置的模型输出路径,则可在models/PaddleSlim/output目录下看到`float``int8``mobile`三个目录,其中:
* float目录: 参数范围为int8范围但参数数据类型为float32的量化模型。Paddle-Lite即使用该目录下的模型文件及参数进行量化模型的部署。
* int8目录: 参数范围为int8范围且参数数据类型为int8的量化模型。
* mobile目录:参数特点与int8目录相同且兼容paddle-mobile的量化模型(目前paddle-mobile已升级为Paddle-Lite)。
#### 1. 在手机端准备量化模型文件
这里我们主要使用float目录下的模型文件(用户亦可以选择使用官方已经预训练好的MobileNetV1量化模型,[点击此处](https://paddle-inference-dist.bj.bcebos.com/int8%2Fpretrain%2Fmobilenet_v1_quant%2Ffloat.zip)进行下载)。
使用如下命令将float目录下的量化模型文件导入到手机端:
```bash
adb shell mkdir -p /data/local/tmp/mobilenet_v1_quant
adb push float/* /data/local/tmp/mobilenet_v1_quant
```
#### 2. 使用模型优化工具对量化模型进行优化
克隆[PaddlePaddle/Paddle-Lite](https://github.com/PaddlePaddle/Paddle-Lite)到本地(注意执行以下所有命令时均默认Paddle-Lite源码文件夹在当前目录下)。根据[Docker开发环境的配置说明文档](https://github.com/PaddlePaddle/Paddle-Lite/wiki/source_compile#1-docker%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83)准备Paddle-Lite编译环境。若用户按照文档配置docker编译环境,则进入docker容器可看到宿主机端的Paddle-Lite源码文件夹被映射挂载到容器的/Paddle-Lite目录下。在docker容器中执行以下编译命令:
```bash
cd /Paddle-Lite
./lite/tools/build.sh \
--arm_os=android \
--arm_abi=armv8 \
--arm_lang=gcc \
--android_stl=c++_static \
full_publish
```
* 编译完成后退出docker容器,模型优化工具model\_optimize\_tool在宿主机的存放位置为`Paddle-Lite/build.lite.android.armv8.gcc/lite/api/model_optimize_tool`。此时,目录结构如下所示:
```bash
Paddle-Lite/
|-- build.lite.android.armv8.gcc
| |-- lite
| | |-- api
| | | |-- model_optimize_tool
```
* 在宿主机执行如下命令将`model_optimize_tool`文件导入到手机端。
```bash
adb push Paddle-Lite/build.lite.android.armv8.gcc/lite/api/model_optimize_tool /data/local/tmp
```
* 在宿主机执行如下命令,完成对量化训练模型的优化,产生适合在移动端直接部署的量化模型。
```bash
adb shell rm -rf /data/local/tmp/mobilenet_v1_quant_opt
adb shell chmod +x /data/local/tmp/model_optimize_tool
adb shell /data/local/tmp/model_optimize_tool \
--model_file=/data/local/tmp/mobilenet_v1_quant/model \
--param_file=/data/local/tmp/mobilenet_v1_quant/weights \
--optimize_out_type=naive_buffer \
--optimize_out=/data/local/tmp/mobilenet_v1_quant_opt \
--valid_targets=arm \
--prefer_int8_kernel=true
```
model\_optimize\_tool的详细使用方法请猛戳[此处](https://github.com/PaddlePaddle/Paddle-Lite/wiki/model_optimize_tool#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95)
> 备注:如前所述,Paddle-Lite所使用的float目录下量化模型参数范围为int8范围但参数数据类型仍为float32类型,仅这样确实没有起到模型参数压缩的效果。但是,经过model\_optimize\_tool工具优化后对应的量化参数均会以int8类型重新存储达到参数压缩的效果,且模型结构也被优化(如进行了各种operator fuse操作)。
#### 3. 使用mobilenetv1\_light\_api运行优化后的量化模型
在docker容器中执行如下命令获取Paddle-Lite轻量级API的demo:
```bash
cd /Paddle-Lite/build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_light
make clean && make -j
```
执行完上述命令后退出docker容器,并可在宿主机`Paddle-Lite/build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_light/`路径下看到`mobilenetv1_light_api`可执行文件。将`mobilenetv1_light_api`导入到手机端并运行量化模型推理。执行命令如下:
```bash
adb push Paddle-Lite/build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_light/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_quant_opt
```
**程序运行结果如下:**
```bash
Output dim: 1000
Output[0]: 0.000228
Output[100]: 0.000260
Output[200]: 0.000250
Output[300]: 0.000560
Output[400]: 0.000950
Output[500]: 0.000275
Output[600]: 0.005143
Output[700]: 0.002509
Output[800]: 0.000538
Output[900]: 0.000969
```
在C++中使用Paddle-Lite API的方法请猛戳[此处](https://github.com/PaddlePaddle/Paddle-Lite/wiki/demos#如何在代码中使用-api),用户也可参考[mobilenetv1_light_api.cc](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc)的代码示例。
### 三、FAQ
**问题**:Compiled with WITH_GPU, but no GPU found in runtime
**解答**:检查本机是否支持GPU训练,如果不支持请使用CPU训练。如果在docker进行GPU训练,请使用nvidia_docker启动容器。
**问题**:Inufficient GPU memory to allocation. at [/paddle/paddle/fluid/platform/gpu_info.cc:262]
**解答**:正确设置run.sh脚本中`CUDA_VISIBLE_DEVICES`,确保显卡剩余内存大于需要内存。
---
layout: post
title: Lite支持NPU在线编译
---
Paddle Lite可以在线分析模型特点,在线编译并生成NPU所需要的IR并实时运行。
是首个支持NPU在线模型的预测框架。
也可以离线分析并调优模型后,保存离线模型,直接线上部署使用。
# 编译
只需要提前准备华为DKK库和Lite 代码。
我们也提供了编译NPU的[脚本](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/tools/build_npu.sh)可以直接使用。
例如:
```shell
$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --ddk_root=/to/your/ddk_path build
```
## 细节说明
CMAKE编译选项:
- 设置`LITE_WITH_NPU=ON``LITE_WITH_ARM=ON`
- 设置DDK根目录路径 `NPU_DDK_ROOT`
其他编译选项与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 \
-DWITH_ARM_DOTPROD=ON \
-DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \
-DWITH_TESTING=ON \
-DLITE_WITH_NPU=ON \
-DANDROID_API_LEVEL=24 \
-DNPU_DDK_ROOT="/path/to/ai_ddk_lib/" \
-DARM_TARGET_OS=android -DARM_TARGET_ARCH_ABI=armv8 -DARM_TARGET_LANG=gcc
make test_mobilenetv1 -j
```
Note: 当前仅支持armv8和gcc编译。
# 运行示例
把MobilenetV1的模型和参数push到指定的`working_dir`.
```shell
working_dir=/data/local/tmp
test_bin=test_npu_pass
model_dir=mobilenet_v1 # as example
repeats=10
batch_size=1
im_channel=3
im_height=224
im_width=224
optimized_model="${model_dir}_opt"
adb shell "mkdir -p ${working_dir}"
adb push $test_bin $working_dir/
adb push $model_dir $working_dir
adb push ai_ddk_lib/lib64/* $working_dir
adb shell chmod +x "${working_dir}/${test_bin}"
adb shell "rm -rf ${working_dir}/${optimized_model}"
adb shell "cd ${working_dir} ; export LD_LIBRARY_PATH=./; ./${test_bin} --model_dir=${model_dir} --optimized_model=${optimized_model} --repeats=${repeats} --batch_size=${batch_size} --im_channel=${im_channel} --im_height=${im_height} --im_width=${im_width}"
```
在华为810的机器上,由运行结果可知单侧通过并且预测速度为6ms左右。
一般第一次的运行时间略长,可以重复多次得到稳定结果。
# 如何在Code中使用
在Lite中使用NPU非常简单,不需要添加太多额外代码。
- 只需要在添加有效place的时候包括`Place{TARGET(kNPU), PRECISION(kFloat)}`即可。
后续的运行和使用没有任何变化。
Note:
唯一需要注意的是,因为构建NPU子图需要提前知晓各个op输入的具体大小,所以生成NPU的`RuntimeProgram`时需要提前初始化输入的大小,主要包括batchsize大小。
如果不提前设置好大小,生成NPU模型时会报错退出。
代码示例:
```cpp
std::vector<Place> valid_places({Place{TARGET(kHost), PRECISION(kFloat)},
Place{TARGET(kARM), PRECISION(kFloat)}});
// if want to use NPU
valid_places.push_back(Place{TARGET(kNPU), PRECISION(kFloat)});
DeviceInfo::Init();
DeviceInfo::Global().SetRunMode(LITE_POWER_HIGH, FLAGS_threads);
lite::Predictor predictor;
predictor.Build(model_dir, preferred_place, valid_places);
auto* input_tensor = predictor.GetInput(0);
input_tensor->Resize(DDim(std::vector<DDim::value_type>({1, 3, 224, 224})));
auto* data = input_tensor->mutable_data<float>();
auto item_size = input_tensor->dims().production();
for (int i = 0; i < item_size; i++) {
data[i] = 1;
}
predictor.Run();
```
# FAQ
## 关于开发板
由于该框架针对的是华为HiAI最新的NPU架构,应该还没有现成的开发板集成了该架构的NPU,所以通常看到的比如海思2359A上的NPU不一样的。
## 关于手机
支持目前最新的是华为810,以及未来要发布的NPU系列手机。
# Note
注意:由于我们的开发是基于华为内部的最新DDK版本编译,如果您的DDK不是最新的,有可能会遇到编译时某个op找不到定义的情况,此时您可以联系我们尝试一起解决。
---
layout: post
title: 基于OpenCL的ARM GPU预测
---
Lite支持在Android系统上运行基于OpenCL的程序,目前提供armv8和armv7的交叉编译。
## 编译
- 编译环境: 使用基于`paddle/fluid/lite/tools/Dockerfile.mobile`生成docker镜像。
- cmake编译选项介绍
* `ARM_TARGET_OS` 代表目标操作系统, 目前仅支持android, 亦为默认值。
* `ARM_TARGET_ARCH_ABI` 代表体系结构类型,支持输入armv8和armv7。其中,armv8等效于arm64-v8a,亦为默认值;armv7等效于 armeabi-v7a。
* `ARM_TARGET_LANG` 代表编译目标文件所使用的编译器, 默认为gcc,支持 gcc和clang两种。
- 参考示例
```bash
# 假设处于Lite源码根目录下
mkdir -p build_opencl && cd build_opencl
cmake .. \
-DLITE_WITH_OPENCL=ON \
-DWITH_GPU=OFF \
-DWITH_MKL=OFF \
-DWITH_LITE=ON \
-DLITE_WITH_CUDA=OFF \
-DLITE_WITH_X86=OFF \
-DLITE_WITH_ARM=ON \
-DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \
-DWITH_TESTING=ON \
-DARM_TARGET_OS="android" -DARM_TARGET_ARCH_ABI="armv8" -DARM_TARGET_LANG="gcc"
# 注意:在编译其他目标对象前,需要先执行如下命令完成OpenCL所需头文件的下载和生成
make opencl_clhpp
# 接着,用户可以选择完整编译
make lite_compile_deps -j4
# 或者选择只编译某一目标文件,例如test_mobilenetv1
make test_mobilenetv1 -j4
```
## 运行示例
- **运行文件准备**
下面以MobileNetV1为例,介绍如何在手机上执行基于OpenCL的ARM GPU推理过程。
**注意:** 以下命令均在Lite源码根目录下运行。
```bash
# 在/data/local/tmp目录下创建OpenCL文件目录
adb shell mkdir -p /data/local/tmp/opencl
adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/buffer
adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/image
# 将OpenCL的kernels文件推送到/data/local/tmp/opencl目录下
adb push lite/opencl/cl_kernel/cl_common.h /data/local/tmp/opencl/cl_kernel/
adb push lite/opencl/cl_kernel/buffer/* /data/local/tmp/opencl/cl_kernel/buffer/
adb push lite/opencl/cl_kernel/image/* /data/local/tmp/opencl/cl_kernel/image/
# 将mobilenet_v1的模型文件推送到/data/local/tmp/opencl目录下
adb shell mkdir -p /data/local/tmp/opencl/mobilenet_v1
adb push build_opencl/third_party/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1/
# 将OpenCL测试程序(如test_mobilenetv1)推送到/data/local/tmp/opencl目录下
adb push build_opencl/lite/api/test_mobilenetv1 /data/local/tmp/opencl
```
- **执行OpenCL推理过程**
使用如下命令运行OpenCL程序。其中,`--cl_path`指定了OpenCL的kernels文件即cl\_kernel所在目录,
`--modle_dir`指定了模型文件所在目录。
```bash
adb shell /data/local/tmp/opencl/test_mobilenetv1 --cl_path=/data/local/tmp/opencl --model_dir=/data/local/tmp/opencl/mobilenet_v1 --warmup=1 --repeats=1
```
**注意:** 因为权重参数均会在Op Kernel第一次运行时进行加载,所以第一次的执行时间会略长。一般将warmup的值设为1,repeats值设为多次。
# 如何在Code中使用
Lite支持对ARM CPU和ARM GPU的混调执行,具体描述如下:
1. 设置Lite推断执行的有效Places,使其包含ARM CPU(kARM)和ARM GPU(kOpenCL);
2. 设置Lite推断执行的偏好Place为ARM GPU(kOpenCL)。
通过以上两步设置,Lite在推断执行过程中如果发现某一Op存在着基于OpenCL的实现,其会优先选择使用该实现执行Op的计算过程。若发现某一Op没有基于OpenCL实现的Kernel,其会自动选择执行基于ARM CPU的实现。
代码示例:
```cpp
DeviceInfo::Init();
DeviceInfo::Global().SetRunMode(LITE_POWER_HIGH, FLAGS_threads);
lite::Predictor predictor;
// 设置Lite推断执行的有效Places为{kHost, kARM, kOpenCL}
std::vector<Place> valid_places({
Place{TARGET(kHost), PRECISION(kFloat)},
Place{TARGET(kARM), PRECISION(kFloat)},
Place{TARGET(kOpenCL), PRECISION(kFloat)},
});
// 设置Lite推断执行的偏好Place为kOpenCL
auto preferred_place = Place({TARGET(kOpenCL), PRECISION(kFloat)});
// 根据有效Places和偏好Place构建模型
predictor.Build(model_dir, preferred_place, valid_places);
// 设置模型的输入
auto* input_tensor = predictor.GetInput(0);
input_tensor->Resize(DDim(std::vector<DDim::value_type>({1, 3, 224, 224})));
auto* data = input_tensor->mutable_data<float>();
auto item_size = input_tensor->dims().production();
for (int i = 0; i < item_size; i++) {
data[i] = 1;
}
// 执行模型推断并获取模型的预测结果
predictor.Run();
auto* out = predictor.GetOutput(0);
```
\ No newline at end of file
---
layout: post
title:
---
1. [./run_test_on_android.md](https://github.com/PaddlePaddle/paddle-mobile/wiki/%E5%A6%82%E4%BD%95%E5%9C%A8Android%E6%89%8B%E6%9C%BA%E4%B8%8A%E8%BF%90%E8%A1%8C%E5%8D%95%E6%B5%8B)
\ No newline at end of file
---
layout: post
title:
---
# Road map
这篇文档会介绍 Paddle-Lite 近期对外的开源版本和计划。
其中包含的 feature 为最小集合,按最终发布的版本为准。
## 2.0.0-beta1-prerelease
预计发布 *2019-8-26 ~ 2days*
- 完善编译和 benchmark 文档
- 增加第三方依赖代码的离线下载功能,加速编译过程
- 去掉 `tiny_publish` 模式下无关的第三方代码下载,可以不依赖任何第三方
## 2.0.0-beta1
预计发布 *2019-9-1~2days*
- `model_optimize_tool` 从 ARM 上执行修改为 Host 上执行,只从 kernel 分布来确定计算图优化;后续硬件针对优化会发布新的工具;
- Paddle 模型支持参数 composed 的格式
- 增加分层编译来控制常用模型的部署库的大小,分两个模式 `basic`, `extra`;默认 `basic` 模式只发布核心的op 和kernel;将控制流相关的Op和kernel 折叠进 `extra` 按需编译
- 增加 INT8 量化,从 PaddleSlim 训练到 PaddleLite 部署完整案例
- 支持内存中加载模型,以支持 APP 的简易加密
## 2.0.0-rc ?
预计发布 *2019-9-16~7days*
---
layout: post
title: 源码编译指南
---
<!--ts-->
* [源码编译指南](#源码编译指南)
* [一、环境准备](#一环境准备)
* [1、 Docker开发环境](#1-docker开发环境)
* [准备Docker镜像](#准备docker镜像)
* [进入Docker容器](#进入docker容器)
* [Docker常用命令](#docker常用命令)
* [2、Linux 开发环境](#2linux-开发环境)
* [交叉编译环境要求](#交叉编译环境要求)
* [具体步骤](#具体步骤)
* [3、Mac OS 开发环境(只支持 tiny publish 编译 )](#3mac-os-开发环境只支持-tiny-publish-编译-)
* [交叉编译环境要求](#交叉编译环境要求-1)
* [具体步骤](#具体步骤-1)
* [二、编译PaddleLite](#二编译paddlelite)
* [下载代码](#下载代码)
* [编译模式与参数](#编译模式与参数)
* [编译代码](#编译代码)
* [加速第三方依赖库的下载](#加速第三方依赖库的下载)
<!-- Added by: yanchunwei, at: Thu Aug 29 16:00:45 CST 2019 -->
<!--te-->
Paddle-Lite 提供了移动端的一键源码编译脚本 `lite/tools/build.sh`,编译流程如下:
1. 环境准备(选择其一):Docker交叉编译环境、Linux交叉编译环境
2. 编译:调用`build.sh`脚本一键编译
## 一、环境准备
目前支持两种编译的环境:
1. Docker 容器环境;
2. Linux(推荐 Ubuntu 16.04)环境。
### 1、 Docker开发环境
[Docker](https://www.docker.com/) 是一个开源的应用容器引擎, 使用沙箱机制创建独立容器,方便运行不同程序。Docker初学者可以参考[Docker使用方法](https://thenewstack.io/docker-station-part-one-essential-docker-concepts-tools-terminology/)正确安装Docker。
#### 准备Docker镜像
有两种方式准备Docker镜像,推荐方式一:从Dockerhub直接拉取Docker镜像
```shell
# 方式一:从Dockerhub直接拉取Docker镜像
docker pull paddlepaddle/paddle-lite:2.0.0_beta
# 方式二:本地源码编译Docker镜像
git clone https://github.com/PaddlePaddle/Paddle-Lite.git
cd Paddle-Lite/lite/tools
mkdir mobile_image
cp Dockerfile.mobile mobile_image/Dockerfile
cd mobile_image
docker build -t paddlepaddle/paddle-lite .
# 镜像编译成功后,可用`docker images`命令,看到`paddlepaddle/paddle-lite`镜像。
```
#### 进入Docker容器
在拉取PaddleLite仓库代码的上层目录,执行如下代码,进入Docker容器:
```shell
docker run -it \
--name paddlelite_docker \
-v $PWD/Paddle-Lite:/Paddle-Lite \
--net=host \
paddlepaddle/paddle-lite /bin/bash
```
该命令的含义:将容器命名为`paddlelite_docker``<container-name>`,将当前目录下的`Paddle-Lite`文件夹挂载到容器中的`/Paddle-Lite`这个根目录下,并进入容器中。至此,完成Docker环境的准备。
#### Docker常用命令
```shell
# 退出容器但不停止/关闭容器:键盘同时按住三个键:CTRL + q + p
# 启动停止的容器
docker start <container-name>
# 从shell进入已启动的容器
docker attach <container-name>
# 停止正在运行的Docker容器
docker stop <container-name>
# 重新启动正在运行的Docker容器
docker restart <container-name>
# 删除Docker容器
docker rm <container-name>
```
### 2、Linux 开发环境
#### 交叉编译环境要求
- gcc、g++、git、make、wget、python、adb
- Java environment
- cmake(建议使用3.10或以上版本)
- Android NDK (建议ndk-r17c)
#### 具体步骤
安装软件部分以 Ubuntu 为例,其他 Linux 发行版类似。
```shell
# 1. Install basic software
apt update
apt-get install -y --no-install-recommends \
gcc g++ git make wget python unzip adb
# 2. Prepare Java env.
apt-get install -y default-jdk
# 3. Install cmake 3.10 or above
wget -c https://mms-res.cdn.bcebos.com/cmake-3.10.3-Linux-x86_64.tar.gz && \
tar xzf cmake-3.10.3-Linux-x86_64.tar.gz && \
mv cmake-3.10.3-Linux-x86_64 /opt/cmake-3.10 && \
ln -s /opt/cmake-3.10/bin/cmake /usr/bin/cmake && \
ln -s /opt/cmake-3.10/bin/ccmake /usr/bin/ccmake
# 4. Download Android NDK for linux-x86_64
# Note: Skip this step if NDK installed
# recommand android-ndk-r17c-darwin-x86_64
# ref: https://developer.android.com/ndk/downloads
cd /tmp && curl -O https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip
cd /opt && unzip /tmp/android-ndk-r17c-linux-x86_64.zip
# 5. Add environment ${NDK_ROOT} to `~/.bashrc`
echo "export NDK_ROOT=/opt/android-ndk-r17c" >> ~/.bashrc
source ~/.bashrc
```
至此,完成 Linux 交叉编译环境的准备。
### 3、Mac OS 开发环境(只支持 tiny publish 编译 )
#### 交叉编译环境要求
- gcc、git、make、curl、unzip、java
- cmake(建议使用3.10或以上版本)
- 编译Android: Android NDK (建议ndk-r17c)
- 编译IOS: XCode(Version 10.1)
#### 具体步骤
```bash
# 1. Install basic software
brew install -y curl gcc git make unzip
# 2. Install cmake 3.10 or above
brew install -y cmake
# 3. Download Android NDK for Mac
# recommand android-ndk-r17c-darwin-x86_64
# ref: https://developer.android.com/ndk/downloads
# Note: Skip this step if NDK installed
cd ~/Documents && curl -O https://dl.google.com/android/repository/android-ndk-r17c-darwin-x86_64.zip
cd ~/Library && unzip ~/Documents/android-ndk-r17c-darwin-x86_64.zip
# 4. Add environment ${NDK_ROOT} to `~/.bash_profile`
echo "export NDK_ROOT=~/Library/android-ndk-r17c" >> ~/.bash_profile
source ~/.bash_profile
# 5. Install Java Environment
brew cask install java
```
至此,完成 Mac 交叉编译环境的准备。
## 二、编译PaddleLite
### 下载代码
```shell
git clone https://github.com/PaddlePaddle/Paddle-Lite.git
cd Paddle-Lite
git checkout <release-version-tag>
```
### 编译模式与参数
编译脚本`./lite/tools/build.sh`,支持三种编译模式:
| 编译模式 | 介绍 | 适用对象 |
|:-------:|-----|:-------:|
| tiny_publish | 编译移动端部署库,无第三方库依赖 | 用户 |
| full_publish | 编译移动端部署库,有第三方依赖如protobuf、glags等,含有可将模型转换为无需protobuf依赖的naive buffer格式的工具,供tiny_publish库使用 | 用户 |
| test | 编译指定`arm_os``arm_abi`下的移动端单元测试 | 框架开发者 |
编译脚本`./lite/tools/build.sh`,追加参数说明:
| 参数 | 介绍 | 值 |
|-----------|-------------|-------------|
| --arm_os |必选,选择安装平台 | `android``ios``ios64``armlinux` |
| --arm_abi |必选,选择编译的arm版本,其中`armv7hf`为ARMLinux编译时选用| `armv8``armv7``armv7hf`|
| --arm_lang |arm_os=android时必选,选择编译器 | `gcc``clang`|
| --android_stl |arm_os=android时必选,选择静态链接STL或动态链接STL | `c++_static``c++_shared`|
| --build_extra | 可选,是否编译控制流相关op、kernel。(**编译demo时必须选择为ON**) | `ON``OFF` |
| target |必选,选择编译模式,`tiny_publish`为编译移动端部署库、`full_publish`为带依赖的移动端部署库、`test`为移动端单元测试、`ios`为编译ios端`tiny_publish` | `tiny_publish``full_publish``test``ios` |
### 编译代码
注意:编译前请删除lite/api目录下的paddle_use_ops.h和paddle_use_kernels.h
#### 编译`tiny publish`动态库
##### Android
```shell
./lite/tools/build.sh \
--arm_os=android \
--arm_abi=armv8 \
--arm_lang=gcc \
--android_stl=c++_static \
tiny_publish
```
##### IOS
```shell
./lite/tools/build.sh \
--arm_os=ios64 \
--arm_abi=armv8 \
ios
```
ios tiny publish支持的编译选项:
* `--arm_os`: 可选ios或者ios64
* `--arm_abi`: 可选armv7和armv8
* 如果mac编译过程中报错:"Invalid CMAKE_DEVELOPER_ROOT: does not exist", 运行:
```shell
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
```
##### ARMLinux(目前只支持Docker编译)
```shell
./lite/tools/build.sh \
--arm_os=armlinux \
--arm_abi=armv7hf \
--arm_lang=gcc \
tiny_publish
```
#### 编译`full publish`动态库(**Mac OS下不支持**)
注意:编译前请删除lite/api目录下的paddle_use_ops.h和paddle_use_kernels.h
##### Android
```shell
./lite/tools/build.sh \
--arm_os=android \
--arm_abi=armv8 \
--arm_lang=gcc \
--android_stl=c++_static \
full_publish
```
##### ARMLinux(目前只支持Docker编译)
```shell
./lite/tools/build.sh \
--arm_os=armlinux \
--arm_abi=armv7hf \
--arm_lang=gcc \
full_publish
```
编译最终产物位于 `build.lite.xxx.xxx.xxx` 下的 `inference_lite_lib.xxx.xxx` ,如 Android 下 ARMv7 的产物位于
![](https://user-images.githubusercontent.com/328693/63631174-5c53e580-c656-11e9-8726-d8cf7500a7f2.png)
相应的内容(可能)如下
![](https://user-images.githubusercontent.com/328693/63631178-65dd4d80-c656-11e9-804e-c091963f6dc0.png)
### 加速第三方依赖库的下载
移动端相关编译所需的第三方库均位于 `<PaddleLite>/third-party` 目录下,默认编译过程中,会利用`git submodule update --init --recursive`链上相关的第三方依赖的仓库。
为加速`full_publish``test`编译模式中对`protobuf`等第三方依赖的下载,`build.sh``ci_build.sh`支持了从国内 CDN 下载第三方依赖的压缩包。
使用方法:`git clone``Paddle-Lite`仓库代码后,手动删除本地仓库根目录下的`third-party`目录:
```shell
git clone https://github.com/PaddlePaddle/Paddle-Lite.git
git checkout <release-version-tag>
cd Paddle-Lite
rm -rf third-party
```
之后再根据本文档,进行后续编译时,便会忽略第三方依赖对应的`submodule`,改为下载第三方压缩包。
---
layout: post
title: 支持OP列表
---
## Ops
- argmax
- axpy
- batch_norm
- beam_search
- beam_search_decode
- bilinear_interp
- box_coder
- calib
- calib_once
- cast
- concat
- conv2d
- conv2d_transpose
- crop
- decode_bboxes
- density_prior_box
- depthwise_conv2d
- dropout
- elementwise_add
- elementwise_max
- elementwise_mul
- elementwise_sub
- exp
- fake_dequantize_max_abs
- fake_quantize_moving_average_abs_max
- fc
- feed
- fetch
- fill_constant
- fusion_elementwise_add_activation
- fusion_elementwise_max_activation
- fusion_elementwise_mul_activation
- fusion_elementwise_sub_activation
- graph_op
- gru
- gru_unit
- im2sequence
- increment
- io_copy
- io_copy_once
- is_empty
- layout
- layout_once
- leaky_relu
- less_than
- lod_reset
- log
- logical_and
- logical_xor
- lookup_table
- lrn
- mul
- multiclass_nms
- nearest_interp
- negative
- norm
- pad2d
- pool2d
- power
- prelu
- prior_box
- read_from_array
- reduce_max
- relu
- relu_clipped
- reshape
- reshape2
- scale
- sequence_expand
- sequence_pool
- sequence_softmax
- shape
- shuffle_channel
- sigmoid
- slice
- softmax
- split
- square
- swish
- tanh
- top_k
- transpose
- transpose2
- while
- write_to_array
- yolo_box
## Kernels
### ARM kernels
- argmax
- axpy
- batch_norm
- beam_search
- beam_search_decode
- bilinear_interp
- box_coder
- calib
- calib_once
- cast
- concat
- conv2d
- conv2d_transpose
- crop
- decode_bboxes
- density_prior_box
- depthwise_conv2d
- dropout
- elementwise_add
- elementwise_max
- elementwise_mul
- exp
- fc
- fill_constant
- fusion_elementwise_add_activation
- fusion_elementwise_max_activation
- fusion_elementwise_mul_activation
- gru
- gru_unit
- im2sequence
- increment
- is_empty
- leaky_relu
- less_than
- lod_reset
- log
- logical_and
- logical_xor
- lookup_table
- lrn
- mul
- multiclass_nms
- nearest_interp
- negative
- norm
- pad2d
- pool2d
- power
- prelu
- prior_box
- read_from_array
- reduce_max
- relu
- relu_clipped
- scale
- sequence_expand
- sequence_pool
- sequence_softmax
- shape
- shuffle_channel
- sigmoid
- slice
- softmax
- split
- swish
- tanh
- top_k
- transpose
- transpose2
- while
- write_to_array
- yolo_box
### X86 kernels
- batch_norm
- concat
- conv2d
- depthwise_conv2d
- dropout
- elementwise_add
- elementwise_sub
- fc
- fill_constant
- mul
- pool2d
- relu
- scale
- softmax
- square
### OpenCL kernels
- conv2d
- depthwise_conv2d
- elementwise_add
- fc
- fusion_elementwise_add_activation
- io_copy
- io_copy_once
- mul
- pool2d
- relu
---
layout: post
title: 技术特点
---
不同于普通的移动端预测基于类 Caffe 的架构,Lite 架构最早的设计目标来源于 Paddle Server 和 Mobile 两种场景的要求,其中 Server 端需要有完善的图分析和优化能力,而 Mobile 端要求有轻量级部署的能力,两种场景共同的要求是高性能,多硬件支持等。
基于上述要求,Lite 架构完整实现了相应的能力,重点描述如下。
## 多硬件支持
Lite 架构已经验证和完整支持从 Mobile 到 Server 多种硬件的支持需求,包括 ARM CPU, ARM GPU, Huawei NPU, Intel X86 CPU, NV GPU 等。 得益于对不同硬件适度的抽象,在Lite 框架本身清晰的同时支持不同硬件的特殊调度需求,使得Lite架构在框架的清晰程度和硬件的特定调度优化上达到很好的平衡,比如 Nvidia GPU 上复杂的 stream, event 分配,在 Lite 中可以清晰表示。
多种硬件的 Kernel 在代码层和执行层均互不干扰,用户可以自由插拔任何硬件的支持。
## 高性能
高性能来源于两方面,一是 Kernel 优化;二是框架执行。
Kernel 方面,我们对相应硬件上的 Kernel 通过指令集、操作熔合、算法改写等方式进行了深入优化。
框架执行方面,通过简化 Op 和 Kernel 的功能,使得执行期的框架开销极低;此外,框架极大的灵活性可以支持各种硬件的特定调度优化以提升整体效率。
## 量化支持
Lite 支持Paddle Slim 强大的量化训练完毕的模型,因此完整保留了量化计算的高性能以及量化训练的高精度。
## 强大的图分析和优化能力
在图分析优化上,不同于常规的移动端预测引擎基于 Python 脚本工具转化模型, Lite 架构上有完整基于 C++ 开发的 IR 及相应 Pass 集合,以支持操作熔合 (Operator fusion),计算剪枝 (Computation pruning),存储优化 (Memory optimization),量化计算 (Quantitative computation) 等多类计算图优化。
更多的优化策略可以简单通过添加 Pass 的方式模块化支持。
## 轻量级部署
尽管图优化上有复杂的策略,但并不影响移动端的轻量级部署,图分析模块和最终的执行引擎可以拆开使用,最终部署只有一层薄薄的 Kernel 。
## 可支持任意硬件的混合调度
Lite 支持系统可见任意硬件的混合调度,目前已经支持 ARM CPU 和 ARM GPU 的 Kernel 自动混合调度,并验证了 X86 CPU 和 Nvidia GPU 间的混合调度。
支持混合调度的考量有两点:
1. 当系统内同时存在多种硬件可用时,混合调度可以充分利用各类硬件资源
2. 随着支持模型的增多,各硬件对kernel的支持丰富度不一,难免需要混合调度才能跑通
Lite架构通过从底层支持 `Type system` 的方式通用建模各类混合执行的行为,从而能够相对完备地支持混调。
---
layout: post
title: 文档指南
---
Lite是一种轻量级、灵活性强、易于扩展的高性能的深度学习预测框架,它可以支持诸如ARM、OpenCL、NPU等等多种终端,同时拥有强大的图优化及预测加速能力。如果您希望将Lite框架集成到自己的项目中,那么只需要如下几步简单操作即可。
# 一. 准备模型
Lite框架目前支持的模型结构为[PaddlePaddle](https://github.com/PaddlePaddle/Paddle)深度学习框架产出的模型格式。因此,在您开始使用 Lite 框架前您需要准备一个由PaddlePaddle框架保存的模型。
如果您手中的模型是由诸如Caffe2、Tensorflow等框架产出的,那么我们推荐您使用 [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) 工具进行模型格式转换。
# 二. 模型优化
Lite框架拥有强大的加速、优化策略及实现,其中包含诸如量化、子图融合、Kernel优选等等优化手段,为了方便您使用这些优化策略,我们提供了[Model Optimize Tool](../model_optimize_tool)帮助您轻松进行模型优化。优化后的模型更轻量级,耗费资源更少,并且执行速度也更快。
Model Optimize Tool的详细介绍,请您参考 [模型优化方法](../model_optimize_tool)
使用Model Optimize Tool,您只需执行以下代码:
## 1. Android
- 将Android设备通过USB连接到PC机,在PC机的shell中执行如下命令(不是在docker里面):
```shell
$ cd <PaddleLite_base_path>
$ adb push ./build.lite.android.armv8.gcc/lite/api/model_optimize_tool /data/local/tmp
$ adb shell
```
注意:如果系统不能识别adb命令,请参考https://developer.android.google.cn/studio/releases/platform-tools 安装适合PC机的Android SDK
- 进入手机shell后,执行如下命令:
```shell
./model_optimize_tool \
--model_dir=<model_param_dir> \
--model_file=<model_path> \
--param_file=<param_path> \
--optimize_out_type=(protobuf|naive_buffer) \
--optimize_out=<output_optimize_model_dir> \
--valid_targets=(arm|opencl|x86) \
--prefer_int8_kernel=(ture|false)
```
## 2. ARM Linux
- 将build.lite.android.armv8.gcc/lite/api目录下的model_optimize_tool拷贝至ARM Linux设备的/home/[user]/目录下(例如采用scp方式),然后在ARM Linux设备的/home/[user]/目录下直接执行如下命令:
```shell
./model_optimize_tool \
--model_dir=<model_param_dir> \
--model_file=<model_path> \
--param_file=<param_path> \
--optimize_out_type=(protobuf|naive_buffer) \
--optimize_out=<output_optimize_model_dir> \
--valid_targets=(arm|opencl|x86) \
--prefer_int8_kernel=(ture|false)
```
其中,optimize_out为您希望的优化模型的输出路径。optimize_out_type则可以指定输出模型的序列化方式,其目前支持Protobuf与Naive Buffer两种方式,其中Naive Buffer是一种更轻量级的序列化/反序列化实现。如果你需要使用Lite在mobile端进行预测,那么您需要设置optimize_out_type=naive_buffer。
# 三. 使用Lite框架执行预测
在上一节中,我们已经通过Model Optimize Tool获取到了优化后的模型,使用优化模型进行预测也十分的简单。为了方便您的使用,Lite进行了良好的API设计,隐藏了大量您不需要投入时间研究的细节。您只需要简单的五步即可使用Lite在移动端完成预测(以C++ API进行说明):
1. 声明MobileConfig。在config中可以设置**从文件加载模型**也可以设置**从memory加载模型**。从文件加载模型需要声明模型文件路径,如 `config.set_model_dir(FLAGS_model_dir)` ;从memory加载模型方法现只支持加载优化后模型的naive buffer,实现方法为:
`void set_model_buffer(model_buffer,model_buffer_size,param_buffer,param_buffer_size) `
2. 创建Predictor。Predictor即为Lite框架的预测引擎,为了方便您的使用我们提供了 `CreatePaddlePredictor` 接口,你只需要简单的执行一行代码即可完成预测引擎的初始化,`std::shared_ptr<PaddlePredictor> predictor = CreatePaddlePredictor(config)`
3. 准备输入。执行predictor->GetInput(0)您将会获得输入的第0个field,同样的,如果您的模型有多个输入,那您可以执行 `predictor->GetInput(i)` 来获取相应的输入变量。得到输入变量后您可以使用Resize方法指定其具体大小,并填入输入值。
4. 执行预测。您只需要执行 `predictor->Run()` 即可使用Lite框架完成预测。
5. 获取输出。与输入类似,您可以使用 `predictor->GetOutput(i)` 来获得输出的第i个变量。您可以通过其shape()方法获取输出变量的维度,通过 `data<T>()` 模板方法获取其输出值。
# 四. Lite API
为了方便您的使用,我们提供了C++与Java两种API,并且提供了相应的api使用的[完整示例](../demos),您可以参考示例中的说明快速了解C++/Java的API使用方法,并集成到您自己的项目中去。需要说明的是,为了减少第三方库的依赖、提高Lite预测框架的通用性,在移动端使用Lite API您需要准备Naive Buffer存储格式的模型,具体方法可参考第2节`模型优化`
# 五. 测试工具
为了使您更好的了解并使用Lite框架,我们向有进一步使用需求的用户开放了 [Lite Model Debug Tool](../debug_tools)[Profile Monitor Tool](../debug_tools)。Lite Model Debug Tool可以用来查找Lite框架与PaddlePaddle框架在执行预测时模型中的对应变量值是否有差异,进一步快速定位问题Op,方便复现与排查问题。Profile Monitor Tool可以帮助您了解每个Op的执行时间消耗,其会自动统计Op执行的次数,最长、最短、平均执行时间等等信息,为性能调优做一个基础参考。您可以通过 [相关专题](../debug_tools) 了解更多内容。
---
layout: post
title: 通过 X2Paddle 转换模型
---
[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)支持将Caffe/TensorFlow模型转换为PaddlePaddle模型。目前X2Paddle支持的模型参考[x2paddle_model_zoo](https://github.com/PaddlePaddle/X2Paddle/blob/develop/x2paddle_model_zoo.md)
## 安装
```
pip install x2paddle
```
安装最新版本,可使用如下安装方式
```
pip install git+https://github.com/PaddlePaddle/X2Paddle.git@develop
```
## 使用
### Caffe
```
x2paddle --framework caffe \
--prototxt model.proto \
--weight model.caffemodel \
--save_dir paddle_model
```
### TensorFlow
```
x2paddle --framework tensorflow \
--model model.pb \
--save_dir paddle_model
```
## 转换结果说明
在指定的`save_dir`下生成两个目录
1. inference_model : 模型结构和参数均序列化保存的模型格式
2. model_with_code : 保存了模型参数文件和模型的python代码
## 问题反馈
X2Paddle使用时存在问题时,欢迎您将问题或Bug报告以[Github Issues](https://github.com/PaddlePaddle/X2Paddle/issues)的形式提交给我们,我们会实时跟进。
......@@ -38,4 +38,9 @@ plugins:
# - vendor/cache/
# - vendor/gems/
# - vendor/ruby/
permalink: /:title/
#permalink: /:title/
collections:
all_pages:
output: true
permalink: /:path/
......@@ -8,43 +8,43 @@ Paddle-Lite 框架是 PaddleMobile 新一代架构,重点支持移动端推理
## 简介
- [技术特点]({{ site.baseurl }}/tech_highlights)
- [架构设计]({{ site.baseurl }}/architecture)
- [Road Map]({{ site.baseurl }}/roadmap)
- [技术特点]({{ site.baseurl }}/develop/tech_highlights)
- [架构设计]({{ site.baseurl }}/develop/architecture)
- [Road Map]({{ site.baseurl }}/develop/roadmap)
## Benchmark
- [最新性能]({{ site.baseurl }}/benchmark)
- [测试方法]({{ site.baseurl }}/benchmark_tools)
- [最新性能]({{ site.baseurl }}/develop/benchmark)
- [测试方法]({{ site.baseurl }}/develop/benchmark_tools)
## 安装
- [源码编译]({{ site.baseurl }}/source_compile)
- [源码编译]({{ site.baseurl }}/develop/source_compile)
## 使用
- [使用流程]({{ site.baseurl }}/tutorial)
- [C++实例]({{ site.baseurl }}/cpp_demo)
- [Java实例]({{ site.baseurl }}/java_demo)
- [使用流程]({{ site.baseurl }}/develop/tutorial)
- [C++实例]({{ site.baseurl }}/develop/cpp_demo)
- [Java实例]({{ site.baseurl }}/develop/java_demo)
- [Android/IOS APP demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)
- [模型转化方法]({{ site.baseurl }}/model_optimize_tool)
- [模型转化方法]({{ site.baseurl }}/develop/model_optimize_tool)
## 进阶
- [通过 X2Paddle 支持 Caffe, TensorFlow 模型]({{ site.baseurl }}/x2paddle)
- [模型量化]({{ site.baseurl }}/model_quantization)
- [支持Op列表]({{ site.baseurl }}/support_operation_list)
- [新增Op方法]({{ site.baseurl }}/add_new_operation)
- [测试工具]({{ site.baseurl }}/debug_tools)
- [调试方法]({{ site.baseurl }}/debug_tools)
- [使用华为NPU]({{ site.baseurl }}/npu)
- [使用Android GPU]({{ site.baseurl }}/opencl)
- [使用FPGA]({{ site.baseurl }}/fpga)
- [模型量化]({{ site.baseurl }}/develop/model_quantization)
- [支持Op列表]({{ site.baseurl }}/develop/support_operation_list)
- [新增Op方法]({{ site.baseurl }}/develop/add_new_operation)
- [测试工具]({{ site.baseurl }}/develop/debug_tools)
- [调试方法]({{ site.baseurl }}/develop/debug_tools)
- [使用华为NPU]({{ site.baseurl }}/develop/npu)
- [使用Android GPU]({{ site.baseurl }}/develop/opencl)
- [使用FPGA]({{ site.baseurl }}/develop/fpga)
## 开发者文档
- [开发基础须知]({{ site.baseurl }}/for-developer)
- [架构详解]({{ site.baseurl }}/architecture-intro)
- [开发基础须知]({{ site.baseurl }}/develop/for-developer)
- [架构详解]({{ site.baseurl }}/develop/architecture-intro)
## FAQ
......@@ -53,4 +53,7 @@ Paddle-Lite 框架是 PaddleMobile 新一代架构,重点支持移动端推理
## paddle-mobile
- [paddle-mobile 编译]({{ site.baseurl }}/mobile)
- [paddle-mobile 编译]({{ site.baseurl }}/develop/mobile)
## 以前文档
- [v2.0.0-beta1]({{ site.baseurl }}/v2.0.0-beta1/index)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册