未验证 提交 1cca6f31 编写于 作者: myq406450149's avatar myq406450149 提交者: GitHub

Merge pull request #5 from PaddlePaddle/develop

sync 4.1
...@@ -105,3 +105,5 @@ metal/paddle-mobile-demo/paddle-mobile-demo/Resources ...@@ -105,3 +105,5 @@ metal/paddle-mobile-demo/paddle-mobile-demo/Resources
metal/paddle-mobile-demo/paddle-mobile-demo/Resources/images metal/paddle-mobile-demo/paddle-mobile-demo/Resources/images
metal/paddle-mobile-demo/paddle-mobile-demo/Resources/models metal/paddle-mobile-demo/paddle-mobile-demo/Resources/models
metal/MobileNetDemo/MobileNetDemo/Resources metal/MobileNetDemo/MobileNetDemo/Resources
build*
...@@ -61,6 +61,7 @@ lite_option(LITE_WITH_ARM "Enable ARM in lite mode" OFF) ...@@ -61,6 +61,7 @@ lite_option(LITE_WITH_ARM "Enable ARM in lite mode" OFF)
lite_option(LITE_WITH_NPU "Enable NPU in lite mode" OFF) lite_option(LITE_WITH_NPU "Enable NPU in lite mode" OFF)
lite_option(LITE_WITH_XPU "Enable XPU in lite mode" OFF) lite_option(LITE_WITH_XPU "Enable XPU in lite mode" OFF)
lite_option(LITE_WITH_BM "Enable BM in lite mode" OFF) lite_option(LITE_WITH_BM "Enable BM in lite mode" OFF)
lite_option(LITE_WITH_TRAIN "Enable training operators and kernels in lite" OFF)
lite_option(LITE_WITH_OPENMP "Enable OpenMP in lite framework" ON) lite_option(LITE_WITH_OPENMP "Enable OpenMP in lite framework" ON)
lite_option(LITE_WITH_OPENCL "Enable OpenCL support in lite" OFF) lite_option(LITE_WITH_OPENCL "Enable OpenCL support in lite" OFF)
lite_option(LITE_WITH_FPGA "Enable FPGA support in lite" OFF) lite_option(LITE_WITH_FPGA "Enable FPGA support in lite" OFF)
...@@ -76,6 +77,7 @@ lite_option(LITE_BUILD_TAILOR "Enable tailoring library according to model" OFF) ...@@ -76,6 +77,7 @@ lite_option(LITE_BUILD_TAILOR "Enable tailoring library according to model" OFF)
# cv build options # cv build options
lite_option(LITE_WITH_CV "Enable build cv image in lite" OFF) lite_option(LITE_WITH_CV "Enable build cv image in lite" OFF)
lite_option(LITE_WITH_STATIC_CUDA "Statically link cuda libraries." ON) lite_option(LITE_WITH_STATIC_CUDA "Statically link cuda libraries." ON)
lite_option(LITE_WITH_ARM_CLANG "when arm lang is clang, its ON." OFF)
# TODO(Superjomn) Remove WITH_ANAKIN option if not needed latter. # TODO(Superjomn) Remove WITH_ANAKIN option if not needed latter.
if(ANDROID OR IOS OR ARMLINUX) if(ANDROID OR IOS OR ARMLINUX)
...@@ -130,7 +132,8 @@ endif() ...@@ -130,7 +132,8 @@ endif()
if (WITH_LITE AND LITE_WITH_LIGHT_WEIGHT_FRAMEWORK) if (WITH_LITE AND LITE_WITH_LIGHT_WEIGHT_FRAMEWORK)
message(STATUS "Building the mobile framework") message(STATUS "Building the mobile framework")
include(cross_compiling/postproject) include(cross_compiling/postproject)
include(cross_compiling/npu) # check and prepare NPU DDK include(device/npu) # check and prepare NPU DDK
include(device/xpu) # check and prepare XPU SDK
# We compile the mobile deployment library when LITE_ON_TINY_PUBLISH=ON # We compile the mobile deployment library when LITE_ON_TINY_PUBLISH=ON
# So the following third party dependencies are not needed. # So the following third party dependencies are not needed.
...@@ -171,7 +174,7 @@ endif() ...@@ -171,7 +174,7 @@ endif()
######################################################################################## ########################################################################################
if(LITE_WITH_XPU) if(LITE_WITH_XPU)
include(xpu) include(device/xpu)
endif() endif()
include(external/mklml) # download mklml package include(external/mklml) # download mklml package
......
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
# Paddle Lite # Paddle Lite
<!--[![Build Status](https://travis-ci.org/PaddlePaddle/Paddle-Lite.svg?branch=develop&longCache=true&style=flat-square)](https://travis-ci.org/PaddlePaddle/Paddle-Lite)--> <!--[![Build Status](https://travis-ci.org/PaddlePaddle/Paddle-Lite.svg?branch=develop&longCache=true&style=flat-square)](https://travis-ci.org/PaddlePaddle/Paddle-Lite)-->
[![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://paddlepaddle.github.io/Paddle-Lite/) [![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://paddle-lite.readthedocs.io/zh/latest/)
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE)
<!-- [![Release](https://img.shields.io/github/release/PaddlePaddle/Paddle-Mobile.svg)](https://github.com/PaddlePaddle/Paddle-Mobile/releases) --> <!-- [![Release](https://img.shields.io/github/release/PaddlePaddle/Paddle-Mobile.svg)](https://github.com/PaddlePaddle/Paddle-Mobile/releases) -->
Paddle Lite is an updated version of Paddle-Mobile, an open-open source deep learning framework designed to make it easy to perform inference on mobile, embeded, and IoT devices. It is compatible with PaddlePaddle and pre-trained models from other sources. Paddle Lite is an updated version of Paddle-Mobile, an open-open source deep learning framework designed to make it easy to perform inference on mobile, embeded, and IoT devices. It is compatible with PaddlePaddle and pre-trained models from other sources.
For tutorials, please see [PaddleLite Document](https://paddlepaddle.github.io/Paddle-Lite/). For tutorials, please see [PaddleLite Document](https://paddle-lite.readthedocs.io/zh/latest/).
## Key Features ## Key Features
......
# Paddle Lite # Paddle Lite
<!--[![Build Status](https://travis-ci.org/PaddlePaddle/Paddle-Lite.svg?branch=develop&longCache=true&style=flat-square)](https://travis-ci.org/PaddlePaddle/Paddle-Lite)--> <!--[![Build Status](https://travis-ci.org/PaddlePaddle/Paddle-Lite.svg?branch=develop&longCache=true&style=flat-square)](https://travis-ci.org/PaddlePaddle/Paddle-Lite)-->
[![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://paddlepaddle.github.io/Paddle-Lite/) [![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://paddle-lite.readthedocs.io/zh/latest/)
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE)
<!-- [![Release](https://img.shields.io/github/release/PaddlePaddle/Paddle-Mobile.svg)](https://github.com/PaddlePaddle/Paddle-Mobile/releases) --> <!-- [![Release](https://img.shields.io/github/release/PaddlePaddle/Paddle-Mobile.svg)](https://github.com/PaddlePaddle/Paddle-Mobile/releases) -->
Paddle Lite为Paddle-Mobile的升级版,定位支持包括手机移动端在内更多场景的轻量化高效预测,支持更广泛的硬件和平台,是一个高性能、轻量级的深度学习预测引擎。在保持和PaddlePaddle无缝对接外,也兼容支持其他训练框架产出的模型。 Paddle Lite为Paddle-Mobile的升级版,定位支持包括手机移动端在内更多场景的轻量化高效预测,支持更广泛的硬件和平台,是一个高性能、轻量级的深度学习预测引擎。在保持和PaddlePaddle无缝对接外,也兼容支持其他训练框架产出的模型。
完整使用文档位于 [PaddleLite 文档](https://paddlepaddle.github.io/Paddle-Lite/) 完整使用文档位于 [PaddleLite 文档](https://paddle-lite.readthedocs.io/zh/latest/)
## 特性 ## 特性
......
...@@ -122,6 +122,9 @@ if (LITE_WITH_ARM) ...@@ -122,6 +122,9 @@ if (LITE_WITH_ARM)
endif() endif()
endif() endif()
if (LITE_WITH_TRAIN)
add_definitions("-DLITE_WITH_TRAIN")
endif()
if (WITH_ARM_DOTPROD) if (WITH_ARM_DOTPROD)
add_definitions("-DWITH_ARM_DOTPROD") add_definitions("-DWITH_ARM_DOTPROD")
......
...@@ -23,7 +23,7 @@ endif() ...@@ -23,7 +23,7 @@ endif()
get_filename_component(AR_PATH ${CMAKE_CXX_COMPILER} PATH) get_filename_component(AR_PATH ${CMAKE_CXX_COMPILER} PATH)
find_file(AR_TOOL NAMES llvm-ar PATHS ${AR_PATH}) find_file(AR_TOOL NAMES llvm-ar PATHS ${AR_PATH} NO_DEFAULT_PATH)
if(NOT AR_TOOL) if(NOT AR_TOOL)
message(ERROR "Failed to find AR_TOOL in ${AR_PATH}") message(ERROR "Failed to find AR_TOOL in ${AR_PATH}")
......
...@@ -57,10 +57,14 @@ function(check_linker_flag) ...@@ -57,10 +57,14 @@ function(check_linker_flag)
endforeach() endforeach()
set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} PARENT_SCOPE) set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} PARENT_SCOPE)
endfunction() endfunction()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
if (LITE_ON_TINY_PUBLISH) if (LITE_ON_TINY_PUBLISH)
if(NOT LITE_WITH_PYTHON) if((NOT LITE_WITH_PYTHON))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
endif()
if(LITE_WITH_OPENCL AND (ARM_TARGET_LANG STREQUAL "clang"))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
endif() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -Ofast -Os -fomit-frame-pointer -fno-asynchronous-unwind-tables -fno-unwind-tables") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -Ofast -Os -fomit-frame-pointer -fno-asynchronous-unwind-tables -fno-unwind-tables")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections")
......
...@@ -17,15 +17,16 @@ if(NOT LITE_WITH_NPU) ...@@ -17,15 +17,16 @@ if(NOT LITE_WITH_NPU)
endif() endif()
if(NOT DEFINED NPU_DDK_ROOT) if(NOT DEFINED NPU_DDK_ROOT)
set(NPU_DDK_ROOT $ENV{NPU_DDK_ROOT}) set(NPU_DDK_ROOT $ENV{NPU_DDK_ROOT})
if(NOT NPU_DDK_ROOT) if(NOT NPU_DDK_ROOT)
message(FATAL_ERROR "Must set NPU_DDK_ROOT or env NPU_DDK_ROOT when LITE_WITH_NPU=ON") message(FATAL_ERROR "Must set NPU_DDK_ROOT or env NPU_DDK_ROOT when LITE_WITH_NPU=ON")
endif() endif()
endif() endif()
message(STATUS "NPU_DDK_ROOT: ${NPU_DDK_ROOT}") message(STATUS "NPU_DDK_ROOT: ${NPU_DDK_ROOT}")
find_path(NPU_DDK_INC NAMES HiAiModelManagerService.h find_path(NPU_DDK_INC NAMES HiAiModelManagerService.h
PATHS ${NPU_DDK_ROOT}/include NO_DEFAULT_PATH) PATHS ${NPU_DDK_ROOT}/include
NO_DEFAULT_PATH)
if(NOT NPU_DDK_INC) if(NOT NPU_DDK_INC)
message(FATAL_ERROR "Can not find HiAiModelManagerService.h in ${NPU_DDK_ROOT}/include") message(FATAL_ERROR "Can not find HiAiModelManagerService.h in ${NPU_DDK_ROOT}/include")
endif() endif()
...@@ -34,21 +35,24 @@ include_directories("${NPU_DDK_ROOT}/include") ...@@ -34,21 +35,24 @@ include_directories("${NPU_DDK_ROOT}/include")
set(NPU_SUB_LIB_PATH "lib64") set(NPU_SUB_LIB_PATH "lib64")
if(ARM_TARGET_ARCH_ABI STREQUAL "armv8") if(ARM_TARGET_ARCH_ABI STREQUAL "armv8")
set(NPU_SUB_LIB_PATH "lib64") set(NPU_SUB_LIB_PATH "lib64")
endif() endif()
if(ARM_TARGET_ARCH_ABI STREQUAL "armv7") if(ARM_TARGET_ARCH_ABI STREQUAL "armv7")
set(NPU_SUB_LIB_PATH "lib") set(NPU_SUB_LIB_PATH "lib")
endif() endif()
find_library(NPU_DDK_HIAI_FILE NAMES hiai find_library(NPU_DDK_HIAI_FILE NAMES hiai
PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}) PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}
NO_DEFAULT_PATH)
find_library(NPU_DDK_IR_FILE NAMES hiai_ir find_library(NPU_DDK_IR_FILE NAMES hiai_ir
PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}) PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}
NO_DEFAULT_PATH)
find_library(NPU_DDK_IR_BUILD_FILE NAMES hiai_ir_build find_library(NPU_DDK_IR_BUILD_FILE NAMES hiai_ir_build
PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}) PATHS ${NPU_DDK_ROOT}/${NPU_SUB_LIB_PATH}
NO_DEFAULT_PATH)
if(NOT NPU_DDK_HIAI_FILE) if(NOT NPU_DDK_HIAI_FILE)
message(FATAL_ERROR "Can not find NPU_DDK_HIAI_FILE in ${NPU_DDK_ROOT}") message(FATAL_ERROR "Can not find NPU_DDK_HIAI_FILE in ${NPU_DDK_ROOT}")
...@@ -76,6 +80,3 @@ endif() ...@@ -76,6 +80,3 @@ endif()
set(npu_runtime_libs npu_ddk_hiai CACHE INTERNAL "npu ddk runtime libs") set(npu_runtime_libs npu_ddk_hiai CACHE INTERNAL "npu ddk runtime libs")
set(npu_builder_libs npu_ddk_ir npu_ddk_ir_build CACHE INTERNAL "npu ddk builder libs") set(npu_builder_libs npu_ddk_ir npu_ddk_ir_build CACHE INTERNAL "npu ddk builder libs")
...@@ -17,15 +17,16 @@ if(NOT LITE_WITH_XPU) ...@@ -17,15 +17,16 @@ if(NOT LITE_WITH_XPU)
endif() endif()
if(NOT DEFINED XPU_SDK_ROOT) if(NOT DEFINED XPU_SDK_ROOT)
set(XPU_SDK_ROOT $ENV{XPU_SDK_ROOT}) set(XPU_SDK_ROOT $ENV{XPU_SDK_ROOT})
if(NOT XPU_SDK_ROOT) if(NOT XPU_SDK_ROOT)
message(FATAL_ERROR "Must set XPU_SDK_ROOT or env XPU_SDK_ROOT when LITE_WITH_XPU=ON") message(FATAL_ERROR "Must set XPU_SDK_ROOT or env XPU_SDK_ROOT when LITE_WITH_XPU=ON")
endif() endif()
endif() endif()
message(STATUS "XPU_SDK_ROOT: ${XPU_SDK_ROOT}") message(STATUS "XPU_SDK_ROOT: ${XPU_SDK_ROOT}")
find_path(XPU_SDK_INC NAMES xtcl.h find_path(XPU_SDK_INC NAMES xtcl.h
PATHS ${XPU_SDK_ROOT}/XTCL/include/xtcl NO_DEFAULT_PATH) PATHS ${XPU_SDK_ROOT}/XTCL/include/xtcl
NO_DEFAULT_PATH)
if(NOT XPU_SDK_INC) if(NOT XPU_SDK_INC)
message(FATAL_ERROR "Can not find xtcl.h in ${XPU_SDK_ROOT}/include") message(FATAL_ERROR "Can not find xtcl.h in ${XPU_SDK_ROOT}/include")
endif() endif()
...@@ -34,7 +35,8 @@ include_directories("${XPU_SDK_ROOT}/XTCL/include") ...@@ -34,7 +35,8 @@ include_directories("${XPU_SDK_ROOT}/XTCL/include")
include_directories("${XPU_SDK_ROOT}/XTDK/include") include_directories("${XPU_SDK_ROOT}/XTDK/include")
find_library(XPU_SDK_XTCL_FILE NAMES xtcl find_library(XPU_SDK_XTCL_FILE NAMES xtcl
PATHS ${XPU_SDK_ROOT}/XTCL/so) PATHS ${XPU_SDK_ROOT}/XTCL/so
NO_DEFAULT_PATH)
if(NOT XPU_SDK_XTCL_FILE) if(NOT XPU_SDK_XTCL_FILE)
message(FATAL_ERROR "Can not find XPU XTCL Library in ${XPU_SDK_ROOT}") message(FATAL_ERROR "Can not find XPU XTCL Library in ${XPU_SDK_ROOT}")
...@@ -45,7 +47,8 @@ else() ...@@ -45,7 +47,8 @@ else()
endif() endif()
find_library(XPU_SDK_TVM_FILE NAMES tvm find_library(XPU_SDK_TVM_FILE NAMES tvm
PATHS ${XPU_SDK_ROOT}/XTCL/so) PATHS ${XPU_SDK_ROOT}/XTCL/so
NO_DEFAULT_PATH)
if(NOT XPU_SDK_TVM_FILE) if(NOT XPU_SDK_TVM_FILE)
message(FATAL_ERROR "Can not find XPU TVM Library in ${XPU_SDK_ROOT}") message(FATAL_ERROR "Can not find XPU TVM Library in ${XPU_SDK_ROOT}")
...@@ -56,7 +59,8 @@ else() ...@@ -56,7 +59,8 @@ else()
endif() endif()
find_library(XPU_SDK_XPU_API_FILE NAMES xpuapi find_library(XPU_SDK_XPU_API_FILE NAMES xpuapi
PATHS ${XPU_SDK_ROOT}/XTDK/shlib) PATHS ${XPU_SDK_ROOT}/XTDK/shlib
NO_DEFAULT_PATH)
if(NOT XPU_SDK_XPU_API_FILE) if(NOT XPU_SDK_XPU_API_FILE)
message(FATAL_ERROR "Can not find XPU API Library in ${XPU_SDK_ROOT}") message(FATAL_ERROR "Can not find XPU API Library in ${XPU_SDK_ROOT}")
...@@ -67,7 +71,8 @@ else() ...@@ -67,7 +71,8 @@ else()
endif() endif()
find_library(XPU_SDK_XPU_RT_FILE NAMES xpurt find_library(XPU_SDK_XPU_RT_FILE NAMES xpurt
PATHS ${XPU_SDK_ROOT}/XTDK/shlib) PATHS ${XPU_SDK_ROOT}/XTDK/shlib
NO_DEFAULT_PATH)
if(NOT XPU_SDK_XPU_RT_FILE) if(NOT XPU_SDK_XPU_RT_FILE)
message(FATAL_ERROR "Can not find XPU RT Library in ${XPU_SDK_ROOT}") message(FATAL_ERROR "Can not find XPU RT Library in ${XPU_SDK_ROOT}")
...@@ -78,18 +83,12 @@ else() ...@@ -78,18 +83,12 @@ else()
endif() endif()
find_library(XPU_SDK_XPU_JITC_FILE NAMES xpujitc find_library(XPU_SDK_XPU_JITC_FILE NAMES xpujitc
PATHS ${XPU_SDK_ROOT}/XTDK/shlib) PATHS ${XPU_SDK_ROOT}/XTDK/shlib
NO_DEFAULT_PATH)
if(NOT XPU_SDK_XPU_JITC_FILE)
message(FATAL_ERROR "Can not find XPU JITC Library in ${XPU_SDK_ROOT}")
else()
message(STATUS "Found XPU JITC Library: ${XPU_SDK_XPU_JITC_FILE}")
add_library(xpu_sdk_xpu_jitc SHARED IMPORTED GLOBAL)
set_property(TARGET xpu_sdk_xpu_jitc PROPERTY IMPORTED_LOCATION ${XPU_SDK_XPU_JITC_FILE})
endif()
find_library(XPU_SDK_LLVM_FILE NAMES LLVM-8 find_library(XPU_SDK_LLVM_FILE NAMES LLVM-8
PATHS ${XPU_SDK_ROOT}/XTDK/shlib) PATHS ${XPU_SDK_ROOT}/XTDK/shlib
NO_DEFAULT_PATH)
if(NOT XPU_SDK_LLVM_FILE) if(NOT XPU_SDK_LLVM_FILE)
message(FATAL_ERROR "Can not find LLVM Library in ${XPU_SDK_ROOT}") message(FATAL_ERROR "Can not find LLVM Library in ${XPU_SDK_ROOT}")
...@@ -99,7 +98,7 @@ else() ...@@ -99,7 +98,7 @@ else()
set_property(TARGET xpu_sdk_llvm PROPERTY IMPORTED_LOCATION ${XPU_SDK_LLVM_FILE}) set_property(TARGET xpu_sdk_llvm PROPERTY IMPORTED_LOCATION ${XPU_SDK_LLVM_FILE})
endif() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDMLC_USE_GLOG=1 -D_GLIBCXX_USE_CXX11_ABI=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDMLC_USE_GLOG=0")
set(xpu_runtime_libs xpu_sdk_xtcl xpu_sdk_tvm xpu_sdk_xpu_api xpu_sdk_xpu_rt xpu_sdk_xpu_jitc xpu_sdk_llvm CACHE INTERNAL "xpu runtime libs") set(xpu_runtime_libs xpu_sdk_xtcl xpu_sdk_tvm xpu_sdk_xpu_api xpu_sdk_xpu_rt xpu_sdk_llvm CACHE INTERNAL "xpu runtime libs")
set(xpu_builder_libs xpu_sdk_xtcl xpu_sdk_tvm xpu_sdk_xpu_api xpu_sdk_xpu_rt xpu_sdk_xpu_jitc xpu_sdk_llvm CACHE INTERNAL "xpu builder libs") set(xpu_builder_libs xpu_sdk_xtcl xpu_sdk_tvm xpu_sdk_xpu_api xpu_sdk_xpu_rt xpu_sdk_llvm CACHE INTERNAL "xpu builder libs")
...@@ -275,6 +275,11 @@ set(host_kernels CACHE INTERNAL "host kernels") ...@@ -275,6 +275,11 @@ set(host_kernels CACHE INTERNAL "host kernels")
set(kernels_src_list "${CMAKE_BINARY_DIR}/kernels_src_list.txt") set(kernels_src_list "${CMAKE_BINARY_DIR}/kernels_src_list.txt")
file(WRITE ${kernels_src_list} "") # clean file(WRITE ${kernels_src_list} "") # clean
# file to record faked kernels for opt python lib
set(fake_kernels_src_list "${CMAKE_BINARY_DIR}/fake_kernels_src_list.txt")
file(WRITE ${fake_kernels_src_list} "") # clean
if(LITE_BUILD_TAILOR) if(LITE_BUILD_TAILOR)
set(tailored_kernels_list_path "${LITE_OPTMODEL_DIR}/.tailored_kernels_source_list") set(tailored_kernels_list_path "${LITE_OPTMODEL_DIR}/.tailored_kernels_source_list")
file(STRINGS ${tailored_kernels_list_path} tailored_kernels_list) file(STRINGS ${tailored_kernels_list_path} tailored_kernels_list)
...@@ -303,62 +308,74 @@ function(add_kernel TARGET device level) ...@@ -303,62 +308,74 @@ function(add_kernel TARGET device level)
return() return()
endif() endif()
if (LITE_ON_MODEL_OPTIMIZE_TOOL)
# the source list will collect for model_optimize_tool to fake kernel generation.
foreach(src ${args_SRCS})
file(APPEND ${kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return()
endif()
# when compiling the model_optimize_tool, a source file with all the fake kernel definitions will be generated,
# no need to continue the compilation of the true kernel source.
if (LITE_ON_MODEL_OPTIMIZE_TOOL)
return()
endif(LITE_ON_MODEL_OPTIMIZE_TOOL)
if ("${device}" STREQUAL "Host") if ("${device}" STREQUAL "Host")
set(host_kernels "${host_kernels};${TARGET}" CACHE INTERNAL "") set(host_kernels "${host_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "ARM") if ("${device}" STREQUAL "ARM")
if (NOT LITE_WITH_ARM) if (NOT LITE_WITH_ARM)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(arm_kernels "${arm_kernels};${TARGET}" CACHE INTERNAL "") set(arm_kernels "${arm_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "X86") if ("${device}" STREQUAL "X86")
if (NOT LITE_WITH_X86) if (NOT LITE_WITH_X86)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return()
elseif (LITE_ON_MODEL_OPTIMIZE_TOOL)
foreach(src ${args_SRCS})
file(APPEND ${kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(x86_kernels "${x86_kernels};${TARGET}" CACHE INTERNAL "") set(x86_kernels "${x86_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "NPU") if ("${device}" STREQUAL "NPU")
if (NOT LITE_WITH_NPU) if (NOT LITE_WITH_NPU)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(npu_kernels "${npu_kernels};${TARGET}" CACHE INTERNAL "") set(npu_kernels "${npu_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "XPU") if ("${device}" STREQUAL "XPU")
if (NOT LITE_WITH_XPU) if (NOT LITE_WITH_XPU)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(xpu_kernels "${xpu_kernels};${TARGET}" CACHE INTERNAL "") set(xpu_kernels "${xpu_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "FPGA") if ("${device}" STREQUAL "FPGA")
if (NOT LITE_WITH_FPGA) if (NOT LITE_WITH_FPGA)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(fpga_kernels "${fpga_kernels};${TARGET}" CACHE INTERNAL "") set(fpga_kernels "${fpga_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "BM") if ("${device}" STREQUAL "BM")
if (NOT LITE_WITH_BM) if (NOT LITE_WITH_BM)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(bm_kernels "${bm_kernels};${TARGET}" CACHE INTERNAL "") set(bm_kernels "${bm_kernels};${TARGET}" CACHE INTERNAL "")
endif() endif()
if ("${device}" STREQUAL "OPENCL") if ("${device}" STREQUAL "OPENCL")
if (NOT LITE_WITH_OPENCL) if (NOT LITE_WITH_OPENCL)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(opencl_kernels "${opencl_kernels};${TARGET}" CACHE INTERNAL "") set(opencl_kernels "${opencl_kernels};${TARGET}" CACHE INTERNAL "")
...@@ -366,6 +383,9 @@ function(add_kernel TARGET device level) ...@@ -366,6 +383,9 @@ function(add_kernel TARGET device level)
if ("${device}" STREQUAL "CUDA") if ("${device}" STREQUAL "CUDA")
if (NOT LITE_WITH_CUDA) if (NOT LITE_WITH_CUDA)
foreach(src ${args_SRCS})
file(APPEND ${fake_kernels_src_list} "${CMAKE_CURRENT_SOURCE_DIR}/${src}\n")
endforeach()
return() return()
endif() endif()
set(cuda_kernels "${cuda_kernels};${TARGET}" CACHE INTERNAL "") set(cuda_kernels "${cuda_kernels};${TARGET}" CACHE INTERNAL "")
......
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(NOT LITE_WITH_MLU)
return()
endif()
if(NOT DEFINED NEUWARE_HOME)
set(NEUWARE_HOME $ENV{NEUWARE_HOME})
if(NOT NEUWARE_HOME)
message(FATAL_ERROR "Must set NEUWARE_HOME or env NEUWARE_HOME when LITE_WITH_MLU=ON")
endif()
endif()
message(STATUS "LITE_WITH_MLU: ${LITE_WITH_MLU}")
find_path(CNML_INC NAMES cnml.h
PATHS ${NEUWARE_HOME}/include NO_DEFAULT_PATH)
if(NOT CNML_INC)
message(FATAL_ERROR "Can not find cnml.h in ${NEUWARE_HOME}/include")
endif()
find_path(CNRT_INC NAMES cnrt.h
PATHS ${NEUWARE_HOME}/include NO_DEFAULT_PATH)
if(NOT CNRT_INC)
message(FATAL_ERROR "Can not find cnrt.h in ${NEUWARE_HOME}/include")
endif()
include_directories("${NEUWARE_HOME}/include")
find_library(CNML_LIB_FILE NAMES cnml
PATHS ${NEUWARE_HOME}/lib64)
if(NOT CNML_LIB_FILE)
message(FATAL_ERROR "Can not find CNML Library in ${NEUWARE_HOME}/lib64")
else()
message(STATUS "Found CNML Library: ${CNML_LIB_FILE}")
add_library(cnml_lib SHARED IMPORTED GLOBAL)
set_property(TARGET cnml_lib PROPERTY IMPORTED_LOCATION ${CNML_LIB_FILE})
endif()
find_library(CNRT_LIB_FILE NAMES cnrt
PATHS ${NEUWARE_HOME}/lib64)
if(NOT CNRT_LIB_FILE)
message(FATAL_ERROR "Can not find CNRT Library in ${NEUWARE_HOME}/lib64")
else()
message(STATUS "Found CNRT Library: ${CNRT_LIB_FILE}")
add_library(cnrt_lib SHARED IMPORTED GLOBAL)
set_property(TARGET cnrt_lib PROPERTY IMPORTED_LOCATION ${CNRT_LIB_FILE})
endif()
# CV图像预处理API
请把编译脚本`Paddle-Lite/lite/too/build.sh``BUILD_CV`变量设置为`ON`, 其他编译参数设置请参考[源码编译](../user_guides/source_compile), 以确保 Lite 可以正确编译。这样`CV`图像的加速库就会编译进去,且会生成`paddle_image_preprocess.h`的API文件
- 硬件平台: `ARM`
- 操作系统:`MAC``LINUX`
## CV 图像预处理功能
Lite 支持不同颜色空间的图像相互转换 `Convert` 、缩放 `Resize` 、翻转 `Flip`、旋转 `Rotate` 和图像数据转换为 `Tensor` 存储`ImageToTensor` 功能,下文将详细介绍每个功能的API接口。
### CV 枚举变量和结构体变量
- 颜色空间
```cpp
enum ImageFormat {
RGBA = 0,
BGRA,
RGB,
BGR,
GRAY,
NV21 = 11,
NV12,
};
```
- 翻转参数
```cpp
enum FlipParam {
X = 0, // flip along the X axis
Y, // flip along the Y axis
XY // flip along the XY axis
};
```
- 转换参数
```cpp
typedef struct {
int ih; // input height
int iw; // input width
int oh; // outpu theight
int ow; // output width
FlipParam flip_param; // flip, support x, y, xy
float rotate_param; // rotate, support 90, 180, 270
} TransParam;
```
### ImagePreprocess 类的成员变量
`ImagePreprocess` 类含有以下三个私有成员变量,通过构造函数进行初始化。
```cpp
private:
ImageFormat srcFormat_; // input image color format
ImageFormat dstFormat_; // output image color format
TransParam transParam_; // image transform parameter
// init
ImagePreprocess::ImagePreprocess(ImageFormat srcFormat, ImageFormat dstFormat, TransParam param) {
this->srcFormat_ = srcFormat;
this->dstFormat_ = dstFormat;
this->transParam_ = param;
}
```
### 颜色空间转换 Convert
`Convert` 函数支持颜色空间:GRAY、NV12(NV21)、RGB(BGR)和RGBA(BGRA)
+ 目前支持以下颜色空间的相互转换:
- GRAY2BGR
- GRAY2RGB
- BGR2RGB
- BGRA2BGR
- BGRA2RGB
- RGBA2RGB
- RGBA2BGR
- BGRA2RGBA
+ 目前支持以下颜色空间的单向转换:
- NV12—BGR
- NV21—BGR
- NV12—RGB
- NV21—RGB
- NV12—BGRA
- NV21—BGRA
- NV12—RGBA
- NV21—RGBA
+ `Convert` 功能的API接口
```cpp
// 方法一
void ImagePreprocess::imageCovert(const uint8_t* src, uint8_t* dst);
// 方法二
void ImagePreprocess::imageCovert(const uint8_t* src,
uint8_t* dst, ImageFormat srcFormat, ImageFormat dstFormat);
```
+ 第一个 `imageCovert` 接口,缺省参数来源于 `ImagePreprocess` 类的成员变量。故在初始化 `ImagePreprocess` 类的对象时,必须要给以下成员变量赋值:
- param srcFormat:`ImagePreprocess` 类的成员变量`srcFormat_`
- param dstFormat:`ImagePreprocess` 类的成员变量`dstFormat_`
- 第二个`imageCovert` 接口,可以直接使用
### 缩放 Resize
`Resize` 功能支持颜色空间:GRAY、NV12(NV21)、RGB(BGR)和RGBA(BGRA)
`Resize` 功能目前支持的方法:`bilinear`
+ `Resize` 功能的API接口
```cpp
// 方法一
void ImagePreprocess::imageResize(const uint8_t* src, uint8_t* dst);
// 方法二
void ImagePreprocess::imageResize(const uint8_t* src, uint8_t* dst, ImageFormat srcFormat, ImageFormat srcFormat, int srcw, int srch, int dstw, int dsth);
```
+ 第一个`imageResize` 接口,缺省参数来源于`ImagePreprocess` 类的成员变量。故在初始化`ImagePreprocess` 类的对象时,必须要给以下成员变量赋值:
- param srcFormat:`ImagePreprocess` 类的成员变量`dstFormat_`
- param srcw:`ImagePreprocess` 类的成员变量`transParam_.iw`
- param srch:`ImagePreprocess` 类的成员变量`transParam_.ih`
- param dstw:`ImagePreprocess` 类的成员变量`transParam_.ow`
- param dsth:`ImagePreprocess` 类的成员变量`transParam_.ow`
- 第二个`imageResize` 接口,可以直接使用
### 旋转 Rotate
`Rotate` 功能支持颜色空间:GRAY、RGB(BGR)和RGBA(BGRA)
`Rotate` 功能目前支持的角度:90、180 和 270
+ `Rotate` 功能的API接口
```cpp
// 方法一
void ImagePreprocess::imageRotate(const uint8_t* src, uint8_t* dst);
// 方法二
void ImagePreprocess::imageRotate(const uint8_t* src, uint8_t* dst, ImageFormat srcFormat, ImageFormat srcFormat, int srcw, int srch, float degree);
```
+ 第一个`imageRotate` 接口,缺省参数来源于`ImagePreprocess` 类的成员变量。故在初始化`ImagePreprocess` 类的对象时,必须要给以下成员变量赋值:
- param srcFormat:`ImagePreprocess` 类的成员变量`dstFormat_`
- param srcw:`ImagePreprocess` 类的成员变量`transParam_.ow`
- param srch:`ImagePreprocess` 类的成员变量`transParam_.oh`
- param degree:`ImagePreprocess` 类的成员变量`transParam_.rotate_param`
- 第二个`imageRotate` 接口,可以直接使用
### 翻转 Flip
`Flip` 功能支持颜色空间:GRAY、RGB(BGR)和RGBA(BGRA)
`Flip` 功能目前支持的功能:沿X轴翻转、沿Y轴翻转和沿XY轴翻转
+ `Flip` 功能的API接口
```cpp
// 方法一
void ImagePreprocess::imageFlip(const uint8_t* src, uint8_t* dst);
// 方法二
void ImagePreprocess::imageFlip(const uint8_t* src, uint8_t* dst, ImageFormat srcFormat, ImageFormat srcFormat, int srcw, int srch, FlipParam flip_param);
```
+ 第一个`imageFlip` 接口,缺省参数来源于`ImagePreprocess` 类的成员变量。故在初始化`ImagePreprocess` 类的对象时,必须要给以下成员变量赋值:
- param srcFormat:`ImagePreprocess` 类的成员变量`dstFormat_`
- param srcw:`ImagePreprocess` 类的成员变量`transParam_.ow`
- param srch:`ImagePreprocess` 类的成员变量`transParam_.oh`
- param flip_param:`ImagePreprocess` 类的成员变量`transParam_.flip_param`
- 第二个`imageFlip` 接口,可以直接使用
### Image2Tensor
`Image2Tensor` 功能支持颜色空间:RGB(BGR)和RGBA(BGRA)
`Image2Tensor` 功能目前支持的Layout:`NCHW``NHWC`
`Image2Tensor` 不仅完成图像转换为`Tensor`数据处理,而且还完成了图像数据的归一化处理
+ `Image2Tensor` 功能的API接口
```cpp
// 方法一
void ImagePreprocess::image2Tensor(const uint8_t* src, Tensor* dstTensor, LayoutType layout, float* means, float* scales);
// 方法二
void ImagePreprocess::image2Tensor(const uint8_t* src, Tensor* dstTensor, ImageFormat srcFormat, srcw, int srch, LayoutType layout, float* means, float* scales;
```
+ 第一个`image2Tensor` 接口,缺省参数来源于`ImagePreprocess` 类的成员变量。故在初始化`ImagePreprocess` 类的对象时,必须要给以下成员变量赋值:
- param srcFormat:`ImagePreprocess` 类的成员变量`dstFormat_`
- param srcw:`ImagePreprocess` 类的成员变量`transParam_.ow`
- param srch:`ImagePreprocess` 类的成员变量`transParam_.oh`
- 第二个`image2Tensor` 接口,可以直接使用
## CV 图像预处理 Demo 示例
例子:输入 `1920x1080` 大小的 `NV12` 图像src,输出 `960x540` 大小 `RGB` 格式的图像dst;然后,完成 `90` 度旋转和沿 `X` 轴翻转功能;最后,用 `NHWC` 格式存储在Tensor里。
定义 `ImagePreprocess` 类的对象,初始化成员变量
```cpp
// init
srcFormat = ImageFormat::NV12;
dstFormat = ImageFormat::RGB;
srch = 1920;
srcw = 1080;
dsth = 960;
dstw = 540;
flip_param = FlipParam::X;
degree = 90;
layout = LayoutType::NHWC
// 方法一:
TransParam tparam;
tparam.ih = srch;
tparam.iw = srcw;
tparam.oh = dsth;
tparam.ow = dstw;
tparam.flip_param = flip_param;
tparam.rotate_param = degree;
ImagePreprocess image_preprocess(srcFormat, dstFormat, tparam);
// 方法二:
ImagePreprocess image_preprocess();
```
### imageConvert Demo
```cpp
// 方法一:
image_preprocess.imageCovert(src, lite_dst);
// 方法二:
image_preprocess.imageCovert(src, lite_dst, (ImageFormat)srcFormat, (ImageFormat)dstFormat);
```
### imageResize Demo
```cpp
// 方法一:
image_preprocess.imageResize(lite_dst, resize_tmp);
// 方法二:
image_preprocess.imageResize(lite_dst,resize_tmp, (ImageFormat)dstFormat, srcw,
srch, dstw, dsth);
```
### imageRotate Demo
```cpp
// 方法一:
image_preprocess.imageRotate(resize_tmp, tv_out_ratote);
// 方法二:
image_preprocess.imageRotate(resize_tmp,tv_out_ratote, (ImageFormat)dstFormat, dstw, dsth, degree);
```
### imageFlip Demo
```cpp
// 方法一:
image_preprocess.imageFlip(tv_out_ratote, tv_out_flip);
// 方法二:
image_preprocess.imageFlip(tv_out_ratote, tv_out_flip, (ImageFormat)dstFormat dstw, dsth, flip_param);
```
### image2Tensor Demo
```cpp
// 方法一:
image_preprocess.image2Tensor(tv_out_flip, &dst_tensor, layout, means, scales);
// 方法二:
image_preprocess.image2Tensor(tv_out_flip, &dst_tensor,(ImageFormat)dstFormat, dstw, dsth, layout, means, scales);
```
# C++ API文档 # C++ API
## CreatePaddlePredictor ## CreatePaddlePredictor
...@@ -260,14 +260,14 @@ class MobileConfig; ...@@ -260,14 +260,14 @@ class MobileConfig;
`MobileConfig`用来配置构建轻量级PaddlePredictor的配置信息,如NaiveBuffer格式的模型地址、模型的内存地址(从内存加载模型时使用)、能耗模式、工作线程数等等。 `MobileConfig`用来配置构建轻量级PaddlePredictor的配置信息,如NaiveBuffer格式的模型地址、模型的内存地址(从内存加载模型时使用)、能耗模式、工作线程数等等。
*注意:输入的模型需要使用[Model Optimize Tool](../model_optimize_tool)转化为NaiveBuffer格式的优化模型。* *注意:输入的模型需要使用[Model Optimize Tool](../user_guides/model_optimize_tool)转化为NaiveBuffer格式的优化模型。*
示例: 示例:
```c++ ```c++
MobileConfig config; MobileConfig config;
// 设置NaiveBuffer格式模型目录,从文件加载模型时使用 // 设置NaiveBuffer格式模型目录,从文件加载模型时使用
config.set_model_dir(FLAGS_model_dir); config.set_model_from_file(<your_model_path>);
// 设置工作线程数 // 设置工作线程数
config.set_threads(4); config.set_threads(4);
// 设置能耗模式 // 设置能耗模式
...@@ -277,13 +277,13 @@ config.set_power_mode(LITE_POWER_HIGH); ...@@ -277,13 +277,13 @@ config.set_power_mode(LITE_POWER_HIGH);
std::shared_ptr<PaddlePredictor> predictor = CreatePaddlePredictor<MobileConfig>(config); std::shared_ptr<PaddlePredictor> predictor = CreatePaddlePredictor<MobileConfig>(config);
``` ```
### `set_model_from_file(model_dir)` ### `set_model_from_file(model_file)`
设置模型文件,当需要从磁盘加载模型时使用。 设置模型文件,当需要从磁盘加载模型时使用。
参数: 参数:
- `model_dir(std::string)` - 模型文件路径 - `model_file(std::string)` - 模型文件路径
返回:`None` 返回:`None`
...@@ -589,7 +589,7 @@ for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) { ...@@ -589,7 +589,7 @@ for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) {
根据名称获取输出Tensor的指针。 根据名称获取输出Tensor的指针。
**注意**`GetTensor`接口是为开发者设计的调试接口,可以输出[转化](../model_optimize_tool)后模型中的任一节点。如果出现`GetTensor(InputName)`返回值为空`Tensor`,可能原因是以该`InputName`命名的Tensor在模型转化的**子图融合**过程被融合替换了。 **注意**`GetTensor`接口是为开发者设计的调试接口,可以输出[转化](../user_guides/model_optimize_tool)后模型中的任一节点。如果出现`GetTensor(InputName)`返回值为空`Tensor`,可能原因是以该`InputName`命名的Tensor在模型转化的**子图融合**过程被融合替换了。
参数: 参数:
......
# Java API
## MobileConfig
```java
public class MobileConfig extends ConfigBase;
```
`MobileConfig`用来配置构建轻量级PaddlePredictor的配置信息,如NaiveBuffer格式的模型地址、能耗模式、工作线程数等等。
*注意:输入的模型需要使用Model Optimize Tool转化为NaiveBuffer格式的优化模型。*
示例:
```java
MobileConfig config = new MobileConfig();
// 设置NaiveBuffer格式模型目录
config.setModelFromFile(modelfile);
// 设置能耗模式
config.setPowerMode(PowerMode.LITE_POWER_HIGH);
// 设置工作线程数
config.setThreads(1);
// 根据MobileConfig创建PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
```
### ``setModelFromFile(model_file)``
设置模型文件夹路径。
参数:
- `model_file(String)` - 模型文件路径
返回:`None`
返回类型:`void`
### ``setModelDir(model_dir)``
**注意**:Lite模型格式在release/v2.3.0之后修改,本接口为加载老格式模型的接口,将在release/v3.0.0废弃。建议替换为`setModelFromFile`接口。
设置模型文件夹路径。
参数:
- `model_dir(String)` - 模型文件夹路径
返回:`None`
返回类型:`void`
### ``setModelFromBuffer(model_buffer)``
设置模型的内存数据,当需要从内存加载模型时使用。
参数:
- `model_buffer(str)` - 内存中的模型数据
返回:`None`
返回类型:`void`
### `getModelDir()`
返回设置的模型文件夹路径。
参数:
- `None`
返回:模型文件夹路径
返回类型:`String`
### `setPowerMode(mode)`
设置CPU能耗模式。若不设置,则默认使用`LITE_POWER_HIGH`
*注意:只在开启`OpenMP`时生效,否则系统自动调度。*
参数:
- `mode(PowerMode)` - CPU能耗模式。
返回:`None`
返回类型:`void`
### `getPowerMode()`
获取设置的CPU能耗模式。
参数:
- `None`
返回:设置的CPU能耗模式
返回类型:`PowerMode`
### `setThreads(threads)`
设置工作线程数。若不设置,则默认使用单线程。
*注意:只在开启`OpenMP`的模式下生效,否则只使用单线程。*
参数:
- `threads(int)` - 工作线程数。默认为1。
返回:`None`
返回类型:`void`
### `getThreads()`
获取设置的工作线程数。
参数:
- `None`
返回:工作线程数
返回类型:`int`
## PaddlePredictor
```java
public class PaddlePredictor;
```
`PaddlePredictor`是Paddle-Lite的预测器。用户可以根据PaddlePredictor提供的接口使用MobileConfig创建新的预测器、设置输入数据、执行模型预测、获取输出以及获得当前使用lib的版本信息等。
示例:
```java
// 设置MobileConfig
MobileConfig config = new MobileConfig();
config.setModelDir(modelPath);
// 创建PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
// 设置输入数据
long[] dims = {100, 100};
float[] inputBuffer = new float[10000];
for (int i = 0; i < 10000; ++i) {
inputBuffer[i] = i;
}
Tensor input = predictor.getInput(0);
input.resize(dims);
input.setData(inputBuffer);
// 执行预测
predictor.run();
// 获取输出数据
Tensor output = predictor.getOutput(0);
float[] output = result.getFloatData();
for (int i = 0; i < 1000; ++i) {
System.out.println(output[i]);
}
```
### `CreatePaddlePredictor(config)`
```java
public static PaddlePredictor createPaddlePredictor(ConfigBase config);
```
`CreatePaddlePredictor`用来根据`ConfigBase`动态创建预测器,目前Java API支持使用MobileConfig`。框架会根据您在config中指定的模型路径、能耗模型、工作线程数等自动创建一个预测器。
参数:
- `config(ConfigBase,目前应使用MobileConfig)` - 创建预测器的配置信息
返回:根据config创建完成的预测器
返回类型:`PaddlePredictor`
### `getInput(index)`
获取输入Tensor,用来设置模型的输入数据。
参数:
- `index(int)` - 输入Tensor的索引
返回:第`index`个输入`Tensor`
返回类型:`Tensor`
### `getOutput(index)`
获取输出Tensor,用来获取模型的输出结果。
参数:
- `index(int)` - 输出Tensor的索引
返回:第`index`个输出Tensor
返回类型:`Tensor`
### `run()`
执行模型预测,需要在***设置输入数据后***调用。
参数:
- `None`
返回:预测执行状态,成功返回`true`,否则返回`false`
返回类型:`boolean`
### `getVersion()`
用于获取当前lib使用的代码版本。若代码有相应tag则返回tag信息,如`v2.0-beta`;否则返回代码的`branch(commitid)`,如`develop(7e44619)`。
参数:
- `None`
返回:当前lib使用的代码版本信息
返回类型:`String`
## PowerMode
```java
public enum PowerMode;
```
`PowerMode`为ARM CPU能耗模式,用户可以根据应用场景设置能耗模式获得最优的能效比。
示例:
```java
MobileConfig config = new MobileConfig();
// 设置NaiveBuffer格式模型目录
config.setModelDir(modelPath);
// 设置能耗模式
config.setPowerMode(PowerMode.LITE_POWER_HIGH);
// 根据MobileConfig创建PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
```
PowerMode详细说明如下:
| 选项 | 说明 |
| :------------------: | ------------------------------------------------------------ |
| LITE_POWER_HIGH | 绑定大核运行模式。如果ARM CPU支持big.LITTLE,则优先使用并绑定Big cluster。如果设置的线程数大于大核数量,则会将线程数自动缩放到大核数量。如果系统不存在大核或者在一些手机的低电量情况下会出现绑核失败,如果失败则进入不绑核模式。 |
| LITE_POWER_LOW | 绑定小核运行模式。如果ARM CPU支持big.LITTLE,则优先使用并绑定Little cluster。如果设置的线程数大于小核数量,则会将线程数自动缩放到小核数量。如果找不到小核,则自动进入不绑核模式。 |
| LITE_POWER_FULL | 大小核混用模式。线程数可以大于大核数量。当线程数大于核心数量时,则会自动将线程数缩放到核心数量。 |
| LITE_POWER_NO_BIND | 不绑核运行模式(推荐)。系统根据负载自动调度任务到空闲的CPU核心上。 |
| LITE_POWER_RAND_HIGH | 轮流绑定大核模式。如果Big cluster有多个核心,则每预测10次后切换绑定到下一个核心。 |
| LITE_POWER_RAND_LOW | 轮流绑定小核模式。如果Little cluster有多个核心,则每预测10次后切换绑定到下一个核心。 |
## Tensor
```c++
public class Tensor;
```
Tensor是Paddle-Lite的数据组织形式,用于对底层数据进行封装并提供接口对数据进行操作,包括设置维度、数据等。
*注意:用户应使用`PaddlePredictor`的`getInput`和`getOuput`接口获取输入/输出的`Tensor`。*
示例:
```java
// 导入Java API
import com.baidu.paddle.lite.MobileConfig;
import com.baidu.paddle.lite.Tensor;
import com.baidu.paddle.lite.Predictor;
import com.baidu.paddle.lite.PowerMode;
// 设置MobileConfig
MobileConfig config = new MobileConfig();
config.setModelDir(modelPath);
// 创建PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
// 设置输入数据
long[] dims = {100, 100};
float[] inputBuffer = new float[10000];
for (int i = 0; i < 10000; ++i) {
inputBuffer[i] = i;
}
// 获取输入Tensor
Tensor input = predictor.getInput(0);
// 设置输入维度
input.resize(dims);
// 设置输入数据
input.setData(inputBuffer);
// 执行预测
predictor.run();
// 获取输出Tensor
Tensor result = predictor.getOutput(0);
// 获取输出数据
float[] output = result.getFloatData();
for (int i = 0; i < 1000; ++i) {
System.out.println(output[i]);
}
```
### `resize(dims)`
设置Tensor的维度信息。
参数:
- `dims(long[])` - 维度信息
返回:设置成功返回`true`,否则返回`false`
返回类型:`boolean`
### `shape()`
获取Tensor的维度信息。
参数:
- `None`
返回:Tensor的维度信息
返回类型:`long[]`
### `setData(data)`
设置Tensor数据。
参数:
- `data(float[])` - 需要设置的数据
返回:成功则返回`true`,否则返回`false`
返回类型:`boolean`
### `getFloatData()`
获取Tensor的底层float型数据。
参数:
- `None`
返回:`Tensor`底层数据
返回类型:`float[]`
# Python API
## create_paddle_predictor
```python
CxxPredictor create_paddle_predictor(config); # config为CxxConfig类型
LightPredictor create_paddle_predictor(config); # config为MobileConfig类型
```
`create_paddle_predictor`函数用来根据`CxxConfig``MobileConfig`构建预测器。
示例:
```python
from lite_core import *
# 设置CxxConfig
config = CxxConfig()
config.set_model_dir(<your_model_dir_path>)
places = [Place(TargetType.ARM, PrecisionType.FP32)]
config.set_valid_places(places)
# 根据CxxConfig创建CxxPredictor
predictor = create_paddle_predictor(config)
```
参数:
- `config(CxxConfig或MobileConfig)` - 用于构建Predictor的配置信息。
返回:预测器`predictor`
返回类型:`CxxPredictor``LightPredictor`
## CxxConfig
```python
class CxxConfig;
```
`CxxConfig`用来配置构建CxxPredictor的配置信息,如protobuf格式的模型地址、能耗模式、工作线程数、place信息等等。
示例:
```python
from lite_core import *
config = CxxConfig()
# 设置模型目录,加载非combined模型时使用
config.set_model_dir(<your_model_dir_path>)
# 设置工作线程数
config.set_threads(4);
# 设置能耗模式
config.set_power_mode(PowerMode.LITE_POWER_NO_BIND)
# 设置valid places
places = [Place(TargetType.ARM, PrecisionType.FP32)]
config.set_valid_places(places)
# 根据CxxConfig创建CxxPredictor
predictor = create_paddle_predictor(config)
```
### `set_model_dir(model_dir)`
设置模型文件夹路径,当需要从磁盘加载非combined模型时使用。
参数:
- `model_dir(str)` - 模型文件夹路径
返回:`None`
返回类型:`None`
### `model_dir()`
返回设置的模型文件夹路径。
参数:
- `None`
返回:模型文件夹路径
返回类型:`str`
### `set_model_file(model_file)`
设置模型文件路径,加载combined形式模型时使用。
参数:
- `model_file(str)` - 模型文件路径
返回类型:`None`
### `model_file()`
获取设置模型文件路径,加载combined形式模型时使用。
参数:
- `None`
返回:模型文件路径
返回类型:`str`
### `set_param_file(param_file)`
设置模型参数文件路径,加载combined形式模型时使用。
参数:
- `param_file(str)` - 模型文件路径
返回类型:`None`
### `param_file()`
获取设置模型参数文件路径,加载combined形式模型时使用。
参数:
- `None`
返回:模型参数文件路径
返回类型:`str`
### `set_valid_places(valid_places)`
设置可用的places列表。
参数:
- `valid_places(list)` - 可用place列表。
返回类型:`None`
示例:
```python
from lite_core import *
config = CxxConfig()
# 设置模型目录,加载非combined模型时使用
config.set_model_dir(<your_model_dir_path>)
# 设置valid places
# 注意,valid_places列表中Place的排序表明了用户对Place的偏好程度,如用户想优先使用ARM上Int8精度的
# kernel,则应把Place(TargetType.ARM, PrecisionType.INT8)置于valid_places列表的首位。
places = [Place(TargetType.ARM, PrecisionType.INT8),
Place(TargetType.ARM, PrecisionType.FP32)]
config.set_valid_places(places)
# 根据CxxConfig创建CxxPredictor
predictor = create_paddle_predictor(config)
```
### `set_power_mode(mode)`
设置CPU能耗模式。若不设置,则默认使用`PowerMode.LITE_POWER_HIGH`
*注意:只在开启`OpenMP`时生效,否则系统自动调度。此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `mode(PowerMode)` - CPU能耗模式
返回:`None`
返回类型:`None`
### `power_mode()`
获取设置的CPU能耗模式。
*注意:此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `None`
返回:设置的CPU能耗模式
返回类型:`PowerMode`
### `set_threads(threads)`
设置工作线程数。若不设置,则默认使用单线程。
*注意:只在开启`OpenMP`的模式下生效,否则只使用单线程。此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `threads(int)` - 工作线程数
返回:`None`
返回类型:`None`
### `threads()`
获取设置的工作线程数。
*注意:此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `None`
返回:工作线程数
返回类型:`int`
## MobileConfig
```python
class MobileConfig;
```
`MobileConfig`用来配置构建LightPredictor的配置信息,如NaiveBuffer格式的模型地址、能耗模式、工作线程数等等。
示例:
```python
from lite_core import *
config = MobileConfig()
# 设置NaiveBuffer格式模型目录
config.set_model_from_file(<your_model_path>)
# 设置工作线程数
config.set_threads(4);
# 设置能耗模式
config.set_power_mode(PowerMode.LITE_POWER_NO_BIND)
# 根据MobileConfig创建LightPredictor
predictor = create_paddle_predictor(config)
```
### `set_model_from_file(model_file)`
**注意**`model_file`应该是经过`opt`优化后产生的`NaiveBuffer`格式的模型。
设置模型文件夹路径。
参数:
- `model_file(str)` - 模型文件路径
返回:`None`
返回类型:`None`
### `set_model_dir(model_dir)`
**注意**:Lite模型格式在release/v2.3.0之后修改,本接口为加载老格式模型的接口,将在release/v3.0.0废弃。建议替换为`setModelFromFile`接口。`model_dir`应该是经过`Model Optimize Tool`优化后产生的`NaiveBuffer`格式的模型。
设置模型文件夹路径。
参数:
- `model_dir(str)` - 模型文件夹路径
返回:`None`
返回类型:`None`
### `set_model_from_buffer(model_buffer)`
设置模型的内存数据,当需要从内存加载模型时使用。
参数:
- `model_buffer(str)` - 内存中的模型数据
返回:`None`
返回类型:`void`
### `model_dir()`
返回设置的模型文件夹路径。
参数:
- `None`
返回:模型文件夹路径
返回类型:`str`
### `set_power_mode(mode)`
设置CPU能耗模式。若不设置,则默认使用`PowerMode.LITE_POWER_HIGH`
*注意:只在开启`OpenMP`时生效,否则系统自动调度。此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `mode(PowerMode)` - CPU能耗模式
返回:`None`
返回类型:`None`
### `power_mode()`
获取设置的CPU能耗模式。
*注意:此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `None`
返回:设置的CPU能耗模式
返回类型:`PowerMode`
### `set_threads(threads)`
设置工作线程数。若不设置,则默认使用单线程。
*注意:只在开启`OpenMP`的模式下生效,否则只使用单线程。此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `threads(int)` - 工作线程数
返回:`None`
返回类型:`None`
### `threads()`
获取设置的工作线程数。
*注意:此函数只在使用`LITE_WITH_ARM`编译选项下生效。*
参数:
- `None`
返回:工作线程数
返回类型:`int`
## CxxPredictor
```c++
class CxxPredictor
```
`CxxPredictor`是Paddle-Lite的预测器,由`create_paddle_predictor`根据`CxxConfig`进行创建。用户可以根据CxxPredictor提供的接口设置输入数据、执行模型预测、获取输出以及获得当前使用lib的版本信息等。
示例:
```python
from __future__ import print_function
from lite_core import *
# 1. 设置CxxConfig
config = CxxConfig()
if args.model_file != '' and args.param_file != '':
config.set_model_file(args.model_file)
config.set_param_file(args.param_file)
else:
config.set_model_dir(args.model_dir)
places = [Place(TargetType.ARM, PrecisionType.FP32)]
config.set_valid_places(places)
# 2. 创建CxxPredictor
predictor = create_paddle_predictor(config)
# 3. 设置输入数据
input_tensor = predictor.get_input(0)
input_tensor.resize([1, 3, 224, 224])
input_tensor.set_float_data([1.] * 3 * 224 * 224)
# 4. 运行模型
predictor.run()
# 5. 获取输出数据
output_tensor = predictor.get_output(0)
print(output_tensor.shape())
print(output_tensor.float_data()[:10])
```
### `get_input(index)`
获取输入Tensor,用来设置模型的输入数据。
参数:
- `index(int)` - 输入Tensor的索引
返回:第`index`个输入`Tensor`
返回类型:`Tensor`
### `get_output(index)`
获取输出Tensor,用来获取模型的输出结果。
参数:
- `index(int)` - 输出Tensor的索引
返回:第`index`个输出`Tensor`
返回类型:`Tensor`
### `run()`
执行模型预测,需要在***设置输入数据后***调用。
参数:
- `None`
返回:`None`
返回类型:`None`
### `get_version()`
用于获取当前lib使用的代码版本。若代码有相应tag则返回tag信息,如`v2.0-beta`;否则返回代码的`branch(commitid)`,如`develop(7e44619)`
参数:
- `None`
返回:当前lib使用的代码版本信息
返回类型:`str`
## LightPredictor
```c++
class LightPredictor
```
`LightPredictor`是Paddle-Lite的预测器,由`create_paddle_predictor`根据`MobileConfig`进行创建。用户可以根据LightPredictor提供的接口设置输入数据、执行模型预测、获取输出以及获得当前使用lib的版本信息等。
示例:
```python
from __future__ import print_function
from lite_core import *
# 1. 设置MobileConfig
config = MobileConfig()
config.set_model_dir(args.model_dir)
# 2. 创建LightPredictor
predictor = create_paddle_predictor(config)
# 3. 设置输入数据
input_tensor = predictor.get_input(0)
input_tensor.resize([1, 3, 224, 224])
input_tensor.set_float_data([1.] * 3 * 224 * 224)
# 4. 运行模型
predictor.run()
# 5. 获取输出数据
output_tensor = predictor.get_output(0)
print(output_tensor.shape())
print(output_tensor.float_data()[:10])
```
### `get_input(index)`
获取输入Tensor,用来设置模型的输入数据。
参数:
- `index(int)` - 输入Tensor的索引
返回:第`index`个输入`Tensor`
返回类型:`Tensor`
### `get_output(index)`
获取输出Tensor,用来获取模型的输出结果。
参数:
- `index(int)` - 输出Tensor的索引
返回:第`index`个输出`Tensor`
返回类型:`Tensor`
### `run()`
执行模型预测,需要在***设置输入数据后***调用。
参数:
- `None`
返回:`None`
返回类型:`None`
### `get_version()`
用于获取当前lib使用的代码版本。若代码有相应tag则返回tag信息,如`v2.0-beta`;否则返回代码的`branch(commitid)`,如`develop(7e44619)`
参数:
- `None`
返回:当前lib使用的代码版本信息
返回类型:`str`
## TargetType
```python
class TargetType;
```
`TargetType`为目标设备硬件类型,用户可以根据应用场景选择硬件平台类型。
枚举型变量`TargetType`的所有可能取值包括:
`{X86, CUDA, ARM, OpenCL, FPGA, NPU}`
## PrecisionType
```python
class PrecisionType {FP32};
```
`PrecisionType`为模型中Tensor的数据精度,默认值为FP32(float32)。
枚举型变量`PrecisionType`的所有可能取值包括:
`{FP32, INT8, INT32, INT64}`
## DataLayoutType
```python
class DataLayoutType {NCHW};
```
`DataLayoutType`为Tensor的数据格式,默认值为NCHW(number, channel, height, weigth)。
枚举型变量`DataLayoutType`的所有可能取值包括:
` {NCHW, NHWC}`
## Place
```python
class Place{
TargetType target;
PrecisionType precision{FP32};
DataLayoutType layout{NCHW}
}
```
`Place``TargetType``PrecisionType``DataLayoutType`的集合,说明运行时的设备类型、数据精度和数据格式。
示例:
```python
from lite_core import *
Place{TargetType(ARM), PrecisionType(FP32), DataLayoutType(NCHW)}
```
## PowerMode
```python
class PowerMode;
```
`PowerMode`为ARM CPU能耗模式,用户可以根据应用场景设置能耗模式获得最优的能效比。
示例:
```python
from lite_core import *
config = MobileConfig()
# 设置NaiveBuffer格式模型目录
config.set_model_dir(<your_model_dir_path>)
# 设置能耗模式
config.set_power_mode(PowerMode.LITE_POWER_NO_BIND)
# 根据MobileConfig创建LightPredictor
predictor = create_paddle_predictor(config)
```
PowerMode详细说明如下:
| 选项 | 说明 |
| :------------------: | ------------------------------------------------------------ |
| LITE_POWER_HIGH | 绑定大核运行模式。如果ARM CPU支持big.LITTLE,则优先使用并绑定Big cluster。如果设置的线程数大于大核数量,则会将线程数自动缩放到大核数量。如果系统不存在大核或者在一些手机的低电量情况下会出现绑核失败,如果失败则进入不绑核模式。 |
| LITE_POWER_LOW | 绑定小核运行模式。如果ARM CPU支持big.LITTLE,则优先使用并绑定Little cluster。如果设置的线程数大于小核数量,则会将线程数自动缩放到小核数量。如果找不到小核,则自动进入不绑核模式。 |
| LITE_POWER_FULL | 大小核混用模式。线程数可以大于大核数量。当线程数大于核心数量时,则会自动将线程数缩放到核心数量。 |
| LITE_POWER_NO_BIND | 不绑核运行模式(推荐)。系统根据负载自动调度任务到空闲的CPU核心上。 |
| LITE_POWER_RAND_HIGH | 轮流绑定大核模式。如果Big cluster有多个核心,则每预测10次后切换绑定到下一个核心。 |
| LITE_POWER_RAND_LOW | 轮流绑定小核模式。如果Little cluster有多个核心,则每预测10次后切换绑定到下一个核心。 |
## Tensor
```c++
class Tensor
```
Tensor是Paddle-Lite的数据组织形式,用于对底层数据进行封装并提供接口对数据进行操作,包括设置Shape、数据、LoD信息等。
*注意:用户应使用`CxxPredictor`或`LightPredictor`的`get_input`和`get_output`接口获取输入/输出的`Tensor`。*
示例:
```python
from __future__ import print_function
from lite_core import *
# 1. 设置CxxConfig
config = CxxConfig()
if args.model_file != '' and args.param_file != '':
config.set_model_file(args.model_file)
config.set_param_file(args.param_file)
else:
config.set_model_dir(args.model_dir)
places = [Place(TargetType.ARM, PrecisionType.FP32)]
config.set_valid_places(places)
# 2. 创建CxxPredictor
predictor = create_paddle_predictor(config)
# 3. 设置输入数据
input_tensor = predictor.get_input(0)
input_tensor.resize([1, 3, 224, 224])
input_tensor.set_float_data([1.] * 3 * 224 * 224)
# 4. 运行模型
predictor.run()
# 5. 获取输出数据
output_tensor = predictor.get_output(0)
print(output_tensor.shape())
print(output_tensor.float_data()[:10])
```
### `resize(shape)`
设置Tensor的维度信息。
参数:
- `shape(list)` - 维度信息
返回:`None`
返回类型:`None`
### `shape()`
获取Tensor的维度信息。
参数:
- `None`
返回:Tensor的维度信息
返回类型:`list`
### `float_data()`
获取Tensor的持有的float型数据。
示例:
```python
output_tensor = predictor.get_output(0)
print(output_tensor.shape())
print(output_tensor.float_data()[:10])
```
参数:
- `None`
返回:`Tensor`持有的float型数据
返回类型:`list`
### `set_float_data(float_data)`
设置Tensor持有float数据。
示例:
```python
input_tensor = predictor.get_input(0)
input_tensor.resize([1, 3, 224, 224])
input_tensor.set_float_data([1.] * 3 * 224 * 224)
```
参数:
- `float_data(list)` - 待设置的float型数据
返回:`None`
返回类型:`None`
### `set_lod(lod)`
设置Tensor的LoD信息。
参数:
- `lod(list[list])` - Tensor的LoD信息
返回:`None`
返回类型:`None`
### `lod()`
获取Tensor的LoD信息
参数:
- `None`
返回:`Tensor`的LoD信息
返回类型:`list[list]`
# Benchmark 数据 # 性能数据
可以参考[benchmark_tools](benchmark_tools),推荐**一键benchmark** 可以参考[benchmark_tools](benchmark_tools),推荐**一键benchmark**
...@@ -15,14 +15,12 @@ ...@@ -15,14 +15,12 @@
* int8模型 * int8模型
* mobilenet_v1 * mobilenet_v1
* mobilenet_v2 * mobilenet_v2
* resnet50
* 测试机器(android ndk ndk-r17c) * 测试机器(android ndk ndk-r17c)
* 骁龙855 * 骁龙855
* xiaomi mi9, snapdragon 855 * xiaomi mi9, snapdragon 855
* 4xA76(1@2.84GHz + 3@2.4GHz) + 4xA55@1.78GHz * 4xA76(1@2.84GHz + 3@2.4GHz) + 4xA55@1.78GHz
* 骁龙845 * 骁龙845
* xiaomi mi8, 845 * xiaomi mi8, 845
* 2.8GHz(大四核),1.7GHz(小四核) * 2.8GHz(大四核),1.7GHz(小四核)
...@@ -30,20 +28,12 @@ ...@@ -30,20 +28,12 @@
* 骁龙835 * 骁龙835
* xiaomi mix2, snapdragon 835 * xiaomi mix2, snapdragon 835
* 2.45GHz(大四核),1.9GHz(小四核) * 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 * 麒麟970
* HUAWEI Mate10 * HUAWEI Mate10
* 测试说明 * 测试说明
* branch: release/2.0.0 * branch: release/v2.3.0
* warmup=10, repeats=30,统计平均时间,单位是ms * warmup=10, repeats=30,统计平均时间,单位是ms
* 当线程数为1时,```DeviceInfo::Global().SetRunMode```设置LITE_POWER_HIGH,否者设置LITE_POWER_NO_BIND * 当线程数为1时,```DeviceInfo::Global().SetRunMode```设置LITE_POWER_HIGH,否者设置LITE_POWER_NO_BIND
* 模型的输入图像的维度是{1, 3, 224, 224},输入图像的每一位数值是1 * 模型的输入图像的维度是{1, 3, 224, 224},输入图像的每一位数值是1
...@@ -55,78 +45,59 @@ ...@@ -55,78 +45,59 @@
#### paddlepaddle model #### paddlepaddle model
骁龙855|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙855|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 threads num|1 |2 |4 |1 |2 |4
mobilenet_v1 |32.19 |18.81 |10.90 |30.92 |18.31 |10.15 mobilenet_v1 |33.27 |19.52 |11.14 |31.72 |18.76 |10.24 |
mobilenet_v2 |22.91 |13.75 |8.64 |21.15 |12.79 |7.84 mobilenet_v2 |29.08 |15.79 |9.25 |25.89 |14.17 |8.38 |
shufflenet_v2 |4.67 |3.37 |2.65 |4.43 |3.15 |2.66 shufflenet_v2 |4.40 |3.09 |2.30 |4.28 |3.02 |2.35 |
squeezenet_v1.1 |25.10 |15.93 |9.68 |23.28 |14.61 |8.71 squeezenet_v1.1 |19.96 |12.61 |8.76 |18.25 |11.46 |7.97 |
mnasnet |21.84 |13.14 |7.96 |19.61 |11.88 |7.55 mnasnet |21.00 |12.54 |7.28 |19.65 |11.65 |6.96 |
骁龙845|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 threads num|1 |2 |4 |1 |2 |4
mobilenet_v1 |94.13 |52.17 |30.68 |88.28 |47.58 |26.64 mobilenet_v1 |66.36 |35.97 |19.45 |62.66 |33.87 |17.85 |
mobilenet_v2 |61.24 |34.64 |22.36 |56.66 |32.19 |19.63 mobilenet_v2 |45.86 |25.53 |14.6 |41.58 |23.24 |13.39 |
shufflenet_v2 |10.87 |6.92 |5.12 |10.41 |6.76 |4.97 shufflenet_v2 |7.58 |4.89 |3.41 |7.44 |4.91 |3.58 |
squeezenet_v1.1 |73.61 |42.25 |24.44 |64.87 |38.43 |23.06 squeezenet_v1.1 |37.15 |22.74 |13.51 |34.69 |21.27 |12.74 |
mnasnet |58.22 |33.43 |20.44 |53.43 |30.20 |18.09 mnasnet |40.09 |21.73 |11.91 |38.19 |21.02 |12.11 |
麒麟980|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4
mobilenet_v1 |55.11 |28.24 |13.27 |34.24 |17.74 |12.41
mobilenet_v2 |37.03 |19.80 |51.94 |23.64 |12.98 |9.38
shufflenet_v2 |7.26 |4.94 |15.06 |5.32 |3.33 |2.82
squeezenet_v1.1 |42.73 |23.66 |57.39 |26.03 |14.53 |13.66
mnasnet |36.87 |20.15 |46.04 |21.85 |12.06 |8.68
麒麟970|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 threads num|1 |2 |4 |1 |2 |4
mobilenet_v1 |97.80 |52.64 |34.46 |94.51 |49.36 |28.43 mobilenet_v1 |96.98 |53.92 |32.24 |89.31 |48.02 |27.58 |
mobilenet_v2 |66.55 |38.52 |23.19 |62.89 |34.93 |21.53 mobilenet_v2 |67.72 |37.66 |23.82 |60.10 |34.36 |21.05 |
shufflenet_v2 |13.78 |8.11 |5.93 |11.95 |7.90 |5.91 shufflenet_v2 |10.72 |6.62 |4.63 |10.10 |6.44 |4.63 |
squeezenet_v1.1 |77.64 |43.67 |25.72 |69.91 |40.66 |24.62 squeezenet_v1.1 |53.89 |33.28 |20.73 |50.83 |32.31 |19.51 |
mnasnet |61.86 |34.62 |22.68 |59.61 |32.79 |19.56 mnasnet |59.55 |33.53 |20.32 |56.21 |31.58 |19.06 |
#### caffe model #### caffe model
骁龙855|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙855|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 | threads num|1 |2 |4 |1 |2 |4 |
mobilenet_v1 |32.42 |18.68 |10.86 |30.92 |18.35 |10.07 | mobilenet_v1 |33.36 |19.45 |11.26 |31.63 |18.74 |10.31 |
mobilenet_v2 |29.53 |17.76 |10.89 |27.19 |16.53 |9.75 | mobilenet_v2 |31.63 |19.21 |11.61 |28.34 |17.14 |10.16 |
shufflenet_v2 |4.61 |3.29 |2.61 |4.36 |3.11 |2.51 | shufflenet_v2 |4.46 |3.08 |2.32 |4.26 |2.98 |2.35 |
骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 |
mobilenet_v1 |92.52 |52.34 |30.37 |88.31 |49.75 |27.29 |
mobilenet_v2 |79.50 |45.67 |28.79 |76.13 |44.01 |26.13 |
shufflenet_v2 |10.94 |7.08 |5.16 |10.64 |6.83 |5.01 |
麒麟980|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙845|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 | threads num|1 |2 |4 |1 |2 |4 |
mobilenet_v1 |55.36 |28.18 |13.31 |34.42 |17.93 |12.52 | mobilenet_v1 |66.32 |35.83 |19.56 |62.52 |33.79 |17.91 |
mobilenet_v2 |49.17 |26.10 |65.49 |30.50 |16.66 |11.72 | mobilenet_v2 |58.46 |32.69 |18.56 |53.72 |29.86 |16.80 |
shufflenet_v2 |8.45 |5.00 |15.65 |4.58 |3.14 |2.83 | shufflenet_v2 |7.65 |4.82 |3.46 |7.55 |4.97 |3.62 |
麒麟970|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 | threads num|1 |2 |4 |1 |2 |4 |
mobilenet_v1 |97.85 |53.38 |33.85 |94.29 |49.42 |28.29 | mobilenet_v1 |95.38 |54.09 |32.03 |95.05 |48.33 |27.54 |
mobilenet_v2 |87.40 |50.25 |31.85 |85.55 |48.11 |28.24 | mobilenet_v2 |88.46 |48.98 |30.23 |79.28 |44.64 |27.10 |
shufflenet_v2 |12.16 |8.39 |6.21 |12.21 |8.33 |6.32 | shufflenet_v2 |10.07 |6.51 |4.61 |10.31 |6.50 |4.66 |
#### int8量化模型测试数据 #### int8量化模型测试数据
...@@ -136,6 +107,7 @@ threads num|1 |2 |4 |1 |2 |4 | ...@@ -136,6 +107,7 @@ threads num|1 |2 |4 |1 |2 |4 |
mobilenet_v1 |36.80 |21.58 |11.12 | 14.01 |8.13 |4.32 | mobilenet_v1 |36.80 |21.58 |11.12 | 14.01 |8.13 |4.32 |
mobilenet_v2 |28.72 |19.08 |12.49 | 17.24 |11.55 |7.82 | mobilenet_v2 |28.72 |19.08 |12.49 | 17.24 |11.55 |7.82 |
骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8 骁龙835|armv7 | armv7 | armv7 |armv8 | armv8 |armv8
----| ---- | ---- | ---- | ---- |---- |---- ----| ---- | ---- | ---- | ---- |---- |----
threads num|1 |2 |4 |1 |2 |4 | threads num|1 |2 |4 |1 |2 |4 |
......
# Benchmark 测试方法 # 测试方法
本文将会介绍,在**Ubuntu:16.04交叉编译环境**下,用安卓手机在终端测试Paddle-Lite的性能,并介绍两种Benchmark方法: 本文将会介绍,在**Ubuntu:16.04交叉编译环境**下,用安卓手机在终端测试Paddle-Lite的性能,并介绍两种Benchmark方法:
...@@ -57,7 +57,7 @@ wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_0/bench ...@@ -57,7 +57,7 @@ wget -c https://paddle-inference-dist.bj.bcebos.com/PaddleLite/benchmark_0/bench
#### 方式二:由源码编译benchmark_bin文件 #### 方式二:由源码编译benchmark_bin文件
根据[源码编译](../source_compile)准备编译环境,拉取PaddleLite最新release发布版代码,并在仓库根目录下,执行: 根据[源码编译](../user_guides/source_compile)准备编译环境,拉取PaddleLite最新release发布版代码,并在仓库根目录下,执行:
```shell ```shell
########################################### ###########################################
...@@ -135,53 +135,53 @@ sh benchmark.sh ./benchmark_bin_v8 ./benchmark_models result_armv8.txt true ...@@ -135,53 +135,53 @@ sh benchmark.sh ./benchmark_bin_v8 ./benchmark_models result_armv8.txt true
> 不同手机,不同版本,测试模型的性能数据不同。 > 不同手机,不同版本,测试模型的性能数据不同。
```shell ```shell
run benchmark armv7 run benchmark armv8
-------------------------------------- --------------------------------------
PaddleLite Benchmark PaddleLite Benchmark
Threads=1 Warmup=10 Repeats=30 Threads=1 Warmup=10 Repeats=30
-- mnasnet avg = 159.8427 ms mnasnet min = 19.83500 max = 19.38500 average = 19.65503
-- mobilenet_v1 avg = 235.0072 ms mobilenetv1 min = 32.00600 max = 31.56900 average = 31.81983
-- mobilenet_v2 avg = 173.0387 ms mobilenetv2 min = 22.37900 max = 22.08700 average = 22.28623
-- shufflenet_v2 avg = 76.0040 ms shufflenetv2 min = 10.80400 max = 10.62900 average = 10.68890
-- squeezenet_v11 avg = 164.2957 ms squeezenet min = 17.67400 max = 17.47900 average = 17.57677
Threads=2 Warmup=10 Repeats=30 Threads=2 Warmup=10 Repeats=30
-- mnasnet avg = 83.1287 ms mnasnet min = 11.85600 max = 11.72000 average = 11.77127
-- mobilenet_v1 avg = 121.6029 ms mobilenetv1 min = 18.75000 max = 18.64300 average = 18.70593
-- mobilenet_v2 avg = 86.6175 ms mobilenetv2 min = 14.05100 max = 13.59900 average = 13.71450
-- shufflenet_v2 avg = 41.5761 ms shufflenetv2 min = 6.67200 max = 6.58300 average = 6.63400
-- squeezenet_v11 avg = 87.8678 ms squeezenet min = 12.07100 max = 11.33400 average = 11.41253
Threads=4 Warmup=10 Repeats=30 Threads=4 Warmup=10 Repeats=30
-- mnasnet avg = 73.3880 ms mnasnet min = 7.19300 max = 7.02600 average = 7.08480
-- mobilenet_v1 avg = 119.0739 ms mobilenetv1 min = 10.42000 max = 10.29100 average = 10.34267
-- mobilenet_v2 avg = 85.3050 ms mobilenetv2 min = 8.61900 max = 8.46900 average = 8.54707
-- shufflenet_v2 avg = 38.0762 ms shufflenetv2 min = 4.55200 max = 4.41900 average = 4.46477
-- squeezenet_v11 avg = 64.2201 ms squeezenet min = 8.60000 max = 7.85200 average = 7.98407
-------------------------------------- --------------------------------------
run benchmark armv8 run benchmark armv7
-------------------------------------- --------------------------------------
PaddleLite Benchmark PaddleLite Benchmark
Threads=1 Warmup=10 Repeats=30 Threads=1 Warmup=10 Repeats=30
-- mnasnet avg = 165.3073 ms mnasnet min = 20.98300 max = 20.81400 average = 20.92527
-- mobilenet_v1 avg = 306.0188 ms mobilenetv1 min = 33.19000 max = 32.81700 average = 33.08490
-- mobilenet_v2 avg = 195.1884 ms mobilenetv2 min = 25.91400 max = 25.61700 average = 25.73097
-- shufflenet_v2 avg = 99.3692 ms shufflenetv2 min = 11.14300 max = 10.97600 average = 11.06757
-- squeezenet_v11 avg = 156.6971 ms squeezenet min = 19.31800 max = 19.20000 average = 19.26530
Threads=2 Warmup=10 Repeats=30 Threads=2 Warmup=10 Repeats=30
-- mnasnet avg = 90.2290 ms mnasnet min = 12.59900 max = 12.46600 average = 12.52207
-- mobilenet_v1 avg = 157.0007 ms mobilenetv1 min = 19.05800 max = 18.94700 average = 18.97897
-- mobilenet_v2 avg = 118.1607 ms mobilenetv2 min = 15.28400 max = 15.11300 average = 15.19843
-- shufflenet_v2 avg = 68.6804 ms shufflenetv2 min = 6.97000 max = 6.81400 average = 6.90863
-- squeezenet_v11 avg = 91.3090 ms squeezenet min = 12.87900 max = 12.12900 average = 12.22530
Threads=4 Warmup=10 Repeats=30 Threads=4 Warmup=10 Repeats=30
-- mnasnet avg = 179.9730 ms mnasnet min = 7.31400 max = 7.12900 average = 7.20357
-- mobilenet_v1 avg = 204.0684 ms mobilenetv1 min = 11.44000 max = 10.86900 average = 10.94383
-- mobilenet_v2 avg = 181.6486 ms mobilenetv2 min = 9.14900 max = 9.03800 average = 9.09907
-- shufflenet_v2 avg = 123.2728 ms shufflenetv2 min = 4.60600 max = 4.49400 average = 4.53360
-- squeezenet_v11 avg = 412.9046 ms squeezenet min = 8.27000 max = 8.10600 average = 8.19000
-------------------------------------- --------------------------------------
``` ```
# Android Demo
## 多种应用场景
我们提供的Paddle-Lite示例工程[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo),其中包含[Android](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo)[iOS](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-ios-demo)[Armlinux](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-armlinux-demo)平台的示例工程。涵盖[人脸识别](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/face_detection_demo)[人像分割](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/human_segmentation_demo)[图像分类](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/image_classification_demo)[目标检测](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/object_detection_demo)4个应用场景。
### 1. 人脸识别
人脸检测是Paddle-Lite提供的人像检测demo。在移动端上提供了高精度、实时的人脸检测能力,能处理基于人脸检测的业务场景。在移动端预测的效果图如下:
<p align="center"><img width="300" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/face.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="300" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/face2.jpg"/></p>
### 2. 人像分割
人像分割是Paddle-Lite 提供的图像分割demo ,在移动端上提供了实时的人像分割能力,可以应用证件照自动抠图、面积测量、智能交通(标记车道和交通标志)等场景。 在移动端预测的效果图如下:
<p align="center"><img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/human.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/human2.jpg"/></p>
### 3. 图像分类
图像分类是Paddle-Lite 提供的图像处理demo ,在移动端上提供了实时的物体识别能力,可以应用到生产线自动分拣或质检、识别医疗图像、辅助医生肉眼诊断等场景。在移动端预测的效果图如下:
<p align="center"><img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/tabby_cat.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/tabby_cat2.jpg"/></p>
### 4. 物体检测
物体检测是Paddle-Lite 提供的图像识别demo ,在移动端上提供了检测多个物体的位置、名称、位置及数量的能力。可以应用到视频监控(是否有违规物体或行为)、工业质检(微小瑕疵的数量和位置)、医疗诊断(细胞计数、中药识别)等场景。在移动端预测的效果图如下:
<p align="center"><img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/dog.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/dog2.jpg"/></p>
## Android demo部署方法
下面我们以 **目标检测示例(object_detection_demo)** 为例讲解如何部署。
**目的**:将基于Paddle-Lite预测库的Android APP 部署到手机,实现物体检测
**需要的环境**: Android Studio、Android手机(开启USB调试模式)、下载到本地的[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)工程
**部署步骤**
1、 目标检测的Android示例位于 `Paddle-Lite-Demo\PaddleLite-android-demo\object_detection_demo`
2、用Android Studio 打开object_detection_demo工程 (本步骤需要联网)。
3、手机连接电脑,打开**USB调试****文件传输模式**,在Android Studio上连接自己的手机设备(手机需要开启允许从 USB安装软件权限)
![Android_studio](https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/android/Android_studio.png)
4、按下 Run按钮,自动编译APP并安装到手机。(该过程会自动下载Paddle-Lite预测库和模型,需要联网)
成功后效果如下,图一:APP安装到手机 图二: APP打开后的效果,会自动识别图片中的物体并标记
<p align="center"><img width="300" height="450" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/android/AndroidApp0.png"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="300" height="450" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/android/AndroidApp1.jpg"/></p>
## Android demo结构讲解
Android 示例的代码结构如下图所示:
<p align="center"><img width="600" height="450" src="http://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/android/Android_struct.png"/>
1、 Predictor.java: 预测代码
```shell
# 位置:
object_detection_demo/app/src/main/java/com/baidu/paddle/lite/demo/object_detection/Predictor.java
```
2、 model.nb : 模型文件 (opt 工具转化后Paddle-Lite模型);pascalvoc_label_list:训练模型时的`labels`文件
```shell
# 位置:
object_detection_demo/app/src/main/assets/models/ssd_mobilenet_v1_pascalvoc_for_cpu/model.nb
object_detection_demo/app/src/main/assets/labels/pascalvoc_label_list
```
3、 libpaddle_lite_jni.so、PaddlePredictor.jar:Paddle-Lite Java 预测库与Jar包
```shell
# 位置
object_detection_demo/app/src/main/jniLibs/arm64-v8a/libpaddle_lite_jni.so
object_detection_demo/app/libs/PaddlePredictor.jar
```
4、 build.gradle : 定义编译过程的 gradle 脚本。(不用改动,定义了自动下载Paddle-Lite预测和模型的过程)
```shell
# 位置
object_detection_demo/app/build.gradle
```
## 代码讲解 (使用Paddle-Lite Java API 执行预测)
Android 示例基于Java API 开发,调用Paddle-Lite Java API包括以下五步。更详细的API 描述参考: [Paddle-Lite Java API](https://paddle-lite.readthedocs.io/zh/latest/api_reference/java_api_doc.html)
```c++
// 导入Java API
import com.baidu.paddle.lite.MobileConfig;
import com.baidu.paddle.lite.Tensor;
import com.baidu.paddle.lite.Predictor;
import com.baidu.paddle.lite.PowerMode;
// 1. 写入配置:设置MobileConfig
MobileConfig config = new MobileConfig();
config.setModelFromFile(<modelPath>); // 设置Paddle-Lite模型路径
config.setPowerMode(PowerMode.LITE_POWER_NO_BIND); // 设置CPU运行模式
config.setThreads(4); // 设置工作线程数
// 2. 创建 PaddlePredictor
PaddlePredictor predictor = PaddlePredictor.createPaddlePredictor(config);
// 3. 设置输入数据
long[] dims = {100, 100};
float[] inputBuffer = new float[10000];
for (int i = 0; i < 10000; ++i) {
inputBuffer[i] = i;
}
Tensor input = predictor.getInput(0);
input.resize(dims);
input.setData(inputBuffer);
// 4. 执行预测
predictor.run();
// 5. 获取输出数据
Tensor result = predictor.getOutput(0);
float[] output = result.getFloatData();
for (int i = 0; i < 1000; ++i) {
System.out.println(output[i]);
}
```
# C++ Demo
## 1. 下载最新版本预测库
预测库下载界面位于[Paddle-Lite官方预编译库](../user_guides/release_lib),可根据需求选择合适版本。
**Android-ARMv8架构**为例,可以下载以下版本:
|ARM Version|build_extra|arm_stl|target|下载|
|:-------:|:-----:|:-----:|:-----:|:-------:|
|armv8|OFF|c++_static|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_static.tiny_publish.tar.gz)|
**解压后内容如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/1inference_lib.png)
## 2. 转化模型
PaddlePaddle的原生模型需要经过[opt]()工具转化为Paddle-Lite可以支持的naive_buffer格式。
`mobilenet_v1`模型为例:
(1)下载[mobilenet_v1模型](http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz)后解压:
```shell
wget http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz
tar zxf mobilenet_v1.tar.gz
```
**如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/3inference_model.png)
(2)下载[opt工具](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/opt)。放入同一文件夹,终端输入命令转化模型:
```shell
wget https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/opt
chmod +x opt
./opt --model_dir=./mobilenet_v1 --optimize_out_type=naive_buffer --optimize_out=./mobilenet_v1_opt
```
**结果如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/2opt_model.png)
## 3. 编写预测程序
准备好预测库和模型,我们便可以编写程序来执行预测。我们提供涵盖图像分类、目标检测等多种应用场景的C++示例demo可供参考,位于`inference_lite_lib.android.armv8/demo/cxx`
以mobile net_v1预测为例:`mobile_light`为mobilenet_v1预测示例,可以直接调用。
**示例如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/4light_demo.png)
## 4. 编译
预测程序需要编译为Android可执行文件。
以mobilenet_v1模型为例,C++示例位于`inference_lite_lib.android.armv8/demo/mobile_light`
```shell
cd inference_lite_lib.android.armv8/demo/mobile_light
```
编译demo
```shell
make
```
**结果如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/5compile_demo.png)
## 5. 执行预测
通过adb工具将可执行文件推送到手机上执行预测
(1)保证电脑已经安装adb工具,手机以"USB调试"、"文件传输模式"连接到电脑。
``` shell
adb deveices #查看adb设备是否已被识别
```
**连接如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/6adb_devices.png)
(2)准备预测库、模型和预测文件
1、将模型、动态库和预测文件放入同一文件夹:
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/7files.png)
**注意**:动态预测库文件位于: `inference_lite_lib.android.armv8/cxx/liblibpaddle_light_api_shared.so`
2、文件推送到手机:
``` shell
chmod +x mobilenetv1_light_api
adb push mobilenet_v1_opt.nb /data/local/tmp
adb push libpaddle_light_api_shared.so /data/local/tmp
adb push mobilenetv1_light_api /data/local/tmp
```
**效果如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/8push_file.png)
(3)执行预测
```shell
adb shell 'cd /data/local/tmp && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/tmp && mobilenetv1_light_api ./mobilenet_v1_opt.nb'
```
**结果如下图所示:**
![image](https://paddlelite-data.bj.bcebos.com/doc_images/cxx_demo/9result.png)
上图的`Output`为mobilenet_v1模型在全1输入时,得到的预测输出。至此,Paddle-Lite的C++ demo执行完毕。
## 注:如何在代码中使用 API
C++代码调用Paddle-Lite执行预测库仅需以下五步:
(1)引用头文件和命名空间
```c++
#include "paddle_api.h"
using namespace paddle::lite_api;
```
(2)指定模型文件,创建Predictor
```C++
// 1. Set MobileConfig, model_file_path is
// the path to model model file.
MobileConfig config;
config.set_model_from_file(model_file_path);
// 2. Create PaddlePredictor by MobileConfig
std::shared_ptr<PaddlePredictor> predictor =
CreatePaddlePredictor<MobileConfig>(config);
```
(3)设置模型输入 (下面以全一输入为例)
```c++
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;
}
```
(4)执行预测
```c++
predictor->Run();
```
(5)获得预测结果
```c++
std::unique_ptr<const Tensor> output_tensor(
std::move(predictor->GetOutput(0)));
// 转化为数据
auto output_data=output_tensor->data<float>();
```
## 其他cxx_demo的编译与预期结果
### Light API Demo
```shell
cd ../mobile_light
make
adb push mobilenetv1_light_api /data/local/tmp/
adb shell chmod +x /data/local/tmp/mobilenetv1_light_api
adb shell "/data/local/tmp/mobilenetv1_light_api --model_dir=/data/local/tmp/mobilenet_v1.opt "
```
### 图像分类 Demo
```shell
cd ../mobile_classify
wget http://paddle-inference-dist.bj.bcebos.com/mobilenet_v1.tar.gz
tar zxvf mobilenet_v1.tar.gz
make
adb push mobile_classify /data/local/tmp/
adb push test.jpg /data/local/tmp/
adb push labels.txt /data/local/tmp/
adb push ../../../cxx/lib/libpaddle_light_api_shared.so /data/local/tmp/
adb shell chmod +x /data/local/tmp/mobile_classify
adb shell "export LD_LIBRARY_PATH=/data/local/tmp/:$LD_LIBRARY_PATH && /data/local/tmp/mobile_classify /data/local/tmp/mobilenet_v1.opt /data/local/tmp/test.jpg /data/local/tmp/labels.txt"
```
### 目标检测 Demo
```shell
cd ../mobile_detection
wget https://paddle-inference-dist.bj.bcebos.com/mobilenetv1-ssd.tar.gz
tar zxvf mobilenetv1-ssd.tar.gz
make
adb push mobile_detection /data/local/tmp/
adb push test.jpg /data/local/tmp/
adb push ../../../cxx/lib/libpaddle_light_api_shared.so /data/local/tmp/
adb shell chmod +x /data/local/tmp/mobile_detection
adb shell "export LD_LIBRARY_PATH=/data/local/tmp/:$LD_LIBRARY_PATH && /data/local/tmp/mobile_detection /data/local/tmp/mobilenetv1-ssd /data/local/tmp/test.jpg"
adb pull /data/local/tmp/test_detection_result.jpg ./
```
### light API Demo 运行结果
运行成功后 ,将在控制台输出预测结果的前10个类别的预测概率:
```shell
Output dim: 1000
Output[0]: 0.000191
Output[100]: 0.000160
Output[200]: 0.000264
Output[300]: 0.000211
Output[400]: 0.001032
Output[500]: 0.000110
Output[600]: 0.004829
Output[700]: 0.001845
Output[800]: 0.000202
Output[900]: 0.000586
```
### 图像分类 Demo 运行结果
运行成功后 ,将在控制台输出预测结果的前5个类别的类型索引、名字和预测概率:
```shell
parameter: model_dir, image_path and label_file are necessary
parameter: topk, input_width, input_height, are optional
i: 0, index: 285, name: Egyptian cat, score: 0.482870
i: 1, index: 281, name: tabby, tabby cat, score: 0.471593
i: 2, index: 282, name: tiger cat, score: 0.039779
i: 3, index: 287, name: lynx, catamount, score: 0.002430
i: 4, index: 722, name: ping-pong ball, score: 0.000508
```
### 目标检测 Demo 运行结果
运行成功后 ,将在控制台输出检测目标的类型、预测概率和坐标:
```shell
running result:
detection image size: 935, 1241, detect object: person, score: 0.996098, location: x=187, y=43, width=540, height=592
detection image size: 935, 1241, detect object: person, score: 0.935293, location: x=123, y=639, width=579, height=597
```
# Lite基于CUDA的模型预测 # PaddleLite使用CUDA预测部署
Lite支持在x86_64,arm64架构上(如:TX2)进行CUDA的编译运行。 Lite支持在x86_64,arm64架构上(如:TX2)进行CUDA的编译运行。
...@@ -28,7 +28,27 @@ cd Paddle-Lite ...@@ -28,7 +28,27 @@ cd Paddle-Lite
./lite/tools/build.sh --build_python=ON cuda ./lite/tools/build.sh --build_python=ON cuda
``` ```
编译结束会在 `build_cuda/inference_lite_lib/python/lib/` 目录下生成 `lite_core.so` ## 编译结果说明
cuda的编译结果位于 `build_cuda/inference_lite_lib`
**具体内容**说明:
1、 `bin`文件夹:可执行工具文件,目前为空
2、 `cxx`文件夹:包含c++的库文件与相应的头文件
- `include` : 头文件
- `lib` : 库文件
- 打包的静态库文件:
- `libpaddle_api_full_bundled.a` :包含 full_api 和 light_api 功能的静态库
- 打包的动态态库文件:
- `libpaddle_full_api_shared.so` :包含 full_api 和 light_api 功能的动态库
3、 `third_party` 文件夹:第三方库文件
4、 `demo` 文件夹:c++ demo.
如果编译打开了python选项,则会在 `build_cuda/inference_lite_lib/python/lib/` 目录下生成 `lite_core.so`
## 运行 ## 运行
...@@ -36,7 +56,6 @@ cd Paddle-Lite ...@@ -36,7 +56,6 @@ cd Paddle-Lite
一: 下载darknet_yolov3模型,模型信息请参考[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/yolov3) 一: 下载darknet_yolov3模型,模型信息请参考[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/yolov3)
``` ```
# 下载模型 # 下载模型
wget https://paddle-inference-dist.cdn.bcebos.com/PaddleLite/yolov3_infer.tar.gz wget https://paddle-inference-dist.cdn.bcebos.com/PaddleLite/yolov3_infer.tar.gz
...@@ -47,7 +66,7 @@ wget https://paddle-inference-dist.cdn.bcebos.com/PaddleLite/kite.jpg ...@@ -47,7 +66,7 @@ wget https://paddle-inference-dist.cdn.bcebos.com/PaddleLite/kite.jpg
二: 运行 二: 运行
**NOTE:**此处示例使用的是python接口,后续会开放C++接口以及示例 **NOTE:**此处示例使用的是python接口。
``` python ``` python
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
...@@ -107,4 +126,14 @@ print (output_tensor.float_data()[:6]) ...@@ -107,4 +126,14 @@ print (output_tensor.float_data()[:6])
``` ```
**NOTE:** 对CUDA的支持还在持续开发中。 **NOTE:** 此处示例使用的是C++接口。
```
cd build_cuda/inference_lite_lib/demo/cxx/
mkdir build && cd build
cmake ..
make
wget https://paddle-inference-dist.cdn.bcebos.com/PaddleLite/yolov3_infer.tar.gz
tar -zxf yolov3_infer.tar.gz
./demo yolov3_infer
```
# PaddleLite使用FPGA预测部署
Paddle Lite支持基于arm的FPGA zu3/zu5/zu9的模型预测,提供armv8的交叉编译
Lite基于FPGA运行模型需要相应的FPGA驱动,目前只支持百度[Edgeboard开发板](https://ai.baidu.com/tech/hardware/deepkit)
## Lite实现FPGA简介
Lite支持FPGA作为后端硬件进行模型推理,其主要特性如下:
- Lite中FPGA的kernel(feed、fetch除外)均以FP16、NHWC的格式作为输入输出格式,所有的weights和bias仍为FP32、NCHW的格式,feed的输入和fetch的输出均为FP32、NCHW格式的数据,在提升计算速度的同时能做到用户对数据格式无感知
- 对于FPGA暂不支持的kernel,均会切回arm端运行,实现arm+FPGA混合布署运行
- 目前FPGA成本功耗都较低,Lite基于FPGA的模型性能远远好于arm端,可作为边缘设备首选硬件
## 编译
需要提前准备带有FPGAdrv.ko的FPGA开发板(如edgeboard开发板)和Lite代码
CMAKE编译选项:
- 设置`LITE_WITH_FPGA=ON``LITE_WITH_ARM=ON`
其他编译选项与ARM编译相同,可以参考[“Paddle Lite在Docker下的ARM编译”](../user_guides/source_compile)
示例如下:
```shell
cmake .. \
-DWITH_GPU=OFF \
-DWITH_MKL=OFF \
-DWITH_LITE=ON \
-DLITE_WITH_CUDA=OFF \
-DLITE_WITH_X86=OFF \
-DLITE_WITH_ARM=ON \
-DLITE_WITH_OPENMP=ON \
-DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \
-DWITH_TESTING=OFF \
-DLITE_WITH_FPGA=ON \
-DARM_TARGET_OS=armlinux
make publish_inference -j2
```
Lite提供FPGA编译脚本,位于lite/tools/build_FPGA.sh,在Lite根目录执行该脚本即可编译
## 运行示例
- **运行文件准备**
下面以Resnet50模型为例,介绍如何使用edgeboard开发板实现模型运行
```bash
#连接开发板,并利用screen命令启动 [本机执行]
screen /dev/cu.SLAB_USBtoUART 115200
#查看开发板ip并ssh登录到开发板,假设开发板ip为192.0.1.1 [本机执行]
ssh root@192.0.1.1
#在开发板上建立目录workspace,拷贝FPGA驱动FPGAdrv.ko到workspace目录 [开发板执行]
mkdir workspace && scp $DRIVER_PATH/FPGAdrv.ko workspace
#将Lite中编译好的测试程序拷贝到开发板workspace目录 [本机执行]
scp $LITE_ROOT/build_FPGA/lite/api/test_resnet50_FPGA root@$EDGEBOARD_IP:workspace/
#把Resnet50的模型和参数scp到开发板workspace目录 [本机执行]
scp -r $LITE_ROOT/build_FPGA/lite/third_party/install/resnet50/ root@$EDGEBOARD_IP:workspace/
#在运行模型前需要加载FPGA驱动 [开发板执行]
insmod FPGAdrv.ko
#给测试程序添加可运行权限 [开发板执行]
chmod +x test_resnet50_FPGA
```
- **使用FPGA进行模型预测**
```bash
#以下命令均在开发板上运行
#直接运行单测程序
./test_resnet50_FPGA --model_dir=resnet50
#如果需要测试性能,可以用repeats参数设置模型运行次数(如1000),同时可以设置预热次数(如10)来让硬件事先运行到稳定水平
./test_resnet50_FPGA --model_dir=resnet50 --repeats=1000 --warmup=10
```
## 如何在Code中使用
在Lite中使用FPGA与ARM相似,具体的区别如下:
- 由于fpga运行模式为fp16精度、nhwc布局,所以需要修改相应的`valid_place`
- fpga不需要device的初始化和运行模式设置
代码示例:
```cpp
lite::Predictor predictor;
std::vector<Place> valid_places(
{Place{TARGET(kFPGA), PRECISION(kFP16), DATALAYOUT(kNHWC)},Place{TARGET(kARM)});
predictor.Build(model_dir, "", "", valid_places);
auto* input_tensor = predictor.GetInput(0);
input_tensor->Resize(DDim(std::vector<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);
```
# iOS Demo
## 多种应用场景
我们提供Paddle-Lite示例工程[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo),其中包含[Android](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo)[iOS](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-ios-demo)[Armlinux](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-armlinux-demo)平台的示例工程。iOS demo涵盖[图像分类](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/image_classification_demo)[目标检测](https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/object_detection_demo)2个应用场景。
### 1. 图像分类
图像分类是Paddle-Lite 提供的图像处理demo ,在移动端上提供了实时的物体识别能力,可以应用到生产线自动分拣或质检、识别医疗图像、辅助医生肉眼诊断等场景。在移动端预测的效果图如下:
<p align="center"><img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/tabby_cat.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/tabby_cat2.jpg"/></p>
### 2. 物体检测
物体检测是Paddle-Lite 提供的图像识别demo ,在移动端上提供了检测多个物体的位置、名称、位置及数量的能力。可以应用到视频监控(是否有违规物体或行为)、工业质检(微小瑕疵的数量和位置)、医疗诊断(细胞计数、中药识别)等场景。在移动端预测的效果图如下:
<p align="center"><img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/dog.jpg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="250" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/demo/dog2.jpg"/></p>
## iOS demo部署方法
下面我们以**目标检测(object_detection_demo)**为例讲解如何部署iOS工程。
**目的**:将基于Paddle-Lite预测库的iOS APP部署到苹果手机,实现物体检测。
**需要的环境**:Mac 电脑上安装Xcode、苹果手机、下载到本地的[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)工程
**部署步骤**
1、 目标检测的iOS示例位于 `Paddle-Lite-Demo\PaddleLite-ios-demo\object_detection_demo`
2、终端中执行 `download_dependencies.sh`脚本自动下载模型和Paddle-Lite预测库
```shell
cd PaddleLite-ios-demo # 1. 终端中进入 Paddle-Lite-Demo\PaddleLite-ios-demo
sh download_dependencies.sh # 2. 执行脚本下载依赖项 (需要联网)
```
下载完成后会出现提示: `Extract done `
3、用Xcode打开`object_detection_demo/detection_demo.xcodeproj`文件,修改工程配置。
依次修改 `General/Identity``Signing&Capabilities`属性,替换为自己的工程代号和团队名称。(必须修改,不然无法通过编译)
![Xcode1](https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/Xcode1.png)
![Xcode2](https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/Xcode2.png)
4、 IPhone手机连接电脑,在Xcode中连接自己的手机 (第一次连接IPhone到电脑时,需要在IPhone的`设置->通用->设备管理`中选择本电脑并信任)
<p align="center"><img width="600" height="250" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/Xcode-phone.jpg"/>
5、按下左上角的 Run按钮,自动编译APP并安装到手机。在苹果手机中设置信任该APP(进入`设置->通用->设备管理`,选中新安装的APP并`验证该应用`
成功后效果如下,图一:APP安装到手机 图二: APP打开后的效果,会自动识别图片中的物体并标记
<p align="center"><img width="300" height="450" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/IOS2.jpeg"/>&#8194;&#8194;&#8194;&#8194;&#8194;<img width="300" height="450" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/IOS3.jpeg"/></p>
## iOS demo结构讲解
iOS 示例的代码结构如下图所示:
<p align="center"><img width="600" height="450" src="https://paddlelite-data.bj.bcebos.com/doc_images/Android_iOS_demo/iOS/IOS-struct.png"/>
1、 mobilenetv1-ssd: 模型文件 (opt 工具转化后Paddle-Lite模型)
```shell
# 位置:
ios-detection_demo/detection_demo/models/mobilenetv1-ssd
```
2、 libpaddle_api_light_bundled.a、paddle_api.h : Paddle-Lite C++ 预测库和头文件
```shell
# 位置:
# iOS预测库
ios-detection_demo/detection_demo/lib/libpaddle_api_light_bundled.a
# 预测库头文件
ios-detection_demo/detection_demo/include/paddle_api.h
ios-detection_demo/detection_demo/include/paddle_use_kernels.h
ios-detection_demo/detection_demo/include/paddle_use_ops.h
```
3、 ViewController.mm:主要预测代码
```shell
# 位置
ios-detection_demo/detection_demo/ViewController.mm
```
## 代码讲解 (如何使用Paddle-Lite C++ API 执行预测)
IOS 示例基于C++ API 开发,调用Paddle-Lite C++ API包括以下五步。更详细的API 描述参考: [Paddle-Lite C++ API](https://paddle-lite.readthedocs.io/zh/latest/api_reference/java_api_doc.html)
```c++
#include <iostream>
// 引入C++ API
#include "paddle_lite/paddle_api.h"
#include "paddle_lite/paddle_use_ops.h"
#include "paddle_lite/paddle_use_kernels.h"
// 1. 设置MobileConfig
MobileConfig config;
config.set_model_from_file(<modelPath>); // 设置NaiveBuffer格式模型路径
config.set_power_mode(LITE_POWER_NO_BIND); // 设置CPU运行模式
config.set_threads(4); // 设置工作线程数
// 2. 创建PaddlePredictor
std::shared_ptr<PaddlePredictor> predictor = CreatePaddlePredictor<MobileConfig>(config);
// 3. 设置输入数据
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;
}
// 4. 执行预测
predictor->run();
// 5. 获取输出数据
std::unique_ptr<const Tensor> output_tensor(std::move(predictor->GetOutput(0)));
std::cout << "Output shape " << output_tensor->shape()[1] << std::endl;
for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) {
std::cout << "Output[" << i << "]: " << output_tensor->data<float>()[i]
<< std::endl;
}
```
# Java Demo
本节中,Java demo 完整代码位于 [demo/java](https://github.com/PaddlePaddle/Paddle-Lite/tree/develop/lite/demo/java)
要编译和跑起Android demo 程序 PaddlePredictor,你需要准备:
1. 一台能运行安卓程序的安卓手机
2. 一台带有AndroidStudio的开发机
## 编译
首先在PaddleLite的开发 [Docker镜像](../user_guides/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**](../user_guides/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 代表该测试花费的时间。
# PaddleLite使用NPU(华为)预测部署
Paddle Lite是首款支持华为自研达芬奇架构NPU(Kirin 810/990 SoC搭载的NPU)的预测框架。
原理是在线分析Paddle模型,将Paddle算子转成HiAI IR后,调用HiAI IR/Builder/Runtime APIs生成并执行HiAI模型。
## 已支持的设备
- 华为nova5、nova5i pro、mate30、mate30 pro、mate30 5G、荣耀v30,以及即将推出的mate40、p40。据华为透露,今后上市的大部分手机都会搭载其自研达芬奇架构NPU。
## 已支持的模型
- MobileNetV1
- MobileNetV2
- ResNet-18/50
- ShuffleNetV2
- CycleGAN (暂时需要华为内部rom的支持)
- 百度内部业务模型(由于涉密,不方便透露具体细节)
## 已支持(或部分支持)的Paddle算子
- sigmoid
- relu
- tanh
- relu_clipped
- leaky_relu
- softsign
- hard_sigmoid
- batch_norm
- concat
- conv2d
- depthwise_conv2d
- conv2d_transpose
- dropout
- elementwise_add
- elementwise_sub
- elementwise_mul
- elementwise_div
- fusion_elementwise_add_activation
- fusion_elementwise_sub_activation
- fusion_elementwise_mul_activation
- fusion_elementwise_div_activation
- fc
- bilinear_interp
- nearest_interp
- matmul
- mul
- pad2d
- pool2d
- reduce_mean
- reshape
- reshape2
- scale
- shuffle_channel
- softmax
- split
- sqrt
- square
- transpose
- transpose2
- unsqueeze
- unsqueeze2
- instance_norm (暂时需要华为内部rom的支持)
- layer_norm (暂时需要华为内部rom的支持)
## 编译支持NPU的Paddle Lite库
- 从https://developer.huawei.com/consumer/cn/hiai/下载华为HiAI DDK后解压到任意路径(注意:华为提供了多个版本的DDK,我们需要下载针对麒麟810/990芯片HiAI Foundation开发套件,例如最新的[DDK V310版本](https://obs.cn-north-2.myhwclouds.com/hms-ds-wf/sdk/hwhiai-ddk-100.310.011.010.zip))。
- 将HiAI DDK中的ai_ddk_lib目录拷贝至Paddle Lite源码根目录后,使用[NPU编译脚本](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/tools/build_npu.sh)编译full_publish和tiny_publish。
注意:以下是HiAI DDK V310版解压后的目录结构,需要将ai_ddk_lib目录拷贝至Paddle Lite源码根目录。
```shell
- app_sample
- ddk
- ai_ddk_lib
- include
- lib # for armv7
- lib64 # for armv8
- document
- tools
```
- full_publish and tiny_publish for armv8,由于HiAI DDK的armv7和armv8的so库均基于c++_shared构建,因此,建议使用c++_shared编译Paddle Lite。
```shell
$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_shared full_publish
$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_shared tiny_publish
```
- full_publish and tiny_publish for armv7
```shell
$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_shared full_publish
$ ./lite/tools/build_npu.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_shared tiny_publish
```
注意:为了保证编译环境一致,建议参考[源码编译](../user_guides/source_compile)中的Docker开发环境进行配置,然后再执行上述命令。
## 优化生成NPU模型
- model_optimize_tool工具已经支持生成NPU模型,仅需要将valid_targets设置为npu,arm即可,具体参考[模型转化方法](../user_guides/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=npu,arm \
--record_tailoring_info =(true|false)
```
- model_optimize_tool生成的模型只是标记了NPU支持的Paddle算子,并没有真正生成NPU HiAI模型,只有在执行时才会将标记的Paddle算子转成HiAI IR,最终生成并执行HiAI模型,具体实现参考PR[2576](https://github.com/PaddlePaddle/Paddle-Lite/pull/2576)
- 不同模型,不同型号(ROM版本)的华为手机,在执行阶段,由于某些Paddle算子无法完全转成HiAI IR,或目标手机的HiAI版本过低等原因,可能导致HiAI模型无法成功生成,在这种情况下,Paddle Lite会调用CPU版算子进行运算完成整个预测任务。
## 通过JAVA接口加载并执行NPU模型
- 使用方法和[Java实例](java_demo)一致,无需额外设置任何参数,只需将模型换成NPU模型即可。[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)中的Image Classification Demo for Android是同时支持CPU和NPU两种模型的图像分类Demo。
注意:在拷贝libpaddle_lite_jni.so的时候,由于依赖HiAI DDK so和libc++_shared.so库,需要将HiAI DDK中ai_ddk_lib/lib或ai_ddk_lib/lib64目录下的所有so和libc++_shared.so,拷到libpaddle_lite_jni.so同级目录下。
## 通过C++接口加载并执行NPU模型
- 使用方法和[C++实例](cpp_demo)一致,同样无需额外设置任何参数,只需将模型换成NPU模型即可。
注意:1)不能使用安卓模拟器,需要使用真实设备,且必须是支持NPU的华为手机。2)在使用adb push命令向手机推送目标程序时,需要将HiAI DDK中ai_ddk_lib/lib或ai_ddk_lib/lib64目录下的所有so和libc++_shared.so,推送到目标程序同级目录下。
## 其它说明
- 华为达芬奇架构的NPU内部大量采用float16进行运算,因此,预测结果会存在偏差,但大部分情况下精度不会有较大损失,可参考[Paddle-Lite-Demo](https://github.com/PaddlePaddle/Paddle-Lite-Demo)中Image Classification Demo for Android对同一张图片CPU与NPU的预测结果。
- 华为Kirin 810/990 Soc搭载的自研达芬奇架构的NPU,与Kirin 970/980 Soc搭载的寒武纪NPU不一样,同样的,与Hi3559A、Hi3519A使用的NNIE也不一样,Paddle Lite只支持华为自研达芬奇架构NPU。
- 我们正在持续增加能够适配HiAI IR的Paddle算子bridge/converter,以便适配更多Paddle模型,同时华为研发同学也在持续对HiAI IR性能进行优化。
# Lite基于OpenCL的ARM GPU预测 # PaddleLite使用OpenCL预测部署
Lite支持在Android系统上运行基于OpenCL的程序,目前支持Ubuntu环境下armv8、armv7的交叉编译。 Lite支持在Android系统上运行基于OpenCL的程序,目前支持Ubuntu环境下armv8、armv7的交叉编译。
...@@ -11,18 +11,45 @@ Lite支持在Android系统上运行基于OpenCL的程序,目前支持Ubuntu环 ...@@ -11,18 +11,45 @@ Lite支持在Android系统上运行基于OpenCL的程序,目前支持Ubuntu环
详见 **源码编译指南-环境准备** 章节。 详见 **源码编译指南-环境准备** 章节。
### 编译选项
|参数|介绍|值|
|--------|--------|--------|
|--arm_os|代表目标操作系统|目前仅支持且默认为`android`|
|--arm_abi|代表体系结构类型,支持armv8和armv7|默认为`armv8`即arm64-v8a;`armv7`即armeabi-v7a|
|--arm_lang|代表编译目标文件所使用的编译器|默认为gcc,支持 gcc和clang两种|
### 编译Paddle-Lite OpenCL库范例 ### 编译Paddle-Lite OpenCL库范例
注:以android-armv8-opencl的目标、Docker容器的编译开发环境为例,CMake3.10,android-ndk-r17c位于`/opt/`目录下。 注:以android-armv8-opencl的目标、Docker容器的编译开发环境为例,CMake3.10,android-ndk-r17c位于`/opt/`目录下。
#### 针对 Lite 用户的编译命令(无单元测试,有编译产物)
- `arm_os`: `[android]`,目前不支持linux;
- `arm_abi`: `[armv7 | armv8]`
- `arm_lang`: `[gcc]`,目前不支持clang;
- `build_extra`: `[OFF | ON]`,编译全量op和kernel,体积会大,编译时间长;
- `build_cv`: `[OFF | ON]`,编译arm cpu neon实现的的cv预处理模块;
- `android_stl`: `[c++_shared | c++_static]`,paddlelite的库以何种方式链接`android_stl`,选择`c++_shared`得到的动态库体积更小,但使用时候记得上传paddlelite所编译版本(armv7或armv8)一致的`libc++_shared.so`(来自Android-NDK);
注:调用`./lite/tools/build.sh`执行编译。
```bash
# 假设当前位于处于Lite源码根目录下
# 导入NDK_ROOT变量,注意检查您的安装目录若与本示例不同
export NDK_ROOT=/opt/android-ndk-r17c
# 删除上一次CMake自动生成的.h文件
rm ./lite/api/paddle_use_kernels.h
rm ./lite/api/paddle_use_ops.h
# 根据指定编译参数编译
./lite/tools/build.sh \
--arm_os=android \
--arm_abi=armv8 \
--arm_lang=gcc \
--build_extra=OFF \
--build_cv=OFF \
--android_stl=c++_shared \
opencl
```
#### 针对 Lite 开发者的编译命令(有单元测试,编译产物)
注:调用`./lite/tools/ci_build.sh`执行编译,该命令会编译armv7和armv8的opencl库。虽然有编译产物,但因编译单元测试,编译产物包体积可能较大,不推荐使用。
```bash ```bash
# 假设当前位于处于Lite源码根目录下 # 假设当前位于处于Lite源码根目录下
...@@ -38,16 +65,20 @@ rm ./lite/api/paddle_use_ops.h ...@@ -38,16 +65,20 @@ rm ./lite/api/paddle_use_ops.h
--arm_os=android \ --arm_os=android \
--arm_abi=armv8 \ --arm_abi=armv8 \
--arm_lang=gcc \ --arm_lang=gcc \
build_test_arm_opencl build_opencl
``` ```
注:如果要调试cl kernel,假设已经完成上述脚本编译(已生成cmake文件)。调试只需要修改`./lite/backends/opencl/cl_kernel/`下对应的kernel文件,保存后在项目根目录执行`python ./lite/tools/cmake_tools/gen_opencl_code.py ./lite/backends/opencl/cl_kernel ./lite/backends/opencl/opencl_kernels_source.cc`,该命令会自动将修改后,再切到build目录下执行`make publish_inference`或者你要编译的单测的可执行文件名,cl kernel文件的内容会随着编译自动打包到产物包如 .so 中或者对应单测可执行文件中。
### 编译产物说明
编译产物位于`build.lite.android.armv8.gcc.opencl`下的`inference_lite_lib.android.armv8.opencl`文件夹内,这里仅罗列关键产物: 编译产物位于`build.lite.android.armv8.gcc.opencl`下的`inference_lite_lib.android.armv8.opencl`文件夹内,这里仅罗列关键产物:
- `cxx`:该目录是编译目标的C++的头文件和库文件; - `cxx`:该目录是编译目标的C++的头文件和库文件;
- `demo`:该目录包含了两个demo,用来调用使用`libpaddle_api_full_bundled.a``libpaddle_api_light_bundled.a`,分别对应`mobile_full``mobile_light`文件夹。编译对应的demo仅需在`mobile_full``mobile_light` - `demo`:该目录包含了两个demo,用来调用使用`libpaddle_api_full_bundled.a``libpaddle_api_light_bundled.a`,分别对应`mobile_full``mobile_light`文件夹。编译对应的demo仅需在`mobile_full``mobile_light`
- `mobile_full`:使用cxx config,可直接加载fluid模型,若使用OpenCL需要在`mobilenetv1_full_api.cc`代码里开启`DEMO_USE_OPENCL`的宏,详细见代码注释; - `mobile_full`:使用cxx config,可直接加载fluid模型,若使用OpenCL需要在`mobilenetv1_full_api.cc`代码里开启`DEMO_USE_OPENCL`的宏,详细见代码注释;
- `mobile_light`:使用mobile config,只能加载`model_optimize_tool`优化过的模型; - `mobile_light`:使用mobile config,只能加载`model_optimize_tool`优化过的模型
- `opencl`:该目录存放opencl实现的相关kernel 注:`opencl`实现的相关kernel已经打包到动态库中
```bash ```bash
. .
...@@ -65,40 +96,23 @@ rm ./lite/api/paddle_use_ops.h ...@@ -65,40 +96,23 @@ rm ./lite/api/paddle_use_ops.h
| |-- libpaddle_api_light_bundled.a | |-- libpaddle_api_light_bundled.a
| |-- libpaddle_full_api_shared.so | |-- libpaddle_full_api_shared.so
| `-- libpaddle_light_api_shared.so | `-- libpaddle_light_api_shared.so
|-- demo `-- demo
| `-- cxx `-- cxx
| |-- Makefile.def |-- Makefile.def
| |-- README.md |-- README.md
| |-- include |-- include
| | |-- paddle_api.h | |-- paddle_api.h
| | |-- paddle_lite_factory_helper.h | |-- paddle_lite_factory_helper.h
| | |-- paddle_place.h | |-- paddle_place.h
| | |-- paddle_use_kernels.h | |-- paddle_use_kernels.h
| | |-- paddle_use_ops.h | |-- paddle_use_ops.h
| | `-- paddle_use_passes.h | `-- paddle_use_passes.h
| |-- mobile_full |-- mobile_full
| | |-- Makefile | |-- Makefile
| | `-- mobilenetv1_full_api.cc | `-- mobilenetv1_full_api.cc
| `-- mobile_light `-- mobile_light
| |-- Makefile |-- Makefile
| `-- mobilenetv1_light_api.cc `-- mobilenetv1_light_api.cc
`-- opencl
`-- cl_kernel
|-- buffer
| |-- depthwise_conv2d_kernel.cl
| |-- elementwise_add_kernel.cl
| |-- fc_kernel.cl
| |-- im2col_kernel.cl
| |-- layout_kernel.cl
| |-- mat_mul_kernel.cl
| |-- pool_kernel.cl
| `-- relu_kernel.cl
|-- cl_common.h
`-- image
|-- channel_add_kernel.cl
|-- elementwise_add_kernel.cl
|-- pool_kernel.cl
`-- relu_kernel.cl
``` ```
调用`libpaddle_api_full_bundled.a``libpaddle_api_light_bundled.a`见下一部分运行示例。 调用`libpaddle_api_full_bundled.a``libpaddle_api_light_bundled.a`见下一部分运行示例。
...@@ -109,48 +123,9 @@ rm ./lite/api/paddle_use_ops.h ...@@ -109,48 +123,9 @@ rm ./lite/api/paddle_use_ops.h
下面以android、ARMv8、gcc的环境为例,介绍3个示例,分别如何在手机上执行基于OpenCL的ARM GPU推理过程。 下面以android、ARMv8、gcc的环境为例,介绍3个示例,分别如何在手机上执行基于OpenCL的ARM GPU推理过程。
**注意:** 以下命令均在Lite源码根目录下运行。在3个示例前,下面这段命令都先要执行用来准备环境:
```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/backends/opencl/cl_kernel/cl_common.h /data/local/tmp/opencl/cl_kernel/
adb push lite/backends/opencl/cl_kernel/buffer/* /data/local/tmp/opencl/cl_kernel/buffer/
adb push lite/backends/opencl/cl_kernel/image/* /data/local/tmp/opencl/cl_kernel/image/
```
### 运行示例1: 编译产物demo示例 ### 运行示例1: 编译产物demo示例
```bash ```bash
######################################################################
# 编译mobile_full的demo #
######################################################################
# 步骤: #
# 0.确保编译Paddle-Lite时编译了OpenCL; #
# 1.编辑`mobilenetv1_full_api.cc`代码, 开启`DEMO_USE_OPENCL`的宏; #
# 2.在产物目录`demo/cxx/mobile_full`下编译`mobile_full`的demo; #
# 3.上传demo, 模型, opencl kernel文件到手机; #
# 4.运行demo得到预期结果. #
######################################################################
adb shell mkdir /data/local/tmp/opencl/mobilenet_v1
chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_full/mobilenetv1_full_api
adb push ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_full/mobilenetv1_full_api /data/local/tmp/opencl/
adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1
# use mobile_full run mobilenet_v1
# `GLOG_v` is log level
adb shell "export GLOG_v=0; \
/data/local/tmp/opencl/mobilenetv1_full_api \
--model_dir=/data/local/tmp/opencl/mobilenet_v1 \
--optimized_model_dir=/data/local/tmp/opencl/full_api_opt_model"
###################################################################### ######################################################################
# 编译mobile_light的demo # # 编译mobile_light的demo #
###################################################################### ######################################################################
...@@ -158,33 +133,40 @@ adb shell "export GLOG_v=0; \ ...@@ -158,33 +133,40 @@ adb shell "export GLOG_v=0; \
# 0.确保编译Paddle-Lite时编译了OpenCL; # # 0.确保编译Paddle-Lite时编译了OpenCL; #
# 1.编译model_optimize_tool并对模型优化, `targets`参数为`opencl`; # # 1.编译model_optimize_tool并对模型优化, `targets`参数为`opencl`; #
# 2.在产物目录`demo/cxx/mobile_light`下编译`mobile_light`的demo; # # 2.在产物目录`demo/cxx/mobile_light`下编译`mobile_light`的demo; #
# 3.上传demo, 模型, opencl kernel文件到手机; # # 3.上传demo, 模型文件到手机; #
# 4.运行demo得到预期结果. # # 4.运行demo得到预期结果. #
###################################################################### ######################################################################
# 在/data/local/tmp目录下创建OpenCL文件目录
adb shell mkdir -p /data/local/tmp/opencl
# use model_optimize_tool to optimize model # use model_optimize_tool to optimize model
./build.model_optimize_tool/lite/api/model_optimize_tool \ ./build.model_optimize_tool/lite/api/model_optimize_tool \
--model_dir=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \ --model_dir=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \
--optimize_out_type=naive_buffer \ --optimize_out_type=naive_buffer \
--optimize_out=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \ --optimize_out=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/mobilenetv1_opt \
--valid_targets=opencl --valid_targets=opencl
adb shell mkdir /data/local/tmp/opencl/mobilenet_v1 adb shell mkdir /data/local/tmp/opencl/mobilenet_v1/
chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api
adb push ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api /data/local/tmp/opencl/ adb push ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api /data/local/tmp/opencl/
adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1 adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/mobilenetv1_opt.nb /data/local/tmp/opencl/
# use mobile_light run mobilenet_v1 # use mobile_light run mobilenet_v1
adb shell "export GLOG_v=5; \ adb shell "export GLOG_v=1; \
/data/local/tmp/opencl/mobilenetv1_light_api \ /data/local/tmp/opencl/mobilenetv1_light_api \
--model_dir=/data/local/tmp/opencl/" /data/local/tmp/opencl/mobilenetv1_opt.nb"
``` ```
**注:** `GLOG_v`是指定需要显示VLOG的日志级别,默认为0。权重参数会在第一次运行时加载,所以第一次执行时间略长。一般将warmup的值设为10,repeats值设为多次。
### 运行示例2: test_mobilenetv1单元测试 ### 运行示例2: test_mobilenetv1单元测试
- **运行文件准备** - **运行文件准备**
```bash ```bash
# 在/data/local/tmp目录下创建OpenCL文件目录
adb shell mkdir -p /data/local/tmp/opencl
# 将mobilenet_v1的模型文件推送到/data/local/tmp/opencl目录下 # 将mobilenet_v1的模型文件推送到/data/local/tmp/opencl目录下
adb shell mkdir -p /data/local/tmp/opencl/mobilenet_v1 adb shell mkdir -p /data/local/tmp/opencl/mobilenet_v1
adb push build.lite.android.armv8.gcc.opencl/third_party/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1/ adb push build.lite.android.armv8.gcc.opencl/third_party/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1/
...@@ -195,42 +177,26 @@ adb push build.lite.android.armv8.gcc.opencl/lite/api/test_mobilenetv1 /data/loc ...@@ -195,42 +177,26 @@ adb push build.lite.android.armv8.gcc.opencl/lite/api/test_mobilenetv1 /data/loc
- **执行OpenCL推理过程** - **执行OpenCL推理过程**
使用如下命令运行OpenCL程序。其中:
- `--cl_path`指定了OpenCL的kernels文件即cl\_kernel所在目录;
- `--modle_dir`指定了模型文件所在目录。
```bash ```bash
adb shell chmod +x /data/local/tmp/opencl/test_mobilenetv1 adb shell chmod +x /data/local/tmp/opencl/test_mobilenetv1
adb shell /data/local/tmp/opencl/test_mobilenetv1 \ adb shell "export GLOG_v=1; \
--cl_path=/data/local/tmp/opencl \ /data/local/tmp/opencl-image/test_mobilenetv1 \
--model_dir=/data/local/tmp/opencl/mobilenet_v1 \ --model_dir=/data/local/tmp/opencl-image/mobilenetv1_fluid/ \
--warmup=1 \ --warmup=10 \
--repeats=1 --repeats=100"
``` ```
**注意:** 因为权重参数均会在Op Kernel第一次运行时进行加载,所以第一次的执行时间会略长。一般将warmup的值设为1,repeats值设为多次。
### 运行示例3: test_layout_opencl单元测试 ### 运行示例3: test_layout_opencl单元测试
- **运行文件准备**
```bash
# 将OpenCL单元测试程序test_layout_opencl,推送到/data/local/tmp/opencl目录下
adb push build.lite.android.armv8.gcc.opencl/lite/kernels/opencl/test_layout_opencl /data/local/tmp/opencl/
```
OpenCL推理过程**
```bash ```bash
adb shell mkdir -p /data/local/tmp/opencl
adb shell chmod +x /data/local/tmp/opencl/test_layout_opencl adb shell chmod +x /data/local/tmp/opencl/test_layout_opencl
adb shell /data/local/tmp/opencl/test_layout_opencl adb shell "export GLOG_v=4; \
/data/local/tmp/opencl/test_layout_opencl"
``` ```
### 如何在Code中使用
# 如何在Code中使用
见运行示例1的demo代码: 见运行示例1的demo代码:
......
# 使用X86预测库 # PaddleLite使用X86预测部署
Paddle-Lite 支持在Docker或Linux环境编译x86预测库。环境搭建参考[环境准备](../installation/source_compile) Paddle-Lite 支持在Docker或Linux环境编译x86预测库。环境搭建参考[环境准备](../user_guides/source_compile)
(注意:非docker Linux环境需要是Ubuntu16.04) (注意:非docker Linux环境需要是Ubuntu16.04)
...@@ -9,8 +9,8 @@ Paddle-Lite 支持在Docker或Linux环境编译x86预测库。环境搭建参考 ...@@ -9,8 +9,8 @@ Paddle-Lite 支持在Docker或Linux环境编译x86预测库。环境搭建参考
1、 下载代码 1、 下载代码
```bash ```bash
git clone https://github.com/PaddlePaddle/Paddle-Lite.git git clone https://github.com/PaddlePaddle/Paddle-Lite.git
#需要切换到 release/v2.0.0之后版本 # 切换到release分支
git checkout <release_tag> git checkout release/v2.3
``` ```
2、 源码编译 2、 源码编译
...@@ -42,43 +42,56 @@ x86编译结果位于 `build.lite.x86/inference_lite_lib` ...@@ -42,43 +42,56 @@ x86编译结果位于 `build.lite.x86/inference_lite_lib`
## x86预测API使用示例 ## x86预测API使用示例
1、我们提供Linux环境下x86 API运行mobilenet_v1的示例:[mobilenet_full_x86demo](https://paddlelite-data.bj.bcebos.com/x86/mobilenet_full_x86demo.zip)。下载解压后内容如下:
![](https://paddlelite-data.bj.bcebos.com/x86/x86-doc/demo.png)
`mobilenet_v1`为模型文件、`lib``include`分别是Paddle-Lite的预测库和头文件、`third_party`下是编译时依赖的第三方库`mklml``mobilenet_full_api.cc`是x86示例的源代码、`build.sh`为编译的脚本。
2、demo内容与使用方法
``` bash
# 1、编译
sh build.sh
```
编译结果为当前目录下的 `mobilenet_full_api `
``` bash
# 2、执行预测
mobilenet_full_api mobilenet_v1
```
`mobilenet_v1`为当前目录下的模型路径,`mobilenet_full_api`为第一步编译出的可执行文件。
3、示例源码`mobilenet_full_api.cc`
```c++ ```c++
#include <gflags/gflags.h>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "paddle_api.h" // NOLINT #include "paddle_api.h"
#include "paddle_use_kernels.h" // NOLINT
#include "paddle_use_ops.h" // NOLINT
#include "paddle_use_passes.h" // NOLINT
using namespace paddle::lite_api; // NOLINT
DEFINE_string(model_dir, "", "Model dir path."); using namespace paddle::lite_api; // NOLINT
DEFINE_string(optimized_model_dir, "", "Optimized model dir.");
DEFINE_bool(prefer_int8_kernel, false, "Prefer to run model with int8 kernels");
int64_t ShapeProduction(const shape_t& shape) { int64_t ShapeProduction(const shape_t& shape) {
int64_t res = 1; int64_t res = 1;
for (auto i : shape) res *= i; for (auto i : shape) res *= i;
return res; return res;
} }
void RunModel() {
// 1. Set CxxConfig
CxxConfig config;
config.set_model_file(FLAGS_model_dir + "model");
config.set_param_file(FLAGS_model_dir + "params");
config.set_valid_places({
lite_api::Place{TARGET(kX86), PRECISION(kFloat)}
});
void RunModel(std::string model_dir) {
// 1. Create CxxConfig
CxxConfig config;
config.set_model_dir(model_dir);
config.set_valid_places({
Place{TARGET(kX86), PRECISION(kFloat)},
Place{TARGET(kHost), PRECISION(kFloat)}
});
// 2. Create PaddlePredictor by CxxConfig // 2. Create PaddlePredictor by CxxConfig
std::shared_ptr<PaddlePredictor> predictor = std::shared_ptr<PaddlePredictor> predictor =
CreatePaddlePredictor<CxxConfig>(config); CreatePaddlePredictor<CxxConfig>(config);
// 3. Prepare input data // 3. Prepare input data
std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0))); std::unique_ptr<Tensor> input_tensor(std::move(predictor->GetInput(0)));
input_tensor->Resize(shape_t({1, 3, 224, 224})); input_tensor->Resize({1, 3, 224, 224});
auto* data = input_tensor->mutable_data<float>(); auto* data = input_tensor->mutable_data<float>();
for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) { for (int i = 0; i < ShapeProduction(input_tensor->shape()); ++i) {
data[i] = 1; data[i] = 1;
...@@ -90,15 +103,21 @@ void RunModel() { ...@@ -90,15 +103,21 @@ void RunModel() {
// 5. Get output // 5. Get output
std::unique_ptr<const Tensor> output_tensor( std::unique_ptr<const Tensor> output_tensor(
std::move(predictor->GetOutput(0))); std::move(predictor->GetOutput(0)));
std::cout << "Output dim: " << output_tensor->shape()[1] << std::endl; std::cout << "Output shape " << output_tensor->shape()[1] << std::endl;
for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) { for (int i = 0; i < ShapeProduction(output_tensor->shape()); i += 100) {
std::cout << "Output[" << i << "]:" << output_tensor->data<float>()[i] << std::endl; std::cout << "Output[" << i << "]: " << output_tensor->data<float>()[i]
<< std::endl;
} }
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
google::ParseCommandLineFlags(&argc, &argv, true); if (argc < 2) {
RunModel(); std::cerr << "[ERROR] usage: ./" << argv[0] << " naive_buffer_model_dir\n";
exit(1);
}
std::string model_dir = argv[1];
RunModel(model_dir);
return 0; return 0;
} }
``` ```
# 如何增加Layout # 新增Layout
Paddle-Lite中Place包含了Target、Layout、Precision信息,用来注册和选择模型中的具体Kernel。下面以增加Place中的layout:`ImageDefault``ImageFolder``ImageNW`为例,讲解如何增加新Layout。 Paddle-Lite中Place包含了Target、Layout、Precision信息,用来注册和选择模型中的具体Kernel。下面以增加Place中的layout:`ImageDefault``ImageFolder``ImageNW`为例,讲解如何增加新Layout。
......
# 新增Pass
# 新增Pass方法
本文从三个方面介绍了`Lite`中的`Pass`结构:**Pass是什么****Pass的实现与接口****Pass的一般注册流程**。最后以`Fc_fuse_pass`为例介绍了`fusion_pass`的作用与注册方法。 本文从三个方面介绍了`Lite`中的`Pass`结构:**Pass是什么****Pass的实现与接口****Pass的一般注册流程**。最后以`Fc_fuse_pass`为例介绍了`fusion_pass`的作用与注册方法。
......
# 新增OP的方法 # 新增OP
以下以添加argmax为例,详细说明新增op的方法。 以下以添加argmax为例,详细说明新增op的方法。
......
# 架构详解
这篇文档会从开发者角度详细介绍开发 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 有分析期和执行期两个阶段,如果分析期没有特殊的优化,则无需考虑;否则,需要注意将分析期的信息整理并序列化到离线模型中,用于执行期直接加载。
# 开发基础须知
可以参考 [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 编译完毕
...@@ -13,10 +13,12 @@ Welcome to Paddle-Lite's documentation! ...@@ -13,10 +13,12 @@ Welcome to Paddle-Lite's documentation!
introduction/tech_highlights introduction/tech_highlights
introduction/architecture introduction/architecture
introduction/support_hardware
introduction/support_operation_list
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: Benchmark数据和方法 :caption: Benchmark
:name: sec-benchmark :name: sec-benchmark
benchmark/benchmark benchmark/benchmark
...@@ -24,46 +26,67 @@ Welcome to Paddle-Lite's documentation! ...@@ -24,46 +26,67 @@ Welcome to Paddle-Lite's documentation!
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: 安装 :caption: 使用方法
:name: sec-install
installation/source_compile
.. toctree::
:maxdepth: 1
:caption: 使用指南
:name: sec-user-guides :name: sec-user-guides
user_guides/tutorial
user_guides/release_lib
user_guides/source_compile
user_guides/x2paddle
user_guides/model_optimize_tool user_guides/model_optimize_tool
user_guides/post_quant_with_data
user_guides/post_quant_no_data
user_guides/model_quantization
user_guides/debug
user_guides/library_tailoring user_guides/library_tailoring
user_guides/cuda
user_guides/opencl
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: 进阶使用指南 :caption: 部署示例
:name: sec-demo_guides
advanced_user_guides/support_operation_list
advanced_user_guides/add_operation demo_guides/cpp_demo
advanced_user_guides/add_layout demo_guides/java_demo
advanced_user_guides/model_quantization demo_guides/android_app_demo
advanced_user_guides/add_new_pass demo_guides/ios_app_demo
advanced_user_guides/x86 demo_guides/x86
demo_guides/cuda
demo_guides/opencl
demo_guides/fpga
demo_guides/npu
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: 开发者文档 :caption: API文档
api_reference/cxx_api_doc
api_reference/java_api_doc
api_reference/python_api_doc
api_reference/cv
.. toctree::
:maxdepth: 1
:caption: 开发者贡献
develop_guides/for-developer
develop_guides/architecture-intro
develop_guides/add_operation
develop_guides/add_layout
develop_guides/add_new_pass
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: API文档 :caption: Roadmap
:name: sec-roadmap
api_reference/cxx_api_doc introduction/roadmap
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: FAQ :caption: FAQ
introduction/faq
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
:caption: paddle-mobile :caption: paddle-mobile
......
# 预测库说明
Paddle-Lite的编译结果为预测库文件(包括静态库和动态库),具体编译过程参考[源码编译](./source_compile)
Lite预测库分为**基础预测库****全量预测库**:基础预测库只打包了基础模型需要的基础算子,预测库体积较小;全量预测库打包了所有的Lite算子,可以支持更多的模型,但是预测库的体积也更大。 编译时由编译选项 `build_extra`(默认为OFF)控制,`--build_extra=OFF`时编译基础预测库,`--build_extra=ON`时编译全量的预测库。
## 基础预测库
### 编译方法
编译时设置`--build_extra=OFF` (默认值) 或不指定即可编译出基础预测库。例如:
```
./lite/tools/build.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_static tiny_publish
```
### 基础预测库支持的功能
(1)支持基础CV模型
(2)支持基础的in8量化模型
(3)支持[benchmark测试](../benchmark/benchmark)
### 基础预测库支持的基础模型:
1. fluid基础模型(paddle model 提供的基础模型9个)
```
mobileNetV1 mnasnet yolov3 ssd_mobilenetv1 shufflenet_v2
mobileNetV2 resnet50 unet squeezenet_v11
```
2. int8量化模型模型
```
mobilenet_v1 mobilenet_v2 resnet50
```
### 特点
轻量级预测库,体积更小,支持常用的基础模型。
## 全量预测库
### 编译方法
编译时设置`--build_extra=ON` 即可编译出全量预测库。例如:
```
./lite/tools/build.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_static --build_extra=ON tiny_publish
```
### 全量预测库功能
(1) 基础预测库所有功能
(2)支持所有Paddle-Lite中注册的所有算子
### 特点
支持更多的硬件平台和算子,可以支持更多模型但体量更大。
# FAQ 常见问题
问题或建议可以发Issue,为加快问题解决效率,可先检索是否有类似问题,我们也会及时解答!
欢迎加入Paddle-Lite百度官方QQ群:696965088
1. 在Host端采用交叉编译方式编译PaddleLite,将编译后的libpaddle_light_api_shared.so和可执行程序放到板卡上运行,出现了如下图所示的错误,怎么解决?
![host_target_compiling_env_miss_matched](https://user-images.githubusercontent.com/9973393/75761527-31b8b700-5d74-11ea-8a9a-0bc0253ee003.png)
- 原因是Host端的交叉编译环境与Target端板卡的运行环境不一致,导致libpaddle_light_api_shared.so链接的GLIBC库高于板卡环境的GLIBC库。目前有四种解决办法(为了保证编译环境与官方一致,推荐第一种方式):1)在Host端,参考[源码编译](../user_guides/source_compile)中的Docker方式重新编译libpaddle_light_api_shared.so;2)在Host端,使用与Target端版本一致的ARM GCC和GLIBC库重新编译libpaddle_light_api_shared.so;3)在Target端板卡上,参考[源码编译](../user_guides/source_compile)中的ARM Linux本地编译方式重新编译libpaddle_light_api_shared.so;4)在Target端板卡上,将GLIBC库升级到和Host端一致的版本,即GLIBC2.27。
# 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.3
[v2.3 project](https://github.com/PaddlePaddle/Paddle-Lite/milestone/3?closed=1)
## 2.6
[v2.6 project](https://github.com/PaddlePaddle/Paddle-Lite/milestones/v2.6)
# 支持硬件
## ARM CPU
Paddle Lite支持[ARM Cortex-A系列处理器](https://en.wikipedia.org/wiki/ARM_Cortex-A),支持列表如下:
### 32bit(ARMv7a)
- Cortex-A5
- Cortex-A7
- Cortex-A8
- Cortex-A9
- Cortex-A12
- Cortex-A15
- Cortex-A17(RK3288)
- Cortex-A32
### 64bit(ARMv7a, ARMv8a)
- Cortex-A35
- Cortex-A53(树莓派3)
- Cortex-A55
- Cortex-A57(Nvidia tx1,Nvidia tx2, 高通810等)
- Cortex-A72(麒麟95X,高通820, RK3399,树莓派4等)
- Cortex-A73(麒麟960,麒麟970,高通835, 联发科X30等)
- Cortex-A75(高通845等)
- Cortex-A76(麒麟980,麒麟990,高通855,高通730,联发科G90等)
- Cortex-A77
- ARMv8-A compatible(Apple A系列处理器, Nvidia tegra, Qualcomm Kryo, Falkor, Samsung Mongoose)
## 移动端GPU
Paddle Lite支持移动端GPU和Nvidia端上GPU设备,支持列表如下:
- ARM Mali G 系列
- Qualcomm Adreno 系列
- Nvida tegra系列: tx1, tx2, nano, xavier
## NPU
Paddle Lite支持NPU,支持列表如下:
- 华为达芬奇架构NPU
## FPGA
Paddle Lite支持FPGA,支持列表如下:
- 百度Edgeboard系列:ZU9, ZU5, ZU3
## XPU
Paddle Lite支持XPU,支持列表如下:
- 百度昆仑818-100芯片
- 百度昆仑818-300芯片
# 支持OP列表 # 支持OP
## Ops ## Ops (共计158个算子)
### Basic Operators (默认编译的算子)
- affine_channel - affine_channel
- anchor_generator
- arg_max - arg_max
- assign
- assign_value
- attention_padding_mask
- axpy
- batch_norm - batch_norm
- beam_search
- beam_search_decode
- bilinear_interp - bilinear_interp
- box_clip
- box_coder - box_coder
- calib - calib
- calib_once
- cast - cast
- collect_fpn_proposals
- concat - concat
- conditional_block
- conv2d - conv2d
- conv2d_transpose - conv2d_transpose
- crop
- decode_bboxes
- density_prior_box - density_prior_box
- depthwise_conv2d - depthwise_conv2d
- distribute_fpn_proposals
- dropout - dropout
- elementwise_add - elementwise_add
- elementwise_div - elementwise_div
- elementwise_max - elementwise_max
- elementwise_mul - elementwise_mul
- elementwise_sub - elementwise_sub
- equal
- exp - exp
- expand - expand
- fake_channel_wise_dequantize_max_abs - fake_channel_wise_dequantize_max_abs
- fake_dequantize_max_abs - fake_dequantize_max_abs
- fake_quantize_abs_max
- fake_quantize_dequantize_moving_average_abs_max - fake_quantize_dequantize_moving_average_abs_max
- fake_quantize_moving_average_abs_max - fake_quantize_moving_average_abs_max
- fake_quantize_range_abs_max - fake_quantize_range_abs_max
...@@ -55,6 +42,72 @@ ...@@ -55,6 +42,72 @@
- fusion_elementwise_max_activation - fusion_elementwise_max_activation
- fusion_elementwise_mul_activation - fusion_elementwise_mul_activation
- fusion_elementwise_sub_activation - fusion_elementwise_sub_activation
- gelu
- grid_sampler
- hard_sigmoid
- instance_norm
- io_copy
- io_copy_once
- layout
- leaky_relu
- log
- matmul
- mean
- mul
- multiclass_nms
- nearest_interp
- pad2d
- pool2d
- prelu
- prior_box
- range
- reduce_mean
- relu
- relu6
- relu_clipped
- reshape
- reshape2
- rsqrt
- scale
- search_fc
- sequence_topk_avg_pooling
- shuffle_channel
- sigmoid
- slice
- softmax
- softsign
- split
- sqrt
- square
- squeeze
- squeeze2
- stack
- subgraph
- swish
- tanh
- transpose
- transpose2
- unsqueeze
- unsqueeze2
- yolo_box
### Extra Operators (打开 `--build_extra=ON`开关才会编译)
- anchor_generator
- assign
- assign_value
- attention_padding_mask
- axpy
- beam_search
- beam_search_decode
- box_clip
- calib_once
- collect_fpn_proposals
- conditional_block
- crop
- decode_bboxes
- distribute_fpn_proposals
- equal
- gather - gather
- generate_proposals - generate_proposals
- graph_op - graph_op
...@@ -62,21 +115,14 @@ ...@@ -62,21 +115,14 @@
- greater_than - greater_than
- gru - gru
- gru_unit - gru_unit
- hard_sigmoid
- im2sequence - im2sequence
- increment - increment
- instance_norm
- io_copy
- io_copy_once
- is_empty - is_empty
- layer_norm - layer_norm
- layout
- layout_once - layout_once
- leaky_relu
- less_equal - less_equal
- less_than - less_than
- lod_reset - lod_reset
- log
- logical_and - logical_and
- logical_not - logical_not
- logical_or - logical_or
...@@ -85,37 +131,18 @@ ...@@ -85,37 +131,18 @@
- lookup_table_v2 - lookup_table_v2
- lrn - lrn
- match_matrix_tensor - match_matrix_tensor
- matmul
- mean
- merge_lod_tensor - merge_lod_tensor
- mul
- multiclass_nms
- nearest_interp
- negative - negative
- norm - norm
- notequal - not_equal
- pad2d
- pool2d
- power - power
- prelu
- prior_box
- range
- read_from_array - read_from_array
- reduce_max - reduce_max
- reduce_mean
- reduce_prod - reduce_prod
- reduce_sum - reduce_sum
- relu
- relu6
- relu_clipped
- reshape
- reshape2
- roi_align - roi_align
- rsqrt
- scale
- search_aligned_mat_mul - search_aligned_mat_mul
- search_attention_padding_mask - search_attention_padding_mask
- search_fc
- search_grnn - search_grnn
- search_group_padding - search_group_padding
- search_seq_arithmetic - search_seq_arithmetic
...@@ -130,32 +157,15 @@ ...@@ -130,32 +157,15 @@
- sequence_reshape - sequence_reshape
- sequence_reverse - sequence_reverse
- sequence_softmax - sequence_softmax
- sequence_topk_avg_pooling
- shape - shape
- shuffle_channel
- sigmoid
- slice
- softmax
- softsign
- split
- split_lod_tensor - split_lod_tensor
- sqrt
- square
- squeeze
- squeeze2
- stack
- swish
- tanh
- top_k - top_k
- transpose
- transpose2
- uniform_random - uniform_random
- unsqueeze
- unsqueeze2
- var_conv_2d - var_conv_2d
- while - while
- write_to_array - write_to_array
- yolo_box
## Kernels ## Kernels
......
# 调试
## Profiler工具
Basic profiler 用于 CPU 上kernel 耗时的统计。
### 开启方法:
参照 [编译安装](../user_guides/source_compile) 中的**full_publish**部分进行环境配置,在 cmake 时添加 `-DLITE_WITH_PROFILE=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
```
## Debug工具
**Lite Model Debug Tool** 是用来检查Paddle-Lite框架与Paddle-Fluid框架运行时tensor(包括variable与weight)之间diff信息的基础工具。
### 编译方法:
1. 参照 [编译安装](../user_guides/source_compile) 中的**full_publish**部分进行环境配置和编译。
2. 在生成的`build`目录下,执行`make lite_model_debug_tool``lite_model_debug_tool`产出在编译目录的`lite/tools/debug`目录下。
### 工作流程:
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` 脚本中的代码以获得更多细节.
# `build_extra`参数说明:
Lite预测库分为**基础预测库****全量预测库(with_extra)**:基础预测库只包含基础CV算子(OP),体积较小;全量预测库包含所有Lite算子,体积较大,支持模型较多。
编译时由编译选项 `build_extra`(默认为OFF)控制,`--build_extra=OFF`时编译**基础预测库**`--build_extra=ON`时编译**全量预测库**
## 基础预测库( [基础OP列表](../advanced_user_guides/support_operation_list.html#basic-operators) )
### 支持功能
(1)87个[基础OP](../advanced_user_guides/support_operation_list.html#basic-operators) (2)9个基础模型 (3)3个in8量化模型
### 支持的模型
1. fluid基础模型(来源:[paddle-models](https://github.com/PaddlePaddle/models)
```
mobilenetV1 mnasnet yolov3 ssd_mobilenetv1 shufflenet_v2
mobilenetV2 resnet50 unet squeezenet_v11
```
2. int8量化模型
```
mobilenet_v1 mobilenet_v2 resnet50
```
### 特点
轻量级预测库,体积更小,支持常用模型。
### 编译方法
编译时设置`--build_extra=OFF` (默认值) 编译出基础预测库。例如:
```
./lite/tools/build.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_static tiny_publish
```
## 全量预测库( [OP列表](../advanced_user_guides/support_operation_list.html#op) )
### 支持功能
Paddle-Lite中的全量算子( [基础OP](../advanced_user_guides/support_operation_list.html#basic-operators) + [Extra OP](../advanced_user_guides/support_operation_list.html#extra-operators-build-extra-on)
### 特点
包含更多算子、支持更多模型,但体量更大。
### 编译方法
设置`--build_extra=ON` 可编译出全量预测库。例如:
```
./lite/tools/build.sh --arm_os=android --arm_abi=armv8 --arm_lang=gcc --android_stl=c++_static --build_extra=ON tiny_publish
```
# 裁剪预测库方法 # 裁剪预测库
Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编译会将所有已注册的operator打包到预测库中,造成库文件体积膨胀;**裁剪预测库**能针对具体的模型,只打包优化后该模型需要的operator,有效降低预测库文件大小。 Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编译会将所有已注册的operator打包到预测库中,造成库文件体积膨胀;**裁剪预测库**能针对具体的模型,只打包优化后该模型需要的operator,有效降低预测库文件大小。
...@@ -39,7 +39,7 @@ Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编 ...@@ -39,7 +39,7 @@ Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编
例如: 例如:
```bash ```bash
./lite/tools/build.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_static --build_extra=ON --build_tailor=ON --opt_model_dir=../mobilenet_v1NB full_publish ./lite/tools/build.sh --arm_os=android --arm_abi=armv7 --arm_lang=gcc --android_stl=c++_static --build_extra=ON --build_tailor=ON --opt_model_dir=../mobilenet_v1NB tiny_publish
``` ```
**注意**:上面命令中的`../mobilenet_v1NB`是第1步得到的转化模型的输出路径 **注意**:上面命令中的`../mobilenet_v1NB`是第1步得到的转化模型的输出路径
...@@ -88,9 +88,6 @@ Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编 ...@@ -88,9 +88,6 @@ Paddle-Lite支持**根据模型裁剪预测库**功能。Paddle-Lite的一般编
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include "paddle_api.h" // NOLINT #include "paddle_api.h" // NOLINT
#include "paddle_use_kernels.h" // NOLINT
#include "paddle_use_ops.h" // NOLINT
#include "paddle_use_passes.h" // NOLINT
using namespace paddle::lite_api; // NOLINT using namespace paddle::lite_api; // NOLINT
...@@ -182,4 +179,4 @@ int main(int argc, char** argv) { ...@@ -182,4 +179,4 @@ int main(int argc, char** argv) {
1. 模型集合**必须**均为combined参数模型或均为非combined参数模型。 1. 模型集合**必须**均为combined参数模型或均为非combined参数模型。
2. 使用非combined参数模型时,模型拓扑文件名应为`__model__`,使用非combined参数模型时,集合中各模型的拓扑与参数名应相同,分别由`--model_filename``--param_filename`指定。 2. 使用非combined参数模型时,模型拓扑文件名应为`__model__`,使用非combined参数模型时,集合中各模型的拓扑与参数名应相同,分别由`--model_filename``--param_filename`指定。
3. 模型集合**必须**均为INT8量化模型或均为非INT8量化模型。 3. 模型集合**必须**均为INT8量化模型或均为非INT8量化模型。
4. 需要使用Paddle-Lite 最新版本(release/v2.1.0之后)代码编译出的model_optimize_tool 4. 需要使用Paddle-Lite `release/v2.1.0`之后版本代码编译出的模型优化工具
# 模型转化方法 # 模型优化工具 opt
Lite架构在预测过程中表现出来的高性能得益于其丰富的优化组件,其中包括量化、子图融合、混合调度、Kernel优选等等策略。为了使优化过程更加方便易用,我们提供了**opt**来自动完成优化步骤,输出一个轻量的、最优的可执行模型。具体使用方法介绍如下: Paddle-Lite 提供了多种策略来自动优化原始的训练模型,其中包括量化、子图融合、混合调度、Kernel优选等等方法。为了使优化过程更加方便易用,我们提供了**opt** 工具来自动完成优化步骤,输出一个轻量的、最优的可执行模型。
**注意**:release/v2.2.0之前的模型转化工具名称为`model_optimize_tool`,从release/v2.3开始模型转化工具名称修改为`opt` 具体使用方法介绍如下:
**注意**`v2.2.0` 之前的模型转化工具名称为`model_optimize_tool`,从 `v2.3` 开始模型转化工具名称修改为 `opt`
## 准备opt ## 准备opt
当前获得opt方法有三种: 当前获得opt方法有三种:
1. 我们提供当前develop分支编译结果下载:[opt](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt)[opt_mac](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt_mac) 1. **推荐!** 可以进入Paddle-Lite Github仓库的[release界面](https://github.com/PaddlePaddle/Paddle-Lite/releases),选择release版本下载对应的转化工具`opt`
release/v2.2.0之前版本的model_optimize_tool: [model_optimize_tool](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/model_optimize_tool)[model_optimize_tool_mac](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/model_optimize_tool_mac)
2. 可以进入Paddle-Lite Github仓库的[release界面](https://github.com/PaddlePaddle/Paddle-Lite/releases),选择release版本下载对应的转化工具`opt`
(release/v2.2.0之前的转化工具为model_optimize_tool、release/v2.3.0之后为opt) (release/v2.2.0之前的转化工具为model_optimize_tool、release/v2.3.0之后为opt)
2. 本文提供`release/v2.3``release/v2.2.0`版本的优化工具下载
|版本 | Linux | MacOS|
|---|---|---|
| `release/v2.3`| [opt](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt) | [opt_mac](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt_mac) |
|`release/v2.2.0` | [model_optimize_tool](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/model_optimize_tool) | [model_optimize_tool_mac](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/model_optimize_tool_mac) |
3. 可以下载Paddle-Lite源码,从源码编译出opt工具
3. 如果 release 列表里的工具不符合您的环境,可以下载Paddle-Lite 源码,源码编译出opt工具
```bash ```bash
git clone https://github.com/PaddlePaddle/Paddle-Lite.git git clone https://github.com/PaddlePaddle/Paddle-Lite.git
cd Paddle-Lite cd Paddle-Lite
...@@ -22,11 +28,11 @@ git checkout <release-version-tag> ...@@ -22,11 +28,11 @@ git checkout <release-version-tag>
./lite/tools/build.sh build_optimize_tool ./lite/tools/build.sh build_optimize_tool
``` ```
编译结果位于`Paddle-Lite/build.opt/lite/api/opt` 编译结果位于`Paddle-Lite/build.opt/lite/api/opt`
**注意**:从源码编译opt前需要先[安装Paddle-Lite的开发环境](../installation/source_compile) **注意**:从源码编译opt前需要先[安装Paddle-Lite的开发环境](source_compile)
## 使用opt ## 使用opt
opt是x86平台上的可执行文件,需要在PC端运行:包括Linux终端和Mac终端。 opt是 x86 平台上的可执行文件,需要在PC端运行:支持Linux终端和Mac终端。
### 帮助信息 ### 帮助信息
执行opt时不加入任何输入选项,会输出帮助信息,提示当前支持的选项: 执行opt时不加入任何输入选项,会输出帮助信息,提示当前支持的选项:
...@@ -36,7 +42,10 @@ opt是x86平台上的可执行文件,需要在PC端运行:包括Linux终端 ...@@ -36,7 +42,10 @@ opt是x86平台上的可执行文件,需要在PC端运行:包括Linux终端
![](https://paddlelite-data.bj.bcebos.com/doc_images/1.png) ![](https://paddlelite-data.bj.bcebos.com/doc_images/1.png)
### 功能一:转化模型为Paddle-Lite格式 ### 功能一:转化模型为Paddle-Lite格式
opt可以将PaddlePaddle支持的模型转化为Paddle-Lite支持的模型格式,期间执行的操作包括:将protobuf格式的模型文件转化为naive_buffer格式的模型文件,有效降低模型体积;执行“量化、子图融合、混合调度、Kernel优选”等图优化操作,提升其在Paddle-Lite上的运行速度、内存占用等性能指标。 opt可以将PaddlePaddle的部署模型格式转化为Paddle-Lite 支持的模型格式,期间执行的操作包括:
- 将protobuf格式的模型文件转化为naive_buffer格式的模型文件,有效降低模型体积
- 执行“量化、子图融合、混合调度、Kernel优选”等图优化操作,提升其在Paddle-Lite上的运行速度、内存占用等效果
模型优化过程: 模型优化过程:
...@@ -54,7 +63,10 @@ PaddlePaddle模型有两种保存格式: ...@@ -54,7 +63,10 @@ PaddlePaddle模型有两种保存格式:
**使用示例**:转化`mobilenet_v1`模型 **使用示例**:转化`mobilenet_v1`模型
``` ```
./opt --model_dir=./mobilenet_v1 --valid_targets=arm --optimize_out_type=naive_buffer --optimize_out=mobilenet_v1_opt ./opt --model_dir=./mobilenet_v1 \
--valid_targets=arm \
--optimize_out_type=naive_buffer \
--optimize_out=mobilenet_v1_opt
``` ```
以上命令可以将`mobilenet_v1`模型转化为arm硬件平台、naive_buffer格式的Paddle_Lite支持模型,优化后的模型文件为`mobilenet_v1_opt.nb`,转化结果如下图所示: 以上命令可以将`mobilenet_v1`模型转化为arm硬件平台、naive_buffer格式的Paddle_Lite支持模型,优化后的模型文件为`mobilenet_v1_opt.nb`,转化结果如下图所示:
...@@ -71,7 +83,6 @@ PaddlePaddle模型有两种保存格式: ...@@ -71,7 +83,6 @@ PaddlePaddle模型有两种保存格式:
--optimize_out_type=(protobuf|naive_buffer) \ --optimize_out_type=(protobuf|naive_buffer) \
--optimize_out=<output_optimize_model_dir> \ --optimize_out=<output_optimize_model_dir> \
--valid_targets=(arm|opencl|x86|npu|xpu) \ --valid_targets=(arm|opencl|x86|npu|xpu) \
--prefer_int8_kernel=(true|false) \
--record_tailoring_info =(true|false) --record_tailoring_info =(true|false)
``` ```
...@@ -83,12 +94,12 @@ PaddlePaddle模型有两种保存格式: ...@@ -83,12 +94,12 @@ PaddlePaddle模型有两种保存格式:
| --optimize_out_type | 输出模型类型,目前支持两种类型:protobuf和naive_buffer,其中naive_buffer是一种更轻量级的序列化/反序列化实现。若您需要在mobile端执行模型预测,请将此选项设置为naive_buffer。默认为protobuf。 | | --optimize_out_type | 输出模型类型,目前支持两种类型:protobuf和naive_buffer,其中naive_buffer是一种更轻量级的序列化/反序列化实现。若您需要在mobile端执行模型预测,请将此选项设置为naive_buffer。默认为protobuf。 |
| --optimize_out | 优化模型的输出路径。 | | --optimize_out | 优化模型的输出路径。 |
| --valid_targets | 指定模型可执行的backend,默认为arm。目前可支持x86、arm、opencl、npu、xpu,可以同时指定多个backend(以空格分隔),Model Optimize Tool将会自动选择最佳方式。如果需要支持华为NPU(Kirin 810/990 Soc搭载的达芬奇架构NPU),应当设置为npu, arm。 | | --valid_targets | 指定模型可执行的backend,默认为arm。目前可支持x86、arm、opencl、npu、xpu,可以同时指定多个backend(以空格分隔),Model Optimize Tool将会自动选择最佳方式。如果需要支持华为NPU(Kirin 810/990 Soc搭载的达芬奇架构NPU),应当设置为npu, arm。 |
| --prefer_int8_kernel | 若待优化模型为int8量化模型(如量化训练得到的量化模型),则设置该选项为true以使用int8内核函数进行推理加速,默认为false。 |
| --record_tailoring_info | 当使用 [根据模型裁剪库文件](./library_tailoring.html) 功能时,则设置该选项为true,以记录优化后模型含有的kernel和OP信息,默认为false。 | | --record_tailoring_info | 当使用 [根据模型裁剪库文件](./library_tailoring.html) 功能时,则设置该选项为true,以记录优化后模型含有的kernel和OP信息,默认为false。 |
* 如果待优化的fluid模型是非combined形式,请设置`--model_dir`,忽略`--model_file``--param_file` * 如果待优化的fluid模型是非combined形式,请设置`--model_dir`,忽略`--model_file``--param_file`
* 如果待优化的fluid模型是combined形式,请设置`--model_file``--param_file`,忽略`--model_dir` * 如果待优化的fluid模型是combined形式,请设置`--model_file``--param_file`,忽略`--model_dir`
* 优化后的模型包括__model__.nb和param.nb文件。 * 优化后的模型为以`.nb`名称结尾的单个文件。
* 删除`prefer_int8_kernel`的输入参数,`opt`自动判别是否是量化模型,进行相应的优化操作。
### 功能二:统计模型算子信息、判断是否支持 ### 功能二:统计模型算子信息、判断是否支持
...@@ -121,14 +132,14 @@ opt可以统计并打印出model中的算子信息、判断Paddle-Lite是否支 ...@@ -121,14 +132,14 @@ opt可以统计并打印出model中的算子信息、判断Paddle-Lite是否支
**背景**:如果想用Paddle-Lite运行第三方来源(tensorflow、caffe、onnx)模型,一般需要经过两次转化。即使用x2paddle工具将第三方模型转化为PaddlePaddle格式,再使用opt将PaddlePaddle模型转化为Padde-Lite可支持格式。 **背景**:如果想用Paddle-Lite运行第三方来源(tensorflow、caffe、onnx)模型,一般需要经过两次转化。即使用x2paddle工具将第三方模型转化为PaddlePaddle格式,再使用opt将PaddlePaddle模型转化为Padde-Lite可支持格式。
为了简化这一过程,我们提供一键脚本,将x2paddle转化和opt转化合并: 为了简化这一过程,我们提供一键脚本,将x2paddle转化和opt转化合并:
**一键转化脚本**[auto_transform.sh](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/auto_transform.sh) **一键转化脚本**[auto_transform.sh](https://github.com/PaddlePaddle/Paddle-Lite/blob/release/v2.3/lite/tools/auto_transform.sh)
**环境要求**:使用`auto_transform.sh`脚本转化第三方模型时,需要先安装x2paddle环境,请参考[x2paddle环境安装方法](https://github.com/PaddlePaddle/X2Paddle#环境依赖) 安装x2paddle和其环境依赖项 **环境要求**:使用`auto_transform.sh`脚本转化第三方模型时,需要先安装x2paddle环境,请参考[x2paddle环境安装方法](https://github.com/PaddlePaddle/X2Paddle#环境依赖) 安装x2paddle和x2paddle依赖项(tensorflow、caffe等)
**使用方法** **使用方法**
(1)打印帮助帮助信息:` ./auto_transform.sh` (1)打印帮助帮助信息:` sh ./auto_transform.sh`
(2)转化模型方法 (2)转化模型方法
...@@ -138,7 +149,7 @@ USAGE: ...@@ -138,7 +149,7 @@ USAGE:
tranform model from tensorflow/caffe/onnx form into paddle-lite naive-buffer form. tranform model from tensorflow/caffe/onnx form into paddle-lite naive-buffer form.
---------------------------------------- ----------------------------------------
example: example:
./auto_transform.sh --framework=tensorflow --model=tf_model.pb --optimize_out=opt_model_result sh ./auto_transform.sh --framework=tensorflow --model=tf_model.pb --optimize_out=opt_model_result
---------------------------------------- ----------------------------------------
Arguments about x2paddle: Arguments about x2paddle:
--framework=(tensorflow|caffe|onnx); --framework=(tensorflow|caffe|onnx);
......
# 模型量化 # 模型量化-量化训练
本文主要介绍使用Paddle-Lite加载PaddlePaddle产出的量化模型,并进行推理执行。我们以MobileNetV1模型为示例,首先介绍准备量化模型,然后介绍部署执行 本文主要介绍使用Paddle-Lite加载PaddlePaddle产出的量化模型,并进行推理执行。我们以MobileNetV1模型为示例,首先说明产出量化模型,然后说明预测部署
## 准备量化模型 ## 1 简介
PaddlePaddle使用量化训练和训练后量化两种方法将FP32模型量化成Int8模型,下面分别介绍两种方法如何产出量化模型 量化训练是基于大量训练数据,对训练好的预测模型进行量化。该方法使用模拟量化的思想,在训练阶段更新权重,实现减小量化误差
### 量化训练 使用条件:
* 有预训练模型
* 有较多训练数据
使用步骤:
* 产出量化模型:使用PaddlePaddle调用量化训练接口,产出量化模型
* 量化模型预测:使用PaddleLite加载量化模型进行预测推理
优点:
* 减小计算量、降低计算内存、减小模型大小
* 模型精度受量化影响小
缺点:
* 使用条件较苛刻,使用门槛稍高
建议首先使用“有校准数据训练后量化”对模型进行量化,然后使用使用量化模型进行预测。如果该量化模型的精度达不到要求,再使用“量化训练”。
## 2 产出量化模型
目前,PaddlePaddle框架的量化训练主要针对卷积层(包括二维卷积和Depthwise卷积)、和全连接层,对应算子是conv2d、depthwise_conv2d和mul,更多量化训练的原理请参考[文档](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)。Paddle-Lite支持运行PaddlePaddle框架量化训练产出的模型,可以进一步加快模型在移动端的执行速度。 目前,PaddlePaddle框架的量化训练主要针对卷积层(包括二维卷积和Depthwise卷积)、和全连接层,对应算子是conv2d、depthwise_conv2d和mul,更多量化训练的原理请参考[文档](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)。Paddle-Lite支持运行PaddlePaddle框架量化训练产出的模型,可以进一步加快模型在移动端的执行速度。
温馨提示:如果您是初次接触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) 温馨提示:如果您是初次接触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)
您可以选择下载训练好的量化模型,或者使用PaddleSlim模型压缩工具训练得到量化模型。 您可以选择下载训练好的量化模型,或者使用PaddleSlim模型压缩工具训练得到量化模型。
#### 下载量化模型 ### 下载量化模型
官方发布了[MobileNetV1量化模型](https://paddle-inference-dist.bj.bcebos.com/int8%2Fpretrain%2Fmobilenet_v1_quant%2Ffloat.zip),直接下载到本地。 官方发布了[MobileNetV1量化模型](https://paddle-inference-dist.bj.bcebos.com/int8%2Fpretrain%2Fmobilenet_v1_quant%2Ffloat.zip),直接下载到本地。
...@@ -23,9 +40,9 @@ PaddlePaddle使用量化训练和训练后量化两种方法将FP32模型量化 ...@@ -23,9 +40,9 @@ PaddlePaddle使用量化训练和训练后量化两种方法将FP32模型量化
wget https://paddle-inference-dist.bj.bcebos.com/int8%2Fpretrain%2Fmobilenet_v1_quant%2Ffloat.zip wget https://paddle-inference-dist.bj.bcebos.com/int8%2Fpretrain%2Fmobilenet_v1_quant%2Ffloat.zip
``` ```
#### 使用PaddleSlim模型压缩工具训练量化模型 ### 使用PaddleSlim模型压缩工具训练量化模型
##### 安装PaddlePaddle #### 安装PaddlePaddle
根据操作系统、安装方式、Python版本和CUDA版本,按照[官方说明](https://paddlepaddle.org.cn/start)安装PaddlePaddle。例如: 根据操作系统、安装方式、Python版本和CUDA版本,按照[官方说明](https://paddlepaddle.org.cn/start)安装PaddlePaddle。例如:
...@@ -39,7 +56,7 @@ Ubuntu 16.04.4 LTS操作系统,CPU版本安装: ...@@ -39,7 +56,7 @@ Ubuntu 16.04.4 LTS操作系统,CPU版本安装:
pip install paddlepaddle==1.6.0 -i https://mirrors.aliyun.com/pypi/simple/ pip install paddlepaddle==1.6.0 -i https://mirrors.aliyun.com/pypi/simple/
``` ```
##### 克隆量化训练所需的代码库 #### 克隆量化训练所需的代码库
克隆[PaddlePaddle/models](https://github.com/PaddlePaddle/models)到本地,并进入models/PaddleSlim路径。 克隆[PaddlePaddle/models](https://github.com/PaddlePaddle/models)到本地,并进入models/PaddleSlim路径。
...@@ -48,12 +65,13 @@ git clone https://github.com/PaddlePaddle/models.git ...@@ -48,12 +65,13 @@ git clone https://github.com/PaddlePaddle/models.git
cd models/PaddleSlim cd models/PaddleSlim
``` ```
##### 数据准备 #### 准备数据和模型
###### 训练数据准备
##### 训练数据准备
参考[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#data-preparation)中的数据准备教程,下载训练数据,并且保存到PaddleSlim/data路径下。 参考[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#data-preparation)中的数据准备教程,下载训练数据,并且保存到PaddleSlim/data路径下。
###### 预训练模型准备 ##### 预训练模型准备
参考/models/PaddleSlim/run.sh脚本, 从[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/image_classification#supported-models-and-performances)下载MobileNetV1的预训练模型,并保存到PaddleSlim/pretrain路径下。 参考/models/PaddleSlim/run.sh脚本, 从[models/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/image_classification#supported-models-and-performances)下载MobileNetV1的预训练模型,并保存到PaddleSlim/pretrain路径下。
...@@ -84,8 +102,7 @@ cd models/PaddleSlim ...@@ -84,8 +102,7 @@ cd models/PaddleSlim
`compress.py`中定义了执行压缩任务需要的所有模型相关的信息,这里对几个关键的步骤进行简要介绍: `compress.py`中定义了执行压缩任务需要的所有模型相关的信息,这里对几个关键的步骤进行简要介绍:
###### 目标网络的定义 **目标网络的定义**
compress.py的以下代码片段定义了train program, 这里train program只有前向计算操作。 compress.py的以下代码片段定义了train program, 这里train program只有前向计算操作。
```python ```python
out = model.net(input=image, class_dim=args.class_dim) out = model.net(input=image, class_dim=args.class_dim)
...@@ -103,7 +120,7 @@ val_program = fluid.default_main_program().clone() ...@@ -103,7 +120,7 @@ val_program = fluid.default_main_program().clone()
定义完目标网络结构,需要对其初始化,并根据需要加载预训练模型。 定义完目标网络结构,需要对其初始化,并根据需要加载预训练模型。
###### 定义feed_list和fetch_list **定义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中即可。 对于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 ```python
train_feed_list = [('image', image.name), ('label', label.name)] train_feed_list = [('image', image.name), ('label', label.name)]
...@@ -119,7 +136,7 @@ val_feed_list = [('image', image.name), ('label', label.name)] ...@@ -119,7 +136,7 @@ val_feed_list = [('image', image.name), ('label', label.name)]
val_fetch_list = [('acc_top1', acc_top1.name), ('acc_top5', acc_top5.name)] val_fetch_list = [('acc_top1', acc_top1.name), ('acc_top5', acc_top5.name)]
``` ```
###### Compressor和量化配置文件 **Compressor和量化配置文件**
`compress.py`主要使用Compressor和yaml文件完成对模型的量化训练工作。Compressor类的定义如下: `compress.py`主要使用Compressor和yaml文件完成对模型的量化训练工作。Compressor类的定义如下:
```python ```python
class Compressor(object): class Compressor(object):
...@@ -192,7 +209,7 @@ compressor: ...@@ -192,7 +209,7 @@ compressor:
> >
> 3)**目前,Paddle-Lite仅支持运行weight量化方式使用`abs_max`且activation量化方式使用`moving_average_abs_max`或`range_abs_max`产出的量化模型**。 > 3)**目前,Paddle-Lite仅支持运行weight量化方式使用`abs_max`且activation量化方式使用`moving_average_abs_max`或`range_abs_max`产出的量化模型**。
##### 执行int8量化训练 #### 执行量化训练
修改run.sh,即注释掉`# enable GC strategy``# for sensitivity filter pruning`之间的内容并打开`#for quantization`相关的脚本命令(所需打开注释的命令如下所示)。 修改run.sh,即注释掉`# enable GC strategy``# for sensitivity filter pruning`之间的内容并打开`#for quantization`相关的脚本命令(所需打开注释的命令如下所示)。
...@@ -214,56 +231,13 @@ python compress.py \ ...@@ -214,56 +231,13 @@ python compress.py \
* int8目录: 参数范围为int8范围且参数数据类型为int8的量化模型。 * int8目录: 参数范围为int8范围且参数数据类型为int8的量化模型。
* mobile目录:参数特点与int8目录相同且兼容paddle-mobile的量化模型(目前paddle-mobile已升级为Paddle-Lite)。 * mobile目录:参数特点与int8目录相同且兼容paddle-mobile的量化模型(目前paddle-mobile已升级为Paddle-Lite)。
### 训练后量化 ## 3 使用Paddle-Lite运行量化模型推理
下面以MobileNetV1为例,介绍使用训练后量化方法产出量化模型。关于训练后量化的原理和详细使用方法,请参考[文档](https://github.com/PaddlePaddle/models/tree/develop/PaddleSlim/quant_low_level_api)
> 该示例的代码放在[models/PaddleSlim/quant_low_level_api/](https://github.com/PaddlePaddle/models/tree/develop/PaddleSlim/quant_low_level_api)目录下。如果需要执行该示例,首先clone下来[models](https://github.com/PaddlePaddle/models.git),安装具有训练后量化功能的PaddlePaddle。因为目前Lite支持支持对conv2d、depthwise_conv2d和mul量化,所以修改[run_post_training_quanzation.sh](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/quant_low_level_api/run_post_training_quanzation.sh) 脚本,设置is_full_quantize=False,然后执行该脚本;执行结束后,量化模型保存在`mobilenetv1_int8_model`目录下。下面介绍详细步骤。
1)**准备模型和校准数据**
安装PaddlePaddle的develop分支编译的whl包,准备已经训练好的FP32预测模型。
准备校准数据,文件结构如下。val文件夹中有100张图片,val_list.txt文件中包含图片的label。
```bash
samples_100
└──val
└──val_list.txt
```
2)**配置校准数据生成器**
MobileNetV1的输入是图片和标签,所以配置读取校准数据的sample_generator,每次返回一张图片和一个标签。详细代码在[models/PaddleSlim/reader.py](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/reader.py)
3)**调用训练后量化**
调用训练后量化的核心代码如下,详细代码在[post_training_quantization.py](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/quant_low_level_api/post_training_quantization.py)
``` python
place = fluid.CUDAPlace(0) if args.use_gpu == "True" else fluid.CPUPlace()
exe = fluid.Executor(place)
sample_generator = reader.val(data_dir=args.data_path)
ptq = PostTrainingQuantization(
executor=exe,
sample_generator=sample_generator,
model_dir=args.model_dir,
model_filename=args.model_filename,
params_filename=args.params_filename,
batch_size=args.batch_size,
batch_nums=args.batch_nums,
algo=args.algo,
is_full_quantize=args.is_full_quantize == "True")
quantized_program = ptq.quantize()
ptq.save_quantized_model(args.save_model_path)
```
## 使用Paddle-Lite运行量化模型推理
#### 使用模型优化工具对量化模型进行优化 ### 使用模型优化工具对量化模型进行优化
接下来,使用原始的量化模型生成适合在移动端直接部署的模型。 接下来,使用原始的量化模型生成适合在移动端直接部署的模型。
参考[源码编译](../source_compile)配置编译环境,确保可以编译成功。参考[模型转化方法](../model_optimize_tool),首先编译model_optimize_tool工具,然后执行下面命令对量化训练的模型进行优化(注意,需要自行修改model_file、param_file和optimize_out)。 参考[源码编译](source_compile)配置编译环境,确保可以编译成功。参考[模型转化方法](model_optimize_tool),首先编译model_optimize_tool工具,然后执行下面命令对量化训练的模型进行优化(注意,需要自行修改model_file、param_file和optimize_out)。
```bash ```bash
./model_optimize_tool \ ./model_optimize_tool \
--model_file=mobilenet_v1_quant/float/model \ --model_file=mobilenet_v1_quant/float/model \
...@@ -271,12 +245,11 @@ ptq.save_quantized_model(args.save_model_path) ...@@ -271,12 +245,11 @@ ptq.save_quantized_model(args.save_model_path)
--optimize_out_type=naive_buffer \ --optimize_out_type=naive_buffer \
--optimize_out=mobilenet_v1_quant_opt \ --optimize_out=mobilenet_v1_quant_opt \
--valid_targets=arm \ --valid_targets=arm \
--prefer_int8_kernel=true
``` ```
如前所述,量化训练后,float目录下的模型参数范围为int8,但参数数据类型仍为float32类型,这样确实没有起到模型参数压缩的效果。但是,经过model\_optimize\_tool工具优化后对应的量化参数均会以int8类型重新存储达到参数压缩的效果,且模型结构也被优化(如进行了各种operator fuse操作)。 如前所述,量化训练后,float目录下的模型参数范围为int8,但参数数据类型仍为float32类型,这样确实没有起到模型参数压缩的效果。但是,经过model\_optimize\_tool工具优化后对应的量化参数均会以int8类型重新存储达到参数压缩的效果,且模型结构也被优化(如进行了各种operator fuse操作)。
#### 在手机端准备量化模型文件 ### 在手机端准备量化模型文件
使用如下命令将mobilenet_v1_quant_opt目录下的量化模型文件导入到手机端: 使用如下命令将mobilenet_v1_quant_opt目录下的量化模型文件导入到手机端:
...@@ -284,9 +257,9 @@ ptq.save_quantized_model(args.save_model_path) ...@@ -284,9 +257,9 @@ ptq.save_quantized_model(args.save_model_path)
adb push mobilenet_v1_quant_opt /data/local/tmp adb push mobilenet_v1_quant_opt /data/local/tmp
``` ```
#### 使用mobilenetv1\_light\_api运行优化后的量化模型 ### 使用mobilenetv1\_light\_api运行优化后的量化模型
参考[源码编译](../source_compile)配置编译环境后,在Paddle-Lite执行如下命令获取轻量级API的demo: 参考[源码编译](source_compile)配置编译环境后,在Paddle-Lite执行如下命令获取轻量级API的demo:
```bash ```bash
cd /Paddle-Lite/build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_light cd /Paddle-Lite/build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/demo/cxx/mobile_light
...@@ -314,9 +287,9 @@ Output[700]: 0.002509 ...@@ -314,9 +287,9 @@ Output[700]: 0.002509
Output[800]: 0.000538 Output[800]: 0.000538
Output[900]: 0.000969 Output[900]: 0.000969
``` ```
在C++中使用Paddle-Lite API的方法请猛戳[此处](../cpp_demo),用户也可参考[mobilenetv1_light_api.cc](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc)的代码示例。 在C++中使用Paddle-Lite API的方法请猛戳[此处](../demo_guides/cpp_demo),用户也可参考[mobilenetv1_light_api.cc](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc)的代码示例。
### FAQ ## FAQ
**问题**:Compiled with WITH_GPU, but no GPU found in runtime **问题**:Compiled with WITH_GPU, but no GPU found in runtime
......
# paddle-mobile 编译
详情可以参考 [mobile/README](https://github.com/PaddlePaddle/Paddle-Lite/tree/develop/mobile)
要切换 paddle-mobile 编译,cmake 需要加上 **-DWITH_PADDLE_MOBILE=ON** 开关,其余 flag 请参考上面文档添加到后面
所有其他选项跟 paddle-mobile 原始操作完全一致
# 模型量化-无校准数据训练后量化
本文首先简单介绍无校准数据训练后量化,然后说明产出量化模型,最好阐述量化模型预测。
## 1 简介
无校准数据训练后量化,将模型中特定OP的权重从FP32类型量化成INT8/16类型,可以减小预测模型的大小。使用该量化模型预测,首先将INT8/16类型的权重反量化成FP32类型,然后再进行预测。
使用条件:
* 有训练好的预测模型
使用步骤:
* 产出量化模型:使用PaddlePaddle调用无校准数据训练后量化接口,产出量化模型
* 量化模型预测:使用PaddleLite加载量化模型进行预测推理
优点:
* 权重量化成INT16类型,模型精度不受影响,模型大小为原始的1/2
* 权重量化成INT8类型,模型精度会受到影响,模型大小为原始的1/4
缺点:
* 暂无
## 2 产出量化模型
大家可以使用PaddlePaddle调用无校准数据训练后量化接口,得到量化模型。
### 2.1 安装PaddlePaddle
参考PaddlePaddle[官网](https://www.paddlepaddle.org.cn/install/quick),安装PaddlePaddle CPU/GPU 1.7版本。
### 2.2 准备模型
准备已经训练好的FP32预测模型,即 `save_inference_model()` 保存的模型。
### 2.3 调用无校准数据训练后量化
对于调用无校准数据训练后量化,首先给出一个例子。
```python
from paddle.fluid.contrib.slim.quantization import WeightQuantization
model_dir = path/to/fp32_model_params
save_model_dir = path/to/save_model_path
weight_quant = WeightQuantization(model_dir=model_dir)
weight_quant.quantize_weight_to_int(save_model_dir=save_model_dir,
weight_bits=16,
quantizable_op_type=['conv2d', 'depthwise_conv2d', 'mul'])
```
对于调用无校准数据训练后量化,以下对api接口进行详细介绍。
```python
class WeightQuantization(model_dir, model_filename=None, params_filename=None)
```
参数说明如下:
* model_dir(str):待量化模型的路径,其中保存模型文件和权重文件。
* model_filename(str, optional):待量化模型的模型文件名,如果模型文件名不是`__model__`,则需要使用model_filename设置模型文件名。
* params_filename(str, optional):待量化模型的权重文件名,如果所有权重保存成一个文件,则需要使用params_filename设置权重文件名。
```python
WeightQuantization.quantize_weight_to_int(save_model_dir,
save_model_filename=None,
save_params_filename=None,
quantizable_op_type=['conv2d', 'mul'],
weight_bits=8,
threshold_rate=0.0)
```
参数说明如下:
* save_model_dir(str):保存量化模型的路径。
* save_model_filename(str, optional):如果save_model_filename等于None,则模型的网络结构保存到__model__文件,如果save_model_filename不等于None,则模型的网络结构保存到特定的文件。默认为None。
* save_params_filename(str, optional):如果save_params_filename等于None,则模型的参数分别保存到一系列文件中,如果save_params_filename不等于None,则模型的参数会保存到一个文件中,文件名为设置的save_params_filename。默认为None。
* quantizable_op_type(list[str]): 需要量化的op类型,默认是`['conv2d', 'mul']`,列表中的值可以是任意支持量化的op类型 `['conv2d', 'depthwise_conv2d', 'mul']`
* weight_bits(int, optional):权重量化保存的比特数,可以是8~16,一般设置为8/16。默认为8。
## 3 量化模型预测
目前,对于无校准数据训练后量化产出的量化模型,不支持PaddlePaddle加载执行,只能使用PaddleLite进行预测部署。
很简单,首先使用PaddleLite提供的模型转换工具(opt)将量化模型转换成移动端预测的模型,然后加载转换后的模型进行预测部署。
注意,PaddleLite 2.3版本才支持无校准数据训练后量化产出的量化,所以转换工具和预测库必须是2.3及之后的版本。
### 3.1 模型转换
参考[模型转换](../user_guides/model_optimize_tool)准备模型转换工具,建议从Release页面下载。
参考[模型转换](../user_guides/model_optimize_tool)使用模型转换工具。
比如在安卓手机ARM端进行预测,模型转换的命令为:
```bash
./opt --model_dir=./mobilenet_v1_quant \
--optimize_out_type=naive_buffer \
--optimize_out=mobilenet_v1_quant_opt \
--valid_targets=arm
```
### 3.2 量化模型预测
和FP32模型一样,转换后的量化模型可以在Android/IOS APP中加载预测,建议参考[C++ Demo](../demo_guides/cpp_demo)[Java Demo](../demo_guides/java_demo)[Android/IOS Demo](../demo_guides/android_app_demo)
此差异已折叠。
# 预编译库
## 编译版本介绍
- ARM_Version=`armv7/armv8` arm版本,可选择armv7或者armv8
- arm_os=`android\ios\ios64\armlinux` 安装平台,支持的arm端移动平台包括 `ios\ios64``armlinux``android`
- arm_lang=`gcc/clang` 源码编译时的编译器,默认为`gcc`编译器
- arm_stl=`c++_static/c++_shared` Lite预测库链接STL库的方式,支持静态或动态链接
- build_extra=`ON/OFF` 是否编译全量OP,OFF时只编译CV相关基础OP,[参数详情](library)
- `tiny_publish/full_publish` 编译模式,`tiny_publish`编译移动端部署库、`full_publish`编译部署库的同时编译第三方依赖库
## Android
|ARM Version|build_extra|arm_stl|target|下载|
|:-------:|:-----:|:-----:|:-----:|:-------:|
|armv7|OFF|c++_static|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_static.tiny_publish.tar.gz)|
|armv7|OFF|c++_static|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_static.full_publish.tar.gz)|
|armv7|OFF|c++_shared|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_shared.tiny_publish.tar.gz)|
|armv7|OFF|c++_shared|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_shared.full_publish.tar.gz)|
|armv7|ON|c++_static|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_static.with_extra.tiny_publish.tar.gz)|
|armv7|ON|c++_static|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_static.with_extra.full_publish.tar.gz)|
|armv7|ON|c++_shared|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_shared.with_extra.tiny_publish.tar.gz)|
|armv7|ON|c++_shared|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv7.gcc.c++_shared.with_extra.full_publish.tar.gz)|
|armv8|OFF|c++_static|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_static.tiny_publish.tar.gz)|
|armv8|OFF|c++_static|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_static.full_publish.tar.gz)|
|armv8|OFF|c++_shared|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_shared.tiny_publish.tar.gz)|
|armv8|OFF|c++_shared|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_shared.full_publish.tar.gz)|
|armv8|ON|c++_static|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_static.with_extra.tiny_publish.tar.gz)|
|armv8|ON|c++_static|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_static.with_extra.full_publish.tar.gz)|
|armv8|ON|c++_shared|tiny_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_shared.with_extra.tiny_publish.tar.gz)|
|armv8|ON|c++_shared|full_publish|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.android.armv8.gcc.c++_shared.with_extra.full_publish.tar.gz)|
## iOS
|ARM Version|arm_os|with_extra|下载|
|:-------:|:-----:|:-----:|:-----:|
|armv7|ios|OFF|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.ios.armv7.tar.gz)|
|armv7|ios|ON|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.ios.armv7.with_extra.tar.gz)|
|armv8|ios64|OFF|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.ios64.armv8.tar.gz)|
|armv8|ios64|ON|[release/v2.3](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/inference_lite_lib.ios64.armv8.with_extra.tar.gz)|
## opt 工具
| 运行系统 | 下载 |
| :---------: | :--------------: |
| Linux | [release/v2.3](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt) |
| MacOs | [release/v2.3](https://paddlelite-data.bj.bcebos.com/model_optimize_tool/opt_mac) |
## 对应源码编译方法
- [opt源码编译](../user_guides/model_optimize_tool.html#opt)
- [Android源码编译](./source_compile.html#paddlelite)
- [iOS源码编译](./source_compile.html#paddlelite)
- [ArmLinux源码编译](./source_compile.html#paddlelite)
- [x86源码编译](../demo_guides/x86)
- [opencl源码编译](../demo_guides/opencl)
- [CUDA源码编译](../demo_guides/cuda)
- [FPGA源码编译](../demo_guides/fpga)
# 源码编译 # 预测库编译
Paddle-Lite 提供了移动端的一键源码编译脚本 `lite/tools/build.sh`,编译流程如下: PaddleLite已经提供官方Release预测库下载,请参考[文档](release_lib)
PaddleLite 提供了移动端的一键源码编译脚本 `lite/tools/build.sh`,编译流程如下:
1. 环境准备(选择其一):Docker交叉编译环境、Linux交叉编译环境 1. 环境准备(选择其一):Docker交叉编译环境、Linux交叉编译环境
2. 编译:调用`build.sh`脚本一键编译 2. 编译:调用`build.sh`脚本一键编译
...@@ -234,6 +236,8 @@ brew cask install java ...@@ -234,6 +236,8 @@ brew cask install java
## 二、编译PaddleLite ## 二、编译PaddleLite
**注:编译OpenCL、华为NPU、FPGA、CUDA、X86预测库、CV模块,见进阶使用指南的对应章节。**
### 下载代码 ### 下载代码
```shell ```shell
...@@ -260,7 +264,7 @@ git checkout <release-version-tag> ...@@ -260,7 +264,7 @@ git checkout <release-version-tag>
| --arm_abi |必选,选择编译的arm版本,其中`armv7hf`为ARMLinux编译时选用| `armv8``armv7``armv7hf`(仅`armlinux`支持) | | --arm_abi |必选,选择编译的arm版本,其中`armv7hf`为ARMLinux编译时选用| `armv8``armv7``armv7hf`(仅`armlinux`支持) |
| --arm_lang |arm_os=android时必选,选择编译器 | `gcc``clang`(`clang`当前暂不支持) | | --arm_lang |arm_os=android时必选,选择编译器 | `gcc``clang`(`clang`当前暂不支持) |
| --android_stl |arm_os=android时必选,选择静态链接STL或动态链接STL | `c++_static``c++_shared`| | --android_stl |arm_os=android时必选,选择静态链接STL或动态链接STL | `c++_static``c++_shared`|
| --build_java | 可选,是否编译java预测库(默认为OFF) | `ON``OFF` | | --build_java | 可选,是否编译java预测库(默认为ON) | `ON``OFF` |
| --build_extra | 可选,是否编译全量预测库(默认为OFF)。详情可参考[预测库说明](./library.html)。 | `ON``OFF` | | --build_extra | 可选,是否编译全量预测库(默认为OFF)。详情可参考[预测库说明](./library.html)。 | `ON``OFF` |
| target |必选,选择编译模式,`tiny_publish`为编译移动端部署库、`full_publish`为带依赖的移动端部署库、`test`为移动端单元测试、`ios`为编译ios端`tiny_publish` | `tiny_publish``full_publish``test``ios` | | target |必选,选择编译模式,`tiny_publish`为编译移动端部署库、`full_publish`为带依赖的移动端部署库、`test`为移动端单元测试、`ios`为编译ios端`tiny_publish` | `tiny_publish``full_publish``test``ios` |
...@@ -278,7 +282,6 @@ git checkout <release-version-tag> ...@@ -278,7 +282,6 @@ git checkout <release-version-tag>
--build_extra=OFF \ --build_extra=OFF \
--arm_lang=gcc \ --arm_lang=gcc \
--android_stl=c++_static \ --android_stl=c++_static \
--build_extra=OFF \
tiny_publish tiny_publish
``` ```
##### IOS ##### IOS
...@@ -306,7 +309,6 @@ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer ...@@ -306,7 +309,6 @@ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
--arm_os=armlinux \ --arm_os=armlinux \
--arm_abi=armv7hf \ --arm_abi=armv7hf \
--arm_lang=gcc \ --arm_lang=gcc \
--build_extra=OFF \
tiny_publish tiny_publish
``` ```
- `--arm_abi`: 树莓派3b使用armv7hf,RK3399使用armv8 - `--arm_abi`: 树莓派3b使用armv7hf,RK3399使用armv8
...@@ -321,7 +323,6 @@ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer ...@@ -321,7 +323,6 @@ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
--build_extra=OFF \ --build_extra=OFF \
--arm_lang=gcc \ --arm_lang=gcc \
--android_stl=c++_static \ --android_stl=c++_static \
--build_extra=OFF \
full_publish full_publish
``` ```
##### ARMLinux ##### ARMLinux
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -25,7 +25,11 @@ if (NOT LITE_ON_TINY_PUBLISH) ...@@ -25,7 +25,11 @@ if (NOT LITE_ON_TINY_PUBLISH)
endif() endif()
else() else()
add_library(paddle_lite_jni SHARED "") add_library(paddle_lite_jni SHARED "")
set_target_properties(paddle_lite_jni PROPERTIES COMPILE_FLAGS "-flto -fdata-sections") set(TARGET_COMIPILE_FLAGS "-fdata-sections")
if (NOT (ARM_TARGET_LANG STREQUAL "clang")) #gcc
set(TARGET_COMIPILE_FLAGS "${TARGET_COMIPILE_FLAGS} -flto")
endif()
set_target_properties(paddle_lite_jni PROPERTIES COMPILE_FLAGS ${TARGET_COMIPILE_FLAGS})
target_sources(paddle_lite_jni PUBLIC ${__lite_cc_files} paddle_lite_jni.cc tensor_jni.cc) target_sources(paddle_lite_jni PUBLIC ${__lite_cc_files} paddle_lite_jni.cc tensor_jni.cc)
add_dependencies(paddle_lite_jni op_list_h kernel_list_h) add_dependencies(paddle_lite_jni op_list_h kernel_list_h)
if (LITE_WITH_NPU) if (LITE_WITH_NPU)
......
...@@ -17,11 +17,6 @@ ...@@ -17,11 +17,6 @@
#include <jni.h> #include <jni.h>
/* Header for class com_baidu_paddle_lite_PaddlePredictor */ /* Header for class com_baidu_paddle_lite_PaddlePredictor */
#include "lite/api/paddle_lite_factory_helper.h" #include "lite/api/paddle_lite_factory_helper.h"
#include "lite/api/paddle_use_kernels.h"
#include "lite/api/paddle_use_ops.h"
#ifndef LITE_ON_TINY_PUBLISH
#include "lite/api/paddle_use_passes.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
......
...@@ -78,7 +78,7 @@ public class MobileConfig extends ConfigBase { ...@@ -78,7 +78,7 @@ public class MobileConfig extends ConfigBase {
* *
* @return liteModelFile * @return liteModelFile
*/ */
public String getModelFile() { public String getModelFromFile() {
return liteModelFile; return liteModelFile;
} }
...@@ -96,7 +96,7 @@ public class MobileConfig extends ConfigBase { ...@@ -96,7 +96,7 @@ public class MobileConfig extends ConfigBase {
* *
* @return liteModelBuffer * @return liteModelBuffer
*/ */
public String getModelBuffer() { public String getModelFromBuffer() {
return liteModelBuffer; return liteModelBuffer;
} }
......
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
#include <vector> #include <vector>
#include "lite/api/cxx_api.h" #include "lite/api/cxx_api.h"
#include "lite/api/light_api.h" #include "lite/api/light_api.h"
#include "lite/api/paddle_use_kernels.h"
#include "lite/api/paddle_use_ops.h"
#include "lite/api/paddle_use_passes.h"
#include "lite/core/mir/pass_registry.h" #include "lite/core/mir/pass_registry.h"
DEFINE_string(model_dir, "", ""); DEFINE_string(model_dir, "", "");
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册