diff --git "a/.github/ISSUE_TEMPLATE/\346\212\245\345\221\212issue.md" "b/.github/ISSUE_TEMPLATE/\346\212\245\345\221\212issue.md" index 898eee84b7..34085055f2 100644 --- "a/.github/ISSUE_TEMPLATE/\346\212\245\345\221\212issue.md" +++ "b/.github/ISSUE_TEMPLATE/\346\212\245\345\221\212issue.md" @@ -19,3 +19,7 @@ assignees: '' - 性能问题,描述清楚对比的方式 - - 注意性能测试,循环跑N次,取后80%的用时平均(模型启动时,刚开始受限于资源分配,速度会较慢) - - FastDeploy的Predict包含模型本身之外的数据前后处理用时 +- 模型部署出错 +- - 先执行`examples`下的部署示例,包括使用examples提供的模型,确认是否可以正确执行 +- - 如若`examples`下的代码可以运行,但自己的模型,或自己的代码不能运行 +- - - 提供自己的代码使用方式或自己的模型,供工程师快速定位问题 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index eb728c2f48..1b4727fd33 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ ### PR types(PR类型) -### Describe +### Description diff --git a/CMakeLists.txt b/CMakeLists.txt index efc35b51c2..667951e714 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ include(${PROJECT_SOURCE_DIR}/cmake/utils.cmake) if(NOT MSVC) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "-Wno-format") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) endif(NOT MSVC) if(UNIX AND (NOT APPLE) AND (NOT ANDROID) AND (NOT ENABLE_TIMVX)) @@ -425,13 +426,6 @@ if(ENABLE_VISION) endif() endif() -if(ANDROID OR IOS) - if(ENABLE_TEXT) - set(ENABLE_TEXT OFF CACHE BOOL "Force ENABLE_TEXT OFF" FORCE) - message(STATUS "Found Android or IOS, force ENABLE_TEXT OFF. We do not support fast_tokenizer with Android/IOS now.") - endif() -endif() - if(ENABLE_TEXT) add_definitions(-DENABLE_TEXT) list(APPEND ALL_DEPLOY_SRCS ${DEPLOY_TEXT_SRCS}) @@ -488,6 +482,8 @@ set_target_properties(${LIBRARY_NAME} PROPERTIES VERSION ${FASTDEPLOY_VERSION}) if(MSVC) # disable warnings for dll export target_compile_options(${LIBRARY_NAME} PRIVATE "$<$>:/wd4251>$<$>:-Xcompiler=/wd4251>") + file(GLOB FD_FILES_REQUIRE_BIGOBJ ${CSRCS_DIR_NAME}/fastdeploy/function/reduce.cc) + set_source_files_properties(${FD_FILES_REQUIRE_BIGOBJ} PROPERTIES COMPILE_FLAGS "/bigobj") endif() # extra depend libs for android @@ -506,8 +502,12 @@ target_link_libraries(${LIBRARY_NAME} ${DEPEND_LIBS}) if(WIN32) if(ENABLE_VISION) - add_custom_target(copy_yaml_library ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/third_party/yaml-cpp/Release ${CMAKE_CURRENT_BINARY_DIR}/third_libs/install/yaml-cpp/lib DEPENDS ${LIBRARY_NAME}) - add_custom_target(copy_yaml_include ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/third_party/yaml-cpp/include ${CMAKE_CURRENT_BINARY_DIR}/third_libs/install/yaml-cpp/include DEPENDS ${LIBRARY_NAME}) + if("${CMAKE_GENERATOR}" STREQUAL "Ninja") + add_custom_target(copy_yaml_library ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/third_party/yaml-cpp ${CMAKE_CURRENT_BINARY_DIR}/third_libs/install/yaml-cpp/lib DEPENDS ${LIBRARY_NAME}) + else() + add_custom_target(copy_yaml_library ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/third_party/yaml-cpp/Release ${CMAKE_CURRENT_BINARY_DIR}/third_libs/install/yaml-cpp/lib DEPENDS ${LIBRARY_NAME}) + add_custom_target(copy_yaml_include ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/third_party/yaml-cpp/include ${CMAKE_CURRENT_BINARY_DIR}/third_libs/install/yaml-cpp/include DEPENDS ${LIBRARY_NAME}) + endif() endif() endif() diff --git a/FastDeploy.cmake.in b/FastDeploy.cmake.in index 5e2eacf3a5..fd0ea847a5 100755 --- a/FastDeploy.cmake.in +++ b/FastDeploy.cmake.in @@ -35,9 +35,12 @@ list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/include) # Note(zhoushunjie): include some useful utils function include(${CMAKE_CURRENT_LIST_DIR}/utils.cmake) -if(NOT CMAKE_CXX_STANDARD) +# Set C++11 as standard for the whole project +if(NOT MSVC) set(CMAKE_CXX_STANDARD 11) -endif() + set(CMAKE_CXX_FLAGS "-Wno-format") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) +endif(NOT MSVC) if(ANDROID) add_library(fastdeploy STATIC IMPORTED GLOBAL) @@ -210,11 +213,18 @@ endif() if (ENABLE_TEXT) if(ANDROID) - message(FATAL_ERROR "Not support fastdeploy text APIs with Android now!") + if(NOT ANDROID_TOOLCHAIN MATCHES "clang") + message(FATAL_ERROR "Currently, only support clang toolchain while cross compiling FastDeploy for Android with FastTokenizer, but found ${ANDROID_TOOLCHAIN}.") + endif() + add_library(core_tokenizers STATIC IMPORTED GLOBAL) + set_property(TARGET core_tokenizers PROPERTY IMPORTED_LOCATION + ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/fast_tokenizer/lib/${ANDROID_ABI}/libcore_tokenizers.so) + list(APPEND FASTDEPLOY_LIBS core_tokenizers) + else() + # Add dependency libs later: Linux/Mac/Win/... + find_library(FAST_TOKENIZER_LIB core_tokenizers ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/fast_tokenizer/lib NO_DEFAULT_PATH) + list(APPEND FASTDEPLOY_LIBS ${FAST_TOKENIZER_LIB}) endif() - # Add dependency libs later - find_library(FAST_TOKENIZER_LIB core_tokenizers ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/fast_tokenizer/lib NO_DEFAULT_PATH) - list(APPEND FASTDEPLOY_LIBS ${FAST_TOKENIZER_LIB}) list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/fast_tokenizer/include) list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/fast_tokenizer/third_party/include) endif() diff --git a/README_CN.md b/README_CN.md old mode 100644 new mode 100755 index 354f9cd804..8814215fee --- a/README_CN.md +++ b/README_CN.md @@ -56,7 +56,6 @@ * **📲 移动端和端侧部署** - * [Paddle Lite NPU部署](#fastdeploy-edge-sdk-npu) * [端侧模型支持列表](#fastdeploy-edge-models) * **🌐 Web和小程序部署** @@ -69,8 +68,8 @@
-
- +
+ Python SDK快速开始(点开查看详情)
#### 快速安装 @@ -132,7 +131,7 @@ cv2.imwrite("vis_image.jpg", vis_im)
- + C++ SDK快速开始(点开查看详情)
@@ -256,7 +255,7 @@ int main(int argc, char* argv[]) { | Video Super-Resolution | [PaddleGAN/PP-MSVSR](./examples/vision/sr/ppmsvsr) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | | Information Extraction | [PaddleNLP/UIE](./examples/text/uie) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | | | NLP | [PaddleNLP/ERNIE-3.0](./examples/text/ernie-3.0) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | -| Speech | [PaddleSpeech/PP-TTS](./examples/text/uie) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | -- | ✅ | +| Speech | [PaddleSpeech/PP-TTS](./examples/audio/pp-tts) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | -- | ✅ |
@@ -275,7 +274,7 @@ int main(int argc, char* argv[]) {
-| 任务场景 | 模型 | 大小(MB) | Linux | Android | iOS | Linux | Linux | Linux | Linux | 更新中... | +| 任务场景 | 模型 | 大小(MB) | Linux | Android | Linux | Linux | Linux | Linux | Linux | 更新中... | |:------------------:|:-----------------------------------------------------------------------------------------:|:--------:|:-------:|:-------:|:-------:|:-----------------------:|:------------------------------:|:---------------------------:|:--------------------------------:|:-------:| | --- | --- | --- | ARM CPU | ARM CPU | 瑞芯微NPU
RK3568/RK3588 | 瑞芯微NPU
RV1109/RV1126/RK1808 | 晶晨NPU
A311D/S905D/C308X | 恩智浦NPU
i.MX 8M Plus | 更新中...| | | Classification | [PaddleClas/ResNet50](examples/vision/classification/paddleclas) | 98 | ✅ | ✅ | ❔ | ✅ | | | | diff --git a/README_EN.md b/README_EN.md old mode 100644 new mode 100755 index f116f2a51e..1157caa7d9 --- a/README_EN.md +++ b/README_EN.md @@ -253,7 +253,7 @@ Notes: ✅: already supported; ❔: to be supported in the future; N/A: Not Ava | Video Super-Resolution | [PaddleGAN/PP-MSVSR](./examples/vision/sr/ppmsvsr) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | | Information Extraction | [PaddleNLP/UIE](./examples/text/uie) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ❔ | | | NLP | [PaddleNLP/ERNIE-3.0](./examples/text/ernie-3.0) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | -| Speech | [PaddleSpeech/PP-TTS](./examples/text/uie) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | -- | ✅ | +| Speech | [PaddleSpeech/PP-TTS](./examples/audio/pp-tts) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | -- | ✅ |
diff --git a/benchmark/benchmark_ppcls.py b/benchmark/benchmark_ppcls.py index 8eeeb8cfca..6b88658eee 100755 --- a/benchmark/benchmark_ppcls.py +++ b/benchmark/benchmark_ppcls.py @@ -75,6 +75,11 @@ def build_option(args): option.use_ort_backend() elif backend == "paddle": option.use_paddle_backend() + elif backend == "ov": + option.use_openvino_backend() + option.set_openvino_device(name="GPU") + # change name and shape for models + option.set_openvino_shape_info({"x": [1, 3, 224, 224]}) elif backend in ["trt", "paddle_trt"]: option.use_trt_backend() if backend == "paddle_trt": @@ -108,27 +113,109 @@ def build_option(args): return option -def get_current_memory_mb(gpu_id=None): - import pynvml - import psutil - pid = os.getpid() - p = psutil.Process(pid) - info = p.memory_full_info() - cpu_mem = info.uss / 1024. / 1024. - gpu_mem = 0 - if gpu_id is not None: - pynvml.nvmlInit() - handle = pynvml.nvmlDeviceGetHandleByIndex(0) - meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle) - gpu_mem = meminfo.used / 1024. / 1024. - return cpu_mem, gpu_mem +class StatBase(object): + """StatBase""" + nvidia_smi_path = "nvidia-smi" + gpu_keys = ('index', 'uuid', 'name', 'timestamp', 'memory.total', + 'memory.free', 'memory.used', 'utilization.gpu', + 'utilization.memory') + nu_opt = ',nounits' + cpu_keys = ('cpu.util', 'memory.util', 'memory.used') + + +class Monitor(StatBase): + """Monitor""" + + def __init__(self, use_gpu=False, gpu_id=0, interval=0.1): + self.result = {} + self.gpu_id = gpu_id + self.use_gpu = use_gpu + self.interval = interval + self.cpu_stat_q = multiprocessing.Queue() + + def start(self): + cmd = '%s --id=%s --query-gpu=%s --format=csv,noheader%s -lms 50' % ( + StatBase.nvidia_smi_path, self.gpu_id, ','.join(StatBase.gpu_keys), + StatBase.nu_opt) + if self.use_gpu: + self.gpu_stat_worker = subprocess.Popen( + cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + shell=True, + close_fds=True, + preexec_fn=os.setsid) + # cpu stat + pid = os.getpid() + self.cpu_stat_worker = multiprocessing.Process( + target=self.cpu_stat_func, + args=(self.cpu_stat_q, pid, self.interval)) + self.cpu_stat_worker.start() + def stop(self): + try: + if self.use_gpu: + os.killpg(self.gpu_stat_worker.pid, signal.SIGUSR1) + # os.killpg(p.pid, signal.SIGTERM) + self.cpu_stat_worker.terminate() + self.cpu_stat_worker.join(timeout=0.01) + except Exception as e: + print(e) + return -def get_current_gputil(gpu_id): - import GPUtil - GPUs = GPUtil.getGPUs() - gpu_load = GPUs[gpu_id].load - return gpu_load + # gpu + if self.use_gpu: + lines = self.gpu_stat_worker.stdout.readlines() + lines = [ + line.strip().decode("utf-8") for line in lines + if line.strip() != '' + ] + gpu_info_list = [{ + k: v + for k, v in zip(StatBase.gpu_keys, line.split(', ')) + } for line in lines] + if len(gpu_info_list) == 0: + return + result = gpu_info_list[0] + for item in gpu_info_list: + for k in item.keys(): + if k not in ["name", "uuid", "timestamp"]: + result[k] = max(int(result[k]), int(item[k])) + else: + result[k] = max(result[k], item[k]) + self.result['gpu'] = result + + # cpu + cpu_result = {} + if self.cpu_stat_q.qsize() > 0: + cpu_result = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + while not self.cpu_stat_q.empty(): + item = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + for k in StatBase.cpu_keys: + cpu_result[k] = max(cpu_result[k], item[k]) + cpu_result['name'] = cpuinfo.get_cpu_info()['brand_raw'] + self.result['cpu'] = cpu_result + + def output(self): + return self.result + + def cpu_stat_func(self, q, pid, interval=0.0): + """cpu stat function""" + stat_info = psutil.Process(pid) + while True: + # pid = os.getpid() + cpu_util, mem_util, mem_use = stat_info.cpu_percent( + ), stat_info.memory_percent(), round(stat_info.memory_info().rss / + 1024.0 / 1024.0, 4) + q.put([cpu_util, mem_util, mem_use]) + time.sleep(interval) + return if __name__ == '__main__': @@ -141,6 +228,7 @@ def get_current_gputil(gpu_id): gpu_id = args.device_id enable_collect_memory_info = args.enable_collect_memory_info + dump_result = dict() end2end_statis = list() cpu_mem = list() gpu_mem = list() @@ -160,6 +248,16 @@ def get_current_gputil(gpu_id): try: model = fd.vision.classification.PaddleClasModel( model_file, params_file, config_file, runtime_option=option) + if enable_collect_memory_info: + import multiprocessing + import subprocess + import psutil + import signal + import cpuinfo + enable_gpu = args.device == "gpu" + monitor = Monitor(enable_gpu, gpu_id) + monitor.start() + model.enable_record_time_of_runtime() im_ori = cv2.imread(args.image) for i in range(args.iter_num): @@ -167,31 +265,28 @@ def get_current_gputil(gpu_id): start = time.time() result = model.predict(im) end2end_statis.append(time.time() - start) - if enable_collect_memory_info: - gpu_util.append(get_current_gputil(gpu_id)) - cm, gm = get_current_memory_mb(gpu_id) - cpu_mem.append(cm) - gpu_mem.append(gm) runtime_statis = model.print_statis_info_of_runtime() warmup_iter = args.iter_num // 5 end2end_statis_repeat = end2end_statis[warmup_iter:] if enable_collect_memory_info: - cpu_mem_repeat = cpu_mem[warmup_iter:] - gpu_mem_repeat = gpu_mem[warmup_iter:] - gpu_util_repeat = gpu_util[warmup_iter:] + monitor.stop() + mem_info = monitor.output() + dump_result["cpu_rss_mb"] = mem_info['cpu'][ + 'memory.used'] if 'cpu' in mem_info else 0 + dump_result["gpu_rss_mb"] = mem_info['gpu'][ + 'memory.used'] if 'gpu' in mem_info else 0 + dump_result["gpu_util"] = mem_info['gpu'][ + 'utilization.gpu'] if 'gpu' in mem_info else 0 - dump_result = dict() dump_result["runtime"] = runtime_statis["avg_time"] * 1000 dump_result["end2end"] = np.mean(end2end_statis_repeat) * 1000 - if enable_collect_memory_info: - dump_result["cpu_rss_mb"] = np.mean(cpu_mem_repeat) - dump_result["gpu_rss_mb"] = np.mean(gpu_mem_repeat) - dump_result["gpu_util"] = np.mean(gpu_util_repeat) f.writelines("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) f.writelines("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + print("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + print("End2End(ms): {} \n".format(str(dump_result["end2end"]))) if enable_collect_memory_info: f.writelines("cpu_rss_mb: {} \n".format( str(dump_result["cpu_rss_mb"]))) @@ -199,6 +294,9 @@ def get_current_gputil(gpu_id): str(dump_result["gpu_rss_mb"]))) f.writelines("gpu_util: {} \n".format( str(dump_result["gpu_util"]))) + print("cpu_rss_mb: {} \n".format(str(dump_result["cpu_rss_mb"]))) + print("gpu_rss_mb: {} \n".format(str(dump_result["gpu_rss_mb"]))) + print("gpu_util: {} \n".format(str(dump_result["gpu_util"]))) except: f.writelines("!!!!!Infer Failed\n") diff --git a/benchmark/benchmark_ppdet.py b/benchmark/benchmark_ppdet.py index 6d08aafb8a..8f7033db4f 100755 --- a/benchmark/benchmark_ppdet.py +++ b/benchmark/benchmark_ppdet.py @@ -75,6 +75,17 @@ def build_option(args): option.use_ort_backend() elif backend == "paddle": option.use_paddle_backend() + elif backend == "ov": + option.use_openvino_backend() + # Using GPU and CPU heterogeneous execution mode + option.set_openvino_device("HETERO:GPU,CPU") + # change name and shape for models + option.set_openvino_shape_info({ + "image": [1, 3, 320, 320], + "scale_factor": [1, 2] + }) + # Set CPU up operator + option.set_openvino_cpu_operators(["MulticlassNms"]) elif backend in ["trt", "paddle_trt"]: option.use_trt_backend() if backend == "paddle_trt": @@ -108,27 +119,109 @@ def build_option(args): return option -def get_current_memory_mb(gpu_id=None): - import pynvml - import psutil - pid = os.getpid() - p = psutil.Process(pid) - info = p.memory_full_info() - cpu_mem = info.uss / 1024. / 1024. - gpu_mem = 0 - if gpu_id is not None: - pynvml.nvmlInit() - handle = pynvml.nvmlDeviceGetHandleByIndex(0) - meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle) - gpu_mem = meminfo.used / 1024. / 1024. - return cpu_mem, gpu_mem +class StatBase(object): + """StatBase""" + nvidia_smi_path = "nvidia-smi" + gpu_keys = ('index', 'uuid', 'name', 'timestamp', 'memory.total', + 'memory.free', 'memory.used', 'utilization.gpu', + 'utilization.memory') + nu_opt = ',nounits' + cpu_keys = ('cpu.util', 'memory.util', 'memory.used') + + +class Monitor(StatBase): + """Monitor""" + + def __init__(self, use_gpu=False, gpu_id=0, interval=0.1): + self.result = {} + self.gpu_id = gpu_id + self.use_gpu = use_gpu + self.interval = interval + self.cpu_stat_q = multiprocessing.Queue() + + def start(self): + cmd = '%s --id=%s --query-gpu=%s --format=csv,noheader%s -lms 50' % ( + StatBase.nvidia_smi_path, self.gpu_id, ','.join(StatBase.gpu_keys), + StatBase.nu_opt) + if self.use_gpu: + self.gpu_stat_worker = subprocess.Popen( + cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + shell=True, + close_fds=True, + preexec_fn=os.setsid) + # cpu stat + pid = os.getpid() + self.cpu_stat_worker = multiprocessing.Process( + target=self.cpu_stat_func, + args=(self.cpu_stat_q, pid, self.interval)) + self.cpu_stat_worker.start() + def stop(self): + try: + if self.use_gpu: + os.killpg(self.gpu_stat_worker.pid, signal.SIGUSR1) + # os.killpg(p.pid, signal.SIGTERM) + self.cpu_stat_worker.terminate() + self.cpu_stat_worker.join(timeout=0.01) + except Exception as e: + print(e) + return -def get_current_gputil(gpu_id): - import GPUtil - GPUs = GPUtil.getGPUs() - gpu_load = GPUs[gpu_id].load - return gpu_load + # gpu + if self.use_gpu: + lines = self.gpu_stat_worker.stdout.readlines() + lines = [ + line.strip().decode("utf-8") for line in lines + if line.strip() != '' + ] + gpu_info_list = [{ + k: v + for k, v in zip(StatBase.gpu_keys, line.split(', ')) + } for line in lines] + if len(gpu_info_list) == 0: + return + result = gpu_info_list[0] + for item in gpu_info_list: + for k in item.keys(): + if k not in ["name", "uuid", "timestamp"]: + result[k] = max(int(result[k]), int(item[k])) + else: + result[k] = max(result[k], item[k]) + self.result['gpu'] = result + + # cpu + cpu_result = {} + if self.cpu_stat_q.qsize() > 0: + cpu_result = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + while not self.cpu_stat_q.empty(): + item = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + for k in StatBase.cpu_keys: + cpu_result[k] = max(cpu_result[k], item[k]) + cpu_result['name'] = cpuinfo.get_cpu_info()['brand_raw'] + self.result['cpu'] = cpu_result + + def output(self): + return self.result + + def cpu_stat_func(self, q, pid, interval=0.0): + """cpu stat function""" + stat_info = psutil.Process(pid) + while True: + # pid = os.getpid() + cpu_util, mem_util, mem_use = stat_info.cpu_percent( + ), stat_info.memory_percent(), round(stat_info.memory_info().rss / + 1024.0 / 1024.0, 4) + q.put([cpu_util, mem_util, mem_use]) + time.sleep(interval) + return if __name__ == '__main__': @@ -141,6 +234,7 @@ def get_current_gputil(gpu_id): gpu_id = args.device_id enable_collect_memory_info = args.enable_collect_memory_info + dump_result = dict() end2end_statis = list() cpu_mem = list() gpu_mem = list() @@ -178,6 +272,16 @@ def get_current_gputil(gpu_id): else: raise Exception("model {} not support now in ppdet series".format( args.model)) + if enable_collect_memory_info: + import multiprocessing + import subprocess + import psutil + import signal + import cpuinfo + enable_gpu = args.device == "gpu" + monitor = Monitor(enable_gpu, gpu_id) + monitor.start() + model.enable_record_time_of_runtime() im_ori = cv2.imread(args.image) for i in range(args.iter_num): @@ -185,31 +289,28 @@ def get_current_gputil(gpu_id): start = time.time() result = model.predict(im) end2end_statis.append(time.time() - start) - if enable_collect_memory_info: - gpu_util.append(get_current_gputil(gpu_id)) - cm, gm = get_current_memory_mb(gpu_id) - cpu_mem.append(cm) - gpu_mem.append(gm) runtime_statis = model.print_statis_info_of_runtime() warmup_iter = args.iter_num // 5 end2end_statis_repeat = end2end_statis[warmup_iter:] if enable_collect_memory_info: - cpu_mem_repeat = cpu_mem[warmup_iter:] - gpu_mem_repeat = gpu_mem[warmup_iter:] - gpu_util_repeat = gpu_util[warmup_iter:] + monitor.stop() + mem_info = monitor.output() + dump_result["cpu_rss_mb"] = mem_info['cpu'][ + 'memory.used'] if 'cpu' in mem_info else 0 + dump_result["gpu_rss_mb"] = mem_info['gpu'][ + 'memory.used'] if 'gpu' in mem_info else 0 + dump_result["gpu_util"] = mem_info['gpu'][ + 'utilization.gpu'] if 'gpu' in mem_info else 0 - dump_result = dict() dump_result["runtime"] = runtime_statis["avg_time"] * 1000 dump_result["end2end"] = np.mean(end2end_statis_repeat) * 1000 - if enable_collect_memory_info: - dump_result["cpu_rss_mb"] = np.mean(cpu_mem_repeat) - dump_result["gpu_rss_mb"] = np.mean(gpu_mem_repeat) - dump_result["gpu_util"] = np.mean(gpu_util_repeat) f.writelines("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) f.writelines("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + print("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + print("End2End(ms): {} \n".format(str(dump_result["end2end"]))) if enable_collect_memory_info: f.writelines("cpu_rss_mb: {} \n".format( str(dump_result["cpu_rss_mb"]))) @@ -217,6 +318,9 @@ def get_current_gputil(gpu_id): str(dump_result["gpu_rss_mb"]))) f.writelines("gpu_util: {} \n".format( str(dump_result["gpu_util"]))) + print("cpu_rss_mb: {} \n".format(str(dump_result["cpu_rss_mb"]))) + print("gpu_rss_mb: {} \n".format(str(dump_result["gpu_rss_mb"]))) + print("gpu_util: {} \n".format(str(dump_result["gpu_util"]))) except: f.writelines("!!!!!Infer Failed\n") diff --git a/benchmark/benchmark_ppocr.py b/benchmark/benchmark_ppocr.py new file mode 100644 index 0000000000..885f9a5a5e --- /dev/null +++ b/benchmark/benchmark_ppocr.py @@ -0,0 +1,377 @@ +# Copyright (c) 2022 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. + +import fastdeploy as fd +import cv2 +import os +import numpy as np +import time + + +def parse_arguments(): + import argparse + import ast + parser = argparse.ArgumentParser() + parser.add_argument( + "--model_dir", required=True, help="Model dir of PPOCR.") + parser.add_argument( + "--det_model", required=True, help="Path of Detection model of PPOCR.") + parser.add_argument( + "--cls_model", + required=True, + help="Path of Classification model of PPOCR.") + parser.add_argument( + "--rec_model", + required=True, + help="Path of Recognization model of PPOCR.") + parser.add_argument( + "--rec_label_file", + required=True, + help="Path of Recognization model of PPOCR.") + parser.add_argument( + "--image", type=str, required=False, help="Path of test image file.") + parser.add_argument( + "--cpu_num_thread", + type=int, + default=8, + help="default number of cpu thread.") + parser.add_argument( + "--device_id", type=int, default=0, help="device(gpu) id") + parser.add_argument( + "--iter_num", + required=True, + type=int, + default=300, + help="number of iterations for computing performace.") + parser.add_argument( + "--device", + default="cpu", + help="Type of inference device, support 'cpu' or 'gpu'.") + parser.add_argument( + "--backend", + type=str, + default="default", + help="inference backend, default, ort, ov, trt, paddle, paddle_trt.") + parser.add_argument( + "--enable_trt_fp16", + type=ast.literal_eval, + default=False, + help="whether enable fp16 in trt backend") + parser.add_argument( + "--enable_collect_memory_info", + type=ast.literal_eval, + default=False, + help="whether enable collect memory info") + args = parser.parse_args() + return args + + +def build_option(args): + option = fd.RuntimeOption() + device = args.device + backend = args.backend + enable_trt_fp16 = args.enable_trt_fp16 + option.set_cpu_thread_num(args.cpu_num_thread) + if device == "gpu": + option.use_gpu() + if backend == "ort": + option.use_ort_backend() + elif backend == "paddle": + option.use_paddle_backend() + elif backend in ["trt", "paddle_trt"]: + option.use_trt_backend() + if backend == "paddle_trt": + option.enable_paddle_to_trt() + if enable_trt_fp16: + option.enable_trt_fp16() + elif backend == "default": + return option + else: + raise Exception( + "While inference with GPU, only support default/ort/paddle/trt/paddle_trt now, {} is not supported.". + format(backend)) + elif device == "cpu": + if backend == "ort": + option.use_ort_backend() + elif backend == "ov": + option.use_openvino_backend() + elif backend == "paddle": + option.use_paddle_backend() + elif backend == "default": + return option + else: + raise Exception( + "While inference with CPU, only support default/ort/ov/paddle now, {} is not supported.". + format(backend)) + else: + raise Exception( + "Only support device CPU/GPU now, {} is not supported.".format( + device)) + + return option + + +class StatBase(object): + """StatBase""" + nvidia_smi_path = "nvidia-smi" + gpu_keys = ('index', 'uuid', 'name', 'timestamp', 'memory.total', + 'memory.free', 'memory.used', 'utilization.gpu', + 'utilization.memory') + nu_opt = ',nounits' + cpu_keys = ('cpu.util', 'memory.util', 'memory.used') + + +class Monitor(StatBase): + """Monitor""" + + def __init__(self, use_gpu=False, gpu_id=0, interval=0.1): + self.result = {} + self.gpu_id = gpu_id + self.use_gpu = use_gpu + self.interval = interval + self.cpu_stat_q = multiprocessing.Queue() + + def start(self): + cmd = '%s --id=%s --query-gpu=%s --format=csv,noheader%s -lms 50' % ( + StatBase.nvidia_smi_path, self.gpu_id, ','.join(StatBase.gpu_keys), + StatBase.nu_opt) + if self.use_gpu: + self.gpu_stat_worker = subprocess.Popen( + cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + shell=True, + close_fds=True, + preexec_fn=os.setsid) + # cpu stat + pid = os.getpid() + self.cpu_stat_worker = multiprocessing.Process( + target=self.cpu_stat_func, + args=(self.cpu_stat_q, pid, self.interval)) + self.cpu_stat_worker.start() + + def stop(self): + try: + if self.use_gpu: + os.killpg(self.gpu_stat_worker.pid, signal.SIGUSR1) + # os.killpg(p.pid, signal.SIGTERM) + self.cpu_stat_worker.terminate() + self.cpu_stat_worker.join(timeout=0.01) + except Exception as e: + print(e) + return + + # gpu + if self.use_gpu: + lines = self.gpu_stat_worker.stdout.readlines() + lines = [ + line.strip().decode("utf-8") for line in lines + if line.strip() != '' + ] + gpu_info_list = [{ + k: v + for k, v in zip(StatBase.gpu_keys, line.split(', ')) + } for line in lines] + if len(gpu_info_list) == 0: + return + result = gpu_info_list[0] + for item in gpu_info_list: + for k in item.keys(): + if k not in ["name", "uuid", "timestamp"]: + result[k] = max(int(result[k]), int(item[k])) + else: + result[k] = max(result[k], item[k]) + self.result['gpu'] = result + + # cpu + cpu_result = {} + if self.cpu_stat_q.qsize() > 0: + cpu_result = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + while not self.cpu_stat_q.empty(): + item = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + for k in StatBase.cpu_keys: + cpu_result[k] = max(cpu_result[k], item[k]) + cpu_result['name'] = cpuinfo.get_cpu_info()['brand_raw'] + self.result['cpu'] = cpu_result + + def output(self): + return self.result + + def cpu_stat_func(self, q, pid, interval=0.0): + """cpu stat function""" + stat_info = psutil.Process(pid) + while True: + # pid = os.getpid() + cpu_util, mem_util, mem_use = stat_info.cpu_percent( + ), stat_info.memory_percent(), round(stat_info.memory_info().rss / + 1024.0 / 1024.0, 4) + q.put([cpu_util, mem_util, mem_use]) + time.sleep(interval) + return + + +if __name__ == '__main__': + + args = parse_arguments() + option = build_option(args) + # Detection Model + det_model_file = os.path.join(args.model_dir, args.det_model, + "inference.pdmodel") + det_params_file = os.path.join(args.model_dir, args.det_model, + "inference.pdiparams") + # Classification Model + cls_model_file = os.path.join(args.model_dir, args.cls_model, + "inference.pdmodel") + cls_params_file = os.path.join(args.model_dir, args.cls_model, + "inference.pdiparams") + # Recognition Model + rec_model_file = os.path.join(args.model_dir, args.rec_model, + "inference.pdmodel") + rec_params_file = os.path.join(args.model_dir, args.rec_model, + "inference.pdiparams") + rec_label_file = os.path.join(args.model_dir, args.rec_label_file) + + gpu_id = args.device_id + enable_collect_memory_info = args.enable_collect_memory_info + dump_result = dict() + end2end_statis = list() + cpu_mem = list() + gpu_mem = list() + gpu_util = list() + if args.device == "cpu": + file_path = args.model_dir + "_model_" + args.backend + "_" + \ + args.device + "_" + str(args.cpu_num_thread) + ".txt" + else: + if args.enable_trt_fp16: + file_path = args.model_dir + "_model_" + args.backend + "_fp16_" + args.device + ".txt" + else: + file_path = args.model_dir + "_model_" + args.backend + "_" + args.device + ".txt" + f = open(file_path, "w") + f.writelines("===={}====: \n".format(os.path.split(file_path)[-1][:-4])) + + try: + rec_option = option + if "OCRv2" in args.model_dir: + det_option = option + if args.backend in ["trt", "paddle_trt"]: + det_option.set_trt_input_shape( + "x", [1, 3, 64, 64], [1, 3, 640, 640], [1, 3, 960, 960]) + det_model = fd.vision.ocr.DBDetector( + det_model_file, det_params_file, runtime_option=det_option) + cls_option = option + if args.backend in ["trt", "paddle_trt"]: + cls_option.set_trt_input_shape( + "x", [1, 3, 48, 10], [10, 3, 48, 320], [64, 3, 48, 1024]) + cls_model = fd.vision.ocr.Classifier( + cls_model_file, cls_params_file, runtime_option=cls_option) + rec_option = option + if args.backend in ["trt", "paddle_trt"]: + rec_option.set_trt_input_shape( + "x", [1, 3, 32, 10], [10, 3, 32, 320], [32, 3, 32, 2304]) + rec_model = fd.vision.ocr.Recognizer( + rec_model_file, + rec_params_file, + rec_label_file, + runtime_option=rec_option) + model = fd.vision.ocr.PPOCRv2( + det_model=det_model, cls_model=cls_model, rec_model=rec_model) + elif "OCRv3" in args.model_dir: + if args.backend in ["trt", "paddle_trt"]: + det_option.set_trt_input_shape( + "x", [1, 3, 64, 64], [1, 3, 640, 640], [1, 3, 960, 960]) + det_model = fd.vision.ocr.DBDetector( + det_model_file, det_params_file, runtime_option=det_option) + if args.backend in ["trt", "paddle_trt"]: + cls_option.set_trt_input_shape( + "x", [1, 3, 48, 10], [10, 3, 48, 320], [64, 3, 48, 1024]) + cls_model = fd.vision.ocr.Classifier( + cls_model_file, cls_params_file, runtime_option=cls_option) + if args.backend in ["trt", "paddle_trt"]: + rec_option.set_trt_input_shape( + "x", [1, 3, 48, 10], [10, 3, 48, 320], [64, 3, 48, 2304]) + rec_model = fd.vision.ocr.Recognizer( + rec_model_file, + rec_params_file, + rec_label_file, + runtime_option=rec_option) + model = fd.vision.ocr.PPOCRv3( + det_model=det_model, cls_model=cls_model, rec_model=rec_model) + else: + raise Exception("model {} not support now in ppocr series".format( + args.model_dir)) + if enable_collect_memory_info: + import multiprocessing + import subprocess + import psutil + import signal + import cpuinfo + enable_gpu = args.device == "gpu" + monitor = Monitor(enable_gpu, gpu_id) + monitor.start() + + det_model.enable_record_time_of_runtime() + cls_model.enable_record_time_of_runtime() + rec_model.enable_record_time_of_runtime() + im_ori = cv2.imread(args.image) + for i in range(args.iter_num): + im = im_ori + start = time.time() + result = model.predict(im) + end2end_statis.append(time.time() - start) + + runtime_statis_det = det_model.print_statis_info_of_runtime() + runtime_statis_cls = cls_model.print_statis_info_of_runtime() + runtime_statis_rec = rec_model.print_statis_info_of_runtime() + + warmup_iter = args.iter_num // 5 + end2end_statis_repeat = end2end_statis[warmup_iter:] + if enable_collect_memory_info: + monitor.stop() + mem_info = monitor.output() + dump_result["cpu_rss_mb"] = mem_info['cpu'][ + 'memory.used'] if 'cpu' in mem_info else 0 + dump_result["gpu_rss_mb"] = mem_info['gpu'][ + 'memory.used'] if 'gpu' in mem_info else 0 + dump_result["gpu_util"] = mem_info['gpu'][ + 'utilization.gpu'] if 'gpu' in mem_info else 0 + + dump_result["runtime"] = ( + runtime_statis_det["avg_time"] + runtime_statis_cls["avg_time"] + + runtime_statis_rec["avg_time"]) * 1000 + dump_result["end2end"] = np.mean(end2end_statis_repeat) * 1000 + + f.writelines("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + f.writelines("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + print("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + print("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + if enable_collect_memory_info: + f.writelines("cpu_rss_mb: {} \n".format( + str(dump_result["cpu_rss_mb"]))) + f.writelines("gpu_rss_mb: {} \n".format( + str(dump_result["gpu_rss_mb"]))) + f.writelines("gpu_util: {} \n".format( + str(dump_result["gpu_util"]))) + print("cpu_rss_mb: {} \n".format(str(dump_result["cpu_rss_mb"]))) + print("gpu_rss_mb: {} \n".format(str(dump_result["gpu_rss_mb"]))) + print("gpu_util: {} \n".format(str(dump_result["gpu_util"]))) + except: + f.writelines("!!!!!Infer Failed\n") + + f.close() diff --git a/benchmark/benchmark_ppseg.py b/benchmark/benchmark_ppseg.py index 7d9df9f077..3c7a9847ef 100755 --- a/benchmark/benchmark_ppseg.py +++ b/benchmark/benchmark_ppseg.py @@ -75,6 +75,11 @@ def build_option(args): option.use_ort_backend() elif backend == "paddle": option.use_paddle_backend() + elif backend == "ov": + option.use_openvino_backend() + option.set_openvino_device(name="GPU") # use gpu + # change name and shape for models + option.set_openvino_shape_info({"x": [1, 3, 512, 512]}) elif backend in ["trt", "paddle_trt"]: option.use_trt_backend() if backend == "paddle_trt": @@ -108,27 +113,109 @@ def build_option(args): return option -def get_current_memory_mb(gpu_id=None): - import pynvml - import psutil - pid = os.getpid() - p = psutil.Process(pid) - info = p.memory_full_info() - cpu_mem = info.uss / 1024. / 1024. - gpu_mem = 0 - if gpu_id is not None: - pynvml.nvmlInit() - handle = pynvml.nvmlDeviceGetHandleByIndex(0) - meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle) - gpu_mem = meminfo.used / 1024. / 1024. - return cpu_mem, gpu_mem +class StatBase(object): + """StatBase""" + nvidia_smi_path = "nvidia-smi" + gpu_keys = ('index', 'uuid', 'name', 'timestamp', 'memory.total', + 'memory.free', 'memory.used', 'utilization.gpu', + 'utilization.memory') + nu_opt = ',nounits' + cpu_keys = ('cpu.util', 'memory.util', 'memory.used') + + +class Monitor(StatBase): + """Monitor""" + + def __init__(self, use_gpu=False, gpu_id=0, interval=0.1): + self.result = {} + self.gpu_id = gpu_id + self.use_gpu = use_gpu + self.interval = interval + self.cpu_stat_q = multiprocessing.Queue() + + def start(self): + cmd = '%s --id=%s --query-gpu=%s --format=csv,noheader%s -lms 50' % ( + StatBase.nvidia_smi_path, self.gpu_id, ','.join(StatBase.gpu_keys), + StatBase.nu_opt) + if self.use_gpu: + self.gpu_stat_worker = subprocess.Popen( + cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + shell=True, + close_fds=True, + preexec_fn=os.setsid) + # cpu stat + pid = os.getpid() + self.cpu_stat_worker = multiprocessing.Process( + target=self.cpu_stat_func, + args=(self.cpu_stat_q, pid, self.interval)) + self.cpu_stat_worker.start() + def stop(self): + try: + if self.use_gpu: + os.killpg(self.gpu_stat_worker.pid, signal.SIGUSR1) + # os.killpg(p.pid, signal.SIGTERM) + self.cpu_stat_worker.terminate() + self.cpu_stat_worker.join(timeout=0.01) + except Exception as e: + print(e) + return -def get_current_gputil(gpu_id): - import GPUtil - GPUs = GPUtil.getGPUs() - gpu_load = GPUs[gpu_id].load - return gpu_load + # gpu + if self.use_gpu: + lines = self.gpu_stat_worker.stdout.readlines() + lines = [ + line.strip().decode("utf-8") for line in lines + if line.strip() != '' + ] + gpu_info_list = [{ + k: v + for k, v in zip(StatBase.gpu_keys, line.split(', ')) + } for line in lines] + if len(gpu_info_list) == 0: + return + result = gpu_info_list[0] + for item in gpu_info_list: + for k in item.keys(): + if k not in ["name", "uuid", "timestamp"]: + result[k] = max(int(result[k]), int(item[k])) + else: + result[k] = max(result[k], item[k]) + self.result['gpu'] = result + + # cpu + cpu_result = {} + if self.cpu_stat_q.qsize() > 0: + cpu_result = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + while not self.cpu_stat_q.empty(): + item = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + for k in StatBase.cpu_keys: + cpu_result[k] = max(cpu_result[k], item[k]) + cpu_result['name'] = cpuinfo.get_cpu_info()['brand_raw'] + self.result['cpu'] = cpu_result + + def output(self): + return self.result + + def cpu_stat_func(self, q, pid, interval=0.0): + """cpu stat function""" + stat_info = psutil.Process(pid) + while True: + # pid = os.getpid() + cpu_util, mem_util, mem_use = stat_info.cpu_percent( + ), stat_info.memory_percent(), round(stat_info.memory_info().rss / + 1024.0 / 1024.0, 4) + q.put([cpu_util, mem_util, mem_use]) + time.sleep(interval) + return if __name__ == '__main__': @@ -141,6 +228,7 @@ def get_current_gputil(gpu_id): gpu_id = args.device_id enable_collect_memory_info = args.enable_collect_memory_info + dump_result = dict() end2end_statis = list() cpu_mem = list() gpu_mem = list() @@ -159,6 +247,16 @@ def get_current_gputil(gpu_id): try: model = fd.vision.segmentation.PaddleSegModel( model_file, params_file, config_file, runtime_option=option) + if enable_collect_memory_info: + import multiprocessing + import subprocess + import psutil + import signal + import cpuinfo + enable_gpu = args.device == "gpu" + monitor = Monitor(enable_gpu, gpu_id) + monitor.start() + model.enable_record_time_of_runtime() im_ori = cv2.imread(args.image) for i in range(args.iter_num): @@ -166,31 +264,28 @@ def get_current_gputil(gpu_id): start = time.time() result = model.predict(im) end2end_statis.append(time.time() - start) - if enable_collect_memory_info: - gpu_util.append(get_current_gputil(gpu_id)) - cm, gm = get_current_memory_mb(gpu_id) - cpu_mem.append(cm) - gpu_mem.append(gm) runtime_statis = model.print_statis_info_of_runtime() warmup_iter = args.iter_num // 5 end2end_statis_repeat = end2end_statis[warmup_iter:] if enable_collect_memory_info: - cpu_mem_repeat = cpu_mem[warmup_iter:] - gpu_mem_repeat = gpu_mem[warmup_iter:] - gpu_util_repeat = gpu_util[warmup_iter:] + monitor.stop() + mem_info = monitor.output() + dump_result["cpu_rss_mb"] = mem_info['cpu'][ + 'memory.used'] if 'cpu' in mem_info else 0 + dump_result["gpu_rss_mb"] = mem_info['gpu'][ + 'memory.used'] if 'gpu' in mem_info else 0 + dump_result["gpu_util"] = mem_info['gpu'][ + 'utilization.gpu'] if 'gpu' in mem_info else 0 - dump_result = dict() dump_result["runtime"] = runtime_statis["avg_time"] * 1000 dump_result["end2end"] = np.mean(end2end_statis_repeat) * 1000 - if enable_collect_memory_info: - dump_result["cpu_rss_mb"] = np.mean(cpu_mem_repeat) - dump_result["gpu_rss_mb"] = np.mean(gpu_mem_repeat) - dump_result["gpu_util"] = np.mean(gpu_util_repeat) f.writelines("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) f.writelines("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + print("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + print("End2End(ms): {} \n".format(str(dump_result["end2end"]))) if enable_collect_memory_info: f.writelines("cpu_rss_mb: {} \n".format( str(dump_result["cpu_rss_mb"]))) @@ -198,6 +293,9 @@ def get_current_gputil(gpu_id): str(dump_result["gpu_rss_mb"]))) f.writelines("gpu_util: {} \n".format( str(dump_result["gpu_util"]))) + print("cpu_rss_mb: {} \n".format(str(dump_result["cpu_rss_mb"]))) + print("gpu_rss_mb: {} \n".format(str(dump_result["gpu_rss_mb"]))) + print("gpu_util: {} \n".format(str(dump_result["gpu_util"]))) except: f.writelines("!!!!!Infer Failed\n") diff --git a/benchmark/benchmark_yolo.py b/benchmark/benchmark_yolo.py index dd63cefb65..8fccad8e08 100755 --- a/benchmark/benchmark_yolo.py +++ b/benchmark/benchmark_yolo.py @@ -75,6 +75,11 @@ def build_option(args): option.use_ort_backend() elif backend == "paddle": option.use_paddle_backend() + elif backend == "ov": + option.use_openvino_backend() + option.set_openvino_device(name="GPU") + # change name and shape for models + option.set_openvino_shape_info({"images": [1, 3, 640, 640]}) elif backend in ["trt", "paddle_trt"]: option.use_trt_backend() if backend == "paddle_trt": @@ -108,27 +113,109 @@ def build_option(args): return option -def get_current_memory_mb(gpu_id=None): - import pynvml - import psutil - pid = os.getpid() - p = psutil.Process(pid) - info = p.memory_full_info() - cpu_mem = info.uss / 1024. / 1024. - gpu_mem = 0 - if gpu_id is not None: - pynvml.nvmlInit() - handle = pynvml.nvmlDeviceGetHandleByIndex(0) - meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle) - gpu_mem = meminfo.used / 1024. / 1024. - return cpu_mem, gpu_mem +class StatBase(object): + """StatBase""" + nvidia_smi_path = "nvidia-smi" + gpu_keys = ('index', 'uuid', 'name', 'timestamp', 'memory.total', + 'memory.free', 'memory.used', 'utilization.gpu', + 'utilization.memory') + nu_opt = ',nounits' + cpu_keys = ('cpu.util', 'memory.util', 'memory.used') + + +class Monitor(StatBase): + """Monitor""" + + def __init__(self, use_gpu=False, gpu_id=0, interval=0.1): + self.result = {} + self.gpu_id = gpu_id + self.use_gpu = use_gpu + self.interval = interval + self.cpu_stat_q = multiprocessing.Queue() + + def start(self): + cmd = '%s --id=%s --query-gpu=%s --format=csv,noheader%s -lms 50' % ( + StatBase.nvidia_smi_path, self.gpu_id, ','.join(StatBase.gpu_keys), + StatBase.nu_opt) + if self.use_gpu: + self.gpu_stat_worker = subprocess.Popen( + cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + shell=True, + close_fds=True, + preexec_fn=os.setsid) + # cpu stat + pid = os.getpid() + self.cpu_stat_worker = multiprocessing.Process( + target=self.cpu_stat_func, + args=(self.cpu_stat_q, pid, self.interval)) + self.cpu_stat_worker.start() + def stop(self): + try: + if self.use_gpu: + os.killpg(self.gpu_stat_worker.pid, signal.SIGUSR1) + # os.killpg(p.pid, signal.SIGTERM) + self.cpu_stat_worker.terminate() + self.cpu_stat_worker.join(timeout=0.01) + except Exception as e: + print(e) + return -def get_current_gputil(gpu_id): - import GPUtil - GPUs = GPUtil.getGPUs() - gpu_load = GPUs[gpu_id].load - return gpu_load + # gpu + if self.use_gpu: + lines = self.gpu_stat_worker.stdout.readlines() + lines = [ + line.strip().decode("utf-8") for line in lines + if line.strip() != '' + ] + gpu_info_list = [{ + k: v + for k, v in zip(StatBase.gpu_keys, line.split(', ')) + } for line in lines] + if len(gpu_info_list) == 0: + return + result = gpu_info_list[0] + for item in gpu_info_list: + for k in item.keys(): + if k not in ["name", "uuid", "timestamp"]: + result[k] = max(int(result[k]), int(item[k])) + else: + result[k] = max(result[k], item[k]) + self.result['gpu'] = result + + # cpu + cpu_result = {} + if self.cpu_stat_q.qsize() > 0: + cpu_result = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + while not self.cpu_stat_q.empty(): + item = { + k: v + for k, v in zip(StatBase.cpu_keys, self.cpu_stat_q.get()) + } + for k in StatBase.cpu_keys: + cpu_result[k] = max(cpu_result[k], item[k]) + cpu_result['name'] = cpuinfo.get_cpu_info()['brand_raw'] + self.result['cpu'] = cpu_result + + def output(self): + return self.result + + def cpu_stat_func(self, q, pid, interval=0.0): + """cpu stat function""" + stat_info = psutil.Process(pid) + while True: + # pid = os.getpid() + cpu_util, mem_util, mem_use = stat_info.cpu_percent( + ), stat_info.memory_percent(), round(stat_info.memory_info().rss / + 1024.0 / 1024.0, 4) + q.put([cpu_util, mem_util, mem_use]) + time.sleep(interval) + return if __name__ == '__main__': @@ -139,6 +226,7 @@ def get_current_gputil(gpu_id): gpu_id = args.device_id enable_collect_memory_info = args.enable_collect_memory_info + dump_result = dict() end2end_statis = list() cpu_mem = list() gpu_mem = list() @@ -170,6 +258,16 @@ def get_current_gputil(gpu_id): else: raise Exception("model {} not support now in yolo series".format( args.model)) + if enable_collect_memory_info: + import multiprocessing + import subprocess + import psutil + import signal + import cpuinfo + enable_gpu = args.device == "gpu" + monitor = Monitor(enable_gpu, gpu_id) + monitor.start() + model.enable_record_time_of_runtime() im_ori = cv2.imread(args.image) for i in range(args.iter_num): @@ -177,31 +275,28 @@ def get_current_gputil(gpu_id): start = time.time() result = model.predict(im) end2end_statis.append(time.time() - start) - if enable_collect_memory_info: - gpu_util.append(get_current_gputil(gpu_id)) - cm, gm = get_current_memory_mb(gpu_id) - cpu_mem.append(cm) - gpu_mem.append(gm) runtime_statis = model.print_statis_info_of_runtime() warmup_iter = args.iter_num // 5 end2end_statis_repeat = end2end_statis[warmup_iter:] if enable_collect_memory_info: - cpu_mem_repeat = cpu_mem[warmup_iter:] - gpu_mem_repeat = gpu_mem[warmup_iter:] - gpu_util_repeat = gpu_util[warmup_iter:] + monitor.stop() + mem_info = monitor.output() + dump_result["cpu_rss_mb"] = mem_info['cpu'][ + 'memory.used'] if 'cpu' in mem_info else 0 + dump_result["gpu_rss_mb"] = mem_info['gpu'][ + 'memory.used'] if 'gpu' in mem_info else 0 + dump_result["gpu_util"] = mem_info['gpu'][ + 'utilization.gpu'] if 'gpu' in mem_info else 0 - dump_result = dict() dump_result["runtime"] = runtime_statis["avg_time"] * 1000 dump_result["end2end"] = np.mean(end2end_statis_repeat) * 1000 - if enable_collect_memory_info: - dump_result["cpu_rss_mb"] = np.mean(cpu_mem_repeat) - dump_result["gpu_rss_mb"] = np.mean(gpu_mem_repeat) - dump_result["gpu_util"] = np.mean(gpu_util_repeat) f.writelines("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) f.writelines("End2End(ms): {} \n".format(str(dump_result["end2end"]))) + print("Runtime(ms): {} \n".format(str(dump_result["runtime"]))) + print("End2End(ms): {} \n".format(str(dump_result["end2end"]))) if enable_collect_memory_info: f.writelines("cpu_rss_mb: {} \n".format( str(dump_result["cpu_rss_mb"]))) @@ -209,6 +304,9 @@ def get_current_gputil(gpu_id): str(dump_result["gpu_rss_mb"]))) f.writelines("gpu_util: {} \n".format( str(dump_result["gpu_util"]))) + print("cpu_rss_mb: {} \n".format(str(dump_result["cpu_rss_mb"]))) + print("gpu_rss_mb: {} \n".format(str(dump_result["gpu_rss_mb"]))) + print("gpu_util: {} \n".format(str(dump_result["gpu_util"]))) except: f.writelines("!!!!!Infer Failed\n") diff --git a/benchmark/run_benchmark_ppocr.sh b/benchmark/run_benchmark_ppocr.sh new file mode 100644 index 0000000000..c9f24afd7e --- /dev/null +++ b/benchmark/run_benchmark_ppocr.sh @@ -0,0 +1,23 @@ +echo "[FastDeploy] Running PPOCR benchmark..." + +# for PPOCRv2 +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend ort --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend paddle --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend ov --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend ort --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle_trt --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle_trt --enable_trt_fp16 True --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend trt --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv2 --det_model ch_PP-OCRv2_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv2_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend trt --enable_trt_fp16 True --enable_collect_memory_info True + +# for PPOCRv3 +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend ort --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend paddle --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --cpu_num_thread 8 --iter_num 2000 --backend ov --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend ort --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle_trt --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend paddle_trt --enable_trt_fp16 True --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend trt --enable_collect_memory_info True +python benchmark_ppocr.py --model_dir ch_PP-OCRv3 --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2.0_cls_infer --rec_model ch_PP-OCRv3_rec_infer --rec_label_file ppocr_keys_v1.txt --image 12.jpg --device gpu --iter_num 2000 --backend trt --enable_trt_fp16 True --enable_collect_memory_info True diff --git a/cmake/fast_tokenizer.cmake b/cmake/fast_tokenizer.cmake index ba38492839..d8ab4d502e 100644 --- a/cmake/fast_tokenizer.cmake +++ b/cmake/fast_tokenizer.cmake @@ -24,9 +24,16 @@ set(FASTTOKENIZER_INC_DIR "${FASTTOKENIZER_INSTALL_DIR}/include" "${FASTTOKENIZER_INSTALL_DIR}/third_party/include" CACHE PATH "fast_tokenizer include directory." FORCE) -set(FASTTOKENIZER_LIB_DIR - "${FASTTOKENIZER_INSTALL_DIR}/lib/" - CACHE PATH "fast_tokenizer lib directory." FORCE) +if(ANDROID) + set(FASTTOKENIZER_LIB_DIR + "${FASTTOKENIZER_INSTALL_DIR}/lib/${ANDROID_ABI}" + CACHE PATH "fast_tokenizer lib directory." FORCE) +else() + set(FASTTOKENIZER_LIB_DIR + "${FASTTOKENIZER_INSTALL_DIR}/lib/" + CACHE PATH "fast_tokenizer lib directory." FORCE) +endif() + set(FASTTOKENIZER_THIRD_LIB_DIR "${FASTTOKENIZER_INSTALL_DIR}/third_party/lib/" CACHE PATH "fast_tokenizer lib directory." FORCE) @@ -37,21 +44,21 @@ include_directories(${FASTTOKENIZER_INC_DIR}) # Set lib path if(WIN32) -set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/core_tokenizers.lib" - CACHE FILEPATH "fast_tokenizer compile library." FORCE) -message("FASTTOKENIZER_COMPILE_LIB = ${FASTTOKENIZER_COMPILE_LIB}") -set(ICUDT_LIB "${FASTTOKENIZER_THIRD_LIB_DIR}/icudt.lib") -set(ICUUC_LIB "${FASTTOKENIZER_THIRD_LIB_DIR}/icuuc.lib") - + set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/core_tokenizers.lib" + CACHE FILEPATH "fast_tokenizer compile library." FORCE) + set(ICUDT_LIB "${FASTTOKENIZER_THIRD_LIB_DIR}/icudt.lib") + set(ICUUC_LIB "${FASTTOKENIZER_THIRD_LIB_DIR}/icuuc.lib") elseif(APPLE) -set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/libcore_tokenizers.dylib" - CACHE FILEPATH "fast_tokenizer compile library." FORCE) + set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/libcore_tokenizers.dylib" + CACHE FILEPATH "fast_tokenizer compile library." FORCE) +elseif(ANDROID) + set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/libcore_tokenizers.so" + CACHE FILEPATH "fast_tokenizer compile library." FORCE) else() - -set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/libcore_tokenizers.so" - CACHE FILEPATH "fast_tokenizer compile library." FORCE) -message("FASTTOKENIZER_COMPILE_LIB = ${FASTTOKENIZER_COMPILE_LIB}") + set(FASTTOKENIZER_COMPILE_LIB "${FASTTOKENIZER_LIB_DIR}/libcore_tokenizers.so" + CACHE FILEPATH "fast_tokenizer compile library." FORCE) endif(WIN32) +message("FASTTOKENIZER_COMPILE_LIB = ${FASTTOKENIZER_COMPILE_LIB}") set(FASTTOKENIZER_URL_BASE "https://bj.bcebos.com/paddlenlp/fast_tokenizer/") set(FASTTOKENIZER_VERSION "1.0.0") @@ -68,6 +75,15 @@ elseif(APPLE) else() set(FASTTOKENIZER_FILE "fast_tokenizer-osx-x86_64-${FASTTOKENIZER_VERSION}.tgz") endif() +elseif(ANDROID) + # check ABI, toolchain + if((NOT ANDROID_ABI MATCHES "armeabi-v7a") AND (NOT ANDROID_ABI MATCHES "arm64-v8a")) + message(FATAL_ERROR "FastDeploy with FastTokenizer on Android only support armeabi-v7a, arm64-v8a now.") + endif() + if(NOT ANDROID_TOOLCHAIN MATCHES "clang") + message(FATAL_ERROR "Currently, only support clang toolchain while cross compiling FastDeploy for Android with FastTokenizer, but found ${ANDROID_TOOLCHAIN}.") + endif() + set(FASTTOKENIZER_FILE "fast_tokenizer-android-${ANDROID_ABI}-${FASTTOKENIZER_VERSION}.tgz") else() if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") set(FASTTOKENIZER_FILE "fast_tokenizer-linux-aarch64-${FASTTOKENIZER_VERSION}.tgz") @@ -77,18 +93,39 @@ else() endif() set(FASTTOKENIZER_URL "${FASTTOKENIZER_URL_BASE}${FASTTOKENIZER_FILE}") -ExternalProject_Add( - ${FASTTOKENIZER_PROJECT} - ${EXTERNAL_PROJECT_LOG_ARGS} - URL ${FASTTOKENIZER_URL} - PREFIX ${FASTTOKENIZER_PREFIX_DIR} - DOWNLOAD_NO_PROGRESS 1 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - UPDATE_COMMAND "" - INSTALL_COMMAND - ${CMAKE_COMMAND} -E copy_directory ${FASTTOKENIZER_SOURCE_DIR} ${FASTTOKENIZER_INSTALL_DIR} - BUILD_BYPRODUCTS ${FASTTOKENIZER_COMPILE_LIB}) +if(ANDROID) + ExternalProject_Add( + ${FASTTOKENIZER_PROJECT} + ${EXTERNAL_PROJECT_LOG_ARGS} + URL ${FASTTOKENIZER_URL} + PREFIX ${FASTTOKENIZER_PREFIX_DIR} + DOWNLOAD_NO_PROGRESS 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E remove_directory ${FASTTOKENIZER_INSTALL_DIR} && + ${CMAKE_COMMAND} -E make_directory ${FASTTOKENIZER_INSTALL_DIR} && + ${CMAKE_COMMAND} -E make_directory ${FASTTOKENIZER_INSTALL_DIR}/lib && + ${CMAKE_COMMAND} -E make_directory ${FASTTOKENIZER_INSTALL_DIR}/third_party && + ${CMAKE_COMMAND} -E rename ${FASTTOKENIZER_SOURCE_DIR}/lib/ ${FASTTOKENIZER_INSTALL_DIR}/lib/${ANDROID_ABI} && + ${CMAKE_COMMAND} -E copy_directory ${FASTTOKENIZER_SOURCE_DIR}/include ${FASTTOKENIZER_INSTALL_DIR}/include && + ${CMAKE_COMMAND} -E copy_directory ${FASTTOKENIZER_SOURCE_DIR}/third_party/include ${FASTTOKENIZER_INSTALL_DIR}/third_party/include + BUILD_BYPRODUCTS ${FASTTOKENIZER_COMPILE_LIB}) +else() + ExternalProject_Add( + ${FASTTOKENIZER_PROJECT} + ${EXTERNAL_PROJECT_LOG_ARGS} + URL ${FASTTOKENIZER_URL} + PREFIX ${FASTTOKENIZER_PREFIX_DIR} + DOWNLOAD_NO_PROGRESS 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${FASTTOKENIZER_SOURCE_DIR} ${FASTTOKENIZER_INSTALL_DIR} + BUILD_BYPRODUCTS ${FASTTOKENIZER_COMPILE_LIB}) +endif() add_library(fast_tokenizer STATIC IMPORTED GLOBAL) set_property(TARGET fast_tokenizer PROPERTY IMPORTED_LOCATION ${FASTTOKENIZER_COMPILE_LIB}) diff --git a/cmake/opencv.cmake b/cmake/opencv.cmake index 912cf2917d..87f8c8bcd9 100755 --- a/cmake/opencv.cmake +++ b/cmake/opencv.cmake @@ -41,10 +41,12 @@ elseif(IOS) else() if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") set(OPENCV_FILENAME "opencv-linux-aarch64-3.4.14") - elseif(TARGET_ABI MATCHES "armhf") - set(OPENCV_FILENAME "opencv-armv7hf") else() - set(OPENCV_FILENAME "opencv-linux-x64-3.4.16") + if(ENABLE_TIMVX) + set(OPENCV_FILENAME "opencv-armv7hf") + else() + set(OPENCV_FILENAME "opencv-linux-x64-3.4.16") + endif() endif() if(ENABLE_OPENCV_CUDA) if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") @@ -57,7 +59,7 @@ endif() set(OPENCV_INSTALL_DIR ${THIRD_PARTY_PATH}/install/) if(ANDROID) set(OPENCV_URL_PREFIX "https://bj.bcebos.com/fastdeploy/third_libs") -elseif(TARGET_ABI MATCHES "armhf") +elseif(ENABLE_TIMVX) set(OPENCV_URL_PREFIX "https://bj.bcebos.com/fastdeploy/test") else() # TODO: use fastdeploy/third_libs instead. set(OPENCV_URL_PREFIX "https://bj.bcebos.com/paddle2onnx/libs") @@ -185,7 +187,7 @@ else() file(RENAME ${THIRD_PARTY_PATH}/install/${OPENCV_FILENAME}/ ${THIRD_PARTY_PATH}/install/opencv) set(OPENCV_FILENAME opencv) set(OpenCV_DIR ${THIRD_PARTY_PATH}/install/${OPENCV_FILENAME}) - if(TARGET_ABI MATCHES "armhf") + if(ENABLE_TIMVX) set(OpenCV_DIR ${OpenCV_DIR}/lib/cmake/opencv4) endif() if (WIN32) diff --git a/cmake/paddle2onnx.cmake b/cmake/paddle2onnx.cmake index ee5c46c556..baaac87591 100755 --- a/cmake/paddle2onnx.cmake +++ b/cmake/paddle2onnx.cmake @@ -43,7 +43,7 @@ else() endif(WIN32) set(PADDLE2ONNX_URL_BASE "https://bj.bcebos.com/fastdeploy/third_libs/") -set(PADDLE2ONNX_VERSION "1.0.4rc0") +set(PADDLE2ONNX_VERSION "1.0.5") if(WIN32) set(PADDLE2ONNX_FILE "paddle2onnx-win-x64-${PADDLE2ONNX_VERSION}.zip") if(NOT CMAKE_CL_64) diff --git a/cmake/paddlelite.cmake b/cmake/paddlelite.cmake index d86ccf2d1d..12a069f6e4 100755 --- a/cmake/paddlelite.cmake +++ b/cmake/paddlelite.cmake @@ -59,10 +59,12 @@ elseif(ANDROID) else() # Linux if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-linux-arm64-20220920.tgz") - elseif(TARGET_ABI MATCHES "armhf") - set(PADDLELITE_URL "https://bj.bcebos.com/fastdeploy/test/lite-linux_armhf_1101.tgz") else() - message(FATAL_ERROR "Only support Linux aarch64 now, x64 is not supported with backend Paddle Lite.") + if(ENABLE_TIMVX) + set(PADDLELITE_URL "https://bj.bcebos.com/fastdeploy/test/lite-linux_armhf_1130.tgz") + else() + message(FATAL_ERROR "Only support Linux aarch64 or ENABLE_TIMVX now, x64 is not supported with backend Paddle Lite.") + endif() endif() endif() diff --git a/cmake/timvx.cmake b/cmake/timvx.cmake index 153f0de190..c6a7d54d27 100755 --- a/cmake/timvx.cmake +++ b/cmake/timvx.cmake @@ -1,11 +1,10 @@ -if (NOT DEFINED TARGET_ABI) +if (NOT DEFINED CMAKE_SYSTEM_PROCESSOR) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_C_COMPILER "arm-linux-gnueabihf-gcc") set(CMAKE_CXX_COMPILER "arm-linux-gnueabihf-g++") set(CMAKE_CXX_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 ${CMAKE_CXX_FLAGS}") set(CMAKE_C_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 ${CMAKE_C_FLAGS}" ) - set(TARGET_ABI armhf) set(CMAKE_BUILD_TYPE MinSizeRel) else() if(NOT ${ENABLE_LITE_BACKEND}) diff --git a/docs/README_CN.md b/docs/README_CN.md index 43e6e30591..5fb8b21274 100644 --- a/docs/README_CN.md +++ b/docs/README_CN.md @@ -10,6 +10,7 @@ - [IPU部署环境编译安装](cn/build_and_install/ipu.md) - [Jetson部署环境编译安装](cn/build_and_install/jetson.md) - [Android平台部署环境编译安装](cn/build_and_install/android.md) +- [服务化部署镜像编译安装](../serving/docs/zh_CN/compile.md) ## 快速使用 @@ -22,6 +23,7 @@ - [Python API文档](https://www.paddlepaddle.org.cn/fastdeploy-api-doc/python/html/) - [C++ API文档](https://www.paddlepaddle.org.cn/fastdeploy-api-doc/cpp/html/) +- [Android Java API文档](../java/android) ## 性能调优 @@ -31,9 +33,9 @@ - [1. 如何配置模型部署的推理后端](cn/faq/how_to_change_backend.md) - [2. Windows上C++ SDK如何使用](cn/faq/use_sdk_on_windows.md) -- [3. Android上如何使用FastDeploy](cn/faq/use_sdk_on_android.md)(进行中) +- [3. Android上如何使用FastDeploy C++ SDK](cn/faq/use_cpp_sdk_on_android.md) - [4. TensorRT使用中的一些技巧](cn/faq/tensorrt_tricks.md) -- [5. 如何增加新的模型](cn/faq/develop_a_new_model.md)(进行中) +- [5. 如何增加新的模型](cn/faq/develop_a_new_model.md) ## 更多FastDeploy部署模块 diff --git a/docs/README_EN.md b/docs/README_EN.md index 53523cbc49..c4f9adfa37 100644 --- a/docs/README_EN.md +++ b/docs/README_EN.md @@ -10,6 +10,7 @@ - [Build and Install FastDeploy Library on IPU Platform](en/build_and_install/ipu.md) - [Build and Install FastDeploy Library on Nvidia Jetson Platform](en/build_and_install/jetson.md) - [Build and Install FastDeploy Library on Android Platform](en/build_and_install/android.md) +- [Build and Install FastDeploy Serving Deployment Image](../serving/docs/EN/compile-en.md) ## A Quick Start - Demos @@ -21,7 +22,8 @@ ## API - [Python API](https://baidu-paddle.github.io/fastdeploy-api/python/html/) -- [C++ API](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/) +- [C++ API](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/) +- [Android Java API](../java/android) ## Performance Optimization @@ -31,11 +33,11 @@ - [1. How to Change Inference Backends](en/faq/how_to_change_backend.md) - [2. How to Use FastDeploy C++ SDK on Windows Platform](en/faq/use_sdk_on_windows.md) -- [3. How to Use FastDeploy C++ SDK on Android Platform](en/faq/use_sdk_on_android.md) +- [3. How to Use FastDeploy C++ SDK on Android Platform](en/faq/use_cpp_sdk_on_android.md) - [4. Tricks of TensorRT](en/faq/tensorrt_tricks.md) - [5. How to Develop a New Model](en/faq/develop_a_new_model.md) ## More FastDeploy Deployment Module -- [deployment AI Model as a Service](../serving) +- [Deployment AI Model as a Service](../serving) - [Benchmark Testing](../benchmark) diff --git a/docs/api_docs/cpp/Doxyfile b/docs/api_docs/cpp/Doxyfile index 4bd48f09d7..afd956162e 100644 --- a/docs/api_docs/cpp/Doxyfile +++ b/docs/api_docs/cpp/Doxyfile @@ -2100,7 +2100,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = protected=private +PREDEFINED = protected=private ENABLE_VISION_VISUALIZE=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/docs/api_docs/cpp/main_page.md b/docs/api_docs/cpp/main_page.md index 585e6d4286..fef288971c 100644 --- a/docs/api_docs/cpp/main_page.md +++ b/docs/api_docs/cpp/main_page.md @@ -1,31 +1,7 @@ # FastDeploy C++ API Summary -## Runtime - -FastDeploy Runtime can be used as an inference engine with the same code, we can deploy Paddle/ONNX model on different device by different backends. -Currently, FastDeploy supported backends listed as below, - -| Backend | Hardware | Support Model Format | Platform | -| :------ | :------- | :------------------- | :------- | -| Paddle Inference | CPU/Nvidia GPU | Paddle | Windows(x64)/Linux(x64) | -| ONNX Runtime | CPU/Nvidia GPU | Paddle/ONNX | Windows(x64)/Linux(x64/aarch64)/Mac(x86/arm64) | -| TensorRT | Nvidia GPU | Paddle/ONNX | Windows(x64)/Linux(x64)/Jetson | -| OpenVINO | CPU | Paddle/ONNX | Windows(x64)/Linux(x64)/Mac(x86) | -| Poros | CPU/Nvidia GPU | TorchScript | Linux(x64) | - -### Example code -- [Python examples](./) -- [C++ examples](./) - -### Related APIs -- [RuntimeOption](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/structfastdeploy_1_1RuntimeOption.html) -- [Runtime](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/structfastdeploy_1_1Runtime.html) - -## Vision Models - -| Task | Model | API | Example | -| :---- | :---- | :---- | :----- | -| object detection | PaddleDetection/PPYOLOE | [fastdeploy::vision::detection::PPYOLOE](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/classfastdeploy_1_1vision_1_1detection_1_1PPYOLOE.html) | [C++](./)/[Python](./) | -| keypoint detection | PaddleDetection/PPTinyPose | [fastdeploy::vision::keypointdetection::PPTinyPose](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/classfastdeploy_1_1pipeline_1_1PPTinyPose.html) | [C++](./)/[Python](./) | -| image classification | PaddleClassification serials | [fastdeploy::vision::classification::PaddleClasModel](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/classfastdeploy_1_1vision_1_1classification_1_1PaddleClasModel.html) | [C++](./)/[Python](./) | -| semantic segmentation | PaddleSegmentation serials | [fastdeploy::vision::classification::PaddleSegModel](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/classfastdeploy_1_1vision_1_1segmentation_1_1PaddleSegModel.html) | [C++](./)/[Python](./) | +- Github: [https://github.com/PaddlePaddle/FastDeploy](https://github.com/PaddlePaddle/FastDeploy) +- [Installation](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/en/build_and_install) +- [Usage Documents](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/README_EN.md) +- [Release Notes](https://github.com/PaddlePaddle/FastDeploy/releases) +- [Examples](https://github.com/PaddlePaddle/FastDeploy/tree/develop/examples) diff --git a/docs/api_docs/python/semantic_segmentation.md b/docs/api_docs/python/semantic_segmentation.md index 6d224e0859..7a0eb6ca9e 100644 --- a/docs/api_docs/python/semantic_segmentation.md +++ b/docs/api_docs/python/semantic_segmentation.md @@ -1,5 +1,14 @@ # Semantic Segmentation(语义分割) + +## fastdeploy.vision.segmentation.PaddleSegPreprocessor + +```{eval-rst} +.. autoclass:: fastdeploy.vision.segmentation.PaddleSegPreprocessor + :members: + :inherited-members: +``` + ## fastdeploy.vision.segmentation.PaddleSegModel ```{eval-rst} @@ -7,3 +16,11 @@ :members: :inherited-members: ``` + +## fastdeploy.vision.segmentation.PaddleSegPostprocessor + +```{eval-rst} +.. autoclass:: fastdeploy.vision.segmentation.PaddleSegPostprocessor + :members: + :inherited-members: +``` diff --git a/docs/api_docs/python/visualize.md b/docs/api_docs/python/visualize.md new file mode 100644 index 0000000000..2170eb453d --- /dev/null +++ b/docs/api_docs/python/visualize.md @@ -0,0 +1,57 @@ +# Visaulize(可视化) + +## fastdeploy.vision.vis_detection + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_detection + :members: + :inherited-members: +``` + +## fastdeploy.vision.vis_segmentation + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_segmentation + :members: + :inherited-members: +``` + +## fastdeploy.vision.vis_keypoint_detection + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_keypoint_detection + :members: + :inherited-members: +``` +## fastdeploy.vision.vis_face_detection + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_face_detection + :members: + :inherited-members: +``` + + +## fastdeploy.vision.vis_face_alignment + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_face_alignment + :members: + :inherited-members: +``` + +## fastdeploy.vision.vis_matting + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_matting + :members: + :inherited-members: +``` + +## fastdeploy.vision.vis_ppocr + +```{eval-rst} +.. autoclass:: fastdeploy.vision.vis_ppocr + :members: + :inherited-members: +``` diff --git a/docs/cn/build_and_install/README.md b/docs/cn/build_and_install/README.md index a40d571f5a..8be1f745a8 100755 --- a/docs/cn/build_and_install/README.md +++ b/docs/cn/build_and_install/README.md @@ -8,10 +8,10 @@ ## 自行编译安装 - [GPU部署环境](gpu.md) - [CPU部署环境](cpu.md) -- [CPU部署环境](ipu.md) +- [IPU部署环境](ipu.md) - [Jetson部署环境](jetson.md) - [Android平台部署环境](android.md) -- [瑞芯微RK1126部署环境](rk1126.md) +- [瑞芯微RV1126部署环境](rv1126.md) ## FastDeploy编译选项说明 @@ -22,6 +22,7 @@ | ENABLE_PADDLE_BACKEND | 默认OFF,是否编译集成Paddle Inference后端(CPU/GPU上推荐打开) | | ENABLE_LITE_BACKEND | 默认OFF,是否编译集成Paddle Lite后端(编译Android库时需要设置为ON) | | ENABLE_RKNPU2_BACKEND | 默认OFF,是否编译集成RKNPU2后端(RK3588/RK3568/RK3566上推荐打开) | +| ENABLE_TIMVX | 默认OFF,需要在RV1126/RV1109上部署时,需设置为ON | | ENABLE_TRT_BACKEND | 默认OFF,是否编译集成TensorRT后端(GPU上推荐打开) | | ENABLE_OPENVINO_BACKEND | 默认OFF,是否编译集成OpenVINO后端(CPU上推荐打开) | | ENABLE_VISION | 默认OFF,是否编译集成视觉模型的部署模块 | diff --git a/docs/cn/build_and_install/download_prebuilt_libraries.md b/docs/cn/build_and_install/download_prebuilt_libraries.md index 87ee4aa7e3..2f48c2c06e 100755 --- a/docs/cn/build_and_install/download_prebuilt_libraries.md +++ b/docs/cn/build_and_install/download_prebuilt_libraries.md @@ -20,7 +20,7 @@ FastDeploy提供各平台预编译库,供开发者直接下载安装使用。 ### Python安装 -Release版本(当前最新0.8.0)安装 +Release版本(当前最新1.0.0)安装 ```bash pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html ``` @@ -41,8 +41,8 @@ Release版本 | 平台 | 文件 | 说明 | | :--- | :--- | :---- | -| Linux x64 | [fastdeploy-linux-x64-gpu-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-0.8.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2编译产出 | -| Windows x64 | [fastdeploy-win-x64-gpu-0.8.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-0.8.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2编译产出 | +| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2编译产出 | +| Windows x64 | [fastdeploy-win-x64-gpu-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2编译产出 | Develop版本(Nightly build) @@ -63,7 +63,7 @@ Develop版本(Nightly build) ### Python安装 -Release版本(当前最新0.7.0)安装 +Release版本(当前最新1.0.0)安装 ```bash pip install fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html ``` @@ -79,16 +79,16 @@ Release版本 | 平台 | 文件 | 说明 | | :--- | :--- | :---- | -| Linux x64 | [fastdeploy-linux-x64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-0.8.0.tgz) | g++ 8.2编译产出 | -| Windows x64 | [fastdeploy-win-x64-0.8.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-0.8.0.zip) | Visual Studio 16 2019编译产出 | -| Mac OSX x64 | [fastdeploy-osx-x86_64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-0.8.0.tgz) | clang++ 10.0.0编译产出| -| Mac OSX arm64 | [fastdeploy-osx-arm64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-0.8.0.tgz) | clang++ 13.0.0编译产出 | -| Linux aarch64 | - | 自行编译,可集成ONNX Runtime、Paddle Lite后端 | +| Linux x64 | [fastdeploy-linux-x64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.0.tgz) | g++ 8.2编译产出 | +| Windows x64 | [fastdeploy-win-x64-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.0.zip) | Visual Studio 16 2019编译产出 | +| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.0.tgz) | clang++ 10.0.0编译产出| +| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.0.tgz) | clang++ 13.0.0编译产出 | +| Linux aarch64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.0.tgz) | gcc 6.3编译产出 | | Android armv7&v8 | [fastdeploy-android-1.0.0-shared.tgz](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-1.0.0-shared.tgz) | NDK 25及clang++编译产出, 支持arm64-v8a及armeabi-v7a | ## Java SDK安装 -Release版本(Java SDK 目前仅支持Android,版本为1.0.0 pre-release) +Release版本(Java SDK 目前仅支持Android,版本为1.0.0) | 平台 | 文件 | 说明 | | :--- | :--- | :---- | diff --git a/docs/cn/build_and_install/rk1126.md b/docs/cn/build_and_install/rk1126.md deleted file mode 100755 index 4eda019810..0000000000 --- a/docs/cn/build_and_install/rk1126.md +++ /dev/null @@ -1,63 +0,0 @@ -# 瑞芯微 RK1126 部署环境编译安装 - -FastDeploy基于 Paddle-Lite 后端支持在瑞芯微(Rockchip)Soc 上进行部署推理。 -更多详细的信息请参考:[PaddleLite部署示例](https://paddle-lite.readthedocs.io/zh/develop/demo_guides/verisilicon_timvx.html)。 - -本文档介绍如何编译基于 PaddleLite 的 C++ FastDeploy 交叉编译库。 - -相关编译选项说明如下: -|编译选项|默认值|说明|备注| -|:---|:---|:---|:---| -|ENABLE_LITE_BACKEND|OFF|编译RK库时需要设置为ON| - | - -更多编译选项请参考[FastDeploy编译选项说明](./README.md) - -## 交叉编译环境搭建 - -### 宿主机环境需求 -- os:Ubuntu == 16.04 -- cmake: version >= 3.10.0 - -### 环境搭建 -```bash - # 1. Install basic software -apt update -apt-get install -y --no-install-recommends \ - gcc g++ git make wget python unzip - -# 2. Install arm gcc toolchains -apt-get install -y --no-install-recommends \ - g++-arm-linux-gnueabi gcc-arm-linux-gnueabi \ - g++-arm-linux-gnueabihf gcc-arm-linux-gnueabihf \ - gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - -# 3. Install cmake 3.10 or above -wget -c https://mms-res.cdn.bcebos.com/cmake-3.10.3-Linux-x86_64.tar.gz && \ - tar xzf cmake-3.10.3-Linux-x86_64.tar.gz && \ - mv cmake-3.10.3-Linux-x86_64 /opt/cmake-3.10 && \ - ln -s /opt/cmake-3.10/bin/cmake /usr/bin/cmake && \ - ln -s /opt/cmake-3.10/bin/ccmake /usr/bin/ccmake -``` - -## 基于 PaddleLite 的 FastDeploy 交叉编译库编译 -搭建好交叉编译环境之后,编译命令如下: -```bash -# Download the latest source code -git clone https://github.com/PaddlePaddle/FastDeploy.git -cd FastDeploy -mkdir build && cd build - -# CMake configuration with RK toolchain -cmake -DCMAKE_TOOLCHAIN_FILE=./../cmake/timvx.cmake \ - -DENABLE_TIMVX=ON \ - -DCMAKE_INSTALL_PREFIX=fastdeploy-tmivx \ - -DENABLE_VISION=ON \ # 是否编译集成视觉模型的部署模块,可选择开启 - -Wno-dev .. - -# Build FastDeploy RK1126 C++ SDK -make -j8 -make install -``` -编译完成之后,会生成 fastdeploy-tmivx 目录,表示基于 PadddleLite TIM-VX 的 FastDeploy 库编译完成。 - -RK1126 上部署 PaddleClas 分类模型请参考:[PaddleClas RK1126开发板 C++ 部署示例](../../../examples/vision/classification/paddleclas/rk1126/README.md) diff --git a/docs/cn/build_and_install/rv1126.md b/docs/cn/build_and_install/rv1126.md new file mode 100755 index 0000000000..f3cd4ed6a7 --- /dev/null +++ b/docs/cn/build_and_install/rv1126.md @@ -0,0 +1,100 @@ +# 瑞芯微 RV1126 部署环境编译安装 + +FastDeploy基于 Paddle-Lite 后端支持在瑞芯微(Rockchip)Soc 上进行部署推理。 +更多详细的信息请参考:[PaddleLite部署示例](https://www.paddlepaddle.org.cn/lite/develop/demo_guides/verisilicon_timvx.html)。 + +本文档介绍如何编译基于 PaddleLite 的 C++ FastDeploy 交叉编译库。 + +相关编译选项说明如下: +|编译选项|默认值|说明|备注| +|:---|:---|:---|:---| +|ENABLE_LITE_BACKEND|OFF|编译RK库时需要设置为ON| - | +|ENABLE_TIMVX|OFF|编译RK库时需要设置为ON| - | + +更多编译选项请参考[FastDeploy编译选项说明](./README.md) + +## 交叉编译环境搭建 + +### 宿主机环境需求 +- os:Ubuntu == 16.04 +- cmake: version >= 3.10.0 + +### 环境搭建 +```bash + # 1. Install basic software +apt update +apt-get install -y --no-install-recommends \ + gcc g++ git make wget python unzip + +# 2. Install arm gcc toolchains +apt-get install -y --no-install-recommends \ + g++-arm-linux-gnueabi gcc-arm-linux-gnueabi \ + g++-arm-linux-gnueabihf gcc-arm-linux-gnueabihf \ + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + +# 3. Install cmake 3.10 or above +wget -c https://mms-res.cdn.bcebos.com/cmake-3.10.3-Linux-x86_64.tar.gz && \ + tar xzf cmake-3.10.3-Linux-x86_64.tar.gz && \ + mv cmake-3.10.3-Linux-x86_64 /opt/cmake-3.10 && \ + ln -s /opt/cmake-3.10/bin/cmake /usr/bin/cmake && \ + ln -s /opt/cmake-3.10/bin/ccmake /usr/bin/ccmake +``` + +## 基于 PaddleLite 的 FastDeploy 交叉编译库编译 +搭建好交叉编译环境之后,编译命令如下: +```bash +# Download the latest source code +git clone https://github.com/PaddlePaddle/FastDeploy.git +cd FastDeploy +mkdir build && cd build + +# CMake configuration with RK toolchain +cmake -DCMAKE_TOOLCHAIN_FILE=./../cmake/timvx.cmake \ + -DENABLE_TIMVX=ON \ + -DCMAKE_INSTALL_PREFIX=fastdeploy-tmivx \ + -DENABLE_VISION=ON \ # 是否编译集成视觉模型的部署模块,可选择开启 + -Wno-dev .. + +# Build FastDeploy RV1126 C++ SDK +make -j8 +make install +``` +编译完成之后,会生成 fastdeploy-tmivx 目录,表示基于 PadddleLite TIM-VX 的 FastDeploy 库编译完成。 + +## 准备设备运行环境 +部署前要保证芯原 Linux Kernel NPU 驱动 galcore.so 版本及所适用的芯片型号与依赖库保持一致,在部署前,请登录开发板,并通过命令行输入以下命令查询 NPU 驱动版本,Rockchip建议的驱动版本为: 6.4.6.5 +```bash +dmesg | grep Galcore +``` + +如果当前版本不符合上述,请用户仔细阅读以下内容,以保证底层 NPU 驱动环境正确。 + +有两种方式可以修改当前的 NPU 驱动版本: +1. 手动替换 NPU 驱动版本。(推荐) +2. 刷机,刷取 NPU 驱动版本符合要求的固件。 + +### 手动替换 NPU 驱动版本 +1. 使用如下命令下载解压 PaddleLite demo,其中提供了现成的驱动文件 +```bash +wget https://paddlelite-demo.bj.bcebos.com/devices/generic/PaddleLite-generic-demo.tar.gz +tar -xf PaddleLite-generic-demo.tar.gz +``` +2. 使用 `uname -a` 查看 `Linux Kernel` 版本,确定为 `Linux` 系统 4.19.111 版本, +3. 将 `PaddleLite-generic-demo/libs/PaddleLite/linux/armhf/lib/verisilicon_timvx/viv_sdk_6_4_6_5/lib/1126/4.19.111/` 路径下的 `galcore.ko` 上传至开发板。 + +4. 登录开发板,命令行输入 `sudo rmmod galcore` 来卸载原始驱动,输入 `sudo insmod galcore.ko` 来加载传上设备的驱动。(是否需要 sudo 根据开发板实际情况,部分 adb 链接的设备请提前 adb root)。此步骤如果操作失败,请跳转至方法 2。 +5. 在开发板中输入 `dmesg | grep Galcore` 查询 NPU 驱动版本,确定为:6.4.6.5 + +### 刷机 +根据具体的开发板型号,向开发板卖家或官网客服索要 6.4.6.5 版本 NPU 驱动对应的固件和刷机方法。 + +更多细节请参考:[PaddleLite准备设备环境](https://www.paddlepaddle.org.cn/lite/develop/demo_guides/verisilicon_timvx.html#zhunbeishebeihuanjing) + +## 基于 FastDeploy 在 RV1126 上的部署示例 +1. RV1126 上部署 PaddleClas 分类模型请参考:[PaddleClas 分类模型在 RV1126 上的 C++ 部署示例](../../../examples/vision/classification/paddleclas/rv1126/README.md) + +2. RV1126 上部署 PPYOLOE 检测模型请参考:[PPYOLOE 检测模型在 RV1126 上的 C++ 部署示例](../../../examples/vision/detection/paddledetection/rv1126/README.md) + +3. RV1126 上部署 YOLOv5 检测模型请参考:[YOLOv5 检测模型在 RV1126 上的 C++ 部署示例](../../../examples/vision/detection/yolov5/rv1126/README.md) + +4. RV1126 上部署 PP-LiteSeg 分割模型请参考:[PP-LiteSeg 分割模型在 RV1126 上的 C++ 部署示例](../../../examples/vision/segmentation/paddleseg/rv1126/README.md) diff --git a/docs/cn/faq/custom_opencv.md b/docs/cn/faq/custom_opencv.md new file mode 100644 index 0000000000..2f697a0a1a --- /dev/null +++ b/docs/cn/faq/custom_opencv.md @@ -0,0 +1,35 @@ +[English](../../en/faq/custom_opencv.md) | 中文 + +# 自定义OpenCV版本 + +受限于不同平台限制,目前FastDeploy提供的预编译包在**Linux平台**内置的OpenCV无法读取视频,或调用`imshow`等操作。对于有这类需求的开发者,可根据本文档来自行编译FastDeploy。 + +FastDeploy目前支持通过`-DOPENCV_DIRECTORY`来指定环境中的OpenCV版本,以Ubuntu为例,我们可以按照如下方式编译安装。 + + +## CPU C++ SDK + +### 1. 安装Opencv +``` +sudo apt-get install libopencv-dev +``` + +### 2. 指定OpenCV编译FastDeploy +``` +git clone https://github.com/PaddlePaddle/FastDeploy +cd FastDeploy +mkdir build && cd build +cmake .. -DENABLE_ORT_BACKEND=ON \ + -DENABLE_PADDLE_BACKEND=ON \ + -DENABLE_OPENVINO_BACKEND=ON \ + -DENABLE_VISION=ON \ + -DCMAKE_INSTALL_PREFIX=${PWD}/installed_fastdeploy \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 +make -j8 +make install +``` +编译完成的C++ SDK即为当前目录下的`installed_fastdeploy`,使用这个新的SDK即可。 + +其它部署硬件上的编译方式同理,通过`-DOPENCV_DIRECTORY`指定环境中的OpenCV编译即可, 注意此处的路径`/usr/lib/x86_64-linux-gnu/cmake/opencv4`需根据你的实际环境路径来设定,此目录下包含`OpenCVConfig-version.cmake`、`OpenCVConfig.cmake`等文件。 + +- [FastDeploy更多部署环境的编译](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/README_CN.md) diff --git a/docs/cn/quantize.md b/docs/cn/quantize.md old mode 100644 new mode 100755 index 57f5837d8a..26a75ec4eb --- a/docs/cn/quantize.md +++ b/docs/cn/quantize.md @@ -36,7 +36,7 @@ FastDeploy基于PaddleSlim的Auto Compression Toolkit(ACT), 给用户提供了 目前, FastDeploy支持自动化压缩,并完成部署测试的模型的Runtime Benchmark和端到端Benchmark如下所示. Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -63,7 +63,7 @@ Benchmark表格说明: | [YOLOv7](../../examples/vision/detection/yolov7/quantize/) | Paddle Inference | CPU | 995.85 | 477.93|None|None | 2.08 |51.1 | 46.2|量化蒸馏训练 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [YOLOv5s](../../examples/vision/detection/yolov5/quantize/) | TensorRT | GPU | 24.61 | 21.20 | 20.78 | 20.94 | 1.18 | 37.6 | 36.7 | 量化蒸馏训练 | | [YOLOv5s](../../examples/vision/detection/yolov5/quantize/) | Paddle-TensorRT | GPU | 23.53 | None | 21.98 | 19.84 | 1.28 | 37.6 | 36.8 | 量化蒸馏训练 | @@ -94,7 +94,7 @@ Benchmark表格说明: | [MobileNetV1_ssld](../../examples/vision/classification/paddleclas/quantize/) | Paddle Inference | CPU | 12.29 | 4.68 | None|None|2.62 |77.89 | 71.36 |离线量化 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 Top1 | INT8 Top1 | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 Top1 | INT8 Top1 | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [ResNet50_vd](../../examples/vision/classification/paddleclas/quantize/) | TensorRT | GPU | 4.92| 2.28|2.24|2.23 | 2.21 | 79.12 | 79.06 | 离线量化 | | [ResNet50_vd](../../examples/vision/classification/paddleclas/quantize/) | Paddle-TensorRT | GPU | 4.48|None |2.09|2.10 | 2.14 | 79.12 | 79.06 | 离线量化 | @@ -119,7 +119,7 @@ NOTE: - TensorRT比Paddle-TensorRT快的原因是在runtime移除了multiclass_nms3算子 #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [ppyoloe_crn_l_300e_coco](../../examples/vision/detection/paddledetection/quantize ) | TensorRT | GPU | 35.75 | 15.42 |20.70|20.85 | 2.32 | 51.4 | 50.7 | 量化蒸馏训练 | | [ppyoloe_crn_l_300e_coco](../../examples/vision/detection/paddledetection/quantize ) | Paddle-TensorRT | GPU | 33.48 |None | 18.47 |18.03 | 1.81 | 51.4 | 50.5| 量化蒸馏训练 | @@ -134,6 +134,6 @@ NOTE: | [PP-LiteSeg-T(STDC1)-cityscapes](../../examples/vision/segmentation/paddleseg/quantize) | Paddle Inference | CPU | 1138.04| 602.62 |None|None | 1.89 |77.37 | 71.62 |量化蒸馏训练 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mIoU | INT8 mIoU | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mIoU | INT8 mIoU | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [PP-LiteSeg-T(STDC1)-cityscapes](../../examples/vision/segmentation/paddleseg/quantize) | Paddle Inference | CPU | 4726.65| 4134.91|None|None | 1.14 |77.37 | 71.62 |量化蒸馏训练 | diff --git a/docs/cn/quick_start/models/cpp.md b/docs/cn/quick_start/models/cpp.md index b99f122995..8b1d3ee28e 100644 --- a/docs/cn/quick_start/models/cpp.md +++ b/docs/cn/quick_start/models/cpp.md @@ -68,7 +68,7 @@ target_link_libraries(infer_demo ${FASTDEPLOY_LIBS}) ## 4. 编译可执行程序 -假设当前目录已经准备好`infer_demo.cc`和`CMakeLists.txt`两个文件,目录结构如下所示,即可进行编译 +假设当前目录已经准备好`infer_demo.cc`和`CMakeLists.txt`两个文件,即可进行编译 ### Linux & Mac diff --git a/docs/en/build_and_install/download_prebuilt_libraries.md b/docs/en/build_and_install/download_prebuilt_libraries.md index 779afe0818..52dbdd627b 100644 --- a/docs/en/build_and_install/download_prebuilt_libraries.md +++ b/docs/en/build_and_install/download_prebuilt_libraries.md @@ -1,3 +1,4 @@ +English | [中文](../../cn/build_and_install/download_prebuilt_libraries.md) # How to Install Prebuilt Library FastDeploy provides pre-built libraries for developers to download and install directly. Meanwhile, FastDeploy also offers easy access to compile so that developers can compile FastDeploy according to their own needs. @@ -21,7 +22,7 @@ FastDeploy supports Computer Vision, Text and NLP model deployment on CPU and Nv ### Python SDK -Install the released version(the newest 0.8.0 for now) +Install the released version(the newest 1.0.0 for now) ``` pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html @@ -41,12 +42,12 @@ conda config --add channels conda-forge && conda install cudatoolkit=11.2 cudnn= ### C++ SDK -Install the released version(Latest 0.8.0) +Install the released version(Latest 1.0.0) | Platform | File | Description | |:----------- |:--------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------- | -| Linux x64 | [fastdeploy-linux-x64-gpu-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-0.8.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2 | -| Windows x64 | [fastdeploy-win-x64-gpu-0.8.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-0.8.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2 | +| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2 | +| Windows x64 | [fastdeploy-win-x64-gpu-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2 | Install the Develop version(Nightly build) @@ -68,7 +69,7 @@ FastDeploy supports computer vision, text and NLP model deployment on CPU with P ### Python SDK -Install the released version(Latest 0.8.0 for now) +Install the released version(Latest 1.0.0 for now) ``` pip install fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html @@ -82,15 +83,15 @@ pip install fastdeploy-python==0.0.0 -f https://www.paddlepaddle.org.cn/whl/fast ### C++ SDK -Install the released version(Latest 0.8.0 for now, Android is 1.0.0 pre-release) +Install the released version(Latest 1.0.0 for now, Android is 1.0.0) | Platform | File | Description | |:------------- |:--------------------------------------------------------------------------------------------------------------------- |:------------------------------ | -| Linux x64 | [fastdeploy-linux-x64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-0.8.0.tgz) | g++ 8.2 | -| Windows x64 | [fastdeploy-win-x64-0.8.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-0.8.0.zip) | Visual Studio 16 2019 | -| Mac OSX x64 | [fastdeploy-osx-x86_64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-0.8.0.tgz) | clang++ 10.0.0| -| Mac OSX arm64 | [fastdeploy-osx-arm64-0.8.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-0.8.0.tgz) | clang++ 13.0.0 | -| Linux aarch64 | - | - | +| Linux x64 | [fastdeploy-linux-x64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.0.tgz) | g++ 8.2 | +| Windows x64 | [fastdeploy-win-x64-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.0.zip) | Visual Studio 16 2019 | +| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.0.tgz) | clang++ 10.0.0| +| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.0.tgz) | clang++ 13.0.0 | +| Linux aarch64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.0.tgz) | gcc 6.3 | | Android armv7&v8 | [fastdeploy-android-1.0.0-shared.tgz](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-1.0.0-shared.tgz)| NDK 25, clang++, support arm64-v8a及armeabi-v7a | ## Java SDK diff --git a/docs/en/faq/custom_opencv.md b/docs/en/faq/custom_opencv.md new file mode 100644 index 0000000000..41ccc72c6e --- /dev/null +++ b/docs/en/faq/custom_opencv.md @@ -0,0 +1,37 @@ +English | [中文](../../cn/faq/custom_opencv.md) + +# Use Own OpenCV Library + +The prebuilt FastDeploy library has a built-in OpenCV library, which is not able to read video file or call `imshow` because the prebuilt FastDeploy has to build in manylinux version. If you need to read video or other functions provided by opencv, this document shows how to build FastDeploy with your own OpenCV in your environment. + +FastDeploy provides flag `-DOPENCV_DIRECTORY` to set path of OpenCV library, the following steps show how to build CPU C++ SDK on Ubuntu. + +## CPU C++ SDK + +### 1. Install OpenCV + +``` +sudo apt-get install libopencv-dev +``` + +### 2. Build FastDeploy + +``` +git clone https://github.com/PaddlePaddle/FastDeploy +cd FastDeploy +mkdir build && cd build +cmake .. -DENABLE_ORT_BACKEND=ON \ + -DENABLE_PADDLE_BACKEND=ON \ + -DENABLE_OPENVINO_BACKEND=ON \ + -DENABLE_VISION=ON \ + -DCMAKE_INSTALL_PREFIX=${PWD}/installed_fastdeploy \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 +make -j8 +make install +``` + +Now we get the C++ SDK in current directory `installed_fastdeploy`, this library can use all the functions from your own OpenCV library. + +This document also works for other hardware deployment(GPU/IPU/XPU...) on Linux platform. + +- [More Options to build FastDeploy](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/README_EN.md) diff --git a/examples/multimodal/stable_diffusion/cpp/CMakeLists.txt b/examples/multimodal/stable_diffusion/cpp/CMakeLists.txt new file mode 100644 index 0000000000..33b4afb93a --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2022 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. + +PROJECT(main C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10) + +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") +set(THIRD_LIBS "") +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +include_directories(${FASTDEPLOY_INCS}) + +file(GLOB_RECURSE ALL_SRCS ${PROJECT_SOURCE_DIR}/*.cc) + +add_executable(main ${ALL_SRCS}) +target_link_libraries(main ${FASTDEPLOY_LIBS} ${THIRD_LIBS}) diff --git a/examples/multimodal/stable_diffusion/cpp/README.md b/examples/multimodal/stable_diffusion/cpp/README.md new file mode 100644 index 0000000000..06d085febb --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/README.md @@ -0,0 +1,12 @@ +# StableDiffusion C++部署示例 + +在部署前,需确认以下两个步骤 + +- 1. 软硬件环境满足要求,参考[FastDeploy环境要求](../../../../docs/cn/build_and_install/download_prebuilt_libraries.md) +- 2. 根据开发环境,下载预编译部署库和samples代码,参考[FastDeploy预编译库](../../../../docs/cn/build_and_install/download_prebuilt_libraries.md) + +本目录下提供`*_infer.cc`快速完成StableDiffusion各任务的C++部署示例。 + +## Inpaint任务 + +StableDiffusion Inpaint任务是一个根据提示文本补全图片的任务,具体而言就是用户给定提示文本,原始图片以及原始图片的mask图片,该任务输出补全后的图片。 diff --git a/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.cc b/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.cc new file mode 100644 index 0000000000..b61c5b5db1 --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.cc @@ -0,0 +1,398 @@ +// Copyright (c) 2022 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. + +#include "dpm_solver_multistep_scheduler.h" +#include "fastdeploy/core/fd_scalar.h" +#include "fastdeploy/function/functions.h" +#include +#include + +namespace fastdeploy { + +void DPMSolverMultistepScheduler::BetaForAlphaBar(FDTensor* out, + int num_diffusion_timesteps, + float max_beta) { + auto alpha_bar = [](float time_step) -> float { + constexpr float pi = 3.14159265358979323846; + return std::pow(std::cos((time_step + 0.008) / 1.008 * pi / 2), 2); + }; + std::vector betas; + for (int i = 0; i < num_diffusion_timesteps; ++i) { + float t1 = i / num_diffusion_timesteps; + float t2 = (i + 1) / num_diffusion_timesteps; + float beta_val = (std::min)(1 - alpha_bar(t1) / alpha_bar(t2), max_beta); + betas.emplace_back(Scalar(beta_val)); + } + function::Concat(betas, out); +} + +DPMSolverMultistepScheduler::DPMSolverMultistepScheduler( + int num_train_timesteps, float beta_start, float beta_end, + const std::string& beta_schedule, const std::vector& trained_betas, + int solver_order, bool predict_epsilon, bool thresholding, + float dynamic_thresholding_ratio, float sample_max_value, + const std::string& algorithm_type, const std::string& solver_type, + bool lower_order_final) + : config({num_train_timesteps, beta_start, beta_end, beta_schedule, + solver_order, predict_epsilon, thresholding, + dynamic_thresholding_ratio, sample_max_value, algorithm_type, + solver_type, lower_order_final}) { + int beta_size = trained_betas.size(); + if (beta_size > 0) { + betas_.Allocate({beta_size}, FDDataType::FP32); + std::copy(trained_betas.data(), trained_betas.data() + beta_size, + reinterpret_cast(betas_.Data())); + } else if (beta_schedule == "linear") { + function::Linspace(beta_start, beta_end, num_train_timesteps, &betas_, + FDDataType::FP32); + } else if (beta_schedule == "scaled_linear") { + function::Linspace(std::sqrt(beta_start), std::sqrt(beta_end), + num_train_timesteps, &betas_, FDDataType::FP32); + betas_ = betas_ * betas_; + } else if (beta_schedule == "squaredcos_cap_v2") { + BetaForAlphaBar(&betas_, num_train_timesteps); + } else { + FDASSERT(false, "%s is not implemented for DPMSolverMultistepScheduler", + beta_schedule.c_str()); + } + + alphas_ = 1.0f - betas_; + function::Cumprod(alphas_, &alphas_cumprod_); + function::Sqrt(alphas_cumprod_, &alpha_t_); + function::Sqrt(1.0f - alphas_cumprod_, &sigma_t_); + FDTensor alpha_t_log, sigma_t_log; + function::Log(alpha_t_, &alpha_t_log); + function::Log(sigma_t_, &sigma_t_log); + lambda_t_ = alpha_t_log - sigma_t_log; + + FDASSERT(config.algorithm_type_ == "dpmsolver" || + config.algorithm_type_ == "dpmsolver++", + "%s does is not implemented for DPMSolverMultistepScheduler", + config.algorithm_type_.c_str()); + FDASSERT(config.solver_type_ == "midpoint" || config.solver_type_ == "heun", + "%s does is not implemented for DPMSolverMultistepScheduler", + config.solver_type_.c_str()); + num_inference_steps_ = -1; + + function::Linspace(0, config.num_train_timesteps_ - 1, + config.num_train_timesteps_, ×teps_); + function::Cast(timesteps_, ×teps_, FDDataType::INT64); + // Reverse timesteps + int64_t* timesteps_data = reinterpret_cast(timesteps_.Data()); + std::reverse(timesteps_data, timesteps_data + timesteps_.Numel()); + + model_outputs_.resize(config.solver_order_); + lower_order_nums_ = 0; +} + +float DPMSolverMultistepScheduler::InitNoiseSigma() { return 1.0; } + +void DPMSolverMultistepScheduler::ConvertModelOutput( + const FDTensor& model_output, int timestep, const FDTensor& sample, + FDTensor* out) { + if (config.algorithm_type_ == "dpmsolver++") { + FDTensor x0_pred; + if (config.predict_epsilon_) { + FDTensor alpha_t, sigma_t; + function::Slice(alpha_t_, {0}, {timestep}, &alpha_t); + function::Slice(sigma_t_, {0}, {timestep}, &sigma_t); + x0_pred = (sample - sigma_t * model_output) / alpha_t; + } else { + x0_pred = model_output; + } + if (config.thresholding_) { + FDTensor dynamic_max_val, x0_pred_abs; + function::Abs(x0_pred, &x0_pred_abs); + x0_pred_abs.Reshape({x0_pred_abs.Shape()[0], -1}); + function::Quantile(x0_pred_abs, {config.dynamic_thresholding_ratio_}, {1}, + &dynamic_max_val); + + FDTensor max_value, dy_max_val; + function::FullLike(dynamic_max_val, config.sample_max_value_, &max_value, + dynamic_max_val.Dtype()); + function::Maximum(dynamic_max_val, max_value, &dy_max_val); + int expand_dims = x0_pred.Shape().size() - 1; + for (int i = 0; i < expand_dims; ++i) { + dy_max_val.ExpandDim(dy_max_val.Shape().size()); + } + float clip_max = reinterpret_cast(dy_max_val.Data())[0]; + function::Clip(x0_pred, -clip_max, clip_max, &x0_pred); + x0_pred = x0_pred / dy_max_val; + } + *out = std::move(x0_pred); + } else if (config.algorithm_type_ == "dpmsolver") { + if (config.predict_epsilon_) { + *out = model_output; + } else { + FDTensor alpha_t, sigma_t; + function::Slice(alpha_t_, {0}, {timestep}, &alpha_t); + function::Slice(sigma_t_, {0}, {timestep}, &sigma_t); + *out = (sample - (alpha_t * model_output)) / sigma_t; + } + } +} + +void DPMSolverMultistepScheduler::DPMSolverFirstOrderUpdate( + const FDTensor& model_output, int timestep, int prev_timestep, + const FDTensor& sample, FDTensor* out) { + FDTensor lambda_t, lambda_s; + function::Slice(lambda_t_, {0}, {prev_timestep}, &lambda_t); + function::Slice(lambda_t_, {0}, {timestep}, &lambda_s); + + FDTensor alpha_t, alpha_s; + function::Slice(alpha_t_, {0}, {prev_timestep}, &alpha_t); + function::Slice(alpha_t_, {0}, {timestep}, &alpha_s); + + FDTensor sigma_t, sigma_s; + function::Slice(sigma_t_, {0}, {prev_timestep}, &sigma_t); + function::Slice(sigma_t_, {0}, {timestep}, &sigma_s); + + FDTensor h = lambda_t - lambda_s; + if (config.algorithm_type_ == "dpmsolver++") { + function::Exp(0.0f - h, &h); + *out = (sigma_t / sigma_s) * sample - (alpha_t * (h - 1.0f)) * model_output; + } else if (config.algorithm_type_ == "dpmsolver") { + function::Exp(h, &h); + *out = (alpha_t / alpha_s) * sample - (sigma_t * (h - 1.0f)) * model_output; + } +} + +void DPMSolverMultistepScheduler::MultiStepDPMSolverSecondOrderUpdate( + const std::vector& model_output_list, + const std::vector& timestep_list, int prev_timestep, + const FDTensor& sample, FDTensor* out) { + int timestep_size = timestep_list.size(); + int model_output_size = model_output_list.size(); + int t = prev_timestep; + int s0 = timestep_list[timestep_size - 1]; + int s1 = timestep_list[timestep_size - 2]; + const FDTensor& m0 = model_output_list[model_output_size - 1]; + const FDTensor& m1 = model_output_list[model_output_size - 2]; + FDTensor lambda_t, lambda_s0, lambda_s1; + function::Slice(lambda_t_, {0}, {t}, &lambda_t); + function::Slice(lambda_t_, {0}, {s0}, &lambda_s0); + function::Slice(lambda_t_, {0}, {s1}, &lambda_s1); + + FDTensor alpha_t, alpha_s0, sigma_t, sigma_s0; + function::Slice(alpha_t_, {0}, {t}, &alpha_t); + function::Slice(alpha_t_, {0}, {s0}, &alpha_s0); + function::Slice(sigma_t_, {0}, {t}, &sigma_t); + function::Slice(sigma_t_, {0}, {s0}, &sigma_s0); + + FDTensor h = lambda_t - lambda_s0; + FDTensor h0 = lambda_s0 - lambda_s1; + FDTensor r0 = h0 / h; + FDTensor D0 = m0; + FDTensor D1 = (1.0f / r0) * (m0 - m1); + if (config.algorithm_type_ == "dpmsolver++") { + if (config.solver_type_ == "midpoint") { + function::Exp(0.0f - h, &h); + *out = (sigma_t / sigma_s0 * sample) - (alpha_t * (h - 1.0f) * D0) - + (0.5f * alpha_t * (h - 1.0f) * D1); + } else if (config.solver_type_ == "heun") { + FDTensor h_exp; + function::Exp(0.0f - h, &h_exp); + *out = (sigma_t / sigma_s0 * sample) - (alpha_t * (h_exp - 1.0f) * D0) + + (alpha_t * ((h_exp - 1.0f) / h + 1.0f) * D1); + } + } else if (config.algorithm_type_ == "dpmsolver") { + FDTensor h_exp; + function::Exp(h, &h_exp); + if (config.solver_type_ == "midpoint") { + *out = alpha_t / alpha_s0 * sample - sigma_t * (h_exp - 1.0f) * D0 - + 0.5 * (sigma_t * (h_exp - 1.0f) * D1); + } else if (config.solver_type_ == "heun") { + *out = alpha_t / alpha_s0 * sample - sigma_t * (h_exp - 1.0f) * D0 - + (sigma_t * ((h_exp - 1.0f) / h - 1.0f) * D1); + } + } +} + +void DPMSolverMultistepScheduler::MultiStepDPMSolverThirdOrderUpdate( + const std::vector& model_output_list, + const std::vector& timestep_list, int prev_timestep, + const FDTensor& sample, FDTensor* out) { + int timestep_size = timestep_list.size(); + int model_output_size = model_output_list.size(); + int t = prev_timestep; + + int s0 = timestep_list[timestep_size - 1]; + int s1 = timestep_list[timestep_size - 2]; + int s2 = timestep_list[timestep_size - 3]; + const FDTensor& m0 = model_output_list[model_output_size - 1]; + const FDTensor& m1 = model_output_list[model_output_size - 2]; + const FDTensor& m2 = model_output_list[model_output_size - 3]; + + FDTensor lambda_t, lambda_s0, lambda_s1, lambda_s2; + function::Slice(lambda_t_, {0}, {t}, &lambda_t); + function::Slice(lambda_t_, {0}, {s0}, &lambda_s0); + function::Slice(lambda_t_, {0}, {s1}, &lambda_s1); + function::Slice(lambda_t_, {0}, {s2}, &lambda_s2); + + FDTensor alpha_t, alpha_s0, sigma_t, sigma_s0; + function::Slice(alpha_t_, {0}, {t}, &alpha_t); + function::Slice(alpha_t_, {0}, {s0}, &alpha_s0); + function::Slice(sigma_t_, {0}, {t}, &sigma_t); + function::Slice(sigma_t_, {0}, {s0}, &sigma_s0); + + FDTensor h = lambda_t - lambda_s0; + FDTensor h0 = lambda_s0 - lambda_s1; + FDTensor h1 = lambda_s1 - lambda_s2; + + FDTensor r0 = h0 / h; + FDTensor r1 = h1 / h; + FDTensor D0 = m0; + FDTensor D1_0 = (1.0f / r0) * (m0 - m1); + FDTensor D1_1 = (1.0f / r1) * (m1 - m2); + FDTensor D1 = D1_0 + (r0 / (r0 + r1)) * (D1_0 - D1_1); + FDTensor D2 = (1.0f / (r0 + r1)) * (D1_0 - D1_1); + + if (config.algorithm_type_ == "dpmsolver++") { + FDTensor h_exp; + function::Exp(0.0f - h, &h_exp); + *out = (sigma_t / sigma_s0) * sample - (alpha_t * (h_exp - 1.0f)) * D0 + + (alpha_t * ((h_exp - 1.0) / h + 1.0)) * D1 - + (alpha_t * ((h_exp - 1.0 + h) / (h * h) - 0.5)) * D2; + + } else if (config.algorithm_type_ == "dpmsolver") { + FDTensor h_exp; + function::Exp(h, &h_exp); + *out = (alpha_t / alpha_s0) * sample - (sigma_t * (h_exp - 1.0f)) * D0 + + (sigma_t * ((h_exp - 1.0) / h - 1.0)) * D1 - + (sigma_t * ((h_exp - 1.0 - h) / (h * h) - 0.5)) * D2; + } +} + +void DPMSolverMultistepScheduler::ScaleModelInput( + const FDTensor& sample, FDTensor* out, + const std::vector& timesteps) { + *out = sample; +} + +void DPMSolverMultistepScheduler::SetTimesteps(int num_inference_steps) { + num_inference_steps_ = num_inference_steps; + function::Linspace(0, config.num_train_timesteps_ - 1, + num_inference_steps + 1, ×teps_); + function::Round(timesteps_, ×teps_); + // Reverse timesteps + float* timesteps_data = reinterpret_cast(timesteps_.Data()); + std::reverse(timesteps_data, timesteps_data + timesteps_.Numel()); + FDTensor timestep_tmp; + timestep_tmp.Allocate({num_inference_steps}, timesteps_.Dtype()); + float* timestep_tmp_data = reinterpret_cast(timestep_tmp.Data()); + std::copy(timesteps_data, timesteps_data + num_inference_steps, + timestep_tmp_data); + timesteps_ = std::move(timestep_tmp); + + function::Cast(timesteps_, ×teps_, FDDataType::INT64); + + model_outputs_.clear(); + model_outputs_.resize(config.solver_order_); + + lower_order_nums_ = 0; +} + +void DPMSolverMultistepScheduler::Step(const FDTensor& model_output, + int timestep, const FDTensor& sample, + FDTensor* prev_sample) { + FDASSERT(num_inference_steps_ > -1, + "Number of inference steps is -1, you need to run SetTimesteps " + "after creating the scheduler"); + int64_t step_index = timesteps_.Numel() - 1; + int64_t* timesteps_data = reinterpret_cast(timesteps_.Data()); + int64_t* timesteps_iter = + std::find(timesteps_data, timesteps_data + timesteps_.Numel(), timestep); + if (timesteps_iter - timesteps_data < timesteps_.Numel()) { + step_index = timesteps_iter - timesteps_data; + } + int64_t prev_timestep = 0; + if (step_index != timesteps_.Numel() - 1) { + prev_timestep = timesteps_data[step_index + 1]; + } + bool lower_order_final = (step_index == timesteps_.Numel() - 1) && + config.lower_order_final_ && + (timesteps_.Numel() < 15); + bool lower_order_second = (step_index == timesteps_.Numel() - 2) && + config.lower_order_final_ && + (timesteps_.Numel() < 15); + FDTensor model_out; + ConvertModelOutput(model_output, timestep, sample, &model_out); + for (int i = 0; i < config.solver_order_ - 1; ++i) { + model_outputs_[i] = std::move(model_outputs_[i + 1]); + } + model_outputs_[config.solver_order_ - 1] = std::move(model_out); + + if (config.solver_order_ == 1 || lower_order_nums_ < 1 || lower_order_final) { + DPMSolverFirstOrderUpdate(model_outputs_[config.solver_order_ - 1], + timestep, prev_timestep, sample, prev_sample); + } else if (config.solver_order_ == 2 || lower_order_nums_ < 2 || + lower_order_second) { + int t0 = reinterpret_cast(timesteps_.Data())[step_index - 1]; + std::vector timestep_list = {t0, timestep}; + MultiStepDPMSolverSecondOrderUpdate(model_outputs_, timestep_list, + prev_timestep, sample, prev_sample); + } else { + int t0 = reinterpret_cast(timesteps_.Data())[step_index - 1]; + int t1 = reinterpret_cast(timesteps_.Data())[step_index - 2]; + std::vector timestep_list = {t1, t0, timestep}; + MultiStepDPMSolverThirdOrderUpdate(model_outputs_, timestep_list, + prev_timestep, sample, prev_sample); + } + + if (lower_order_nums_ < config.solver_order_) { + lower_order_nums_ += 1; + } +} + +void DPMSolverMultistepScheduler::AddNoise(const FDTensor& original_samples, + const FDTensor& noise, + const FDTensor& timesteps, + FDTensor* out) { + function::Cast(alphas_cumprod_, &alphas_cumprod_, original_samples.Dtype()); + + const int64_t* timesteps_data = + reinterpret_cast(timesteps.Data()); + std::vector timesteps_vec; + for (int i = 0; i < timesteps.Numel(); ++i) { + timesteps_vec.push_back(timesteps_data[i]); + } + FDTensor sqrt_alpha_prod; + function::Slice(alphas_cumprod_, {0}, timesteps_vec, &sqrt_alpha_prod); + function::Sqrt(sqrt_alpha_prod, &sqrt_alpha_prod); + sqrt_alpha_prod.Reshape({-1}); + int rank_diff = + original_samples.Shape().size() - sqrt_alpha_prod.Shape().size(); + for (int i = 0; i < rank_diff; ++i) { + int curr_rank = sqrt_alpha_prod.Shape().size(); + sqrt_alpha_prod.ExpandDim(curr_rank - 1); + } + + FDTensor sqrt_one_minus_alpha_prod; + function::Slice(alphas_cumprod_, {0}, timesteps_vec, + &sqrt_one_minus_alpha_prod); + sqrt_one_minus_alpha_prod = 1.0f - sqrt_one_minus_alpha_prod; + function::Sqrt(sqrt_one_minus_alpha_prod, &sqrt_one_minus_alpha_prod); + sqrt_one_minus_alpha_prod.Reshape({-1}); + rank_diff = original_samples.Shape().size() - + sqrt_one_minus_alpha_prod.Shape().size(); + for (int i = 0; i < rank_diff; ++i) { + int curr_rank = sqrt_one_minus_alpha_prod.Shape().size(); + sqrt_one_minus_alpha_prod.ExpandDim(curr_rank - 1); + } + *out = sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise; +} + +FDTensor DPMSolverMultistepScheduler::GetTimesteps() { return timesteps_; } + +} // namespace fastdeploy diff --git a/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.h b/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.h new file mode 100644 index 0000000000..0775ba1ee7 --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/dpm_solver_multistep_scheduler.h @@ -0,0 +1,87 @@ +// Copyright (c) 2022 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. + +#pragma once + +#include "./scheduler.h" +#include "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { + +class DPMSolverMultistepScheduler : public Scheduler { + public: + DPMSolverMultistepScheduler(int num_train_timesteps = 1000, + float beta_start = 0.0001, float beta_end = 0.02, + const std::string& beta_schedule = "linear", + const std::vector& trained_betas = {}, + int solver_order = 2, bool predict_epsilon = true, + bool thresholding = false, + float dynamic_thresholding_ratio = 0.995, + float sample_max_value = 1.0, + const std::string& algorithm_type = "dpmsolver++", + const std::string& solver_type = "midpoint", + bool lower_order_final = true); + void BetaForAlphaBar(FDTensor* out, int num_diffusion_timesteps, + float max_beta = 0.999); + void ConvertModelOutput(const FDTensor& model_output, int timestep, + const FDTensor& sample, FDTensor* out); + void DPMSolverFirstOrderUpdate(const FDTensor& model_output, int timestep, + int prev_timestep, const FDTensor& sample, + FDTensor* out); + void MultiStepDPMSolverSecondOrderUpdate( + const std::vector& model_output_list, + const std::vector& timestep_list, int prev_timestep, + const FDTensor& sample, FDTensor* out); + void MultiStepDPMSolverThirdOrderUpdate( + const std::vector& model_output_list, + const std::vector& timestep_list, int prev_timestep, + const FDTensor& sample, FDTensor* out); + void SetTimesteps(int num_inference_steps) override; + void Step(const FDTensor& model_output, int timestep, const FDTensor& sample, + FDTensor* prev_sample) override; + void ScaleModelInput(const FDTensor& sample, FDTensor* out, + const std::vector& timesteps = {}) override; + void AddNoise(const FDTensor& original_samples, const FDTensor& noise, + const FDTensor& timesteps, FDTensor* out) override; + float InitNoiseSigma() override; + FDTensor GetTimesteps() override; + struct Config { + int num_train_timesteps_; + float beta_start_; + float beta_end_; + std::string beta_schedule_; + int solver_order_; + bool predict_epsilon_; + bool thresholding_; + float dynamic_thresholding_ratio_; + float sample_max_value_; + std::string algorithm_type_; + std::string solver_type_; + bool lower_order_final_; + } config; + + private: + FDTensor betas_; + FDTensor alphas_; + FDTensor alphas_cumprod_; + FDTensor alpha_t_; + FDTensor sigma_t_; + FDTensor lambda_t_; + int num_inference_steps_; + FDTensor timesteps_; + int lower_order_nums_; + std::vector model_outputs_; +}; + +} // namespace fastdeploy diff --git a/examples/multimodal/stable_diffusion/cpp/main.cc b/examples/multimodal/stable_diffusion/cpp/main.cc new file mode 100644 index 0000000000..79051279f5 --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/main.cc @@ -0,0 +1,239 @@ +// Copyright (c) 2022 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. + +#include "./dpm_solver_multistep_scheduler.h" +#include "./pipeline_stable_diffusion_inpaint.h" +#include "fastdeploy/utils/perf.h" +#include "fastdeploy/vision/common/processors/mat.h" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include +#include +#include +#include +#include + +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +template std::string Str(const T* value, int size) { + std::ostringstream oss; + oss << "[ " << value[0]; + for (int i = 1; i < size; ++i) { + oss << " ," << value[i]; + } + oss << " ]"; + return oss.str(); +} + +std::unique_ptr CreateRuntime( + const std::string& model_file, const std::string& params_file, + bool use_trt_backend = false, bool use_fp16 = false, + const std::unordered_map>>& + dynamic_shapes = {}, + const std::vector& disable_paddle_trt_ops = {}) { + fastdeploy::RuntimeOption runtime_option; + runtime_option.SetModelPath(model_file, params_file, + fastdeploy::ModelFormat::PADDLE); + runtime_option.UseGpu(); + if (!use_trt_backend) { + runtime_option.UsePaddleBackend(); + } else { + runtime_option.UseTrtBackend(); + runtime_option.EnablePaddleToTrt(); + for (auto it = dynamic_shapes.begin(); it != dynamic_shapes.end(); ++it) { + if (it->second.size() != 3) { + std::cerr << "The size of dynamic_shapes of input `" << it->first + << "` should be 3, but receive " << it->second.size() + << std::endl; + continue; + } + std::vector min_shape = (it->second)[0]; + std::vector opt_shape = (it->second)[1]; + std::vector max_shape = (it->second)[2]; + runtime_option.SetTrtInputShape(it->first, min_shape, opt_shape, + max_shape); + } + runtime_option.SetTrtCacheFile("paddle.trt"); + runtime_option.EnablePaddleTrtCollectShape(); + runtime_option.DisablePaddleTrtOPs(disable_paddle_trt_ops); + if (use_fp16) { + runtime_option.EnableTrtFP16(); + } + } + std::unique_ptr runtime = + std::unique_ptr(new fastdeploy::Runtime()); + if (!runtime->Init(runtime_option)) { + std::cerr << "--- Init FastDeploy Runitme Failed! " + << "\n--- Model: " << model_file << std::endl; + return nullptr; + } else { + std::cout << "--- Init FastDeploy Runitme Done! " + << "\n--- Model: " << model_file << std::endl; + } + return runtime; +} + +int main() { + // 0. Init all configs + std::string model_dir = "sd15_inpaint"; + int max_length = 77; + bool use_trt_backend = true; + bool use_fp16 = true; + int batch_size = 1; + int num_images_per_prompt = 1; + int num_inference_steps = 50; + + int height = 512; + int width = 512; + constexpr int unet_inpaint_channels = 9; + constexpr int latents_channels = 4; + + // 1. Init scheduler + std::unique_ptr dpm( + new fastdeploy::DPMSolverMultistepScheduler( + /* num_train_timesteps */ 1000, + /* beta_start = */ 0.00085, + /* beta_end = */ 0.012, + /* beta_schedule = */ "scaled_linear", + /* trained_betas = */ {}, + /* solver_order = */ 2, + /* predict_epsilon = */ true, + /* thresholding = */ false, + /* dynamic_thresholding_ratio = */ 0.995, + /* sample_max_value = */ 1.0, + /* algorithm_type = */ "dpmsolver++", + /* solver_type = */ "midpoint", + /* lower_order_final = */ true)); + + // 2. Init text encoder runtime + std::unordered_map>> + text_dynamic_shape = {{"input_ids", + {/* min_shape */ {1, max_length}, + /* opt_shape */ {batch_size, max_length}, + /* max_shape */ {2 * batch_size, max_length}}}}; + std::string text_model_dir = model_dir + sep + "text_encoder"; + std::string text_model_file = text_model_dir + sep + "inference.pdmodel"; + std::string text_params_file = text_model_dir + sep + "inference.pdiparams"; + std::unique_ptr text_encoder_runtime = + CreateRuntime(text_model_file, text_params_file, use_trt_backend, + use_fp16, text_dynamic_shape); + + // 3. Init vae encoder runtime + std::unordered_map>> + vae_encoder_dynamic_shape = { + {"sample", + {/* min_shape */ {1, 3, height, width}, + /* opt_shape */ {2 * batch_size, 3, height, width}, + /* max_shape */ {2 * batch_size, 3, height, width}}}}; + std::string vae_encoder_model_dir = model_dir + sep + "vae_encoder"; + std::string vae_encoder_model_file = + vae_encoder_model_dir + sep + "inference.pdmodel"; + std::string vae_encoder_params_file = + vae_encoder_model_dir + sep + "inference.pdiparams"; + std::unique_ptr vae_encoder_runtime = + CreateRuntime(vae_encoder_model_file, vae_encoder_params_file, + use_trt_backend, use_fp16, vae_encoder_dynamic_shape); + + // 4. Init vae decoder runtime + std::unordered_map>> + vae_decoder_dynamic_shape = { + {"latent_sample", + {/* min_shape */ {1, latents_channels, height / 8, width / 8}, + /* opt_shape */ + {2 * batch_size, latents_channels, height / 8, width / 8}, + /* max_shape */ + {2 * batch_size, latents_channels, height / 8, width / 8}}}}; + std::string vae_decoder_model_dir = model_dir + sep + "vae_decoder"; + std::string vae_decoder_model_file = + vae_decoder_model_dir + sep + "inference.pdmodel"; + std::string vae_decoder_params_file = + vae_decoder_model_dir + sep + "inference.pdiparams"; + std::unique_ptr vae_decoder_runtime = + CreateRuntime(vae_decoder_model_file, vae_decoder_params_file, + use_trt_backend, use_fp16, vae_decoder_dynamic_shape); + + // 5. Init unet runtime + std::unordered_map>> + unet_dynamic_shape = { + {"sample", + {/* min_shape */ {1, unet_inpaint_channels, height / 8, width / 8}, + /* opt_shape */ + {2 * batch_size, unet_inpaint_channels, height / 8, width / 8}, + /* max_shape */ + {2 * batch_size, unet_inpaint_channels, height / 8, width / 8}}}, + {"timesteps", {{1}, {1}, {1}}}, + {"encoder_hidden_states", + {{1, max_length, 768}, + {2 * batch_size, max_length, 768}, + {2 * batch_size, max_length, 768}}}}; + std::vector unet_disable_paddle_trt_ops = {"sin", "cos"}; + std::string unet_model_dir = model_dir + sep + "unet"; + std::string unet_model_file = unet_model_dir + sep + "inference.pdmodel"; + std::string unet_params_file = unet_model_dir + sep + "inference.pdiparams"; + std::unique_ptr unet_runtime = + CreateRuntime(unet_model_file, unet_params_file, use_trt_backend, + use_fp16, unet_dynamic_shape, unet_disable_paddle_trt_ops); + + // 6. Init fast tokenizer + paddlenlp::fast_tokenizer::tokenizers_impl::ClipFastTokenizer tokenizer( + "clip/vocab.json", "clip/merges.txt", /* max_length = */ max_length); + fastdeploy::StableDiffusionInpaintPipeline pipe( + /* vae_encoder = */ std::move(vae_encoder_runtime), + /* vae_decoder = */ std::move(vae_decoder_runtime), + /* text_encoder = */ std::move(text_encoder_runtime), + /* unet = */ std::move(unet_runtime), + /* scheduler = */ std::move(dpm), + /* tokenizer = */ tokenizer); + + // 7. Read images + auto image = cv::imread("overture-creations.png"); + auto mask_image = cv::imread("overture-creations-mask.png"); + + // 8. Predict + /* + * One may need to pass the initial noise to predict api. + * There's an example: + * std::vector latents_data = {xxxx}; + * fastdeploy::FDTensor latents; + * latents.SetExternalData({batch_size * num_images_per_prompt, latents_channels, height / 8, width / 8},fastdeploy::FDDataType::FP32, latents_data.data()); + * pipe.Predict(..., /* latents = *\/ &latents, ....); + */ + std::vector prompts = { + "Face of a yellow cat, high resolution, sitting on a park bench"}; + std::vector outputs; + fastdeploy::TimeCounter tc; + tc.Start(); + pipe.Predict(prompts, image, mask_image, &outputs, + /* height = */ height, + /* width = */ width, + /* num_inference_steps = */ num_inference_steps, + /* guidance_scale = */ 7.5, + /* negative_prompt = */ {}, + /* num_images_per_prompt = */ num_images_per_prompt, + /* eta = */ 1.0, + /* max_length = */ max_length, + /* latents = */ nullptr, + /* output_cv_mat = */ true, + /* callback = */ nullptr, + /* callback_steps = */ 1); + tc.End(); + tc.PrintInfo(); + fastdeploy::vision::FDMat mat = fastdeploy::vision::FDMat::Create(outputs[0]); + cv::imwrite("cat_on_bench_new.png", *mat.GetOpenCVMat()); + return 0; +} \ No newline at end of file diff --git a/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.cc b/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.cc new file mode 100644 index 0000000000..4e0f1ed5fa --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2022 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. + +#include "pipeline_stable_diffusion_inpaint.h" +#include "fastdeploy/function/functions.h" +#include "fastdeploy/vision/common/processors/color_space_convert.h" +#include "fastdeploy/vision/common/processors/mat.h" +#include "fastdeploy/vision/common/processors/resize.h" +#include + +using namespace paddlenlp; + +namespace fastdeploy { + +static constexpr int NUM_LATENT_CHANNELS = 4; +static constexpr int NUM_UNET_INPUT_CHANNELS = 9; + +void StableDiffusionInpaintPipeline::PrepareMaskAndMaskedImage( + const cv::Mat& image, const cv::Mat& mask_mat, + const std::vector& shape, FDTensor* mask, FDTensor* mask_image) { + vision::FDMat image_fdmat(image); + vision::BGR2RGB::Run(&image_fdmat, vision::ProcLib::OPENCV); + vision::Resize::Run(&image_fdmat, shape[1] * 8, shape[0] * 8, -1.0f, -1.0f, + cv::INTER_NEAREST, false, vision::ProcLib::OPENCV); + image_fdmat.ShareWithTensor(mask_image); + + vision::FDMat mask_fdmat(mask_mat); + vision::BGR2GRAY::Run(&mask_fdmat, vision::ProcLib::OPENCV); + vision::Resize::Run(&mask_fdmat, shape[1] * 8, shape[0] * 8, -1.0f, -1.0f, + cv::INTER_NEAREST, false, vision::ProcLib::OPENCV); + FDTensor image_mask; + mask_fdmat.ShareWithTensor(&image_mask); + function::Cast(image_mask, &image_mask, FDDataType::FP32); + std::vector float_mask(image_mask.Numel(), 0); + float* image_mask_ptr = reinterpret_cast(image_mask.Data()); + for (int i = 0; i < image_mask.Numel(); ++i) { + if (image_mask_ptr[i] < 127.5) { + float_mask[i] = 1; + } + } + // NCHW format + image_mask.SetExternalData({1, 1, shape[0] * 8, shape[1] * 8}, + FDDataType::FP32, float_mask.data()); + + // Set mask_image + mask_image->ExpandDim(); + function::Transpose(*mask_image, mask_image, {0, 3, 1, 2}); + function::Cast(*mask_image, mask_image, FDDataType::FP32); + *mask_image = *mask_image / 127.5f - 1.0f; + *mask_image = *mask_image * image_mask; + + // Set mask + vision::FDMat mask_fdmat_t(mask_mat); + vision::BGR2GRAY::Run(&mask_fdmat_t, vision::ProcLib::OPENCV); + vision::Resize::Run(&mask_fdmat_t, shape[1], shape[0], -1.0f, -1.0f, + cv::INTER_NEAREST, false, vision::ProcLib::OPENCV); + mask_fdmat_t.ShareWithTensor(mask); + function::Cast(*mask, mask, FDDataType::FP32); + *mask = *mask / 255.0f; + mask->ExpandDim(); + function::Transpose(*mask, mask, {0, 3, 1, 2}); + float* mask_data = reinterpret_cast(mask->Data()); + for (int i = 0; i < mask->Numel(); ++i) { + if (mask_data[i] < 0.5) { + mask_data[i] = 0; + } else { + mask_data[i] = 1; + } + } +} + +StableDiffusionInpaintPipeline::StableDiffusionInpaintPipeline( + std::unique_ptr vae_encoder, std::unique_ptr vae_decoder, + std::unique_ptr text_encoder, std::unique_ptr unet, + std::unique_ptr scheduler, + const paddlenlp::fast_tokenizer::tokenizers_impl::ClipFastTokenizer& + tokenizer) + : vae_encoder_(std::move(vae_encoder)), + vae_decoder_(std::move(vae_decoder)), + text_encoder_(std::move(text_encoder)), unet_(std::move(unet)), + scheduler_(std::move(scheduler)), tokenizer_(tokenizer) {} + +void StableDiffusionInpaintPipeline::Predict( + const std::vector& prompts, const cv::Mat& image, + const cv::Mat& mask_image, std::vector* output_images, int height, + int width, int num_inference_steps, float guidance_scale, + const std::vector& negative_prompt, int num_images_per_prompt, + float eta, uint32_t max_length, const FDTensor* latents, bool output_cv_mat, + callback_ptr callback, int callback_steps) { + int batch_size = prompts.size(); + FDASSERT(batch_size >= 1, "prompts should not be empty"); + FDASSERT( + height % 8 == 0 && width % 8 == 0, + "`height` and `width` have to be divisible by 8 but are {%d} and {%d}.", + height, width); + FDASSERT(callback_steps > 0, + "`callback_steps` has to be a positive integer but is {%d}", + callback_steps); + + // Setting tokenizer attr + if (max_length == 0) { + tokenizer_.EnablePadMethod(fast_tokenizer::core::RIGHT, + tokenizer_.GetPadTokenId(), 0, + tokenizer_.GetPadToken(), nullptr, nullptr); + tokenizer_.DisableTruncMethod(); + } else { + tokenizer_.EnablePadMethod(fast_tokenizer::core::RIGHT, + tokenizer_.GetPadTokenId(), 0, + tokenizer_.GetPadToken(), &max_length, nullptr); + tokenizer_.EnableTruncMethod(max_length, 0, fast_tokenizer::core::RIGHT, + fast_tokenizer::core::LONGEST_FIRST); + } + std::vector encodings; + tokenizer_.EncodeBatchStrings(prompts, &encodings); + + std::vector input_ids; + for (auto& encoding : encodings) { + auto curr_ids = encoding.GetIds(); + input_ids.insert(input_ids.end(), curr_ids.begin(), curr_ids.end()); + } + encodings.clear(); + // Get text encoder output + FDTensor text_intput_ids; + std::vector inputs(1); + inputs[0].SetExternalData({batch_size, max_length}, FDDataType::INT64, + input_ids.data()); + + TensorInfo text_info = text_encoder_->GetInputInfo(0); + inputs[0].name = text_info.name; + int output_size = text_encoder_->GetOutputInfos().size(); + std::vector outputs(output_size); + text_encoder_->Infer(inputs, &outputs); + + FDTensor text_embeddings; + function::Tile(outputs[0], {num_images_per_prompt, 1, 1}, &text_embeddings); + + // here `guidance_scale` is defined analog to the guidance weight `w` of equation (2) + // of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1` + // corresponds to doing no classifier free guidance. + bool do_classifier_free_guidance = guidance_scale > 1.0; + if (do_classifier_free_guidance) { + std::vector uncond_tokens; + if (negative_prompt.size() == 0) { + uncond_tokens = {""}; + } else if (negative_prompt.size() != batch_size) { + FDASSERT(false, + "negative_prompt has batch size %d, but prompt has batch size " + "%d. Please make sure that passed `negative_prompt` matches the " + "batch size of `prompt`.", + prompts.size(), negative_prompt.size()); + } else { + uncond_tokens = negative_prompt; + } + tokenizer_.EncodeBatchStrings(uncond_tokens, &encodings); + input_ids.clear(); + for (auto& encoding : encodings) { + auto curr_ids = encoding.GetIds(); + input_ids.insert(input_ids.end(), curr_ids.begin(), curr_ids.end()); + } + inputs[0].SetExternalData({batch_size, max_length}, FDDataType::INT64, + input_ids.data()); + text_encoder_->Infer(inputs, &outputs); + FDTensor uncond_embeddings; + function::Tile(outputs[0], {num_images_per_prompt, 1, 1}, + &uncond_embeddings); + function::Concat({uncond_embeddings, text_embeddings}, &text_embeddings); + } + std::vector latents_shape = {batch_size * num_images_per_prompt, + NUM_LATENT_CHANNELS, height / 8, + width / 8}; + auto latents_dtype = text_embeddings.Dtype(); + FDTensor actual_latents; + if (latents == nullptr) { + function::GaussianRandom(latents_shape, &actual_latents, latents_dtype); + } else { + bool result = std::equal(latents_shape.begin(), latents_shape.end(), + latents->Shape().begin()); + FDASSERT(result, "Unexpected latents shape, got %s, expected %s", + Str(latents_shape).c_str(), Str(latents->Shape()).c_str()); + actual_latents = *latents; + } + FDTensor mask_t, mask_image_t; + PrepareMaskAndMaskedImage(image, mask_image, {height / 8, width / 8}, &mask_t, + &mask_image_t); + function::Cast(mask_t, &mask_t, actual_latents.Dtype()); + function::Cast(mask_image_t, &mask_image_t, actual_latents.Dtype()); + + // Get vae encoder output + TensorInfo vae_encoder_info = vae_encoder_->GetInputInfo(0); + mask_image_t.name = vae_encoder_info.name; + outputs.resize(vae_encoder_->GetOutputInfos().size()); + inputs = {mask_image_t}; + vae_encoder_->Infer(inputs, &outputs); + FDTensor masked_image_latents = 0.18215f * outputs[0]; + + std::vector mask_shape(mask_t.Shape().size(), 1); + mask_shape[0] = batch_size * num_images_per_prompt; + function::Tile(mask_t, mask_shape, &mask_t); + + std::vector mask_image_shape(masked_image_latents.Shape().size(), 1); + mask_image_shape[0] = batch_size * num_images_per_prompt; + function::Tile(masked_image_latents, mask_image_shape, &masked_image_latents); + + if (do_classifier_free_guidance) { + function::Concat({mask_t, mask_t}, &mask_t); + function::Concat({masked_image_latents, masked_image_latents}, + &masked_image_latents); + } + int num_channels_mask = mask_t.Shape()[1]; + int num_channels_masked_image = masked_image_latents.Shape()[1]; + FDASSERT( + NUM_LATENT_CHANNELS + num_channels_mask + num_channels_masked_image == + NUM_UNET_INPUT_CHANNELS, + "Incorrect configuration settings! The config of `pipeline.unet` expects" + " %d but received `num_channels_latents`: %d + `num_channels_mask`: %d " + "+ `num_channels_masked_image`: %d" + " = %d. Please verify the config of `pipeline.unet` or your `mask_image` " + "or `image` input.", + NUM_UNET_INPUT_CHANNELS, NUM_LATENT_CHANNELS, num_channels_mask, + num_channels_masked_image, + NUM_LATENT_CHANNELS + num_channels_mask + num_channels_masked_image); + + // set timesteps + scheduler_->SetTimesteps(num_inference_steps); + + // scale the initial noise by the standard deviation required by the scheduler + actual_latents = actual_latents * scheduler_->InitNoiseSigma(); + + auto timestep = scheduler_->GetTimesteps(); + int64_t* timestep_data = reinterpret_cast(timestep.Data()); + outputs.resize(unet_->GetOutputInfos().size()); + inputs.resize(unet_->GetInputInfos().size()); + inputs[2] = std::move(text_embeddings); + auto unet_infos = unet_->GetInputInfos(); + for (int i = 0; i < timestep.Numel(); ++i) { + FDTensor t; + function::Slice(timestep, {0}, {i}, &t); + inputs[1] = t; + // expand the latents if we are doing classifier free guidance + FDTensor latent_model_input; + if (do_classifier_free_guidance) { + function::Concat({actual_latents, actual_latents}, &latent_model_input); + } else { + latent_model_input = actual_latents; + } + // concat latents, mask, masked_image_latnets in the channel dimension + function::Concat({latent_model_input, mask_t, masked_image_latents}, + &latent_model_input, 1); + scheduler_->ScaleModelInput(latent_model_input, &latent_model_input, {t}); + inputs[0] = std::move(latent_model_input); + // predict the noise residual + for (int i = 0; i < unet_infos.size(); ++i) { + inputs[i].name = unet_infos[i].name; + } + unet_->Infer(inputs, &outputs); + FDTensor noise_pred = std::move(outputs[0]); + // perform guidance + if (do_classifier_free_guidance) { + std::vector noise_preds; + int dim0 = noise_pred.Shape()[0]; + function::Split(noise_pred, {dim0 - dim0 / 2, dim0 / 2}, &noise_preds); + noise_pred = + noise_preds[0] + guidance_scale * (noise_preds[1] - noise_preds[0]); + } + + // compute the previous noisy sample x_t -> x_t-1 + int64_t time = reinterpret_cast(t.Data())[0]; + scheduler_->Step(noise_pred, time, actual_latents, &actual_latents); + + // call the callback, if provided + if (callback != nullptr && i % callback_steps == 0) { + callback(i, time, &actual_latents); + } + } + actual_latents = (1.0f / 0.18215f) * actual_latents; + + // Get vae decoder output + int actual_latents_bs = actual_latents.Shape()[0]; + TensorInfo vae_decoder_info = vae_decoder_->GetInputInfo(0); + inputs.resize(1); + outputs.resize(vae_decoder_->GetOutputInfos().size()); + std::vector decoder_reuslt; + for (int i = 0; i < actual_latents_bs; ++i) { + function::Slice(actual_latents, {0}, {i}, {i + 1}, &inputs[0]); + inputs[0].name = vae_decoder_info.name; + vae_decoder_->Infer(inputs, &outputs); + decoder_reuslt.emplace_back(std::move(outputs[0])); + } + FDTensor output_image; + function::Concat(decoder_reuslt, &output_image); + + function::Clip(output_image / 2.0f + 0.5f, 0, 1, &output_image); + function::Transpose(output_image, &output_image, {0, 2, 3, 1}); + + if (output_cv_mat) { + output_image = output_image * 255.0f; + function::Round(output_image, &output_image); + function::Cast(output_image, &output_image, FDDataType::UINT8); + } + int output_batch_size = output_image.Shape()[0]; + output_images->resize(output_batch_size); + for (int i = 0; i < output_batch_size; ++i) { + function::Slice(output_image, {0}, {i}, &(*output_images)[i]); + vision::FDMat mask_fdmat_t = vision::FDMat::Create((*output_images)[i]); + vision::RGB2BGR::Run(&mask_fdmat_t, vision::ProcLib::OPENCV); + mask_fdmat_t.CopyToTensor(&(*output_images)[i]); + } +} +} // namespace fastdeploy diff --git a/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.h b/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.h new file mode 100644 index 0000000000..063c370f35 --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/pipeline_stable_diffusion_inpaint.h @@ -0,0 +1,61 @@ +// Copyright (c) 2022 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. + +#pragma once + +#include "./scheduler.h" +#include "fast_tokenizer/tokenizers/clip_fast_tokenizer.h" +#include "fastdeploy/core/fd_tensor.h" +#include "fastdeploy/runtime.h" +#include "opencv2/core/core.hpp" +#include +#include +#include + +namespace fastdeploy { + +class StableDiffusionInpaintPipeline { + public: + typedef void (*callback_ptr)(int, int, FDTensor*); + + StableDiffusionInpaintPipeline( + std::unique_ptr vae_encoder, + std::unique_ptr vae_decoder, + std::unique_ptr text_encoder, std::unique_ptr unet, + std::unique_ptr scheduler, + const paddlenlp::fast_tokenizer::tokenizers_impl::ClipFastTokenizer& + tokenizer); + void Predict(const std::vector& prompts, const cv::Mat& image, + const cv::Mat& mask_image, std::vector* output_images, + int height = 512, int width = 512, int num_inference_steps = 50, + float guidance_scale = 7.5, + const std::vector& negative_prompt = {}, + int num_images_per_prompt = 1, float eta = 0.0, + uint32_t max_length = 77, const FDTensor* latents = nullptr, + bool output_cv_mat = true, callback_ptr callback = nullptr, + int callback_steps = 1); + + private: + void PrepareMaskAndMaskedImage(const cv::Mat& image, const cv::Mat& mask_mat, + const std::vector& shape, + FDTensor* mask, FDTensor* mask_image); + std::unique_ptr vae_encoder_; + std::unique_ptr vae_decoder_; + std::unique_ptr text_encoder_; + std::unique_ptr unet_; + std::unique_ptr scheduler_; + paddlenlp::fast_tokenizer::tokenizers_impl::ClipFastTokenizer tokenizer_; +}; + +} // namespace fastdeploy diff --git a/examples/multimodal/stable_diffusion/cpp/scheduler.h b/examples/multimodal/stable_diffusion/cpp/scheduler.h new file mode 100644 index 0000000000..e4dc452def --- /dev/null +++ b/examples/multimodal/stable_diffusion/cpp/scheduler.h @@ -0,0 +1,34 @@ +// Copyright (c) 2022 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. + +#pragma once + +#include "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { + +class Scheduler { + public: + virtual void SetTimesteps(int num_inference_steps) = 0; + virtual FDTensor GetTimesteps() = 0; + virtual void Step(const FDTensor& model_output, int timestep, + const FDTensor& sample, FDTensor* prev_sample) = 0; + virtual void ScaleModelInput(const FDTensor& sample, FDTensor* out, + const std::vector& timesteps = {}) = 0; + virtual void AddNoise(const FDTensor& original_samples, const FDTensor& noise, + const FDTensor& timesteps, FDTensor* out) = 0; + virtual float InitNoiseSigma() = 0; +}; + +} // namespace fastdeploy diff --git a/examples/text/ernie-3.0/serving/README.md b/examples/text/ernie-3.0/serving/README.md index 6edc1b7907..8b7fbdd9af 100644 --- a/examples/text/ernie-3.0/serving/README.md +++ b/examples/text/ernie-3.0/serving/README.md @@ -51,10 +51,10 @@ models # GPU镜像 docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 # CPU镜像 -docker pull paddlepaddle/fastdeploy:z.y.z-cpu-only-21.10 +docker pull paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 # 运行 -docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v /path/serving/models:/models paddlepaddle/fastdeploy:0.6.0-cpu-only-21.10 bash +docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v /path/serving/models:/models paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 bash ``` ## 部署模型 @@ -67,7 +67,7 @@ token_cls_rpc_client.py # 序列标注任务发送pipeline预测请求的脚 ``` *注意*:启动服务时,Server的每个python后端进程默认申请`64M`内存,默认启动的docker无法启动多个python后端节点。有两个解决方案: -- 1.启动容器时设置`shm-size`参数, 比如:`docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v /path/serving/models:/models paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash` +- 1.启动容器时设置`shm-size`参数, 比如:`docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v /path/serving/models:/models paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash` - 2.启动服务时设置python后端的`shm-default-byte-size`参数, 设置python后端的默认内存为10M: `tritonserver --model-repository=/models --backend-config=python,shm-default-byte-size=10485760` ### 分类任务 diff --git a/examples/text/uie/serving/README.md b/examples/text/uie/serving/README.md index c2ade2a547..f38ff7c5e0 100644 --- a/examples/text/uie/serving/README.md +++ b/examples/text/uie/serving/README.md @@ -34,10 +34,10 @@ models # GPU镜像 docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 # CPU镜像 -docker pull paddlepaddle/fastdeploy:z.y.z-cpu-only-21.10 +docker pull paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 # 运行容器.容器名字为 fd_serving, 并挂载当前目录为容器的 /uie_serving 目录 -docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v `pwd`/:/uie_serving paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash +docker run -it --net=host --name fastdeploy_server --shm-size="1g" -v `pwd`/:/uie_serving paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash # 启动服务(不设置CUDA_VISIBLE_DEVICES环境变量,会拥有所有GPU卡的调度权限) CUDA_VISIBLE_DEVICES=0 fastdeployserver --model-repository=/uie_serving/models --backend-config=python,shm-default-byte-size=10485760 diff --git a/examples/vision/classification/paddleclas/quantize/README.md b/examples/vision/classification/paddleclas/quantize/README.md old mode 100644 new mode 100755 index 6e3f78b4d5..e55f95e261 --- a/examples/vision/classification/paddleclas/quantize/README.md +++ b/examples/vision/classification/paddleclas/quantize/README.md @@ -4,14 +4,14 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) 注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可。 ## 下载量化完成的PaddleClas模型 用户也可以直接下载下表中的量化模型进行部署. Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -33,7 +33,7 @@ Benchmark表格说明: | [MobileNetV1_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/mobilenetv1_ssld_ptq.tar) | Paddle Inference | CPU | 12.29 | 4.68 | None|None|2.62 |77.89 | 71.36 |离线量化 | ### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 Top1 | INT8 Top1 | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 Top1 | INT8 Top1 | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [ResNet50_vd](https://bj.bcebos.com/paddlehub/fastdeploy/resnet50_vd_ptq.tar) | TensorRT | GPU | 4.92| 2.28|2.24|2.23 | 2.21 | 79.12 | 79.06 | 离线量化 | | [ResNet50_vd](https://bj.bcebos.com/paddlehub/fastdeploy/resnet50_vd_ptq.tar) | Paddle-TensorRT | GPU | 4.48|None |2.09|2.10 | 2.14 | 79.12 | 79.06 | 离线量化 | diff --git a/examples/vision/classification/paddleclas/quantize/cpp/README.md b/examples/vision/classification/paddleclas/quantize/cpp/README.md old mode 100644 new mode 100755 index 3dced039ca..999cc7fde3 --- a/examples/vision/classification/paddleclas/quantize/cpp/README.md +++ b/examples/vision/classification/paddleclas/quantize/cpp/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的ResNet50_Vd模型为例, 进行部署,支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) 在本目录执行如下命令即可完成编译,以及量化模型部署. diff --git a/examples/vision/classification/paddleclas/quantize/python/README.md b/examples/vision/classification/paddleclas/quantize/python/README.md old mode 100644 new mode 100755 index 6b874e77ab..a7fc4f9d3a --- a/examples/vision/classification/paddleclas/quantize/python/README.md +++ b/examples/vision/classification/paddleclas/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的ResNet50_Vd模型为例, 进行部署 diff --git a/examples/vision/classification/paddleclas/rk1126/README.md b/examples/vision/classification/paddleclas/rv1126/README.md similarity index 61% rename from examples/vision/classification/paddleclas/rk1126/README.md rename to examples/vision/classification/paddleclas/rv1126/README.md index bac6d7bf8d..065939a278 100755 --- a/examples/vision/classification/paddleclas/rk1126/README.md +++ b/examples/vision/classification/paddleclas/rv1126/README.md @@ -1,11 +1,11 @@ -# PaddleClas 量化模型在 RK1126 上的部署 -目前 FastDeploy 已经支持基于 PaddleLite 部署 PaddleClas 量化模型到 RK1126 上。 +# PaddleClas 量化模型在 RV1126 上的部署 +目前 FastDeploy 已经支持基于 PaddleLite 部署 PaddleClas 量化模型到 RV1126 上。 模型的量化和量化模型的下载请参考:[模型量化](../quantize/README.md) ## 详细部署文档 -在 RK1126 上只支持 C++ 的部署。 +在 RV1126 上只支持 C++ 的部署。 - [C++部署](cpp) diff --git a/examples/vision/classification/paddleclas/rk1126/cpp/CMakeLists.txt b/examples/vision/classification/paddleclas/rv1126/cpp/CMakeLists.txt similarity index 100% rename from examples/vision/classification/paddleclas/rk1126/cpp/CMakeLists.txt rename to examples/vision/classification/paddleclas/rv1126/cpp/CMakeLists.txt diff --git a/examples/vision/classification/paddleclas/rk1126/cpp/README.md b/examples/vision/classification/paddleclas/rv1126/cpp/README.md similarity index 65% rename from examples/vision/classification/paddleclas/rk1126/cpp/README.md rename to examples/vision/classification/paddleclas/rv1126/cpp/README.md index 6d8ecd1512..feaba462fe 100755 --- a/examples/vision/classification/paddleclas/rk1126/cpp/README.md +++ b/examples/vision/classification/paddleclas/rv1126/cpp/README.md @@ -1,22 +1,22 @@ -# PaddleClas RK1126开发板 C++ 部署示例 -本目录下提供的 `infer.cc`,可以帮助用户快速完成 PaddleClas 量化模型在 RK1126 上的部署推理加速。 +# PaddleClas RV1126 开发板 C++ 部署示例 +本目录下提供的 `infer.cc`,可以帮助用户快速完成 PaddleClas 量化模型在 RV1126 上的部署推理加速。 ## 部署准备 ### FastDeploy 交叉编译环境准备 -- 1. 软硬件环境满足要求,以及交叉编译环境的准备,请参考:[FastDeploy 交叉编译环境准备](../../../../../../docs/cn/build_and_install/rk1126.md#交叉编译环境搭建) +- 1. 软硬件环境满足要求,以及交叉编译环境的准备,请参考:[FastDeploy 交叉编译环境准备](../../../../../../docs/cn/build_and_install/rv1126.md#交叉编译环境搭建) ### 量化模型准备 - 1. 用户可以直接使用由 FastDeploy 提供的量化模型进行部署。 -- 2. 用户可以使用 FastDeploy 提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署。(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此 yaml 文件, 用户从 FP32 模型文件夹下复制此 yaml 文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用 FastDeploy 提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署。(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的inference_cls.yaml文件, 自行量化的模型文件夹内不包含此 yaml 文件, 用户从 FP32 模型文件夹下复制此 yaml 文件到量化后的模型文件夹内即可.) - 更多量化相关相关信息可查阅[模型量化](../../quantize/README.md) -## 在 RK1126 上部署量化后的 ResNet50_Vd 分类模型 -请按照以下步骤完成在 RK1126 上部署 ResNet50_Vd 量化模型: -1. 交叉编译编译 FastDeploy 库,具体请参考:[交叉编译 FastDeploy](../../../../../../docs/cn/build_and_install/rk1126.md#基于-paddlelite-的-fastdeploy-交叉编译库编译) +## 在 RV1126 上部署量化后的 ResNet50_Vd 分类模型 +请按照以下步骤完成在 RV1126 上部署 ResNet50_Vd 量化模型: +1. 交叉编译编译 FastDeploy 库,具体请参考:[交叉编译 FastDeploy](../../../../../../docs/cn/build_and_install/rv1126.md#基于-paddlelite-的-fastdeploy-交叉编译库编译) 2. 将编译后的库拷贝到当前目录,可使用如下命令: ```bash -cp -r FastDeploy/build/fastdeploy-tmivx/ FastDeploy/examples/vision/classification/paddleclas/rk1126/cpp/ +cp -r FastDeploy/build/fastdeploy-tmivx/ FastDeploy/examples/vision/classification/paddleclas/rv1126/cpp/ ``` 3. 在当前路径下载部署所需的模型和示例图片: @@ -32,7 +32,7 @@ cp -r ILSVRC2012_val_00000010.jpeg images 4. 编译部署示例,可使入如下命令: ```bash mkdir build && cd build -cmake -DCMAKE_TOOLCHAIN_FILE=../fastdeploy-tmivx/timvx.cmake -DFASTDEPLOY_INSTALL_DIR=fastdeploy-tmivx .. +cmake -DCMAKE_TOOLCHAIN_FILE=${PWD}/../fastdeploy-tmivx/timvx.cmake -DFASTDEPLOY_INSTALL_DIR=${PWD}/../fastdeploy-tmivx .. make -j8 make install # 成功编译之后,会生成 install 文件夹,里面有一个运行 demo 和部署所需的库 @@ -41,7 +41,7 @@ make install 5. 基于 adb 工具部署 ResNet50_vd 分类模型到 Rockchip RV1126,可使用如下命令: ```bash # 进入 install 目录 -cd FastDeploy/examples/vision/classification/paddleclas/rk1126/cpp/build/install/ +cd FastDeploy/examples/vision/classification/paddleclas/rv1126/cpp/build/install/ # 如下命令表示:bash run_with_adb.sh 需要运行的demo 模型路径 图片路径 设备的DEVICE_ID bash run_with_adb.sh infer_demo ResNet50_vd_infer ILSVRC2012_val_00000010.jpeg $DEVICE_ID ``` @@ -50,4 +50,4 @@ bash run_with_adb.sh infer_demo ResNet50_vd_infer ILSVRC2012_val_00000010.jpeg $ -需要特别注意的是,在 RK1126 上部署的模型需要是量化后的模型,模型的量化请参考:[模型量化](../../../../../../docs/cn/quantize.md) +需要特别注意的是,在 RV1126 上部署的模型需要是量化后的模型,模型的量化请参考:[模型量化](../../../../../../docs/cn/quantize.md) diff --git a/examples/vision/classification/paddleclas/rk1126/cpp/infer.cc b/examples/vision/classification/paddleclas/rv1126/cpp/infer.cc similarity index 100% rename from examples/vision/classification/paddleclas/rk1126/cpp/infer.cc rename to examples/vision/classification/paddleclas/rv1126/cpp/infer.cc diff --git a/examples/vision/classification/paddleclas/rk1126/cpp/run_with_adb.sh b/examples/vision/classification/paddleclas/rv1126/cpp/run_with_adb.sh similarity index 100% rename from examples/vision/classification/paddleclas/rk1126/cpp/run_with_adb.sh rename to examples/vision/classification/paddleclas/rv1126/cpp/run_with_adb.sh diff --git a/examples/vision/classification/paddleclas/serving/README.md b/examples/vision/classification/paddleclas/serving/README.md index 971e9bbd0f..0b4771717e 100644 --- a/examples/vision/classification/paddleclas/serving/README.md +++ b/examples/vision/classification/paddleclas/serving/README.md @@ -28,10 +28,10 @@ mv ResNet50_vd_infer/inference.pdiparams models/runtime/1/model.pdiparams # GPU镜像 docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 # CPU镜像 -docker pull paddlepaddle/fastdeploy:z.y.z-cpu-only-21.10 +docker pull paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 # 运行容器.容器名字为 fd_serving, 并挂载当前目录为容器的 /serving 目录 -nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/serving paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash +nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/serving paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash # 启动服务(不设置CUDA_VISIBLE_DEVICES环境变量,会拥有所有GPU卡的调度权限) CUDA_VISIBLE_DEVICES=0 fastdeployserver --model-repository=/serving/models --backend-config=python,shm-default-byte-size=10485760 diff --git a/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java b/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java index dbb76df83e..1277117672 100644 --- a/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java +++ b/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java @@ -305,6 +305,8 @@ protected void onResume() { // Open camera until the permissions have been granted if (!checkAllPermissions()) { svPreview.disableCamera(); + } else { + svPreview.enableCamera(); } svPreview.onResume(); } diff --git a/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java b/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java index 94a5fdbd0e..14217181d3 100644 --- a/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java +++ b/examples/vision/detection/paddledetection/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java @@ -278,6 +278,10 @@ public void disableCamera() { disableCamera = true; } + public void enableCamera() { + disableCamera = false; + } + public void switchCamera() { releaseCamera(); selectedCameraId = (selectedCameraId + 1) % numberOfCameras; diff --git a/examples/vision/detection/paddledetection/coco_label_list.txt b/examples/vision/detection/paddledetection/coco_label_list.txt deleted file mode 100644 index 941cb4e139..0000000000 --- a/examples/vision/detection/paddledetection/coco_label_list.txt +++ /dev/null @@ -1,80 +0,0 @@ -person -bicycle -car -motorcycle -airplane -bus -train -truck -boat -traffic light -fire hydrant -stop sign -parking meter -bench -bird -cat -dog -horse -sheep -cow -elephant -bear -zebra -giraffe -backpack -umbrella -handbag -tie -suitcase -frisbee -skis -snowboard -sports ball -kite -baseball bat -baseball glove -skateboard -surfboard -tennis racket -bottle -wine glass -cup -fork -knife -spoon -bowl -banana -apple -sandwich -orange -broccoli -carrot -hot dog -pizza -donut -cake -chair -couch -potted plant -bed -dining table -toilet -tv -laptop -mouse -remote -keyboard -cell phone -microwave -oven -toaster -sink -refrigerator -book -clock -vase -scissors -teddy bear -hair drier -toothbrush diff --git a/examples/vision/detection/paddledetection/cpp/infer_ppyoloe.cc b/examples/vision/detection/paddledetection/cpp/infer_ppyoloe.cc old mode 100644 new mode 100755 diff --git a/examples/vision/detection/paddledetection/quantize/README.md b/examples/vision/detection/paddledetection/quantize/README.md old mode 100644 new mode 100755 index 8c6f1feeef..f0caf81123 --- a/examples/vision/detection/paddledetection/quantize/README.md +++ b/examples/vision/detection/paddledetection/quantize/README.md @@ -4,14 +4,14 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) ## 下载量化完成的PP-YOLOE-l模型 用户也可以直接下载下表中的量化模型进行部署.(点击模型名字即可下载) Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -32,7 +32,7 @@ NOTE: - TensorRT比Paddle-TensorRT快的原因是在runtime移除了multiclass_nms3算子 #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [ppyoloe_crn_l_300e_coco](https://bj.bcebos.com/paddlehub/fastdeploy/ppyoloe_crn_l_300e_coco_qat.tar ) | TensorRT | GPU | 35.75 | 15.42 |20.70|20.85 | 2.32 | 51.4 | 50.7 | 量化蒸馏训练 | | [ppyoloe_crn_l_300e_coco](https://bj.bcebos.com/paddlehub/fastdeploy/ppyoloe_crn_l_300e_coco_qat.tar ) | Paddle-TensorRT | GPU | 33.48 |None | 18.47 |18.03 | 1.81 | 51.4 | 50.5 | 量化蒸馏训练 | diff --git a/examples/vision/detection/paddledetection/quantize/cpp/README.md b/examples/vision/detection/paddledetection/quantize/cpp/README.md old mode 100644 new mode 100755 index 793fc3938e..4511eb5089 --- a/examples/vision/detection/paddledetection/quantize/cpp/README.md +++ b/examples/vision/detection/paddledetection/quantize/cpp/README.md @@ -9,7 +9,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的infer_cfg.yml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的检测模型仍然需要FP32模型文件夹下的infer_cfg.yml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的PP-YOLOE-l模型为例, 进行部署。支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) 在本目录执行如下命令即可完成编译,以及量化模型部署. diff --git a/examples/vision/detection/paddledetection/quantize/python/README.md b/examples/vision/detection/paddledetection/quantize/python/README.md old mode 100644 new mode 100755 index 3efcd232b9..15e0d463e0 --- a/examples/vision/detection/paddledetection/quantize/python/README.md +++ b/examples/vision/detection/paddledetection/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的infer_cfg.yml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的infer_cfg.yml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的PP-YOLOE-l模型为例, 进行部署 diff --git a/examples/vision/detection/paddledetection/rk1126/download_models_and_libs.sh b/examples/vision/detection/paddledetection/rk1126/download_models_and_libs.sh deleted file mode 100755 index e7a0fca7a2..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/download_models_and_libs.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -e - -DETECTION_MODEL_DIR="$(pwd)/picodet_detection/models" -LIBS_DIR="$(pwd)" - -DETECTION_MODEL_URL="https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/models/picodetv2_relu6_coco_no_fuse.tar.gz" -LIBS_URL="https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/Paddle-Lite-libs.tar.gz" - -download_and_uncompress() { - local url="$1" - local dir="$2" - - echo "Start downloading ${url}" - curl -L ${url} > ${dir}/download.tar.gz - cd ${dir} - tar -zxvf download.tar.gz - rm -f download.tar.gz -} - -download_and_uncompress "${DETECTION_MODEL_URL}" "${DETECTION_MODEL_DIR}" -download_and_uncompress "${LIBS_URL}" "${LIBS_DIR}" - -echo "Download successful!" diff --git a/examples/vision/detection/paddledetection/rk1126/picodet_detection/CMakeLists.txt b/examples/vision/detection/paddledetection/rk1126/picodet_detection/CMakeLists.txt deleted file mode 100755 index 575db78adf..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/picodet_detection/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -set(CMAKE_SYSTEM_NAME Linux) -if(TARGET_ARCH_ABI STREQUAL "armv8") - set(CMAKE_SYSTEM_PROCESSOR aarch64) - set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc") - set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++") -elseif(TARGET_ARCH_ABI STREQUAL "armv7hf") - set(CMAKE_SYSTEM_PROCESSOR arm) - set(CMAKE_C_COMPILER "arm-linux-gnueabihf-gcc") - set(CMAKE_CXX_COMPILER "arm-linux-gnueabihf-g++") -else() - message(FATAL_ERROR "Unknown arch abi ${TARGET_ARCH_ABI}, only support armv8 and armv7hf.") - return() -endif() - -project(object_detection_demo) - -message(STATUS "TARGET ARCH ABI: ${TARGET_ARCH_ABI}") -message(STATUS "PADDLE LITE DIR: ${PADDLE_LITE_DIR}") -include_directories(${PADDLE_LITE_DIR}/include) -link_directories(${PADDLE_LITE_DIR}/libs/${TARGET_ARCH_ABI}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -if(TARGET_ARCH_ABI STREQUAL "armv8") - set(CMAKE_CXX_FLAGS "-march=armv8-a ${CMAKE_CXX_FLAGS}") - set(CMAKE_C_FLAGS "-march=armv8-a ${CMAKE_C_FLAGS}") -elseif(TARGET_ARCH_ABI STREQUAL "armv7hf") - set(CMAKE_CXX_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 ${CMAKE_CXX_FLAGS}") - set(CMAKE_C_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4 ${CMAKE_C_FLAGS}" ) -endif() - -include_directories(${PADDLE_LITE_DIR}/libs/${TARGET_ARCH_ABI}/third_party/yaml-cpp/include) -link_directories(${PADDLE_LITE_DIR}/libs/${TARGET_ARCH_ABI}/third_party/yaml-cpp) - -find_package(OpenMP REQUIRED) -if(OpenMP_FOUND OR OpenMP_CXX_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - message(STATUS "Found OpenMP ${OpenMP_VERSION} ${OpenMP_CXX_VERSION}") - message(STATUS "OpenMP C flags: ${OpenMP_C_FLAGS}") - message(STATUS "OpenMP CXX flags: ${OpenMP_CXX_FLAGS}") - message(STATUS "OpenMP OpenMP_CXX_LIB_NAMES: ${OpenMP_CXX_LIB_NAMES}") - message(STATUS "OpenMP OpenMP_CXX_LIBRARIES: ${OpenMP_CXX_LIBRARIES}") -else() - message(FATAL_ERROR "Could not found OpenMP!") - return() -endif() -find_package(OpenCV REQUIRED) -if(OpenCV_FOUND OR OpenCV_CXX_FOUND) - include_directories(${OpenCV_INCLUDE_DIRS}) - message(STATUS "OpenCV library status:") - message(STATUS " version: ${OpenCV_VERSION}") - message(STATUS " libraries: ${OpenCV_LIBS}") - message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") -else() - message(FATAL_ERROR "Could not found OpenCV!") - return() -endif() - - -add_executable(object_detection_demo object_detection_demo.cc) - -target_link_libraries(object_detection_demo paddle_full_api_shared dl ${OpenCV_LIBS} yaml-cpp) diff --git a/examples/vision/detection/paddledetection/rk1126/picodet_detection/README.md b/examples/vision/detection/paddledetection/rk1126/picodet_detection/README.md deleted file mode 100755 index ddebdeb7ad..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/picodet_detection/README.md +++ /dev/null @@ -1,343 +0,0 @@ -# 目标检测 C++ API Demo 使用指南 - -在 ARMLinux 上实现实时的目标检测功能,此 Demo 有较好的的易用性和扩展性,如在 Demo 中跑自己训练好的模型等。 - - 如果该开发板使用搭载了芯原 NPU (瑞芯微、晶晨、JQL、恩智浦)的 Soc,将有更好的加速效果。 - -## 如何运行目标检测 Demo - -### 环境准备 - -* 准备 ARMLiunx 开发版,将系统刷为 Ubuntu,用于 Demo 编译和运行。请注意,本 Demo 是使用板上编译,而非交叉编译,因此需要图形界面的开发板操作系统。 -* 如果需要使用 芯原 NPU 的计算加速,对 NPU 驱动版本有严格要求,请务必注意事先参考 [芯原 TIM-VX 部署示例](https://paddle-lite.readthedocs.io/zh/develop/demo_guides/verisilicon_timvx.html#id6),将 NPU 驱动改为要求的版本。 -* Paddle Lite 当前已验证的开发板为 Khadas VIM3(芯片为 Amlogic A311d)、荣品 RV1126、荣品RV1109,其它平台用户可自行尝试; - - Khadas VIM3:由于 VIM3 出厂自带 Android 系统,请先刷成 Ubuntu 系统,在此提供刷机教程:[VIM3/3L Linux 文档](https://docs.khadas.com/linux/zh-cn/vim3),其中有详细描述刷机方法。以及系统镜像:VIM3 Linux:VIM3_Ubuntu-gnome-focal_Linux-4.9_arm64_EMMC_V1.0.7-210625:[官方链接](http://dl.khadas.com/firmware/VIM3/Ubuntu/EMMC/VIM3_Ubuntu-gnome-focal_Linux-4.9_arm64_EMMC_V1.0.7-210625.img.xz);[百度云备用链接](https://paddlelite-demo.bj.bcebos.com/devices/verisilicon/firmware/khadas/vim3/VIM3_Ubuntu-gnome-focal_Linux-4.9_arm64_EMMC_V1.0.7-210625.img.xz) - - 荣品 RV1126、1109:由于出场自带 buildroot 系统,如果使用 GUI 界面的 demo,请先刷成 Ubuntu 系统,在此提供刷机教程:[RV1126/1109 教程](https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/os_img/rockchip/RV1126-RV1109%E4%BD%BF%E7%94%A8%E6%8C%87%E5%AF%BC%E6%96%87%E6%A1%A3-V3.0.pdf),[刷机工具](https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/os_img/rockchip/RKDevTool_Release.zip),以及镜像:[1126镜像](https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/os_img/update-pro-rv1126-ubuntu20.04-5-720-1280-v2-20220505.img),[1109镜像](https://paddlelite-demo.bj.bcebos.com/Paddle-Lite-Demo/os_img/update-pro-rv1109-ubuntu20.04-5.5-720-1280-v2-20220429.img)。完整的文档和各种镜像请参考[百度网盘链接](https://pan.baidu.com/s/1Id0LMC0oO2PwR2YcYUAaiQ#list/path=%2F&parentPath=%2Fsharelink2521613171-184070898837664),密码:2345。 -* 准备 usb camera,注意使用 openCV capture 图像时,请注意 usb camera 的 video序列号作为入参。 -* 请注意,瑞芯微芯片不带有 HDMI 接口,图像显示是依赖 MIPI DSI,所以请准备好 MIPI 显示屏(我们提供的镜像是 720*1280 分辨率,网盘中有更多分辨率选择,注意:请选择 camera-gc2093x2 的镜像)。 -* 配置开发板的网络。如果是办公网络红区,可以将开发板和PC用以太网链接,然后PC共享网络给开发板。 -* gcc g++ opencv cmake 的安装(以下所有命令均在设备上操作) - -```bash -$ sudo apt-get update -$ sudo apt-get install gcc g++ make wget unzip libopencv-dev pkg-config -$ wget https://www.cmake.org/files/v3.10/cmake-3.10.3.tar.gz -$ tar -zxvf cmake-3.10.3.tar.gz -$ cd cmake-3.10.3 -$ ./configure -$ make -$ sudo make install -``` - -### 部署步骤 - -1. 将本 repo 上传至 VIM3 开发板,或者直接开发板上下载或者 git clone 本 repo -2. 目标检测 Demo 位于 `Paddle-Lite-Demo/object_detection/linux/picodet_detection` 目录 -3. 进入 `Paddle-Lite-Demo/object_detection/linux` 目录, 终端中执行 `download_models_and_libs.sh` 脚本自动下载模型和 Paddle Lite 预测库 - -```shell -cd Paddle-Lite-Demo/object_detection/linux # 1. 终端中进入 Paddle-Lite-Demo/object_detection/linux -sh download_models_and_libs.sh # 2. 执行脚本下载依赖项 (需要联网) -``` - -下载完成后会出现提示: `Download successful!` -4. 执行用例(保证 ARMLinux 环境准备完成) - -```shell -cd picodet_detection # 1. 终端中进入 -sh build.sh armv8 # 2. 编译 Demo 可执行程序,默认编译 armv8,如果是 32bit 环境,则改成 sh build.sh armv7hf。 -sh run.sh armv8 # 3. 执行物体检测(picodet 模型) demo,会直接开启摄像头,启动图形界面并呈现检测结果。如果是 32bit 环境,则改成 sh run.sh armv7hf -``` - -### Demo 结果如下:(注意,示例的 picodet 仅使用 coco 数据集,在实际场景中效果一般,请使用实际业务场景重新训练) - - demo_view - -## 更新预测库 - -* Paddle Lite 项目:https://github.com/PaddlePaddle/Paddle-Lite - * 参考 [芯原 TIM-VX 部署示例](https://paddle-lite.readthedocs.io/zh/develop/demo_guides/verisilicon_timvx.html#tim-vx),编译预测库 - * 编译最终产物位于 `build.lite.xxx.xxx.xxx` 下的 `inference_lite_lib.xxx.xxx` - * 替换 c++ 库 - * 头文件 - 将生成的 `build.lite.linux.armv8.gcc/inference_lite_lib.armlinux.armv8.nnadapter/cxx/include` 文件夹替换 Demo 中的 `Paddle-Lite-Demo/object_detection/linux/Paddle-Lite/include` - * armv8 - 将生成的 `build.lite.linux.armv8.gcc/inference_lite_lib.armlinux.armv8.nnadapter/cxx/libs/libpaddle_full_api_shared.so、libnnadapter.so、libtim-vx.so、libverisilicon_timvx.so` 库替换 Demo 中的 `Paddle-Lite-Demo/object_detection/linux/Paddle-Lite/libs/armv8/` 目录下同名 so - * armv7hf - 将生成的 `build.lite.linux.armv7hf.gcc/inference_lite_lib.armlinux.armv7hf.nnadapter/cxx/libs/libpaddle_full_api_shared.so、libnnadapter.so、libtim-vx.so、libverisilicon_timvx.so` 库替换 Demo 中的 `Paddle-Lite-Demo/object_detection/linux/Paddle-Lite/libs/armv7hf/` 目录下同名 so - -## Demo 内容介绍 - -先整体介绍下目标检测 Demo 的代码结构,然后再简要地介绍 Demo 每部分功能. - -1. `object_detection_demo.cc`: C++ 预测代码 - -```shell -# 位置: -Paddle-Lite-Demo/object_detection/linux/picodet_detection/object_detection_demo.cc -``` - -2. `models` : 模型文件夹 (执行 download_models_and_libs.sh 后会下载 picodet Paddle 模型), label 使用 Paddle-Lite-Demo/object_detection/assets/labels 目录下 coco_label_list.txt - -```shell -# 位置: -Paddle-Lite-Demo/object_detection/linux/picodet_detection/models/picodetv2_relu6_coco_no_fuse -Paddle-Lite-Demo/object_detection/assets/labels/coco_label_list.txt -``` - -3. `Paddle-Lite`:内含 Paddle-Lite 头文件和 动态库,默认带有 timvx 加速库,以及第三方库 yaml-cpp 用于解析 yml 配置文件(执行 download_models_and_libs.sh 后会下载) - -```shell -# 位置 -# 如果要替换动态库 so,则将新的动态库 so 更新到此目录下 -Paddle-Lite-Demo/object_detection/linux/Paddle-Lite/libs/armv8 -Paddle-Lite-Demo/object_detection/linux/Paddle-Lite/include -``` - -4. `CMakeLists.txt` : C++ 预测代码的编译脚本,用于生成可执行文件 - -```shell -# 位置 -Paddle-Lite-Demo/object_detection/linux/picodet_detection/CMakeLists.txt -# 如果有cmake 编译选项更新,可以在 CMakeLists.txt 进行修改即可,默认编译 armv8 可执行文件; -``` - -5. `build.sh` : 编译脚本 - -```shell -# 位置 -Paddle-Lite-Demo/object_detection/linux/picodet_detection/build.sh -``` - -6. `run.sh` : 运行脚本,请注意设置 arm-aarch,armv8 或者 armv7hf。默认为armv8 - -```shell -# 位置 -Paddle-Lite-Demo/object_detection/linux/picodet_detection/run.sh -``` -- 请注意,运行需要5个元素:测试程序、模型、label 文件、异构配置、yaml 文件。 - -## 代码讲解 (使用 Paddle Lite `C++ API` 执行预测) - -ARMLinux 示例基于 C++ API 开发,调用 Paddle Lite `C++s API` 包括以下五步。更详细的 `API` 描述参考:[Paddle Lite C++ API ](https://paddle-lite.readthedocs.io/zh/latest/api_reference/cxx_api_doc.html)。 - -```c++ -#include -// 引入 C++ API -#include "include/paddle_api.h" -#include "include/paddle_use_ops.h" -#include "include/paddle_use_kernels.h" - -// 使用在线编译模型的方式(等价于使用 opt 工具) - -// 1. 设置 CxxConfig -paddle::lite_api::CxxConfig cxx_config; -std::vector valid_places; -valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kInt8)}); -valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kFloat)}); -// 如果只需要 cpu 计算,那到此结束即可,下面是设置 NPU 的代码段 -valid_places.push_back( - paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kInt8)}); -cxx_config.set_valid_places(valid_places); -std::string device = "verisilicon_timvx"; -cxx_config.set_nnadapter_device_names({device}); -// 设置定制化的异构策略 (如需要) -cxx_config.set_nnadapter_subgraph_partition_config_buffer( - nnadapter_subgraph_partition_config_string); - -// 2. 生成 nb 模型 (等价于 opt 工具的产出) -std::shared_ptr predictor = nullptr; -predictor = paddle::lite_api::CreatePaddlePredictor(cxx_config); -predictor->SaveOptimizedModel( - model_path, paddle::lite_api::LiteModelType::kNaiveBuffer); - -// 3. 设置 MobileConfig -MobileConfig config; -config.set_model_from_file(modelPath); // 设置 NaiveBuffer 格式模型路径 -config.set_power_mode(LITE_POWER_NO_BIND); // 设置 CPU 运行模式 -config.set_threads(4); // 设置工作线程数 - -// 4. 创建 PaddlePredictor -predictor = CreatePaddlePredictor(config); - -// 5. 设置输入数据,注意,如果是带后处理的 picodet ,则是有两个输入 -std::unique_ptr input_tensor(std::move(predictor->GetInput(0))); -input_tensor->Resize({1, 3, 416, 416}); -auto* data = input_tensor->mutable_data(); -// scale_factor tensor -auto scale_factor_tensor = predictor->GetInput(1); -scale_factor_tensor->Resize({1, 2}); -auto scale_factor_data = scale_factor_tensor->mutable_data(); -scale_factor_data[0] = 1.0f; -scale_factor_data[1] = 1.0f; - -// 6. 执行预测 -predictor->run(); - -// 7. 获取输出数据 -std::unique_ptr output_tensor(std::move(predictor->GetOutput(0))); - -``` - -## 如何更新模型和输入/输出预处理 - -### 更新模型 -1. 请参考 PaddleDetection 中 [picodet 重训和全量化文档](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/configs/picodet/FULL_QUANTIZATION.md),基于用户自己数据集重训并且重新全量化 -2. 将模型存放到目录 `object_detection_demo/models/` 下; -3. 模型名字跟工程中模型名字一模一样,即均是使用 `model`、`params`; - -```shell -# shell 脚本 `object_detection_demo/run.sh` -TARGET_ABI=armv8 # for 64bit, such as Amlogic A311D -#TARGET_ABI=armv7hf # for 32bit, such as Rockchip 1109/1126 -if [ -n "$1" ]; then - TARGET_ABI=$1 -fi -export LD_LIBRARY_PATH=../Paddle-Lite/libs/$TARGET_ABI/ -export GLOG_v=0 # Paddle-Lite 日志等级 -export VSI_NN_LOG_LEVEL=0 # TIM-VX 日志等级 -export VIV_VX_ENABLE_GRAPH_TRANSFORM=-pcq:1 # NPU 开启 perchannel 量化模型 -export VIV_VX_SET_PER_CHANNEL_ENTROPY=100 # 同上 -build/object_detection_demo models/picodetv2_relu6_coco_no_fuse ../../assets/labels/coco_label_list.txt models/picodetv2_relu6_coco_no_fuse/subgraph.txt models/picodetv2_relu6_coco_no_fuse/picodet.yml # 执行 Demo 程序,4个 arg 分别为:模型、 label 文件、 自定义异构配置、 yaml -``` - -- 如果需要更新 `label_list` 或者 `yaml` 文件,则修改 `object_detection_demo/run.sh` 中执行命令的第二个和第四个 arg 指定为新的 label 文件和 yaml 配置文件; - -```shell -# 代码文件 `object_detection_demo/rush.sh` -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${PADDLE_LITE_DIR}/libs/${TARGET_ARCH_ABI} -build/object_detection_demo {模型} {label} {自定义异构配置文件} {yaml} -``` - -### 更新输入/输出预处理 - -1. 更新输入预处理 -预处理完全根据 yaml 文件来,如果完全按照 PaddleDetection 中 picodet 重训,只需要替换 yaml 文件即可 - -2. 更新输出预处理 -此处需要更新 `object_detection_demo/object_detection_demo.cc` 中的 `postprocess` 方法 - -```c++ -std::vector postprocess(const float *output_data, int64_t output_size, - const std::vector &word_labels, - const float score_threshold, - cv::Mat &output_image, double time) { - std::vector results; - std::vector colors = { - cv::Scalar(237, 189, 101), cv::Scalar(0, 0, 255), - cv::Scalar(102, 153, 153), cv::Scalar(255, 0, 0), - cv::Scalar(9, 255, 0), cv::Scalar(0, 0, 0), - cv::Scalar(51, 153, 51)}; - for (int64_t i = 0; i < output_size; i += 6) { - if (output_data[i + 1] < score_threshold) { - continue; - } - int class_id = static_cast(output_data[i]); - float score = output_data[i + 1]; - RESULT result; - std::string class_name = "Unknown"; - if (word_labels.size() > 0 && class_id >= 0 && - class_id < word_labels.size()) { - class_name = word_labels[class_id]; - } - result.class_name = class_name; - result.score = score; - result.left = output_data[i + 2] / 416; // 此处416根据输入的 HW 得来 - result.top = output_data[i + 3] / 416; - result.right = output_data[i + 4] / 416; - result.bottom = output_data[i + 5] / 416; - int lx = static_cast(result.left * output_image.cols); - int ly = static_cast(result.top * output_image.rows); - int w = static_cast(result.right * output_image.cols) - lx; - int h = static_cast(result.bottom * output_image.rows) - ly; - cv::Rect bounding_box = - cv::Rect(lx, ly, w, h) & - cv::Rect(0, 0, output_image.cols, output_image.rows); - if (w > 0 && h > 0 && score <= 1) { - cv::Scalar color = colors[results.size() % colors.size()]; - cv::rectangle(output_image, bounding_box, color); - cv::rectangle(output_image, cv::Point2d(lx, ly), - cv::Point2d(lx + w, ly - 10), color, -1); - cv::putText(output_image, std::to_string(results.size()) + "." + - class_name + ":" + std::to_string(score), - cv::Point2d(lx, ly), cv::FONT_HERSHEY_PLAIN, 1, - cv::Scalar(255, 255, 255)); - results.push_back(result); - } - } - return results; -} -``` - -## 更新模型后,自定义 NPU-CPU 异构配置(如需使用 NPU 加速) -由于使用芯原 NPU 在 8bit 量化的情况下有最优的性能,因此部署时,我们往往会考虑量化 - - 由于量化可能会引入一定程度的精度问题,所以我们可以通过自定义的异构定制,来将部分有精度问题的 layer 异构至cpu,从而达到最优的精度 - -### 第一步,确定模型量化后在 arm cpu 上的精度 -如果在 arm cpu 上,精度都无法满足,那量化本身就是失败的,此时可以考虑修改训练集或者预处理。 - - 修改 Demo 程序,仅用 arm cpu 计算 -```c++ -paddle::lite_api::CxxConfig cxx_config; -std::vector valid_places; -valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kInt8)}); -valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kFloat)}); -// 仅用 arm cpu 计算, 注释如下代码即可 -/* -valid_places.push_back( - paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kInt8)}); -valid_places.push_back( - paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kFloat)}); -*/ -``` -如果 arm cpu 计算结果精度达标,则继续 - -### 第二步,获取整网拓扑信息 - - 回退第一步的修改,不再注释,使用 NPU 加速 - - 运行 Demo,如果此时精度良好,则无需参考后面步骤,模型部署和替换非常顺利,enjoy it。 - - 如果精度不行,请参考后续步骤。 - -### 第三步,获取整网拓扑信息 - - 回退第一步的修改,使用 - - 修改 run.sh ,将其中 export GLOG_v=0 改为 export GLOG_v=5 - - 运行 Demo,等摄像头启动,即可 ctrl+c 关闭 Demo - - 收集日志,搜索关键字 "subgraph operators" 随后那一段,便是整个模型的拓扑信息,其格式如下: - - 每行记录由『算子类型:输入张量名列表:输出张量名列表』组成(即以分号分隔算子类型、输入和输出张量名列表),以逗号分隔输入、输出张量名列表中的每个张量名; - - 示例说明: - ``` - op_type0:var_name0,var_name1:var_name2 表示将算子类型为 op_type0、输入张量为var_name0 和 var_name1、输出张量为 var_name2 的节点强制运行在 ARM CPU 上 - ``` - -### 第四步,修改异构配置文件 - - 首先看到示例 Demo 中 Paddle-Lite-Demo/object_detection/linux/picodet_detection/models/picodetv2_relu6_coco_no_fuse 目录下的 subgraph.txt 文件。(feed 和 fetch 分别代表整个模型的输入和输入) - ``` - feed:feed:scale_factor - feed:feed:image - - sqrt:tmp_3:sqrt_0.tmp_0 - reshape2:sqrt_0.tmp_0:reshape2_0.tmp_0,reshape2_0.tmp_1 - - matmul_v2:softmax_0.tmp_0,auto_113_:linear_0.tmp_0 - reshape2:linear_0.tmp_0:reshape2_2.tmp_0,reshape2_2.tmp_1 - - sqrt:tmp_6:sqrt_1.tmp_0 - reshape2:sqrt_1.tmp_0:reshape2_3.tmp_0,reshape2_3.tmp_1 - - matmul_v2:softmax_1.tmp_0,auto_113_:linear_1.tmp_0 - reshape2:linear_1.tmp_0:reshape2_5.tmp_0,reshape2_5.tmp_1 - - sqrt:tmp_9:sqrt_2.tmp_0 - reshape2:sqrt_2.tmp_0:reshape2_6.tmp_0,reshape2_6.tmp_1 - - matmul_v2:softmax_2.tmp_0,auto_113_:linear_2.tmp_0 - ... - ``` - - 在 txt 中的都是需要异构至 cpu 计算的 layer,在示例 Demo 中,我们把 picodet 后处理的部分异构至 arm cpu 做计算,不必担心,Paddle-Lite 的 arm kernel 性能也是非常卓越。 - - 如果新训练的模型没有额外修改 layer,则直接复制使用示例 Demo 中的 subgraph.txt 即可 - - 此时 ./run.sh 看看精度是否符合预期,如果精度符合预期,恭喜,可以跳过本章节,enjoy it。 - - 如果精度不符合预期,则将上文『第二步,获取整网拓扑信息』中获取的拓扑信息,从 "feed" 之后第一行,直到 "sqrt" 之前,都复制进 sugraph.txt。这一步代表了将大量的 backbone 部分算子放到 arm cpu 计算。 - - 此时 ./run.sh 看看精度是否符合预期,如果精度达标,那说明在 backbone 中确实存在引入 NPU 精度异常的层(再次重申,在 subgraph.txt 的代表强制在 arm cpu 计算)。 - - 逐行删除、成片删除、二分法,发挥开发人员的耐心,找到引入 NPU 精度异常的 layer,将其留在 subgraph.txt 中,按照经验,如果有 NPU 精度问题,可能会有 1~5 层conv layer 需要异构。 - - 剩余没有精度问题的 layer 在 subgraph.txt 中删除即可 diff --git a/examples/vision/detection/paddledetection/rk1126/picodet_detection/build.sh b/examples/vision/detection/paddledetection/rk1126/picodet_detection/build.sh deleted file mode 100755 index 1219c481b9..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/picodet_detection/build.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -USE_FULL_API=TRUE -# configure -TARGET_ARCH_ABI=armv8 # for RK3399, set to default arch abi -#TARGET_ARCH_ABI=armv7hf # for Raspberry Pi 3B -PADDLE_LITE_DIR=../Paddle-Lite -THIRD_PARTY_DIR=./third_party -if [ "x$1" != "x" ]; then - TARGET_ARCH_ABI=$1 -fi - -# build -rm -rf build -mkdir build -cd build -cmake -DPADDLE_LITE_DIR=${PADDLE_LITE_DIR} -DTARGET_ARCH_ABI=${TARGET_ARCH_ABI} -DTHIRD_PARTY_DIR=${THIRD_PARTY_DIR} .. -make diff --git a/examples/vision/detection/paddledetection/rk1126/picodet_detection/object_detection_demo.cc b/examples/vision/detection/paddledetection/rk1126/picodet_detection/object_detection_demo.cc deleted file mode 100644 index 8c132dea27..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/picodet_detection/object_detection_demo.cc +++ /dev/null @@ -1,411 +0,0 @@ -// 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. - -#include "paddle_api.h" -#include "yaml-cpp/yaml.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int WARMUP_COUNT = 0; -int REPEAT_COUNT = 1; -const int CPU_THREAD_NUM = 2; -const paddle::lite_api::PowerMode CPU_POWER_MODE = - paddle::lite_api::PowerMode::LITE_POWER_HIGH; -const std::vector INPUT_SHAPE = {1, 3, 416, 416}; -std::vector INPUT_MEAN = {0.f, 0.f, 0.f}; -std::vector INPUT_STD = {1.f, 1.f, 1.f}; -float INPUT_SCALE = 1 / 255.f; -const float SCORE_THRESHOLD = 0.35f; - -struct RESULT { - std::string class_name; - float score; - float left; - float top; - float right; - float bottom; -}; - -inline int64_t get_current_us() { - struct timeval time; - gettimeofday(&time, NULL); - return 1000000LL * (int64_t)time.tv_sec + (int64_t)time.tv_usec; -} - -bool read_file(const std::string &filename, std::vector *contents, - bool binary = true) { - FILE *fp = fopen(filename.c_str(), binary ? "rb" : "r"); - if (!fp) - return false; - fseek(fp, 0, SEEK_END); - size_t size = ftell(fp); - fseek(fp, 0, SEEK_SET); - contents->clear(); - contents->resize(size); - size_t offset = 0; - char *ptr = reinterpret_cast(&(contents->at(0))); - while (offset < size) { - size_t already_read = fread(ptr, 1, size - offset, fp); - offset += already_read; - ptr += already_read; - } - fclose(fp); - return true; -} - -std::vector load_labels(const std::string &path) { - std::ifstream file; - std::vector labels; - file.open(path); - while (file) { - std::string line; - std::getline(file, line); - labels.push_back(line); - } - file.clear(); - file.close(); - return labels; -} - -bool load_yaml_config(std::string yaml_path) { - YAML::Node cfg; - try { - std::cout << "before loadFile" << std::endl; - cfg = YAML::LoadFile(yaml_path); - } catch (YAML::BadFile &e) { - std::cout << "Failed to load yaml file " << yaml_path - << ", maybe you should check this file." << std::endl; - return false; - } - auto preprocess_cfg = cfg["TestReader"]["sample_transforms"]; - for (const auto &op : preprocess_cfg) { - if (!op.IsMap()) { - std::cout << "Require the transform information in yaml be Map type." - << std::endl; - std::abort(); - } - auto op_name = op.begin()->first.as(); - if (op_name == "NormalizeImage") { - INPUT_MEAN = op.begin()->second["mean"].as>(); - INPUT_STD = op.begin()->second["std"].as>(); - INPUT_SCALE = op.begin()->second["scale"].as(); - } - } - return true; -} - -void preprocess(cv::Mat &input_image, std::vector &input_mean, - std::vector &input_std, float input_scale, - int input_width, int input_height, float *input_data) { - cv::Mat resize_image; - cv::resize(input_image, resize_image, cv::Size(input_width, input_height), 0, - 0); - if (resize_image.channels() == 4) { - cv::cvtColor(resize_image, resize_image, cv::COLOR_BGRA2RGB); - } - cv::Mat norm_image; - resize_image.convertTo(norm_image, CV_32FC3, input_scale); - // NHWC->NCHW - int image_size = input_height * input_width; - const float *image_data = reinterpret_cast(norm_image.data); - float32x4_t vmean0 = vdupq_n_f32(input_mean[0]); - float32x4_t vmean1 = vdupq_n_f32(input_mean[1]); - float32x4_t vmean2 = vdupq_n_f32(input_mean[2]); - float32x4_t vscale0 = vdupq_n_f32(1.0f / input_std[0]); - float32x4_t vscale1 = vdupq_n_f32(1.0f / input_std[1]); - float32x4_t vscale2 = vdupq_n_f32(1.0f / input_std[2]); - float *input_data_c0 = input_data; - float *input_data_c1 = input_data + image_size; - float *input_data_c2 = input_data + image_size * 2; - int i = 0; - for (; i < image_size - 3; i += 4) { - float32x4x3_t vin3 = vld3q_f32(image_data); - float32x4_t vsub0 = vsubq_f32(vin3.val[0], vmean0); - float32x4_t vsub1 = vsubq_f32(vin3.val[1], vmean1); - float32x4_t vsub2 = vsubq_f32(vin3.val[2], vmean2); - float32x4_t vs0 = vmulq_f32(vsub0, vscale0); - float32x4_t vs1 = vmulq_f32(vsub1, vscale1); - float32x4_t vs2 = vmulq_f32(vsub2, vscale2); - vst1q_f32(input_data_c0, vs0); - vst1q_f32(input_data_c1, vs1); - vst1q_f32(input_data_c2, vs2); - image_data += 12; - input_data_c0 += 4; - input_data_c1 += 4; - input_data_c2 += 4; - } - for (; i < image_size; i++) { - *(input_data_c0++) = (*(image_data++) - input_mean[0]) / input_std[0]; - *(input_data_c1++) = (*(image_data++) - input_mean[1]) / input_std[1]; - *(input_data_c2++) = (*(image_data++) - input_mean[2]) / input_std[2]; - } -} - -std::vector postprocess(const float *output_data, int64_t output_size, - const std::vector &word_labels, - const float score_threshold, - cv::Mat &output_image, double time) { - std::vector results; - std::vector colors = { - cv::Scalar(237, 189, 101), cv::Scalar(0, 0, 255), - cv::Scalar(102, 153, 153), cv::Scalar(255, 0, 0), - cv::Scalar(9, 255, 0), cv::Scalar(0, 0, 0), - cv::Scalar(51, 153, 51)}; - for (int64_t i = 0; i < output_size; i += 6) { - if (output_data[i + 1] < score_threshold) { - continue; - } - int class_id = static_cast(output_data[i]); - float score = output_data[i + 1]; - RESULT result; - std::string class_name = "Unknown"; - if (word_labels.size() > 0 && class_id >= 0 && - class_id < word_labels.size()) { - class_name = word_labels[class_id]; - } - result.class_name = class_name; - result.score = score; - result.left = output_data[i + 2] / 416; - result.top = output_data[i + 3] / 416; - result.right = output_data[i + 4] / 416; - result.bottom = output_data[i + 5] / 416; - int lx = static_cast(result.left * output_image.cols); - int ly = static_cast(result.top * output_image.rows); - int w = static_cast(result.right * output_image.cols) - lx; - int h = static_cast(result.bottom * output_image.rows) - ly; - cv::Rect bounding_box = - cv::Rect(lx, ly, w, h) & - cv::Rect(0, 0, output_image.cols, output_image.rows); - if (w > 0 && h > 0 && score <= 1) { - cv::Scalar color = colors[results.size() % colors.size()]; - cv::rectangle(output_image, bounding_box, color); - cv::rectangle(output_image, cv::Point2d(lx, ly), - cv::Point2d(lx + w, ly - 10), color, -1); - cv::putText(output_image, std::to_string(results.size()) + "." + - class_name + ":" + std::to_string(score), - cv::Point2d(lx, ly), cv::FONT_HERSHEY_PLAIN, 1, - cv::Scalar(255, 255, 255)); - results.push_back(result); - } - } - return results; -} - -cv::Mat process(cv::Mat &input_image, std::vector &word_labels, - std::shared_ptr &predictor) { - // Preprocess image and fill the data of input tensor - std::unique_ptr input_tensor( - std::move(predictor->GetInput(0))); - input_tensor->Resize(INPUT_SHAPE); - int input_width = INPUT_SHAPE[3]; - int input_height = INPUT_SHAPE[2]; - auto *input_data = input_tensor->mutable_data(); -#if 1 - // scale_factor tensor - auto scale_factor_tensor = predictor->GetInput(1); - scale_factor_tensor->Resize({1, 2}); - auto scale_factor_data = scale_factor_tensor->mutable_data(); - scale_factor_data[0] = 1.0f; - scale_factor_data[1] = 1.0f; -#endif - - double preprocess_start_time = get_current_us(); - preprocess(input_image, INPUT_MEAN, INPUT_STD, INPUT_SCALE, input_width, - input_height, input_data); - double preprocess_end_time = get_current_us(); - double preprocess_time = - (preprocess_end_time - preprocess_start_time) / 1000.0f; - - double prediction_time; - // Run predictor - // warm up to skip the first inference and get more stable time, remove it in - // actual products - for (int i = 0; i < WARMUP_COUNT; i++) { - predictor->Run(); - } - // repeat to obtain the average time, set REPEAT_COUNT=1 in actual products - double max_time_cost = 0.0f; - double min_time_cost = std::numeric_limits::max(); - double total_time_cost = 0.0f; - for (int i = 0; i < REPEAT_COUNT; i++) { - auto start = get_current_us(); - predictor->Run(); - auto end = get_current_us(); - double cur_time_cost = (end - start) / 1000.0f; - if (cur_time_cost > max_time_cost) { - max_time_cost = cur_time_cost; - } - if (cur_time_cost < min_time_cost) { - min_time_cost = cur_time_cost; - } - total_time_cost += cur_time_cost; - prediction_time = total_time_cost / REPEAT_COUNT; - printf("iter %d cost: %f ms\n", i, cur_time_cost); - } - printf("warmup: %d repeat: %d, average: %f ms, max: %f ms, min: %f ms\n", - WARMUP_COUNT, REPEAT_COUNT, prediction_time, max_time_cost, - min_time_cost); - - // Get the data of output tensor and postprocess to output detected objects - std::unique_ptr output_tensor( - std::move(predictor->GetOutput(0))); - const float *output_data = output_tensor->mutable_data(); - int64_t output_size = 1; - for (auto dim : output_tensor->shape()) { - output_size *= dim; - } - cv::Mat output_image = input_image.clone(); - double postprocess_start_time = get_current_us(); - std::vector results = - postprocess(output_data, output_size, word_labels, SCORE_THRESHOLD, - output_image, prediction_time); - double postprocess_end_time = get_current_us(); - double postprocess_time = - (postprocess_end_time - postprocess_start_time) / 1000.0f; - - printf("results: %d\n", results.size()); - for (int i = 0; i < results.size(); i++) { - printf("[%d] %s - %f %f,%f,%f,%f\n", i, results[i].class_name.c_str(), - results[i].score, results[i].left, results[i].top, results[i].right, - results[i].bottom); - } - printf("Preprocess time: %f ms\n", preprocess_time); - printf("Prediction time: %f ms\n", prediction_time); - printf("Postprocess time: %f ms\n\n", postprocess_time); - - return output_image; -} - -int main(int argc, char **argv) { - if (argc < 5 || argc == 6) { - printf("Usage: \n" - "./object_detection_demo model_dir label_path [input_image_path] " - "[output_image_path]" - "use images from camera if input_image_path and input_image_path " - "isn't provided."); - return -1; - } - - std::string model_path = argv[1]; - std::string label_path = argv[2]; - std::vector word_labels = load_labels(label_path); - std::string nnadapter_subgraph_partition_config_path = argv[3]; - - std::string yaml_path = argv[4]; - if (yaml_path != "null") { - load_yaml_config(yaml_path); - } - - // Run inference by using full api with CxxConfig - paddle::lite_api::CxxConfig cxx_config; - if (1) { // combined model - cxx_config.set_model_file(model_path + "/model"); - cxx_config.set_param_file(model_path + "/params"); - } else { - cxx_config.set_model_dir(model_path); - } - cxx_config.set_threads(CPU_THREAD_NUM); - cxx_config.set_power_mode(CPU_POWER_MODE); - - std::shared_ptr predictor = nullptr; - std::vector valid_places; - valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kInt8)}); - valid_places.push_back( - paddle::lite_api::Place{TARGET(kARM), PRECISION(kFloat)}); - valid_places.push_back( - paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kInt8)}); - valid_places.push_back( - paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kFloat)}); - cxx_config.set_valid_places(valid_places); - std::string device = "verisilicon_timvx"; - cxx_config.set_nnadapter_device_names({device}); - // cxx_config.set_nnadapter_context_properties(nnadapter_context_properties); - - // cxx_config.set_nnadapter_model_cache_dir(nnadapter_model_cache_dir); - // Set the subgraph custom partition configuration file - - if (!nnadapter_subgraph_partition_config_path.empty()) { - std::vector nnadapter_subgraph_partition_config_buffer; - if (read_file(nnadapter_subgraph_partition_config_path, - &nnadapter_subgraph_partition_config_buffer, false)) { - if (!nnadapter_subgraph_partition_config_buffer.empty()) { - std::string nnadapter_subgraph_partition_config_string( - nnadapter_subgraph_partition_config_buffer.data(), - nnadapter_subgraph_partition_config_buffer.size()); - cxx_config.set_nnadapter_subgraph_partition_config_buffer( - nnadapter_subgraph_partition_config_string); - } - } else { - printf("Failed to load the subgraph custom partition configuration file " - "%s\n", - nnadapter_subgraph_partition_config_path.c_str()); - } - } - - try { - predictor = paddle::lite_api::CreatePaddlePredictor(cxx_config); - predictor->SaveOptimizedModel( - model_path, paddle::lite_api::LiteModelType::kNaiveBuffer); - } catch (std::exception e) { - printf("An internal error occurred in PaddleLite(cxx config).\n"); - } - - paddle::lite_api::MobileConfig config; - config.set_model_from_file(model_path + ".nb"); - config.set_threads(CPU_THREAD_NUM); - config.set_power_mode(CPU_POWER_MODE); - config.set_nnadapter_device_names({device}); - predictor = - paddle::lite_api::CreatePaddlePredictor( - config); - if (argc > 5) { - WARMUP_COUNT = 1; - REPEAT_COUNT = 5; - std::string input_image_path = argv[5]; - std::string output_image_path = argv[6]; - cv::Mat input_image = cv::imread(input_image_path); - cv::Mat output_image = process(input_image, word_labels, predictor); - cv::imwrite(output_image_path, output_image); - cv::imshow("Object Detection Demo", output_image); - cv::waitKey(0); - } else { - cv::VideoCapture cap(1); - cap.set(cv::CAP_PROP_FRAME_WIDTH, 640); - cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480); - if (!cap.isOpened()) { - return -1; - } - while (1) { - cv::Mat input_image; - cap >> input_image; - cv::Mat output_image = process(input_image, word_labels, predictor); - cv::imshow("Object Detection Demo", output_image); - if (cv::waitKey(1) == char('q')) { - break; - } - } - cap.release(); - cv::destroyAllWindows(); - } - return 0; -} diff --git a/examples/vision/detection/paddledetection/rk1126/picodet_detection/run.sh b/examples/vision/detection/paddledetection/rk1126/picodet_detection/run.sh deleted file mode 100755 index a6025104a1..0000000000 --- a/examples/vision/detection/paddledetection/rk1126/picodet_detection/run.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -#run - -TARGET_ABI=armv8 # for 64bit -#TARGET_ABI=armv7hf # for 32bit -if [ -n "$1" ]; then - TARGET_ABI=$1 -fi -export LD_LIBRARY_PATH=../Paddle-Lite/libs/$TARGET_ABI/ -export GLOG_v=0 -export VSI_NN_LOG_LEVEL=0 -export VIV_VX_ENABLE_GRAPH_TRANSFORM=-pcq:1 -export VIV_VX_SET_PER_CHANNEL_ENTROPY=100 -export TIMVX_BATCHNORM_FUSION_MAX_ALLOWED_QUANT_SCALE_DEVIATION=30000 -build/object_detection_demo models/picodetv2_relu6_coco_no_fuse ../../assets/labels/coco_label_list.txt models/picodetv2_relu6_coco_no_fuse/subgraph.txt models/picodetv2_relu6_coco_no_fuse/picodet.yml diff --git a/examples/vision/detection/paddledetection/rv1126/README.md b/examples/vision/detection/paddledetection/rv1126/README.md new file mode 100755 index 0000000000..ff1d58bab6 --- /dev/null +++ b/examples/vision/detection/paddledetection/rv1126/README.md @@ -0,0 +1,11 @@ +# PP-YOLOE 量化模型在 RV1126 上的部署 +目前 FastDeploy 已经支持基于 PaddleLite 部署 PP-YOLOE 量化模型到 RV1126 上。 + +模型的量化和量化模型的下载请参考:[模型量化](../quantize/README.md) + + +## 详细部署文档 + +在 RV1126 上只支持 C++ 的部署。 + +- [C++部署](cpp) diff --git a/examples/vision/detection/paddledetection/rv1126/cpp/CMakeLists.txt b/examples/vision/detection/paddledetection/rv1126/cpp/CMakeLists.txt new file mode 100755 index 0000000000..7a145177ee --- /dev/null +++ b/examples/vision/detection/paddledetection/rv1126/cpp/CMakeLists.txt @@ -0,0 +1,38 @@ +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10) + +# 指定下载解压后的fastdeploy库路径 +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +# 添加FastDeploy依赖头文件 +include_directories(${FASTDEPLOY_INCS}) +include_directories(${FastDeploy_INCLUDE_DIRS}) + +add_executable(infer_demo ${PROJECT_SOURCE_DIR}/infer_ppyoloe.cc) +# 添加FastDeploy库依赖 +target_link_libraries(infer_demo ${FASTDEPLOY_LIBS}) + +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/build/install) + +install(TARGETS infer_demo DESTINATION ./) + +install(DIRECTORY models DESTINATION ./) +install(DIRECTORY images DESTINATION ./) +# install(DIRECTORY run_with_adb.sh DESTINATION ./) + +file(GLOB FASTDEPLOY_LIBS ${FASTDEPLOY_INSTALL_DIR}/lib/*) +install(PROGRAMS ${FASTDEPLOY_LIBS} DESTINATION lib) + +file(GLOB OPENCV_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/opencv/lib/lib*) +install(PROGRAMS ${OPENCV_LIBS} DESTINATION lib) + +file(GLOB PADDLELITE_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/lib*) +install(PROGRAMS ${PADDLELITE_LIBS} DESTINATION lib) + +file(GLOB TIMVX_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/verisilicon_timvx/*) +install(PROGRAMS ${TIMVX_LIBS} DESTINATION lib) + +file(GLOB ADB_TOOLS run_with_adb.sh) +install(PROGRAMS ${ADB_TOOLS} DESTINATION ./) diff --git a/examples/vision/detection/paddledetection/rv1126/cpp/README.md b/examples/vision/detection/paddledetection/rv1126/cpp/README.md new file mode 100755 index 0000000000..5b366bd83c --- /dev/null +++ b/examples/vision/detection/paddledetection/rv1126/cpp/README.md @@ -0,0 +1,55 @@ +# PP-YOLOE 量化模型 C++ 部署示例 + +本目录下提供的 `infer.cc`,可以帮助用户快速完成 PP-YOLOE 量化模型在 RV1126 上的部署推理加速。 + +## 部署准备 +### FastDeploy 交叉编译环境准备 +- 1. 软硬件环境满足要求,以及交叉编译环境的准备,请参考:[FastDeploy 交叉编译环境准备](../../../../../../docs/cn/build_and_install/rv1126.md#交叉编译环境搭建) + +### 模型准备 +- 1. 用户可以直接使用由 FastDeploy 提供的量化模型进行部署。 +- 2. 用户可以先使用 PaddleDetection 自行导出 Float32 模型,注意导出模型模型时设置参数:use_shared_conv=False,更多细节请参考:[PP-YOLOE](https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.4/configs/ppyoloe) +- 3. 用户可以使用 FastDeploy 提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署。(注意: 推理量化后的检测模型仍然需要FP32模型文件夹下的 infer_cfg.yml 文件,自行量化的模型文件夹内不包含此 yaml 文件,用户从 FP32 模型文件夹下复制此yaml文件到量化后的模型文件夹内即可。) +- 更多量化相关相关信息可查阅[模型量化](../../quantize/README.md) + +## 在 RV1126 上部署量化后的 PP-YOLOE 检测模型 +请按照以下步骤完成在 RV1126 上部署 PP-YOLOE 量化模型: +1. 交叉编译编译 FastDeploy 库,具体请参考:[交叉编译 FastDeploy](../../../../../../docs/cn/build_and_install/rv1126.md#基于-paddlelite-的-fastdeploy-交叉编译库编译) + +2. 将编译后的库拷贝到当前目录,可使用如下命令: +```bash +cp -r FastDeploy/build/fastdeploy-tmivx/ FastDeploy/examples/vision/detection/yolov5/rv1126/cpp +``` + +3. 在当前路径下载部署所需的模型和示例图片: +```bash +mkdir models && mkdir images +wget https://bj.bcebos.com/fastdeploy/models/ppyoloe_noshare_qat.tar.gz +tar -xvf ppyoloe_noshare_qat.tar.gz +cp -r ppyoloe_noshare_qat models +wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg +cp -r 000000014439.jpg images +``` + +4. 编译部署示例,可使入如下命令: +```bash +mkdir build && cd build +cmake -DCMAKE_TOOLCHAIN_FILE=${PWD}/../fastdeploy-tmivx/timvx.cmake -DFASTDEPLOY_INSTALL_DIR=${PWD}/../fastdeploy-tmivx .. +make -j8 +make install +# 成功编译之后,会生成 install 文件夹,里面有一个运行 demo 和部署所需的库 +``` + +5. 基于 adb 工具部署 PP-YOLOE 检测模型到 Rockchip RV1126,可使用如下命令: +```bash +# 进入 install 目录 +cd FastDeploy/examples/vision/detection/paddledetection/rv1126/cpp/build/install/ +# 如下命令表示:bash run_with_adb.sh 需要运行的demo 模型路径 图片路径 设备的DEVICE_ID +bash run_with_adb.sh infer_demo ppyoloe_noshare_qat 000000014439.jpg $DEVICE_ID +``` + +部署成功后运行结果如下: + + + +需要特别注意的是,在 RV1126 上部署的模型需要是量化后的模型,模型的量化请参考:[模型量化](../../../../../../docs/cn/quantize.md) diff --git a/examples/vision/detection/paddledetection/rv1126/cpp/infer_ppyoloe.cc b/examples/vision/detection/paddledetection/rv1126/cpp/infer_ppyoloe.cc new file mode 100755 index 0000000000..77368584f3 --- /dev/null +++ b/examples/vision/detection/paddledetection/rv1126/cpp/infer_ppyoloe.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2022 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. + +#include "fastdeploy/vision.h" +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void InitAndInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto config_file = model_dir + sep + "infer_cfg.yml"; + auto subgraph_file = model_dir + sep + "subgraph.txt"; + + fastdeploy::RuntimeOption option; + option.UseTimVX(); + option.SetLiteSubgraphPartitionPath(subgraph_file); + + auto model = fastdeploy::vision::detection::PPYOLOE(model_file, params_file, + config_file, option); + assert(model.Initialized()); + + auto im = cv::imread(image_file); + + fastdeploy::vision::DetectionResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + + std::cout << res.Str() << std::endl; + + auto vis_im = fastdeploy::vision::VisDetection(im, res, 0.5); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; + +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + std::cout << "Usage: infer_demo path/to/quant_model " + "path/to/image " + "run_option, " + "e.g ./infer_demo ./PPYOLOE_L_quant ./test.jpeg" + << std::endl; + return -1; + } + + std::string model_dir = argv[1]; + std::string test_image = argv[2]; + InitAndInfer(model_dir, test_image); + return 0; +} diff --git a/examples/vision/detection/paddledetection/rv1126/cpp/run_with_adb.sh b/examples/vision/detection/paddledetection/rv1126/cpp/run_with_adb.sh new file mode 100755 index 0000000000..dd7d7b47d2 --- /dev/null +++ b/examples/vision/detection/paddledetection/rv1126/cpp/run_with_adb.sh @@ -0,0 +1,47 @@ +#!/bin/bash +HOST_SPACE=${PWD} +echo ${HOST_SPACE} +WORK_SPACE=/data/local/tmp/test + +# The first parameter represents the demo name +DEMO_NAME=image_classification_demo +if [ -n "$1" ]; then + DEMO_NAME=$1 +fi + +# The second parameter represents the model name +MODEL_NAME=mobilenet_v1_fp32_224 +if [ -n "$2" ]; then + MODEL_NAME=$2 +fi + +# The third parameter indicates the name of the image to be tested +IMAGE_NAME=0001.jpg +if [ -n "$3" ]; then + IMAGE_NAME=$3 +fi + +# The fourth parameter represents the ID of the device +ADB_DEVICE_NAME= +if [ -n "$4" ]; then + ADB_DEVICE_NAME="-s $4" +fi + +# Set the environment variables required during the running process +EXPORT_ENVIRONMENT_VARIABLES="export GLOG_v=5; export SUBGRAPH_ONLINE_MODE=true; export RKNPU_LOGLEVEL=5; export RKNN_LOG_LEVEL=5; ulimit -c unlimited; export VIV_VX_ENABLE_GRAPH_TRANSFORM=-pcq:1; export VIV_VX_SET_PER_CHANNEL_ENTROPY=100; export TIMVX_BATCHNORM_FUSION_MAX_ALLOWED_QUANT_SCALE_DEVIATION=300000; export VSI_NN_LOG_LEVEL=5;" + +EXPORT_ENVIRONMENT_VARIABLES="${EXPORT_ENVIRONMENT_VARIABLES}export LD_LIBRARY_PATH=${WORK_SPACE}/lib:\$LD_LIBRARY_PATH;" + +# Please install adb, and DON'T run this in the docker. +set -e +adb $ADB_DEVICE_NAME shell "rm -rf $WORK_SPACE" +adb $ADB_DEVICE_NAME shell "mkdir -p $WORK_SPACE" + +# Upload the demo, librarys, model and test images to the device +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/lib $WORK_SPACE +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/${DEMO_NAME} $WORK_SPACE +adb $ADB_DEVICE_NAME push models $WORK_SPACE +adb $ADB_DEVICE_NAME push images $WORK_SPACE + +# Execute the deployment demo +adb $ADB_DEVICE_NAME shell "cd $WORK_SPACE; ${EXPORT_ENVIRONMENT_VARIABLES} chmod +x ./${DEMO_NAME}; ./${DEMO_NAME} ./models/${MODEL_NAME} ./images/$IMAGE_NAME" diff --git a/examples/vision/detection/yolov5/quantize/README.md b/examples/vision/detection/yolov5/quantize/README.md old mode 100644 new mode 100755 index 853718381f..aa0a8d5431 --- a/examples/vision/detection/yolov5/quantize/README.md +++ b/examples/vision/detection/yolov5/quantize/README.md @@ -4,13 +4,13 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) ## 下载量化完成的YOLOv5s模型 用户也可以直接下载下表中的量化模型进行部署.(点击模型名字即可下载) Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -29,7 +29,7 @@ Benchmark表格说明: | [YOLOv5s](https://bj.bcebos.com/paddlehub/fastdeploy/yolov5s_quant.tar) | Paddle Inference| CPU | 213.73 | 130.19 | None | None | 1.64 |37.6 | 35.2 | 量化蒸馏训练 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [YOLOv5s](https://bj.bcebos.com/paddlehub/fastdeploy/yolov5s_quant.tar) | TensorRT | GPU | 24.61 | 21.20 | 20.78 | 20.94 | 1.18 | 37.6 | 36.7 | 量化蒸馏训练 | | [YOLOv5s](https://bj.bcebos.com/paddlehub/fastdeploy/yolov5s_quant.tar) | Paddle-TensorRT | GPU | 23.53 | None | 21.98 | 19.84 | 1.28 | 37.6 | 36.8 | 量化蒸馏训练 | diff --git a/examples/vision/detection/yolov5/quantize/README_EN.md b/examples/vision/detection/yolov5/quantize/README_EN.md old mode 100644 new mode 100755 index c704ccce2e..d897710f98 --- a/examples/vision/detection/yolov5/quantize/README_EN.md +++ b/examples/vision/detection/yolov5/quantize/README_EN.md @@ -6,7 +6,7 @@ Users can use the one-click model quantization tool to quantize and deploy the m ## FastDeploy One-Click Model Quantization Tool FastDeploy provides a one-click quantization tool that allows users to quantize a model simply with a configuration file. -For a detailed tutorial, please refer to: [One-Click Model Quantization Tool](../../../../../tools/auto_compression/) +For a detailed tutorial, please refer to: [One-Click Model Quantization Tool](../../../../../tools/common_tools/auto_compression/) ## Download Quantized YOLOv5s Model diff --git a/examples/vision/detection/yolov5/quantize/cpp/README.md b/examples/vision/detection/yolov5/quantize/cpp/README.md old mode 100644 new mode 100755 index 90334c7baf..baee6d351d --- a/examples/vision/detection/yolov5/quantize/cpp/README.md +++ b/examples/vision/detection/yolov5/quantize/cpp/README.md @@ -9,7 +9,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv5s模型为例, 进行部署 在本目录执行如下命令即可完成编译,以及量化模型部署.支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) diff --git a/examples/vision/detection/yolov5/quantize/python/README.md b/examples/vision/detection/yolov5/quantize/python/README.md old mode 100644 new mode 100755 index c63ef712c5..9108e256e6 --- a/examples/vision/detection/yolov5/quantize/python/README.md +++ b/examples/vision/detection/yolov5/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv5s模型为例, 进行部署 diff --git a/examples/vision/detection/yolov5/rv1126/README.md b/examples/vision/detection/yolov5/rv1126/README.md new file mode 100755 index 0000000000..968cc4306a --- /dev/null +++ b/examples/vision/detection/yolov5/rv1126/README.md @@ -0,0 +1,11 @@ +# YOLOv5 量化模型在 RV1126 上的部署 +目前 FastDeploy 已经支持基于 PaddleLite 部署 YOLOv5 量化模型到 RV1126 上。 + +模型的量化和量化模型的下载请参考:[模型量化](../quantize/README.md) + + +## 详细部署文档 + +在 RV1126 上只支持 C++ 的部署。 + +- [C++部署](cpp) diff --git a/examples/vision/detection/yolov5/rv1126/cpp/CMakeLists.txt b/examples/vision/detection/yolov5/rv1126/cpp/CMakeLists.txt new file mode 100755 index 0000000000..3c9eee38a2 --- /dev/null +++ b/examples/vision/detection/yolov5/rv1126/cpp/CMakeLists.txt @@ -0,0 +1,37 @@ +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10) + +# 指定下载解压后的fastdeploy库路径 +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +# 添加FastDeploy依赖头文件 +include_directories(${FASTDEPLOY_INCS}) +include_directories(${FastDeploy_INCLUDE_DIRS}) + +add_executable(infer_demo ${PROJECT_SOURCE_DIR}/infer.cc) +# 添加FastDeploy库依赖 +target_link_libraries(infer_demo ${FASTDEPLOY_LIBS}) + +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/build/install) + +install(TARGETS infer_demo DESTINATION ./) + +install(DIRECTORY models DESTINATION ./) +install(DIRECTORY images DESTINATION ./) + +file(GLOB FASTDEPLOY_LIBS ${FASTDEPLOY_INSTALL_DIR}/lib/*) +install(PROGRAMS ${FASTDEPLOY_LIBS} DESTINATION lib) + +file(GLOB OPENCV_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/opencv/lib/lib*) +install(PROGRAMS ${OPENCV_LIBS} DESTINATION lib) + +file(GLOB PADDLELITE_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/lib*) +install(PROGRAMS ${PADDLELITE_LIBS} DESTINATION lib) + +file(GLOB TIMVX_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/verisilicon_timvx/*) +install(PROGRAMS ${TIMVX_LIBS} DESTINATION lib) + +file(GLOB ADB_TOOLS run_with_adb.sh) +install(PROGRAMS ${ADB_TOOLS} DESTINATION ./) diff --git a/examples/vision/detection/yolov5/rv1126/cpp/README.md b/examples/vision/detection/yolov5/rv1126/cpp/README.md new file mode 100755 index 0000000000..9711577f20 --- /dev/null +++ b/examples/vision/detection/yolov5/rv1126/cpp/README.md @@ -0,0 +1,54 @@ +# YOLOv5 量化模型 C++ 部署示例 + +本目录下提供的 `infer.cc`,可以帮助用户快速完成 YOLOv5 量化模型在 RV1126 上的部署推理加速。 + +## 部署准备 +### FastDeploy 交叉编译环境准备 +- 1. 软硬件环境满足要求,以及交叉编译环境的准备,请参考:[FastDeploy 交叉编译环境准备](../../../../../../docs/cn/build_and_install/rv1126.md#交叉编译环境搭建) + +### 量化模型准备 +- 1. 用户可以直接使用由 FastDeploy 提供的量化模型进行部署。 +- 2. 用户可以使用 FastDeploy 提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署。 +- 更多量化相关相关信息可查阅[模型量化](../../quantize/README.md) + +## 在 RV1126 上部署量化后的 YOLOv5 检测模型 +请按照以下步骤完成在 RV1126 上部署 YOLOv5 量化模型: +1. 交叉编译编译 FastDeploy 库,具体请参考:[交叉编译 FastDeploy](../../../../../../docs/cn/build_and_install/rv1126.md#基于-paddlelite-的-fastdeploy-交叉编译库编译) + +2. 将编译后的库拷贝到当前目录,可使用如下命令: +```bash +cp -r FastDeploy/build/fastdeploy-tmivx/ FastDeploy/examples/vision/detection/yolov5/rv1126/cpp +``` + +3. 在当前路径下载部署所需的模型和示例图片: +```bash +mkdir models && mkdir images +wget https://bj.bcebos.com/fastdeploy/models/yolov5s_ptq_model.tar.gz +tar -xvf yolov5s_ptq_model.tar.gz +cp -r yolov5s_ptq_model models +wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg +cp -r 000000014439.jpg images +``` + +4. 编译部署示例,可使入如下命令: +```bash +mkdir build && cd build +cmake -DCMAKE_TOOLCHAIN_FILE=${PWD}/../fastdeploy-tmivx/timvx.cmake -DFASTDEPLOY_INSTALL_DIR=${PWD}/../fastdeploy-tmivx .. +make -j8 +make install +# 成功编译之后,会生成 install 文件夹,里面有一个运行 demo 和部署所需的库 +``` + +5. 基于 adb 工具部署 YOLOv5 检测模型到 Rockchip RV1126,可使用如下命令: +```bash +# 进入 install 目录 +cd FastDeploy/examples/vision/detection/yolov5/rv1126/cpp/build/install/ +# 如下命令表示:bash run_with_adb.sh 需要运行的demo 模型路径 图片路径 设备的DEVICE_ID +bash run_with_adb.sh infer_demo yolov5s_ptq_model 000000014439.jpg $DEVICE_ID +``` + +部署成功后,vis_result.jpg 保存的结果如下: + + + +需要特别注意的是,在 RV1126 上部署的模型需要是量化后的模型,模型的量化请参考:[模型量化](../../../../../../docs/cn/quantize.md) diff --git a/examples/vision/detection/yolov5/rv1126/cpp/infer.cc b/examples/vision/detection/yolov5/rv1126/cpp/infer.cc new file mode 100755 index 0000000000..f1cf9e8dc3 --- /dev/null +++ b/examples/vision/detection/yolov5/rv1126/cpp/infer.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2022 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. + +#include "fastdeploy/vision.h" +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void InitAndInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto subgraph_file = model_dir + sep + "subgraph.txt"; + + fastdeploy::RuntimeOption option; + option.UseTimVX(); + option.SetLiteSubgraphPartitionPath(subgraph_file); + + auto model = fastdeploy::vision::detection::YOLOv5( + model_file, params_file, option, fastdeploy::ModelFormat::PADDLE); + assert(model.Initialized()); + + auto im = cv::imread(image_file); + + fastdeploy::vision::DetectionResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + + std::cout << res.Str() << std::endl; + + auto vis_im = fastdeploy::vision::VisDetection(im, res); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + std::cout << "Usage: infer_demo path/to/quant_model " + "path/to/image " + "run_option, " + "e.g ./infer_demo ./yolov5s_quant ./000000014439.jpg" + << std::endl; + return -1; + } + + std::string model_dir = argv[1]; + std::string test_image = argv[2]; + InitAndInfer(model_dir, test_image); + return 0; +} diff --git a/examples/vision/detection/yolov5/rv1126/cpp/run_with_adb.sh b/examples/vision/detection/yolov5/rv1126/cpp/run_with_adb.sh new file mode 100755 index 0000000000..aacaed4c51 --- /dev/null +++ b/examples/vision/detection/yolov5/rv1126/cpp/run_with_adb.sh @@ -0,0 +1,47 @@ +#!/bin/bash +HOST_SPACE=${PWD} +echo ${HOST_SPACE} +WORK_SPACE=/data/local/tmp/test + +# The first parameter represents the demo name +DEMO_NAME=image_classification_demo +if [ -n "$1" ]; then + DEMO_NAME=$1 +fi + +# The second parameter represents the model name +MODEL_NAME=mobilenet_v1_fp32_224 +if [ -n "$2" ]; then + MODEL_NAME=$2 +fi + +# The third parameter indicates the name of the image to be tested +IMAGE_NAME=0001.jpg +if [ -n "$3" ]; then + IMAGE_NAME=$3 +fi + +# The fourth parameter represents the ID of the device +ADB_DEVICE_NAME= +if [ -n "$4" ]; then + ADB_DEVICE_NAME="-s $4" +fi + +# Set the environment variables required during the running process +EXPORT_ENVIRONMENT_VARIABLES="export GLOG_v=5; export VIV_VX_ENABLE_GRAPH_TRANSFORM=-pcq:1; export VIV_VX_SET_PER_CHANNEL_ENTROPY=100; export TIMVX_BATCHNORM_FUSION_MAX_ALLOWED_QUANT_SCALE_DEVIATION=300000; export VSI_NN_LOG_LEVEL=5;" + +EXPORT_ENVIRONMENT_VARIABLES="${EXPORT_ENVIRONMENT_VARIABLES}export LD_LIBRARY_PATH=${WORK_SPACE}/lib:\$LD_LIBRARY_PATH;" + +# Please install adb, and DON'T run this in the docker. +set -e +adb $ADB_DEVICE_NAME shell "rm -rf $WORK_SPACE" +adb $ADB_DEVICE_NAME shell "mkdir -p $WORK_SPACE" + +# Upload the demo, librarys, model and test images to the device +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/lib $WORK_SPACE +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/${DEMO_NAME} $WORK_SPACE +adb $ADB_DEVICE_NAME push models $WORK_SPACE +adb $ADB_DEVICE_NAME push images $WORK_SPACE + +# Execute the deployment demo +adb $ADB_DEVICE_NAME shell "cd $WORK_SPACE; ${EXPORT_ENVIRONMENT_VARIABLES} chmod +x ./${DEMO_NAME}; ./${DEMO_NAME} ./models/${MODEL_NAME} ./images/$IMAGE_NAME" diff --git a/examples/vision/detection/yolov5/serving/README.md b/examples/vision/detection/yolov5/serving/README.md index 3e341ff6d2..d1f922433d 100644 --- a/examples/vision/detection/yolov5/serving/README.md +++ b/examples/vision/detection/yolov5/serving/README.md @@ -22,10 +22,10 @@ mv yolov5s.onnx models/runtime/1/model.onnx # GPU镜像 docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 # CPU镜像 -docker pull paddlepaddle/fastdeploy:z.y.z-cpu-only-21.10 +docker pull paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 # 运行容器.容器名字为 fd_serving, 并挂载当前目录为容器的 /yolov5_serving 目录 -nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/yolov5_serving paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash +nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/yolov5_serving paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash # 启动服务(不设置CUDA_VISIBLE_DEVICES环境变量,会拥有所有GPU卡的调度权限) CUDA_VISIBLE_DEVICES=0 fastdeployserver --model-repository=/yolov5_serving/models --backend-config=python,shm-default-byte-size=10485760 @@ -49,7 +49,7 @@ I0928 04:51:15.826578 206 http_server.cc:167] Started Metrics Service at 0.0.0.0 wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg #安装客户端依赖 -python3 -m pip install tritonclient\[all\] +python3 -m pip install tritonclient[all] # 发送请求 python3 yolov5_grpc_client.py diff --git a/examples/vision/detection/yolov5/serving/README_EN.md b/examples/vision/detection/yolov5/serving/README_EN.md index cc85355d89..cb4630463a 100644 --- a/examples/vision/detection/yolov5/serving/README_EN.md +++ b/examples/vision/detection/yolov5/serving/README_EN.md @@ -9,11 +9,11 @@ wget https://bj.bcebos.com/paddlehub/fastdeploy/yolov5s.onnx # Save the model under models/infer/1 and rename it as model.onnx mv yolov5s.onnx models/infer/1/ -# Pull fastdeploy image -docker pull paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 +# Pull fastdeploy image, x.y.z is FastDeploy version, example 1.0.0. +docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 # Run the docker. The docker name is fd_serving, and the current directory is mounted as the docker's /yolov5_serving directory -nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/yolov5_serving paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash +nvidia-docker run -it --net=host --name fd_serving -v `pwd`/:/yolov5_serving paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash # Start the service (Without setting the CUDA_VISIBLE_DEVICES environment variable, it will have scheduling privileges for all GPU cards) CUDA_VISIBLE_DEVICES=0 fastdeployserver --model-repository=models --backend-config=python,shm-default-byte-size=10485760 diff --git a/examples/vision/detection/yolov6/quantize/README.md b/examples/vision/detection/yolov6/quantize/README.md old mode 100644 new mode 100755 index 04af3f6896..57c71cedbf --- a/examples/vision/detection/yolov6/quantize/README.md +++ b/examples/vision/detection/yolov6/quantize/README.md @@ -4,12 +4,12 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) ## 下载量化完成的YOLOv6s模型 用户也可以直接下载下表中的量化模型进行部署.(点击模型名字即可下载) Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -28,7 +28,7 @@ Benchmark表格说明: #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [YOLOv6s](https://bj.bcebos.com/paddlehub/fastdeploy/yolov6s_ptq_model.tar) | TensorRT | GPU | 15.66 | 11.30 | 10.25 |9.59 | 1.63 | 42.5 | 40.7|量化蒸馏训练 | | [YOLOv6s](https://bj.bcebos.com/paddlehub/fastdeploy/yolov6s_ptq_model.tar) | Paddle-TensorRT | GPU | 15.03 | None| 11.36 | 9.32 | 1.61 | 42.5 | 40.7|量化蒸馏训练 | diff --git a/examples/vision/detection/yolov6/quantize/README_EN.md b/examples/vision/detection/yolov6/quantize/README_EN.md old mode 100644 new mode 100755 index b7ae61d115..7a13ef7d0e --- a/examples/vision/detection/yolov6/quantize/README_EN.md +++ b/examples/vision/detection/yolov6/quantize/README_EN.md @@ -6,7 +6,7 @@ Users can use the one-click model quantization tool to quantize and deploy the m ## FastDeploy One-Click Model Quantization Tool FastDeploy provides a one-click quantization tool that allows users to quantize a model simply with a configuration file. -For detailed tutorial, please refer to : [One-Click Model Quantization Tool](../../../../../tools/auto_compression/) +For detailed tutorial, please refer to : [One-Click Model Quantization Tool](../../../../../tools/common_tools/auto_compression/) ## Download Quantized YOLOv6s Model diff --git a/examples/vision/detection/yolov6/quantize/cpp/README.md b/examples/vision/detection/yolov6/quantize/cpp/README.md old mode 100644 new mode 100755 index ee11f315de..7ad762100b --- a/examples/vision/detection/yolov6/quantize/cpp/README.md +++ b/examples/vision/detection/yolov6/quantize/cpp/README.md @@ -9,7 +9,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv6s模型为例, 进行部署 在本目录执行如下命令即可完成编译,以及量化模型部署.支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) diff --git a/examples/vision/detection/yolov6/quantize/python/README.md b/examples/vision/detection/yolov6/quantize/python/README.md old mode 100644 new mode 100755 index 169a0a9468..057e13f9a3 --- a/examples/vision/detection/yolov6/quantize/python/README.md +++ b/examples/vision/detection/yolov6/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv6s模型为例, 进行部署 ```bash diff --git a/examples/vision/detection/yolov7/quantize/README.md b/examples/vision/detection/yolov7/quantize/README.md old mode 100644 new mode 100755 index 5795325680..e1bbc2f699 --- a/examples/vision/detection/yolov7/quantize/README.md +++ b/examples/vision/detection/yolov7/quantize/README.md @@ -4,14 +4,14 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) ## 下载量化完成的YOLOv7模型 用户也可以直接下载下表中的量化模型进行部署.(点击模型名字即可下载) Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -29,7 +29,7 @@ Benchmark表格说明: | [YOLOv7](https://bj.bcebos.com/paddlehub/fastdeploy/yolov7_quant.tar) | Paddle Inference | CPU | 995.85 | 477.93|None|None | 2.08 |51.1 | 46.2|量化蒸馏训练 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mAP | INT8 mAP | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [YOLOv7](https://bj.bcebos.com/paddlehub/fastdeploy/yolov7_quant.tar) | TensorRT | GPU | 36.47 | 18.81 | 20.33| 17.58| 2.07 | 51.1| 50.4|量化蒸馏训练 | | [YOLOv7](https://bj.bcebos.com/paddlehub/fastdeploy/yolov7_quant.tar) | Paddle-TensorRT | GPU | 37.06|None|20.26|17.53 | 2.11 | 51.1| 50.4|量化蒸馏训练 | diff --git a/examples/vision/detection/yolov7/quantize/README_EN.md b/examples/vision/detection/yolov7/quantize/README_EN.md old mode 100644 new mode 100755 index 4e6b2e3533..5a1add2e6c --- a/examples/vision/detection/yolov7/quantize/README_EN.md +++ b/examples/vision/detection/yolov7/quantize/README_EN.md @@ -6,7 +6,7 @@ Users can use the one-click model quantization tool to quantize and deploy the m ## FastDeploy One-Click Model Quantization Tool FastDeploy provides a one-click quantization tool that allows users to quantize a model simply with a configuration file. -For detailed tutorial, please refer to : [One-Click Model Quantization Tool](../../../../../tools/auto_compression/) +For detailed tutorial, please refer to : [One-Click Model Quantization Tool](../../../../../tools/common_tools/auto_compression/) ## Download Quantized YOLOv7 Model diff --git a/examples/vision/detection/yolov7/quantize/cpp/README.md b/examples/vision/detection/yolov7/quantize/cpp/README.md old mode 100644 new mode 100755 index 17eb9eb0fe..d59964bcc9 --- a/examples/vision/detection/yolov7/quantize/cpp/README.md +++ b/examples/vision/detection/yolov7/quantize/cpp/README.md @@ -9,7 +9,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv7模型为例, 进行部署 在本目录执行如下命令即可完成编译,以及量化模型部署.支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) diff --git a/examples/vision/detection/yolov7/quantize/python/README.md b/examples/vision/detection/yolov7/quantize/python/README.md old mode 100644 new mode 100755 index 4389d44c18..08ee726e22 --- a/examples/vision/detection/yolov7/quantize/python/README.md +++ b/examples/vision/detection/yolov7/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署. ## 以量化后的YOLOv7模型为例, 进行部署 ```bash diff --git a/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java b/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java index 169c09cd07..8397531c86 100644 --- a/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java +++ b/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java @@ -300,6 +300,8 @@ protected void onResume() { // Open camera until the permissions have been granted if (!checkAllPermissions()) { svPreview.disableCamera(); + } else { + svPreview.enableCamera(); } svPreview.onResume(); } diff --git a/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java b/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java index 94a5fdbd0e..14217181d3 100644 --- a/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java +++ b/examples/vision/facedet/scrfd/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java @@ -278,6 +278,10 @@ public void disableCamera() { disableCamera = true; } + public void enableCamera() { + disableCamera = false; + } + public void switchCamera() { releaseCamera(); selectedCameraId = (selectedCameraId + 1) % numberOfCameras; diff --git a/examples/vision/ocr/PP-OCRv2/cpp/README.md b/examples/vision/ocr/PP-OCRv2/cpp/README.md index afc35d50ba..965ece7167 100644 --- a/examples/vision/ocr/PP-OCRv2/cpp/README.md +++ b/examples/vision/ocr/PP-OCRv2/cpp/README.md @@ -26,7 +26,7 @@ tar -xvf ch_PP-OCRv2_det_infer.tar wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar tar -xvf ch_ppocr_mobile_v2.0_cls_infer.tar -wgethttps://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar +wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar tar -xvf ch_PP-OCRv2_rec_infer.tar wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.6/doc/imgs/12.jpg diff --git a/examples/vision/ocr/PP-OCRv2/cpp/infer.cc b/examples/vision/ocr/PP-OCRv2/cpp/infer.cc index f05015d86d..7bac320d51 100644 --- a/examples/vision/ocr/PP-OCRv2/cpp/infer.cc +++ b/examples/vision/ocr/PP-OCRv2/cpp/infer.cc @@ -37,9 +37,9 @@ void InitAndInfer(const std::string& det_model_dir, const std::string& cls_model // We recommend that users set the length and height of the detection model to a multiple of 32. det_option.SetTrtInputShape("x", {1, 3, 64,64}, {1, 3, 640, 640}, {1, 3, 960, 960}); - cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {10, 3, 48, 320}, {64, 3, 48, 1024}); + cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {10, 3, 48, 320}, {32, 3, 48, 1024}); rec_option.SetTrtInputShape("x", {1, 3, 32, 10}, {10, 3, 32, 320}, - {64, 3, 32, 2304}); + {32, 3, 32, 2304}); // Users could save TRT cache file to disk as follow. // det_option.SetTrtCacheFile(det_model_dir + sep + "det_trt_cache.trt"); diff --git a/examples/vision/ocr/PP-OCRv2/python/README.md b/examples/vision/ocr/PP-OCRv2/python/README.md index a846f19c0f..89e5fc0738 100644 --- a/examples/vision/ocr/PP-OCRv2/python/README.md +++ b/examples/vision/ocr/PP-OCRv2/python/README.md @@ -16,7 +16,7 @@ tar -xvf ch_PP-OCRv2_det_infer.tar wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar tar -xvf ch_ppocr_mobile_v2.0_cls_infer.tar -wgethttps://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar +wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar tar -xvf ch_PP-OCRv2_rec_infer.tar wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.6/doc/imgs/12.jpg diff --git a/examples/vision/ocr/PP-OCRv2/python/infer.py b/examples/vision/ocr/PP-OCRv2/python/infer.py index 0dce3f95c0..af915143af 100644 --- a/examples/vision/ocr/PP-OCRv2/python/infer.py +++ b/examples/vision/ocr/PP-OCRv2/python/infer.py @@ -119,7 +119,7 @@ def build_option(args): cls_option = runtime_option cls_option.set_trt_input_shape("x", [1, 3, 48, 10], [10, 3, 48, 320], - [64, 3, 48, 1024]) + [32, 3, 48, 1024]) # 用户可以把TRT引擎文件保存至本地 # cls_option.set_trt_cache_file(args.cls_model + "/cls_trt_cache.trt") cls_model = fd.vision.ocr.Classifier( @@ -127,7 +127,7 @@ def build_option(args): rec_option = runtime_option rec_option.set_trt_input_shape("x", [1, 3, 32, 10], [10, 3, 32, 320], - [64, 3, 32, 2304]) + [32, 3, 32, 2304]) # 用户可以把TRT引擎文件保存至本地 # rec_option.set_trt_cache_file(args.rec_model + "/rec_trt_cache.trt") rec_model = fd.vision.ocr.Recognizer( diff --git a/examples/vision/ocr/PP-OCRv3/android/.gitignore b/examples/vision/ocr/PP-OCRv3/android/.gitignore new file mode 100644 index 0000000000..f6eba672f0 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/.gitignore @@ -0,0 +1,20 @@ +.DS_Store +.idea +.gradle +.cxx +cache +build +app/cache +app/libs/fastdeploy* +app/.cxx +app/build +app/src/main/assets/models/* +app/.gradle +app/.idea +fastdeploy/cache +fastdeploy/libs/fastdeploy* +fastdeploy/.cxx +fastdeploy/build +fastdeploy/src/main/assets/models/* +fastdeploy/.gradle +fastdeploy/.idea diff --git a/examples/vision/ocr/PP-OCRv3/android/README.md b/examples/vision/ocr/PP-OCRv3/android/README.md new file mode 100644 index 0000000000..0028547a5b --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/README.md @@ -0,0 +1,106 @@ +# OCR文字识别 Android Demo 使用文档 + +在 Android 上实现实时的OCR文字识别功能,此 Demo 有很好的的易用性和开放性,如在 Demo 中跑自己训练好的模型等。 + +## 环境准备 + +1. 在本地环境安装好 Android Studio 工具,详细安装方法请见[Android Stuido 官网](https://developer.android.com/studio)。 +2. 准备一部 Android 手机,并开启 USB 调试模式。开启方法: `手机设置 -> 查找开发者选项 -> 打开开发者选项和 USB 调试模式` + +## 部署步骤 + +1. OCR文字识别 Demo 位于 `fastdeploy/examples/vision/ocr/PP-OCRv3/android` 目录 +2. 用 Android Studio 打开 PP-OCRv3/android 工程 +3. 手机连接电脑,打开 USB 调试和文件传输模式,并在 Android Studio 上连接自己的手机设备(手机需要开启允许从 USB 安装软件权限) + +

+image +

+ +> **注意:** +>> 如果您在导入项目、编译或者运行过程中遇到 NDK 配置错误的提示,请打开 ` File > Project Structure > SDK Location`,修改 `Andriod SDK location` 为您本机配置的 SDK 所在路径。 + +4. 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网) + 成功后效果如下,图一:APP 安装到手机;图二: APP 打开后的效果,会自动识别图片中的物体并标记;图三:APP设置选项,点击右上角的设置图片,可以设置不同选项进行体验。 + +| APP 图标 | APP 效果 | APP设置项 + | --- | --- | --- | +| ![app_pic](https://user-images.githubusercontent.com/14995488/203484427-83de2316-fd60-4baf-93b6-3755f9b5559d.jpg) | ![app_res](https://user-images.githubusercontent.com/14995488/203495616-af42a5b7-d3bc-4fce-8d5e-2ed88454f618.jpg) | ![app_setup](https://user-images.githubusercontent.com/14995488/203484436-57fdd041-7dcc-4e0e-b6cb-43e5ac1e729b.jpg) | + +### PP-OCRv2 & PP-OCRv3 Java API 说明 + +- 模型初始化 API: 模型初始化API包含两种方式,方式一是通过构造函数直接初始化;方式二是,通过调用init函数,在合适的程序节点进行初始化。 PP-OCR初始化参数说明如下: + - modelFile: String, paddle格式的模型文件路径,如 model.pdmodel + - paramFile: String, paddle格式的参数文件路径,如 model.pdiparams + - labelFile: String, 可选参数,表示label标签文件所在路径,用于可视化,如 ppocr_keys_v1.txt,每一行包含一个label + - option: RuntimeOption,可选参数,模型初始化option。如果不传入该参数则会使用默认的运行时选项。 + 与其他模型不同的是,PP-OCRv2 和 PP-OCRv3 包含 DBDetector、Classifier和Recognizer等基础模型,以及PPOCRv2和PPOCRv3等pipeline类型。 +```java +// 构造函数: constructor w/o label file +public DBDetector(String modelFile, String paramsFile); +public DBDetector(String modelFile, String paramsFile, RuntimeOption option); +public Classifier(String modelFile, String paramsFile); +public Classifier(String modelFile, String paramsFile, RuntimeOption option); +public Recognizer(String modelFile, String paramsFile, String labelPath); +public Recognizer(String modelFile, String paramsFile, String labelPath, RuntimeOption option); +public PPOCRv2(); // 空构造函数,之后可以调用init初始化 +// Constructor w/o classifier +public PPOCRv2(DBDetector detModel, Recognizer recModel); +public PPOCRv2(DBDetector detModel, Classifier clsModel, Recognizer recModel); +public PPOCRv3(); // 空构造函数,之后可以调用init初始化 +// Constructor w/o classifier +public PPOCRv3(DBDetector detModel, Recognizer recModel); +public PPOCRv3(DBDetector detModel, Classifier clsModel, Recognizer recModel); +``` +- 模型预测 API:模型预测API包含直接预测的API以及带可视化功能的API。直接预测是指,不保存图片以及不渲染结果到Bitmap上,仅预测推理结果。预测并且可视化是指,预测结果以及可视化,并将可视化后的图片保存到指定的途径,以及将可视化结果渲染在Bitmap(目前支持ARGB8888格式的Bitmap), 后续可将该Bitmap在camera中进行显示。 +```java +// 直接预测:不保存图片以及不渲染结果到Bitmap上 +public OCRResult predict(Bitmap ARGB8888Bitmap); +// 预测并且可视化:预测结果以及可视化,并将可视化后的图片保存到指定的途径,以及将可视化结果渲染在Bitmap上 +public OCRResult predict(Bitmap ARGB8888Bitmap, String savedImagePath); +public OCRResult predict(Bitmap ARGB8888Bitmap, boolean rendering); // 只渲染 不保存图片 +``` +- 模型资源释放 API:调用 release() API 可以释放模型资源,返回true表示释放成功,false表示失败;调用 initialized() 可以判断模型是否初始化成功,true表示初始化成功,false表示失败。 +```java +public boolean release(); // 释放native资源 +public boolean initialized(); // 检查是否初始化成功 +``` + +## 替换 FastDeploy SDK和模型 +替换FastDeploy预测库和模型的步骤非常简单。预测库所在的位置为 `app/libs/fastdeploy-android-sdk-xxx.aar`,其中 `xxx` 表示当前您使用的预测库版本号。模型所在的位置为,`app/src/main/assets/models`。 +- 替换FastDeploy Android SDK: 下载或编译最新的FastDeploy Android SDK,解压缩后放在 `app/libs` 目录下;详细配置文档可参考: + - [在 Android 中使用 FastDeploy Java SDK](../../../../../java/android/) + +- 替换OCR模型的步骤: + - 将您的OCR模型放在 `app/src/main/assets/models` 目录下; + - 修改 `app/src/main/res/values/strings.xml` 中模型路径的默认值,如: +```xml + +models +labels/ppocr_keys_v1.txt +``` +## 使用量化模型 +如果您使用的是量化格式的模型,只需要使用RuntimeOption的enableLiteInt8()接口设置Int8精度推理即可。 +```java +String detModelFile = "ch_ppocrv3_plate_det_quant/inference.pdmodel"; +String detParamsFile = "ch_ppocrv3_plate_det_quant/inference.pdiparams"; +String recModelFile = "ch_ppocrv3_plate_rec_distillation_quant/inference.pdmodel"; +String recParamsFile = "ch_ppocrv3_plate_rec_distillation_quant/inference.pdiparams"; +String recLabelFilePath = "ppocr_keys_v1.txt"; // ppocr_keys_v1.txt +RuntimeOption detOption = new RuntimeOption(); +RuntimeOption recOption = new RuntimeOption(); +// 使用Int8精度进行推理 +detOption.enableLiteInt8(); +recOption.enableLiteInt8(); +// 初始化PP-OCRv3 Pipeline +PPOCRv3 predictor = new PPOCRv3(); +DBDetector detModel = new DBDetector(detModelFile, detParamsFile, detOption); +Recognizer recModel = new Recognizer(recModelFile, recParamsFile, recLabelFilePath, recOption); +predictor.init(detModel, recModel); +``` +在App中使用,可以参考 [OcrMainActivity.java](./app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java) 中的用法。 + +## 更多参考文档 +如果您想知道更多的FastDeploy Java API文档以及如何通过JNI来接入FastDeploy C++ API感兴趣,可以参考以下内容: +- [在 Android 中使用 FastDeploy Java SDK](../../../../../java/android/) +- [在 Android 中使用 FastDeploy C++ SDK](../../../../../docs/cn/faq/use_cpp_sdk_on_android.md) diff --git a/examples/vision/ocr/PP-OCRv3/android/app/build.gradle b/examples/vision/ocr/PP-OCRv3/android/app/build.gradle new file mode 100644 index 0000000000..de19b87c0d --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/build.gradle @@ -0,0 +1,125 @@ +import java.security.MessageDigest + +apply plugin: 'com.android.application' + +android { + compileSdk 28 + + defaultConfig { + applicationId 'com.baidu.paddle.fastdeploy.app.examples' + minSdkVersion 15 + //noinspection ExpiredTargetSdkVersion + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(include: ['*.aar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:28.0.0' + //noinspection GradleDependency + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'com.android.support:design:28.0.0' + implementation 'org.jetbrains:annotations:15.0' + //noinspection GradleDependency + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} + +def FD_MODEL = [ + [ + 'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ch_PP-OCRv3_det_infer.tgz', + 'dest': 'src/main/assets/models' + ], + [ + 'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ch_ppocr_mobile_v2.0_cls_infer.tgz', + 'dest': 'src/main/assets/models' + ], + [ + 'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ch_PP-OCRv3_rec_infer.tgz', + 'dest': 'src/main/assets/models' + ] +] + +def FD_JAVA_SDK = [ + [ + 'src' : 'https://bj.bcebos.com/fastdeploy/test/fastdeploy-android-sdk-latest-dev.aar', + 'dest': 'libs' + ] +] + +task downloadAndExtractModels(type: DefaultTask) { + doFirst { + println "Downloading and extracting fastdeploy models ..." + } + doLast { + String cachePath = "cache" + if (!file("${cachePath}").exists()) { + mkdir "${cachePath}" + } + FD_MODEL.eachWithIndex { model, index -> + MessageDigest messageDigest = MessageDigest.getInstance('MD5') + messageDigest.update(model.src.bytes) + String[] modelPaths = model.src.split("/") + String modelName = modelPaths[modelPaths.length - 1] + // Download the target model if not exists + boolean copyFiles = !file("${model.dest}").exists() + if (!file("${cachePath}/${modelName}").exists()) { + println "Downloading ${model.src} -> ${cachePath}/${modelName}" + ant.get(src: model.src, dest: file("${cachePath}/${modelName}")) + copyFiles = true + } + if (copyFiles) { + println "Coping ${cachePath}/${modelName} -> ${model.dest}" + copy { + from tarTree("${cachePath}/${modelName}") + into "${model.dest}" + } + } + } + } +} + +task downloadAndExtractSDKs(type: DefaultTask) { + doFirst { + println "Downloading and extracting fastdeploy android java sdk ..." + } + doLast { + String cachePath = "cache" + if (!file("${cachePath}").exists()) { + mkdir "${cachePath}" + } + FD_JAVA_SDK.eachWithIndex { sdk, index -> + String[] sdkPaths = sdk.src.split("/") + String sdkName = sdkPaths[sdkPaths.length - 1] + // Download the target SDK if not exists + boolean copyFiles = !file("${sdk.dest}/${sdkName}").exists() + if (!file("${cachePath}/${sdkName}").exists()) { + println "Downloading ${sdk.src} -> ${cachePath}/${sdkName}" + ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}")) + copyFiles = true + } + if (copyFiles) { + println "Coping ${cachePath}/${sdkName} -> ${sdk.dest}/${sdkName}" + copy { + from "${cachePath}/${sdkName}" + into "${sdk.dest}" + } + } + } + } +} + +preBuild.dependsOn downloadAndExtractSDKs +preBuild.dependsOn downloadAndExtractModels \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/proguard-rules.pro b/examples/vision/ocr/PP-OCRv3/android/app/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/java/android/app/src/androidTest/java/com/baidu/paddle/fastdeploy/ExampleInstrumentedTest.java b/examples/vision/ocr/PP-OCRv3/android/app/src/androidTest/java/com/baidu/paddle/fastdeploy/ExampleInstrumentedTest.java similarity index 100% rename from java/android/app/src/androidTest/java/com/baidu/paddle/fastdeploy/ExampleInstrumentedTest.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/androidTest/java/com/baidu/paddle/fastdeploy/ExampleInstrumentedTest.java diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/AndroidManifest.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..8493c0379f --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/assets/labels/ppocr_keys_v1.txt b/examples/vision/ocr/PP-OCRv3/android/app/src/main/assets/labels/ppocr_keys_v1.txt new file mode 100644 index 0000000000..b75af21303 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/assets/labels/ppocr_keys_v1.txt @@ -0,0 +1,6623 @@ +' +疗 +绚 +诚 +娇 +溜 +题 +贿 +者 +廖 +更 +纳 +加 +奉 +公 +一 +就 +汴 +计 +与 +路 +房 +原 +妇 +2 +0 +8 +- +7 +其 +> +: +] +, +, +骑 +刈 +全 +消 +昏 +傈 +安 +久 +钟 +嗅 +不 +影 +处 +驽 +蜿 +资 +关 +椤 +地 +瘸 +专 +问 +忖 +票 +嫉 +炎 +韵 +要 +月 +田 +节 +陂 +鄙 +捌 +备 +拳 +伺 +眼 +网 +盎 +大 +傍 +心 +东 +愉 +汇 +蹿 +科 +每 +业 +里 +航 +晏 +字 +平 +录 +先 +1 +3 +彤 +鲶 +产 +稍 +督 +腴 +有 +象 +岳 +注 +绍 +在 +泺 +文 +定 +核 +名 +水 +过 +理 +让 +偷 +率 +等 +这 +发 +” +为 +含 +肥 +酉 +相 +鄱 +七 +编 +猥 +锛 +日 +镀 +蒂 +掰 +倒 +辆 +栾 +栗 +综 +涩 +州 +雌 +滑 +馀 +了 +机 +块 +司 +宰 +甙 +兴 +矽 +抚 +保 +用 +沧 +秩 +如 +收 +息 +滥 +页 +疑 +埠 +! +! +姥 +异 +橹 +钇 +向 +下 +跄 +的 +椴 +沫 +国 +绥 +獠 +报 +开 +民 +蜇 +何 +分 +凇 +长 +讥 +藏 +掏 +施 +羽 +中 +讲 +派 +嘟 +人 +提 +浼 +间 +世 +而 +古 +多 +倪 +唇 +饯 +控 +庚 +首 +赛 +蜓 +味 +断 +制 +觉 +技 +替 +艰 +溢 +潮 +夕 +钺 +外 +摘 +枋 +动 +双 +单 +啮 +户 +枇 +确 +锦 +曜 +杜 +或 +能 +效 +霜 +盒 +然 +侗 +电 +晁 +放 +步 +鹃 +新 +杖 +蜂 +吒 +濂 +瞬 +评 +总 +隍 +对 +独 +合 +也 +是 +府 +青 +天 +诲 +墙 +组 +滴 +级 +邀 +帘 +示 +已 +时 +骸 +仄 +泅 +和 +遨 +店 +雇 +疫 +持 +巍 +踮 +境 +只 +亨 +目 +鉴 +崤 +闲 +体 +泄 +杂 +作 +般 +轰 +化 +解 +迂 +诿 +蛭 +璀 +腾 +告 +版 +服 +省 +师 +小 +规 +程 +线 +海 +办 +引 +二 +桧 +牌 +砺 +洄 +裴 +修 +图 +痫 +胡 +许 +犊 +事 +郛 +基 +柴 +呼 +食 +研 +奶 +律 +蛋 +因 +葆 +察 +戏 +褒 +戒 +再 +李 +骁 +工 +貂 +油 +鹅 +章 +啄 +休 +场 +给 +睡 +纷 +豆 +器 +捎 +说 +敏 +学 +会 +浒 +设 +诊 +格 +廓 +查 +来 +霓 +室 +溆 +¢ +诡 +寥 +焕 +舜 +柒 +狐 +回 +戟 +砾 +厄 +实 +翩 +尿 +五 +入 +径 +惭 +喹 +股 +宇 +篝 +| +; +美 +期 +云 +九 +祺 +扮 +靠 +锝 +槌 +系 +企 +酰 +阊 +暂 +蚕 +忻 +豁 +本 +羹 +执 +条 +钦 +H +獒 +限 +进 +季 +楦 +于 +芘 +玖 +铋 +茯 +未 +答 +粘 +括 +样 +精 +欠 +矢 +甥 +帷 +嵩 +扣 +令 +仔 +风 +皈 +行 +支 +部 +蓉 +刮 +站 +蜡 +救 +钊 +汗 +松 +嫌 +成 +可 +. +鹤 +院 +从 +交 +政 +怕 +活 +调 +球 +局 +验 +髌 +第 +韫 +谗 +串 +到 +圆 +年 +米 +/ +* +友 +忿 +检 +区 +看 +自 +敢 +刃 +个 +兹 +弄 +流 +留 +同 +没 +齿 +星 +聆 +轼 +湖 +什 +三 +建 +蛔 +儿 +椋 +汕 +震 +颧 +鲤 +跟 +力 +情 +璺 +铨 +陪 +务 +指 +族 +训 +滦 +鄣 +濮 +扒 +商 +箱 +十 +召 +慷 +辗 +所 +莞 +管 +护 +臭 +横 +硒 +嗓 +接 +侦 +六 +露 +党 +馋 +驾 +剖 +高 +侬 +妪 +幂 +猗 +绺 +骐 +央 +酐 +孝 +筝 +课 +徇 +缰 +门 +男 +西 +项 +句 +谙 +瞒 +秃 +篇 +教 +碲 +罚 +声 +呐 +景 +前 +富 +嘴 +鳌 +稀 +免 +朋 +啬 +睐 +去 +赈 +鱼 +住 +肩 +愕 +速 +旁 +波 +厅 +健 +茼 +厥 +鲟 +谅 +投 +攸 +炔 +数 +方 +击 +呋 +谈 +绩 +别 +愫 +僚 +躬 +鹧 +胪 +炳 +招 +喇 +膨 +泵 +蹦 +毛 +结 +5 +4 +谱 +识 +陕 +粽 +婚 +拟 +构 +且 +搜 +任 +潘 +比 +郢 +妨 +醪 +陀 +桔 +碘 +扎 +选 +哈 +骷 +楷 +亿 +明 +缆 +脯 +监 +睫 +逻 +婵 +共 +赴 +淝 +凡 +惦 +及 +达 +揖 +谩 +澹 +减 +焰 +蛹 +番 +祁 +柏 +员 +禄 +怡 +峤 +龙 +白 +叽 +生 +闯 +起 +细 +装 +谕 +竟 +聚 +钙 +上 +导 +渊 +按 +艾 +辘 +挡 +耒 +盹 +饪 +臀 +记 +邮 +蕙 +受 +各 +医 +搂 +普 +滇 +朗 +茸 +带 +翻 +酚 +( +光 +堤 +墟 +蔷 +万 +幻 +〓 +瑙 +辈 +昧 +盏 +亘 +蛀 +吉 +铰 +请 +子 +假 +闻 +税 +井 +诩 +哨 +嫂 +好 +面 +琐 +校 +馊 +鬣 +缂 +营 +访 +炖 +占 +农 +缀 +否 +经 +钚 +棵 +趟 +张 +亟 +吏 +茶 +谨 +捻 +论 +迸 +堂 +玉 +信 +吧 +瞠 +乡 +姬 +寺 +咬 +溏 +苄 +皿 +意 +赉 +宝 +尔 +钰 +艺 +特 +唳 +踉 +都 +荣 +倚 +登 +荐 +丧 +奇 +涵 +批 +炭 +近 +符 +傩 +感 +道 +着 +菊 +虹 +仲 +众 +懈 +濯 +颞 +眺 +南 +释 +北 +缝 +标 +既 +茗 +整 +撼 +迤 +贲 +挎 +耱 +拒 +某 +妍 +卫 +哇 +英 +矶 +藩 +治 +他 +元 +领 +膜 +遮 +穗 +蛾 +飞 +荒 +棺 +劫 +么 +市 +火 +温 +拈 +棚 +洼 +转 +果 +奕 +卸 +迪 +伸 +泳 +斗 +邡 +侄 +涨 +屯 +萋 +胭 +氡 +崮 +枞 +惧 +冒 +彩 +斜 +手 +豚 +随 +旭 +淑 +妞 +形 +菌 +吲 +沱 +争 +驯 +歹 +挟 +兆 +柱 +传 +至 +包 +内 +响 +临 +红 +功 +弩 +衡 +寂 +禁 +老 +棍 +耆 +渍 +织 +害 +氵 +渑 +布 +载 +靥 +嗬 +虽 +苹 +咨 +娄 +库 +雉 +榜 +帜 +嘲 +套 +瑚 +亲 +簸 +欧 +边 +6 +腿 +旮 +抛 +吹 +瞳 +得 +镓 +梗 +厨 +继 +漾 +愣 +憨 +士 +策 +窑 +抑 +躯 +襟 +脏 +参 +贸 +言 +干 +绸 +鳄 +穷 +藜 +音 +折 +详 +) +举 +悍 +甸 +癌 +黎 +谴 +死 +罩 +迁 +寒 +驷 +袖 +媒 +蒋 +掘 +模 +纠 +恣 +观 +祖 +蛆 +碍 +位 +稿 +主 +澧 +跌 +筏 +京 +锏 +帝 +贴 +证 +糠 +才 +黄 +鲸 +略 +炯 +饱 +四 +出 +园 +犀 +牧 +容 +汉 +杆 +浈 +汰 +瑷 +造 +虫 +瘩 +怪 +驴 +济 +应 +花 +沣 +谔 +夙 +旅 +价 +矿 +以 +考 +s +u +呦 +晒 +巡 +茅 +准 +肟 +瓴 +詹 +仟 +褂 +译 +桌 +混 +宁 +怦 +郑 +抿 +些 +余 +鄂 +饴 +攒 +珑 +群 +阖 +岔 +琨 +藓 +预 +环 +洮 +岌 +宀 +杲 +瀵 +最 +常 +囡 +周 +踊 +女 +鼓 +袭 +喉 +简 +范 +薯 +遐 +疏 +粱 +黜 +禧 +法 +箔 +斤 +遥 +汝 +奥 +直 +贞 +撑 +置 +绱 +集 +她 +馅 +逗 +钧 +橱 +魉 +[ +恙 +躁 +唤 +9 +旺 +膘 +待 +脾 +惫 +购 +吗 +依 +盲 +度 +瘿 +蠖 +俾 +之 +镗 +拇 +鲵 +厝 +簧 +续 +款 +展 +啃 +表 +剔 +品 +钻 +腭 +损 +清 +锶 +统 +涌 +寸 +滨 +贪 +链 +吠 +冈 +伎 +迥 +咏 +吁 +览 +防 +迅 +失 +汾 +阔 +逵 +绀 +蔑 +列 +川 +凭 +努 +熨 +揪 +利 +俱 +绉 +抢 +鸨 +我 +即 +责 +膦 +易 +毓 +鹊 +刹 +玷 +岿 +空 +嘞 +绊 +排 +术 +估 +锷 +违 +们 +苟 +铜 +播 +肘 +件 +烫 +审 +鲂 +广 +像 +铌 +惰 +铟 +巳 +胍 +鲍 +康 +憧 +色 +恢 +想 +拷 +尤 +疳 +知 +S +Y +F +D +A +峄 +裕 +帮 +握 +搔 +氐 +氘 +难 +墒 +沮 +雨 +叁 +缥 +悴 +藐 +湫 +娟 +苑 +稠 +颛 +簇 +后 +阕 +闭 +蕤 +缚 +怎 +佞 +码 +嘤 +蔡 +痊 +舱 +螯 +帕 +赫 +昵 +升 +烬 +岫 +、 +疵 +蜻 +髁 +蕨 +隶 +烛 +械 +丑 +盂 +梁 +强 +鲛 +由 +拘 +揉 +劭 +龟 +撤 +钩 +呕 +孛 +费 +妻 +漂 +求 +阑 +崖 +秤 +甘 +通 +深 +补 +赃 +坎 +床 +啪 +承 +吼 +量 +暇 +钼 +烨 +阂 +擎 +脱 +逮 +称 +P +神 +属 +矗 +华 +届 +狍 +葑 +汹 +育 +患 +窒 +蛰 +佼 +静 +槎 +运 +鳗 +庆 +逝 +曼 +疱 +克 +代 +官 +此 +麸 +耧 +蚌 +晟 +例 +础 +榛 +副 +测 +唰 +缢 +迹 +灬 +霁 +身 +岁 +赭 +扛 +又 +菡 +乜 +雾 +板 +读 +陷 +徉 +贯 +郁 +虑 +变 +钓 +菜 +圾 +现 +琢 +式 +乐 +维 +渔 +浜 +左 +吾 +脑 +钡 +警 +T +啵 +拴 +偌 +漱 +湿 +硕 +止 +骼 +魄 +积 +燥 +联 +踢 +玛 +则 +窿 +见 +振 +畿 +送 +班 +钽 +您 +赵 +刨 +印 +讨 +踝 +籍 +谡 +舌 +崧 +汽 +蔽 +沪 +酥 +绒 +怖 +财 +帖 +肱 +私 +莎 +勋 +羔 +霸 +励 +哼 +帐 +将 +帅 +渠 +纪 +婴 +娩 +岭 +厘 +滕 +吻 +伤 +坝 +冠 +戊 +隆 +瘁 +介 +涧 +物 +黍 +并 +姗 +奢 +蹑 +掣 +垸 +锴 +命 +箍 +捉 +病 +辖 +琰 +眭 +迩 +艘 +绌 +繁 +寅 +若 +毋 +思 +诉 +类 +诈 +燮 +轲 +酮 +狂 +重 +反 +职 +筱 +县 +委 +磕 +绣 +奖 +晋 +濉 +志 +徽 +肠 +呈 +獐 +坻 +口 +片 +碰 +几 +村 +柿 +劳 +料 +获 +亩 +惕 +晕 +厌 +号 +罢 +池 +正 +鏖 +煨 +家 +棕 +复 +尝 +懋 +蜥 +锅 +岛 +扰 +队 +坠 +瘾 +钬 +@ +卧 +疣 +镇 +譬 +冰 +彷 +频 +黯 +据 +垄 +采 +八 +缪 +瘫 +型 +熹 +砰 +楠 +襁 +箐 +但 +嘶 +绳 +啤 +拍 +盥 +穆 +傲 +洗 +盯 +塘 +怔 +筛 +丿 +台 +恒 +喂 +葛 +永 +¥ +烟 +酒 +桦 +书 +砂 +蚝 +缉 +态 +瀚 +袄 +圳 +轻 +蛛 +超 +榧 +遛 +姒 +奘 +铮 +右 +荽 +望 +偻 +卡 +丶 +氰 +附 +做 +革 +索 +戚 +坨 +桷 +唁 +垅 +榻 +岐 +偎 +坛 +莨 +山 +殊 +微 +骇 +陈 +爨 +推 +嗝 +驹 +澡 +藁 +呤 +卤 +嘻 +糅 +逛 +侵 +郓 +酌 +德 +摇 +※ +鬃 +被 +慨 +殡 +羸 +昌 +泡 +戛 +鞋 +河 +宪 +沿 +玲 +鲨 +翅 +哽 +源 +铅 +语 +照 +邯 +址 +荃 +佬 +顺 +鸳 +町 +霭 +睾 +瓢 +夸 +椁 +晓 +酿 +痈 +咔 +侏 +券 +噎 +湍 +签 +嚷 +离 +午 +尚 +社 +锤 +背 +孟 +使 +浪 +缦 +潍 +鞅 +军 +姹 +驶 +笑 +鳟 +鲁 +》 +孽 +钜 +绿 +洱 +礴 +焯 +椰 +颖 +囔 +乌 +孔 +巴 +互 +性 +椽 +哞 +聘 +昨 +早 +暮 +胶 +炀 +隧 +低 +彗 +昝 +铁 +呓 +氽 +藉 +喔 +癖 +瑗 +姨 +权 +胱 +韦 +堑 +蜜 +酋 +楝 +砝 +毁 +靓 +歙 +锲 +究 +屋 +喳 +骨 +辨 +碑 +武 +鸠 +宫 +辜 +烊 +适 +坡 +殃 +培 +佩 +供 +走 +蜈 +迟 +翼 +况 +姣 +凛 +浔 +吃 +飘 +债 +犟 +金 +促 +苛 +崇 +坂 +莳 +畔 +绂 +兵 +蠕 +斋 +根 +砍 +亢 +欢 +恬 +崔 +剁 +餐 +榫 +快 +扶 +‖ +濒 +缠 +鳜 +当 +彭 +驭 +浦 +篮 +昀 +锆 +秸 +钳 +弋 +娣 +瞑 +夷 +龛 +苫 +拱 +致 +% +嵊 +障 +隐 +弑 +初 +娓 +抉 +汩 +累 +蓖 +" +唬 +助 +苓 +昙 +押 +毙 +破 +城 +郧 +逢 +嚏 +獭 +瞻 +溱 +婿 +赊 +跨 +恼 +璧 +萃 +姻 +貉 +灵 +炉 +密 +氛 +陶 +砸 +谬 +衔 +点 +琛 +沛 +枳 +层 +岱 +诺 +脍 +榈 +埂 +征 +冷 +裁 +打 +蹴 +素 +瘘 +逞 +蛐 +聊 +激 +腱 +萘 +踵 +飒 +蓟 +吆 +取 +咙 +簋 +涓 +矩 +曝 +挺 +揣 +座 +你 +史 +舵 +焱 +尘 +苏 +笈 +脚 +溉 +榨 +诵 +樊 +邓 +焊 +义 +庶 +儋 +蟋 +蒲 +赦 +呷 +杞 +诠 +豪 +还 +试 +颓 +茉 +太 +除 +紫 +逃 +痴 +草 +充 +鳕 +珉 +祗 +墨 +渭 +烩 +蘸 +慕 +璇 +镶 +穴 +嵘 +恶 +骂 +险 +绋 +幕 +碉 +肺 +戳 +刘 +潞 +秣 +纾 +潜 +銮 +洛 +须 +罘 +销 +瘪 +汞 +兮 +屉 +r +林 +厕 +质 +探 +划 +狸 +殚 +善 +煊 +烹 +〒 +锈 +逯 +宸 +辍 +泱 +柚 +袍 +远 +蹋 +嶙 +绝 +峥 +娥 +缍 +雀 +徵 +认 +镱 +谷 += +贩 +勉 +撩 +鄯 +斐 +洋 +非 +祚 +泾 +诒 +饿 +撬 +威 +晷 +搭 +芍 +锥 +笺 +蓦 +候 +琊 +档 +礁 +沼 +卵 +荠 +忑 +朝 +凹 +瑞 +头 +仪 +弧 +孵 +畏 +铆 +突 +衲 +车 +浩 +气 +茂 +悖 +厢 +枕 +酝 +戴 +湾 +邹 +飚 +攘 +锂 +写 +宵 +翁 +岷 +无 +喜 +丈 +挑 +嗟 +绛 +殉 +议 +槽 +具 +醇 +淞 +笃 +郴 +阅 +饼 +底 +壕 +砚 +弈 +询 +缕 +庹 +翟 +零 +筷 +暨 +舟 +闺 +甯 +撞 +麂 +茌 +蔼 +很 +珲 +捕 +棠 +角 +阉 +媛 +娲 +诽 +剿 +尉 +爵 +睬 +韩 +诰 +匣 +危 +糍 +镯 +立 +浏 +阳 +少 +盆 +舔 +擘 +匪 +申 +尬 +铣 +旯 +抖 +赘 +瓯 +居 +ˇ +哮 +游 +锭 +茏 +歌 +坏 +甚 +秒 +舞 +沙 +仗 +劲 +潺 +阿 +燧 +郭 +嗖 +霏 +忠 +材 +奂 +耐 +跺 +砀 +输 +岖 +媳 +氟 +极 +摆 +灿 +今 +扔 +腻 +枝 +奎 +药 +熄 +吨 +话 +q +额 +慑 +嘌 +协 +喀 +壳 +埭 +视 +著 +於 +愧 +陲 +翌 +峁 +颅 +佛 +腹 +聋 +侯 +咎 +叟 +秀 +颇 +存 +较 +罪 +哄 +岗 +扫 +栏 +钾 +羌 +己 +璨 +枭 +霉 +煌 +涸 +衿 +键 +镝 +益 +岢 +奏 +连 +夯 +睿 +冥 +均 +糖 +狞 +蹊 +稻 +爸 +刿 +胥 +煜 +丽 +肿 +璃 +掸 +跚 +灾 +垂 +樾 +濑 +乎 +莲 +窄 +犹 +撮 +战 +馄 +软 +络 +显 +鸢 +胸 +宾 +妲 +恕 +埔 +蝌 +份 +遇 +巧 +瞟 +粒 +恰 +剥 +桡 +博 +讯 +凯 +堇 +阶 +滤 +卖 +斌 +骚 +彬 +兑 +磺 +樱 +舷 +两 +娱 +福 +仃 +差 +找 +桁 +÷ +净 +把 +阴 +污 +戬 +雷 +碓 +蕲 +楚 +罡 +焖 +抽 +妫 +咒 +仑 +闱 +尽 +邑 +菁 +爱 +贷 +沥 +鞑 +牡 +嗉 +崴 +骤 +塌 +嗦 +订 +拮 +滓 +捡 +锻 +次 +坪 +杩 +臃 +箬 +融 +珂 +鹗 +宗 +枚 +降 +鸬 +妯 +阄 +堰 +盐 +毅 +必 +杨 +崃 +俺 +甬 +状 +莘 +货 +耸 +菱 +腼 +铸 +唏 +痤 +孚 +澳 +懒 +溅 +翘 +疙 +杷 +淼 +缙 +骰 +喊 +悉 +砻 +坷 +艇 +赁 +界 +谤 +纣 +宴 +晃 +茹 +归 +饭 +梢 +铡 +街 +抄 +肼 +鬟 +苯 +颂 +撷 +戈 +炒 +咆 +茭 +瘙 +负 +仰 +客 +琉 +铢 +封 +卑 +珥 +椿 +镧 +窨 +鬲 +寿 +御 +袤 +铃 +萎 +砖 +餮 +脒 +裳 +肪 +孕 +嫣 +馗 +嵇 +恳 +氯 +江 +石 +褶 +冢 +祸 +阻 +狈 +羞 +银 +靳 +透 +咳 +叼 +敷 +芷 +啥 +它 +瓤 +兰 +痘 +懊 +逑 +肌 +往 +捺 +坊 +甩 +呻 +〃 +沦 +忘 +膻 +祟 +菅 +剧 +崆 +智 +坯 +臧 +霍 +墅 +攻 +眯 +倘 +拢 +骠 +铐 +庭 +岙 +瓠 +′ +缺 +泥 +迢 +捶 +? +? +郏 +喙 +掷 +沌 +纯 +秘 +种 +听 +绘 +固 +螨 +团 +香 +盗 +妒 +埚 +蓝 +拖 +旱 +荞 +铀 +血 +遏 +汲 +辰 +叩 +拽 +幅 +硬 +惶 +桀 +漠 +措 +泼 +唑 +齐 +肾 +念 +酱 +虚 +屁 +耶 +旗 +砦 +闵 +婉 +馆 +拭 +绅 +韧 +忏 +窝 +醋 +葺 +顾 +辞 +倜 +堆 +辋 +逆 +玟 +贱 +疾 +董 +惘 +倌 +锕 +淘 +嘀 +莽 +俭 +笏 +绑 +鲷 +杈 +择 +蟀 +粥 +嗯 +驰 +逾 +案 +谪 +褓 +胫 +哩 +昕 +颚 +鲢 +绠 +躺 +鹄 +崂 +儒 +俨 +丝 +尕 +泌 +啊 +萸 +彰 +幺 +吟 +骄 +苣 +弦 +脊 +瑰 +〈 +诛 +镁 +析 +闪 +剪 +侧 +哟 +框 +螃 +守 +嬗 +燕 +狭 +铈 +缮 +概 +迳 +痧 +鲲 +俯 +售 +笼 +痣 +扉 +挖 +满 +咋 +援 +邱 +扇 +歪 +便 +玑 +绦 +峡 +蛇 +叨 +〖 +泽 +胃 +斓 +喋 +怂 +坟 +猪 +该 +蚬 +炕 +弥 +赞 +棣 +晔 +娠 +挲 +狡 +创 +疖 +铕 +镭 +稷 +挫 +弭 +啾 +翔 +粉 +履 +苘 +哦 +楼 +秕 +铂 +土 +锣 +瘟 +挣 +栉 +习 +享 +桢 +袅 +磨 +桂 +谦 +延 +坚 +蔚 +噗 +署 +谟 +猬 +钎 +恐 +嬉 +雒 +倦 +衅 +亏 +璩 +睹 +刻 +殿 +王 +算 +雕 +麻 +丘 +柯 +骆 +丸 +塍 +谚 +添 +鲈 +垓 +桎 +蚯 +芥 +予 +飕 +镦 +谌 +窗 +醚 +菀 +亮 +搪 +莺 +蒿 +羁 +足 +J +真 +轶 +悬 +衷 +靛 +翊 +掩 +哒 +炅 +掐 +冼 +妮 +l +谐 +稚 +荆 +擒 +犯 +陵 +虏 +浓 +崽 +刍 +陌 +傻 +孜 +千 +靖 +演 +矜 +钕 +煽 +杰 +酗 +渗 +伞 +栋 +俗 +泫 +戍 +罕 +沾 +疽 +灏 +煦 +芬 +磴 +叱 +阱 +榉 +湃 +蜀 +叉 +醒 +彪 +租 +郡 +篷 +屎 +良 +垢 +隗 +弱 +陨 +峪 +砷 +掴 +颁 +胎 +雯 +绵 +贬 +沐 +撵 +隘 +篙 +暖 +曹 +陡 +栓 +填 +臼 +彦 +瓶 +琪 +潼 +哪 +鸡 +摩 +啦 +俟 +锋 +域 +耻 +蔫 +疯 +纹 +撇 +毒 +绶 +痛 +酯 +忍 +爪 +赳 +歆 +嘹 +辕 +烈 +册 +朴 +钱 +吮 +毯 +癜 +娃 +谀 +邵 +厮 +炽 +璞 +邃 +丐 +追 +词 +瓒 +忆 +轧 +芫 +谯 +喷 +弟 +半 +冕 +裙 +掖 +墉 +绮 +寝 +苔 +势 +顷 +褥 +切 +衮 +君 +佳 +嫒 +蚩 +霞 +佚 +洙 +逊 +镖 +暹 +唛 +& +殒 +顶 +碗 +獗 +轭 +铺 +蛊 +废 +恹 +汨 +崩 +珍 +那 +杵 +曲 +纺 +夏 +薰 +傀 +闳 +淬 +姘 +舀 +拧 +卷 +楂 +恍 +讪 +厩 +寮 +篪 +赓 +乘 +灭 +盅 +鞣 +沟 +慎 +挂 +饺 +鼾 +杳 +树 +缨 +丛 +絮 +娌 +臻 +嗳 +篡 +侩 +述 +衰 +矛 +圈 +蚜 +匕 +筹 +匿 +濞 +晨 +叶 +骋 +郝 +挚 +蚴 +滞 +增 +侍 +描 +瓣 +吖 +嫦 +蟒 +匾 +圣 +赌 +毡 +癞 +恺 +百 +曳 +需 +篓 +肮 +庖 +帏 +卿 +驿 +遗 +蹬 +鬓 +骡 +歉 +芎 +胳 +屐 +禽 +烦 +晌 +寄 +媾 +狄 +翡 +苒 +船 +廉 +终 +痞 +殇 +々 +畦 +饶 +改 +拆 +悻 +萄 +£ +瓿 +乃 +訾 +桅 +匮 +溧 +拥 +纱 +铍 +骗 +蕃 +龋 +缬 +父 +佐 +疚 +栎 +醍 +掳 +蓄 +x +惆 +颜 +鲆 +榆 +〔 +猎 +敌 +暴 +谥 +鲫 +贾 +罗 +玻 +缄 +扦 +芪 +癣 +落 +徒 +臾 +恿 +猩 +托 +邴 +肄 +牵 +春 +陛 +耀 +刊 +拓 +蓓 +邳 +堕 +寇 +枉 +淌 +啡 +湄 +兽 +酷 +萼 +碚 +濠 +萤 +夹 +旬 +戮 +梭 +琥 +椭 +昔 +勺 +蜊 +绐 +晚 +孺 +僵 +宣 +摄 +冽 +旨 +萌 +忙 +蚤 +眉 +噼 +蟑 +付 +契 +瓜 +悼 +颡 +壁 +曾 +窕 +颢 +澎 +仿 +俑 +浑 +嵌 +浣 +乍 +碌 +褪 +乱 +蔟 +隙 +玩 +剐 +葫 +箫 +纲 +围 +伐 +决 +伙 +漩 +瑟 +刑 +肓 +镳 +缓 +蹭 +氨 +皓 +典 +畲 +坍 +铑 +檐 +塑 +洞 +倬 +储 +胴 +淳 +戾 +吐 +灼 +惺 +妙 +毕 +珐 +缈 +虱 +盖 +羰 +鸿 +磅 +谓 +髅 +娴 +苴 +唷 +蚣 +霹 +抨 +贤 +唠 +犬 +誓 +逍 +庠 +逼 +麓 +籼 +釉 +呜 +碧 +秧 +氩 +摔 +霄 +穸 +纨 +辟 +妈 +映 +完 +牛 +缴 +嗷 +炊 +恩 +荔 +茆 +掉 +紊 +慌 +莓 +羟 +阙 +萁 +磐 +另 +蕹 +辱 +鳐 +湮 +吡 +吩 +唐 +睦 +垠 +舒 +圜 +冗 +瞿 +溺 +芾 +囱 +匠 +僳 +汐 +菩 +饬 +漓 +黑 +霰 +浸 +濡 +窥 +毂 +蒡 +兢 +驻 +鹉 +芮 +诙 +迫 +雳 +厂 +忐 +臆 +猴 +鸣 +蚪 +栈 +箕 +羡 +渐 +莆 +捍 +眈 +哓 +趴 +蹼 +埕 +嚣 +骛 +宏 +淄 +斑 +噜 +严 +瑛 +垃 +椎 +诱 +压 +庾 +绞 +焘 +廿 +抡 +迄 +棘 +夫 +纬 +锹 +眨 +瞌 +侠 +脐 +竞 +瀑 +孳 +骧 +遁 +姜 +颦 +荪 +滚 +萦 +伪 +逸 +粳 +爬 +锁 +矣 +役 +趣 +洒 +颔 +诏 +逐 +奸 +甭 +惠 +攀 +蹄 +泛 +尼 +拼 +阮 +鹰 +亚 +颈 +惑 +勒 +〉 +际 +肛 +爷 +刚 +钨 +丰 +养 +冶 +鲽 +辉 +蔻 +画 +覆 +皴 +妊 +麦 +返 +醉 +皂 +擀 +〗 +酶 +凑 +粹 +悟 +诀 +硖 +港 +卜 +z +杀 +涕 +± +舍 +铠 +抵 +弛 +段 +敝 +镐 +奠 +拂 +轴 +跛 +袱 +e +t +沉 +菇 +俎 +薪 +峦 +秭 +蟹 +历 +盟 +菠 +寡 +液 +肢 +喻 +染 +裱 +悱 +抱 +氙 +赤 +捅 +猛 +跑 +氮 +谣 +仁 +尺 +辊 +窍 +烙 +衍 +架 +擦 +倏 +璐 +瑁 +币 +楞 +胖 +夔 +趸 +邛 +惴 +饕 +虔 +蝎 +§ +哉 +贝 +宽 +辫 +炮 +扩 +饲 +籽 +魏 +菟 +锰 +伍 +猝 +末 +琳 +哚 +蛎 +邂 +呀 +姿 +鄞 +却 +歧 +仙 +恸 +椐 +森 +牒 +寤 +袒 +婆 +虢 +雅 +钉 +朵 +贼 +欲 +苞 +寰 +故 +龚 +坭 +嘘 +咫 +礼 +硷 +兀 +睢 +汶 +’ +铲 +烧 +绕 +诃 +浃 +钿 +哺 +柜 +讼 +颊 +璁 +腔 +洽 +咐 +脲 +簌 +筠 +镣 +玮 +鞠 +谁 +兼 +姆 +挥 +梯 +蝴 +谘 +漕 +刷 +躏 +宦 +弼 +b +垌 +劈 +麟 +莉 +揭 +笙 +渎 +仕 +嗤 +仓 +配 +怏 +抬 +错 +泯 +镊 +孰 +猿 +邪 +仍 +秋 +鼬 +壹 +歇 +吵 +炼 +< +尧 +射 +柬 +廷 +胧 +霾 +凳 +隋 +肚 +浮 +梦 +祥 +株 +堵 +退 +L +鹫 +跎 +凶 +毽 +荟 +炫 +栩 +玳 +甜 +沂 +鹿 +顽 +伯 +爹 +赔 +蛴 +徐 +匡 +欣 +狰 +缸 +雹 +蟆 +疤 +默 +沤 +啜 +痂 +衣 +禅 +w +i +h +辽 +葳 +黝 +钗 +停 +沽 +棒 +馨 +颌 +肉 +吴 +硫 +悯 +劾 +娈 +马 +啧 +吊 +悌 +镑 +峭 +帆 +瀣 +涉 +咸 +疸 +滋 +泣 +翦 +拙 +癸 +钥 +蜒 ++ +尾 +庄 +凝 +泉 +婢 +渴 +谊 +乞 +陆 +锉 +糊 +鸦 +淮 +I +B +N +晦 +弗 +乔 +庥 +葡 +尻 +席 +橡 +傣 +渣 +拿 +惩 +麋 +斛 +缃 +矮 +蛏 +岘 +鸽 +姐 +膏 +催 +奔 +镒 +喱 +蠡 +摧 +钯 +胤 +柠 +拐 +璋 +鸥 +卢 +荡 +倾 +^ +_ +珀 +逄 +萧 +塾 +掇 +贮 +笆 +聂 +圃 +冲 +嵬 +M +滔 +笕 +值 +炙 +偶 +蜱 +搐 +梆 +汪 +蔬 +腑 +鸯 +蹇 +敞 +绯 +仨 +祯 +谆 +梧 +糗 +鑫 +啸 +豺 +囹 +猾 +巢 +柄 +瀛 +筑 +踌 +沭 +暗 +苁 +鱿 +蹉 +脂 +蘖 +牢 +热 +木 +吸 +溃 +宠 +序 +泞 +偿 +拜 +檩 +厚 +朐 +毗 +螳 +吞 +媚 +朽 +担 +蝗 +橘 +畴 +祈 +糟 +盱 +隼 +郜 +惜 +珠 +裨 +铵 +焙 +琚 +唯 +咚 +噪 +骊 +丫 +滢 +勤 +棉 +呸 +咣 +淀 +隔 +蕾 +窈 +饨 +挨 +煅 +短 +匙 +粕 +镜 +赣 +撕 +墩 +酬 +馁 +豌 +颐 +抗 +酣 +氓 +佑 +搁 +哭 +递 +耷 +涡 +桃 +贻 +碣 +截 +瘦 +昭 +镌 +蔓 +氚 +甲 +猕 +蕴 +蓬 +散 +拾 +纛 +狼 +猷 +铎 +埋 +旖 +矾 +讳 +囊 +糜 +迈 +粟 +蚂 +紧 +鲳 +瘢 +栽 +稼 +羊 +锄 +斟 +睁 +桥 +瓮 +蹙 +祉 +醺 +鼻 +昱 +剃 +跳 +篱 +跷 +蒜 +翎 +宅 +晖 +嗑 +壑 +峻 +癫 +屏 +狠 +陋 +袜 +途 +憎 +祀 +莹 +滟 +佶 +溥 +臣 +约 +盛 +峰 +磁 +慵 +婪 +拦 +莅 +朕 +鹦 +粲 +裤 +哎 +疡 +嫖 +琵 +窟 +堪 +谛 +嘉 +儡 +鳝 +斩 +郾 +驸 +酊 +妄 +胜 +贺 +徙 +傅 +噌 +钢 +栅 +庇 +恋 +匝 +巯 +邈 +尸 +锚 +粗 +佟 +蛟 +薹 +纵 +蚊 +郅 +绢 +锐 +苗 +俞 +篆 +淆 +膀 +鲜 +煎 +诶 +秽 +寻 +涮 +刺 +怀 +噶 +巨 +褰 +魅 +灶 +灌 +桉 +藕 +谜 +舸 +薄 +搀 +恽 +借 +牯 +痉 +渥 +愿 +亓 +耘 +杠 +柩 +锔 +蚶 +钣 +珈 +喘 +蹒 +幽 +赐 +稗 +晤 +莱 +泔 +扯 +肯 +菪 +裆 +腩 +豉 +疆 +骜 +腐 +倭 +珏 +唔 +粮 +亡 +润 +慰 +伽 +橄 +玄 +誉 +醐 +胆 +龊 +粼 +塬 +陇 +彼 +削 +嗣 +绾 +芽 +妗 +垭 +瘴 +爽 +薏 +寨 +龈 +泠 +弹 +赢 +漪 +猫 +嘧 +涂 +恤 +圭 +茧 +烽 +屑 +痕 +巾 +赖 +荸 +凰 +腮 +畈 +亵 +蹲 +偃 +苇 +澜 +艮 +换 +骺 +烘 +苕 +梓 +颉 +肇 +哗 +悄 +氤 +涠 +葬 +屠 +鹭 +植 +竺 +佯 +诣 +鲇 +瘀 +鲅 +邦 +移 +滁 +冯 +耕 +癔 +戌 +茬 +沁 +巩 +悠 +湘 +洪 +痹 +锟 +循 +谋 +腕 +鳃 +钠 +捞 +焉 +迎 +碱 +伫 +急 +榷 +奈 +邝 +卯 +辄 +皲 +卟 +醛 +畹 +忧 +稳 +雄 +昼 +缩 +阈 +睑 +扌 +耗 +曦 +涅 +捏 +瞧 +邕 +淖 +漉 +铝 +耦 +禹 +湛 +喽 +莼 +琅 +诸 +苎 +纂 +硅 +始 +嗨 +傥 +燃 +臂 +赅 +嘈 +呆 +贵 +屹 +壮 +肋 +亍 +蚀 +卅 +豹 +腆 +邬 +迭 +浊 +} +童 +螂 +捐 +圩 +勐 +触 +寞 +汊 +壤 +荫 +膺 +渌 +芳 +懿 +遴 +螈 +泰 +蓼 +蛤 +茜 +舅 +枫 +朔 +膝 +眙 +避 +梅 +判 +鹜 +璜 +牍 +缅 +垫 +藻 +黔 +侥 +惚 +懂 +踩 +腰 +腈 +札 +丞 +唾 +慈 +顿 +摹 +荻 +琬 +~ +斧 +沈 +滂 +胁 +胀 +幄 +莜 +Z +匀 +鄄 +掌 +绰 +茎 +焚 +赋 +萱 +谑 +汁 +铒 +瞎 +夺 +蜗 +野 +娆 +冀 +弯 +篁 +懵 +灞 +隽 +芡 +脘 +俐 +辩 +芯 +掺 +喏 +膈 +蝈 +觐 +悚 +踹 +蔗 +熠 +鼠 +呵 +抓 +橼 +峨 +畜 +缔 +禾 +崭 +弃 +熊 +摒 +凸 +拗 +穹 +蒙 +抒 +祛 +劝 +闫 +扳 +阵 +醌 +踪 +喵 +侣 +搬 +仅 +荧 +赎 +蝾 +琦 +买 +婧 +瞄 +寓 +皎 +冻 +赝 +箩 +莫 +瞰 +郊 +笫 +姝 +筒 +枪 +遣 +煸 +袋 +舆 +痱 +涛 +母 +〇 +启 +践 +耙 +绲 +盘 +遂 +昊 +搞 +槿 +诬 +纰 +泓 +惨 +檬 +亻 +越 +C +o +憩 +熵 +祷 +钒 +暧 +塔 +阗 +胰 +咄 +娶 +魔 +琶 +钞 +邻 +扬 +杉 +殴 +咽 +弓 +〆 +髻 +】 +吭 +揽 +霆 +拄 +殖 +脆 +彻 +岩 +芝 +勃 +辣 +剌 +钝 +嘎 +甄 +佘 +皖 +伦 +授 +徕 +憔 +挪 +皇 +庞 +稔 +芜 +踏 +溴 +兖 +卒 +擢 +饥 +鳞 +煲 +‰ +账 +颗 +叻 +斯 +捧 +鳍 +琮 +讹 +蛙 +纽 +谭 +酸 +兔 +莒 +睇 +伟 +觑 +羲 +嗜 +宜 +褐 +旎 +辛 +卦 +诘 +筋 +鎏 +溪 +挛 +熔 +阜 +晰 +鳅 +丢 +奚 +灸 +呱 +献 +陉 +黛 +鸪 +甾 +萨 +疮 +拯 +洲 +疹 +辑 +叙 +恻 +谒 +允 +柔 +烂 +氏 +逅 +漆 +拎 +惋 +扈 +湟 +纭 +啕 +掬 +擞 +哥 +忽 +涤 +鸵 +靡 +郗 +瓷 +扁 +廊 +怨 +雏 +钮 +敦 +E +懦 +憋 +汀 +拚 +啉 +腌 +岸 +f +痼 +瞅 +尊 +咀 +眩 +飙 +忌 +仝 +迦 +熬 +毫 +胯 +篑 +茄 +腺 +凄 +舛 +碴 +锵 +诧 +羯 +後 +漏 +汤 +宓 +仞 +蚁 +壶 +谰 +皑 +铄 +棰 +罔 +辅 +晶 +苦 +牟 +闽 +\ +烃 +饮 +聿 +丙 +蛳 +朱 +煤 +涔 +鳖 +犁 +罐 +荼 +砒 +淦 +妤 +黏 +戎 +孑 +婕 +瑾 +戢 +钵 +枣 +捋 +砥 +衩 +狙 +桠 +稣 +阎 +肃 +梏 +诫 +孪 +昶 +婊 +衫 +嗔 +侃 +塞 +蜃 +樵 +峒 +貌 +屿 +欺 +缫 +阐 +栖 +诟 +珞 +荭 +吝 +萍 +嗽 +恂 +啻 +蜴 +磬 +峋 +俸 +豫 +谎 +徊 +镍 +韬 +魇 +晴 +U +囟 +猜 +蛮 +坐 +囿 +伴 +亭 +肝 +佗 +蝠 +妃 +胞 +滩 +榴 +氖 +垩 +苋 +砣 +扪 +馏 +姓 +轩 +厉 +夥 +侈 +禀 +垒 +岑 +赏 +钛 +辐 +痔 +披 +纸 +碳 +“ +坞 +蠓 +挤 +荥 +沅 +悔 +铧 +帼 +蒌 +蝇 +a +p +y +n +g +哀 +浆 +瑶 +凿 +桶 +馈 +皮 +奴 +苜 +佤 +伶 +晗 +铱 +炬 +优 +弊 +氢 +恃 +甫 +攥 +端 +锌 +灰 +稹 +炝 +曙 +邋 +亥 +眶 +碾 +拉 +萝 +绔 +捷 +浍 +腋 +姑 +菖 +凌 +涞 +麽 +锢 +桨 +潢 +绎 +镰 +殆 +锑 +渝 +铬 +困 +绽 +觎 +匈 +糙 +暑 +裹 +鸟 +盔 +肽 +迷 +綦 +『 +亳 +佝 +俘 +钴 +觇 +骥 +仆 +疝 +跪 +婶 +郯 +瀹 +唉 +脖 +踞 +针 +晾 +忒 +扼 +瞩 +叛 +椒 +疟 +嗡 +邗 +肆 +跆 +玫 +忡 +捣 +咧 +唆 +艄 +蘑 +潦 +笛 +阚 +沸 +泻 +掊 +菽 +贫 +斥 +髂 +孢 +镂 +赂 +麝 +鸾 +屡 +衬 +苷 +恪 +叠 +希 +粤 +爻 +喝 +茫 +惬 +郸 +绻 +庸 +撅 +碟 +宄 +妹 +膛 +叮 +饵 +崛 +嗲 +椅 +冤 +搅 +咕 +敛 +尹 +垦 +闷 +蝉 +霎 +勰 +败 +蓑 +泸 +肤 +鹌 +幌 +焦 +浠 +鞍 +刁 +舰 +乙 +竿 +裔 +。 +茵 +函 +伊 +兄 +丨 +娜 +匍 +謇 +莪 +宥 +似 +蝽 +翳 +酪 +翠 +粑 +薇 +祢 +骏 +赠 +叫 +Q +噤 +噻 +竖 +芗 +莠 +潭 +俊 +羿 +耜 +O +郫 +趁 +嗪 +囚 +蹶 +芒 +洁 +笋 +鹑 +敲 +硝 +啶 +堡 +渲 +揩 +』 +携 +宿 +遒 +颍 +扭 +棱 +割 +萜 +蔸 +葵 +琴 +捂 +饰 +衙 +耿 +掠 +募 +岂 +窖 +涟 +蔺 +瘤 +柞 +瞪 +怜 +匹 +距 +楔 +炜 +哆 +秦 +缎 +幼 +茁 +绪 +痨 +恨 +楸 +娅 +瓦 +桩 +雪 +嬴 +伏 +榔 +妥 +铿 +拌 +眠 +雍 +缇 +‘ +卓 +搓 +哌 +觞 +噩 +屈 +哧 +髓 +咦 +巅 +娑 +侑 +淫 +膳 +祝 +勾 +姊 +莴 +胄 +疃 +薛 +蜷 +胛 +巷 +芙 +芋 +熙 +闰 +勿 +窃 +狱 +剩 +钏 +幢 +陟 +铛 +慧 +靴 +耍 +k +浙 +浇 +飨 +惟 +绗 +祜 +澈 +啼 +咪 +磷 +摞 +诅 +郦 +抹 +跃 +壬 +吕 +肖 +琏 +颤 +尴 +剡 +抠 +凋 +赚 +泊 +津 +宕 +殷 +倔 +氲 +漫 +邺 +涎 +怠 +$ +垮 +荬 +遵 +俏 +叹 +噢 +饽 +蜘 +孙 +筵 +疼 +鞭 +羧 +牦 +箭 +潴 +c +眸 +祭 +髯 +啖 +坳 +愁 +芩 +驮 +倡 +巽 +穰 +沃 +胚 +怒 +凤 +槛 +剂 +趵 +嫁 +v +邢 +灯 +鄢 +桐 +睽 +檗 +锯 +槟 +婷 +嵋 +圻 +诗 +蕈 +颠 +遭 +痢 +芸 +怯 +馥 +竭 +锗 +徜 +恭 +遍 +籁 +剑 +嘱 +苡 +龄 +僧 +桑 +潸 +弘 +澶 +楹 +悲 +讫 +愤 +腥 +悸 +谍 +椹 +呢 +桓 +葭 +攫 +阀 +翰 +躲 +敖 +柑 +郎 +笨 +橇 +呃 +魁 +燎 +脓 +葩 +磋 +垛 +玺 +狮 +沓 +砜 +蕊 +锺 +罹 +蕉 +翱 +虐 +闾 +巫 +旦 +茱 +嬷 +枯 +鹏 +贡 +芹 +汛 +矫 +绁 +拣 +禺 +佃 +讣 +舫 +惯 +乳 +趋 +疲 +挽 +岚 +虾 +衾 +蠹 +蹂 +飓 +氦 +铖 +孩 +稞 +瑜 +壅 +掀 +勘 +妓 +畅 +髋 +W +庐 +牲 +蓿 +榕 +练 +垣 +唱 +邸 +菲 +昆 +婺 +穿 +绡 +麒 +蚱 +掂 +愚 +泷 +涪 +漳 +妩 +娉 +榄 +讷 +觅 +旧 +藤 +煮 +呛 +柳 +腓 +叭 +庵 +烷 +阡 +罂 +蜕 +擂 +猖 +咿 +媲 +脉 +【 +沏 +貅 +黠 +熏 +哲 +烁 +坦 +酵 +兜 +× +潇 +撒 +剽 +珩 +圹 +乾 +摸 +樟 +帽 +嗒 +襄 +魂 +轿 +憬 +锡 +〕 +喃 +皆 +咖 +隅 +脸 +残 +泮 +袂 +鹂 +珊 +囤 +捆 +咤 +误 +徨 +闹 +淙 +芊 +淋 +怆 +囗 +拨 +梳 +渤 +R +G +绨 +蚓 +婀 +幡 +狩 +麾 +谢 +唢 +裸 +旌 +伉 +纶 +裂 +驳 +砼 +咛 +澄 +樨 +蹈 +宙 +澍 +倍 +貔 +操 +勇 +蟠 +摈 +砧 +虬 +够 +缁 +悦 +藿 +撸 +艹 +摁 +淹 +豇 +虎 +榭 +ˉ +吱 +d +° +喧 +荀 +踱 +侮 +奋 +偕 +饷 +犍 +惮 +坑 +璎 +徘 +宛 +妆 +袈 +倩 +窦 +昂 +荏 +乖 +K +怅 +撰 +鳙 +牙 +袁 +酞 +X +痿 +琼 +闸 +雁 +趾 +荚 +虻 +涝 +《 +杏 +韭 +偈 +烤 +绫 +鞘 +卉 +症 +遢 +蓥 +诋 +杭 +荨 +匆 +竣 +簪 +辙 +敕 +虞 +丹 +缭 +咩 +黟 +m +淤 +瑕 +咂 +铉 +硼 +茨 +嶂 +痒 +畸 +敬 +涿 +粪 +窘 +熟 +叔 +嫔 +盾 +忱 +裘 +憾 +梵 +赡 +珙 +咯 +娘 +庙 +溯 +胺 +葱 +痪 +摊 +荷 +卞 +乒 +髦 +寐 +铭 +坩 +胗 +枷 +爆 +溟 +嚼 +羚 +砬 +轨 +惊 +挠 +罄 +竽 +菏 +氧 +浅 +楣 +盼 +枢 +炸 +阆 +杯 +谏 +噬 +淇 +渺 +俪 +秆 +墓 +泪 +跻 +砌 +痰 +垡 +渡 +耽 +釜 +讶 +鳎 +煞 +呗 +韶 +舶 +绷 +鹳 +缜 +旷 +铊 +皱 +龌 +檀 +霖 +奄 +槐 +艳 +蝶 +旋 +哝 +赶 +骞 +蚧 +腊 +盈 +丁 +` +蜚 +矸 +蝙 +睨 +嚓 +僻 +鬼 +醴 +夜 +彝 +磊 +笔 +拔 +栀 +糕 +厦 +邰 +纫 +逭 +纤 +眦 +膊 +馍 +躇 +烯 +蘼 +冬 +诤 +暄 +骶 +哑 +瘠 +」 +臊 +丕 +愈 +咱 +螺 +擅 +跋 +搏 +硪 +谄 +笠 +淡 +嘿 +骅 +谧 +鼎 +皋 +姚 +歼 +蠢 +驼 +耳 +胬 +挝 +涯 +狗 +蒽 +孓 +犷 +凉 +芦 +箴 +铤 +孤 +嘛 +坤 +V +茴 +朦 +挞 +尖 +橙 +诞 +搴 +碇 +洵 +浚 +帚 +蜍 +漯 +柘 +嚎 +讽 +芭 +荤 +咻 +祠 +秉 +跖 +埃 +吓 +糯 +眷 +馒 +惹 +娼 +鲑 +嫩 +讴 +轮 +瞥 +靶 +褚 +乏 +缤 +宋 +帧 +删 +驱 +碎 +扑 +俩 +俄 +偏 +涣 +竹 +噱 +皙 +佰 +渚 +唧 +斡 +# +镉 +刀 +崎 +筐 +佣 +夭 +贰 +肴 +峙 +哔 +艿 +匐 +牺 +镛 +缘 +仡 +嫡 +劣 +枸 +堀 +梨 +簿 +鸭 +蒸 +亦 +稽 +浴 +{ +衢 +束 +槲 +j +阁 +揍 +疥 +棋 +潋 +聪 +窜 +乓 +睛 +插 +冉 +阪 +苍 +搽 +「 +蟾 +螟 +幸 +仇 +樽 +撂 +慢 +跤 +幔 +俚 +淅 +覃 +觊 +溶 +妖 +帛 +侨 +曰 +妾 +泗 +· +: +瀘 +風 +Ë +( +) +∶ +紅 +紗 +瑭 +雲 +頭 +鶏 +財 +許 +• +¥ +樂 +焗 +麗 +— +; +滙 +東 +榮 +繪 +興 +… +門 +業 +π +楊 +國 +顧 +é +盤 +寳 +Λ +龍 +鳳 +島 +誌 +緣 +結 +銭 +萬 +勝 +祎 +璟 +優 +歡 +臨 +時 +購 += +★ +藍 +昇 +鐵 +觀 +勅 +農 +聲 +畫 +兿 +術 +發 +劉 +記 +專 +耑 +園 +書 +壴 +種 +Ο +● +褀 +號 +銀 +匯 +敟 +锘 +葉 +橪 +廣 +進 +蒄 +鑽 +阝 +祙 +貢 +鍋 +豊 +夬 +喆 +團 +閣 +開 +燁 +賓 +館 +酡 +沔 +順 ++ +硚 +劵 +饸 +陽 +車 +湓 +復 +萊 +氣 +軒 +華 +堃 +迮 +纟 +戶 +馬 +學 +裡 +電 +嶽 +獨 +マ +シ +サ +ジ +燘 +袪 +環 +❤ +臺 +灣 +専 +賣 +孖 +聖 +攝 +線 +▪ +α +傢 +俬 +夢 +達 +莊 +喬 +貝 +薩 +劍 +羅 +壓 +棛 +饦 +尃 +璈 +囍 +醫 +G +I +A +# +N +鷄 +髙 +嬰 +啓 +約 +隹 +潔 +賴 +藝 +~ +寶 +籣 +麺 +  +嶺 +√ +義 +網 +峩 +長 +∧ +魚 +機 +構 +② +鳯 +偉 +L +B +㙟 +畵 +鴿 +' +詩 +溝 +嚞 +屌 +藔 +佧 +玥 +蘭 +織 +1 +3 +9 +0 +7 +點 +砭 +鴨 +鋪 +銘 +廳 +弍 +‧ +創 +湯 +坶 +℃ +卩 +骝 +& +烜 +荘 +當 +潤 +扞 +係 +懷 +碶 +钅 +蚨 +讠 +☆ +叢 +爲 +埗 +涫 +塗 +→ +楽 +現 +鯨 +愛 +瑪 +鈺 +忄 +悶 +藥 +飾 +樓 +視 +孬 +ㆍ +燚 +苪 +師 +① +丼 +锽 +│ +韓 +標 +è +兒 +閏 +匋 +張 +漢 +Ü +髪 +會 +閑 +檔 +習 +裝 +の +峯 +菘 +輝 +И +雞 +釣 +億 +浐 +K +O +R +8 +H +E +P +T +W +D +S +C +M +F +姌 +饹 +» +晞 +廰 +ä +嵯 +鷹 +負 +飲 +絲 +冚 +楗 +澤 +綫 +區 +❋ +← +質 +靑 +揚 +③ +滬 +統 +産 +協 +﹑ +乸 +畐 +經 +運 +際 +洺 +岽 +為 +粵 +諾 +崋 +豐 +碁 +ɔ +V +2 +6 +齋 +誠 +訂 +´ +勑 +雙 +陳 +無 +í +泩 +媄 +夌 +刂 +i +c +t +o +r +a +嘢 +耄 +燴 +暃 +壽 +媽 +靈 +抻 +體 +唻 +É +冮 +甹 +鎮 +錦 +ʌ +蜛 +蠄 +尓 +駕 +戀 +飬 +逹 +倫 +貴 +極 +Я +Й +寬 +磚 +嶪 +郎 +職 +| +間 +n +d +剎 +伈 +課 +飛 +橋 +瘊 +№ +譜 +骓 +圗 +滘 +縣 +粿 +咅 +養 +濤 +彳 +® +% +Ⅱ +啰 +㴪 +見 +矞 +薬 +糁 +邨 +鲮 +顔 +罱 +З +選 +話 +贏 +氪 +俵 +競 +瑩 +繡 +枱 +β +綉 +á +獅 +爾 +™ +麵 +戋 +淩 +徳 +個 +劇 +場 +務 +簡 +寵 +h +實 +膠 +轱 +圖 +築 +嘣 +樹 +㸃 +營 +耵 +孫 +饃 +鄺 +飯 +麯 +遠 +輸 +坫 +孃 +乚 +閃 +鏢 +㎡ +題 +廠 +關 +↑ +爺 +將 +軍 +連 +篦 +覌 +參 +箸 +- +窠 +棽 +寕 +夀 +爰 +歐 +呙 +閥 +頡 +熱 +雎 +垟 +裟 +凬 +勁 +帑 +馕 +夆 +疌 +枼 +馮 +貨 +蒤 +樸 +彧 +旸 +靜 +龢 +暢 +㐱 +鳥 +珺 +鏡 +灡 +爭 +堷 +廚 +Ó +騰 +診 +┅ +蘇 +褔 +凱 +頂 +豕 +亞 +帥 +嘬 +⊥ +仺 +桖 +複 +饣 +絡 +穂 +顏 +棟 +納 +▏ +濟 +親 +設 +計 +攵 +埌 +烺 +ò +頤 +燦 +蓮 +撻 +節 +講 +濱 +濃 +娽 +洳 +朿 +燈 +鈴 +護 +膚 +铔 +過 +補 +Z +U +5 +4 +坋 +闿 +䖝 +餘 +缐 +铞 +貿 +铪 +桼 +趙 +鍊 +[ +㐂 +垚 +菓 +揸 +捲 +鐘 +滏 +𣇉 +爍 +輪 +燜 +鴻 +鮮 +動 +鹞 +鷗 +丄 +慶 +鉌 +翥 +飮 +腸 +⇋ +漁 +覺 +來 +熘 +昴 +翏 +鲱 +圧 +鄉 +萭 +頔 +爐 +嫚 +г +貭 +類 +聯 +幛 +輕 +訓 +鑒 +夋 +锨 +芃 +珣 +䝉 +扙 +嵐 +銷 +處 +ㄱ +語 +誘 +苝 +歸 +儀 +燒 +楿 +內 +粢 +葒 +奧 +麥 +礻 +滿 +蠔 +穵 +瞭 +態 +鱬 +榞 +硂 +鄭 +黃 +煙 +祐 +奓 +逺 +* +瑄 +獲 +聞 +薦 +讀 +這 +樣 +決 +問 +啟 +們 +執 +説 +轉 +單 +隨 +唘 +帶 +倉 +庫 +還 +贈 +尙 +皺 +■ +餅 +產 +○ +∈ +報 +狀 +楓 +賠 +琯 +嗮 +禮 +` +傳 +> +≤ +嗞 +Φ +≥ +換 +咭 +∣ +↓ +曬 +ε +応 +寫 +″ +終 +様 +純 +費 +療 +聨 +凍 +壐 +郵 +ü +黒 +∫ +製 +塊 +調 +軽 +確 +撃 +級 +馴 +Ⅲ +涇 +繹 +數 +碼 +證 +狒 +処 +劑 +< +晧 +賀 +衆 +] +櫥 +兩 +陰 +絶 +對 +鯉 +憶 +◎ +p +e +Y +蕒 +煖 +頓 +測 +試 +鼽 +僑 +碩 +妝 +帯 +≈ +鐡 +舖 +權 +喫 +倆 +ˋ +該 +悅 +ā +俫 +. +f +s +b +m +k +g +u +j +貼 +淨 +濕 +針 +適 +備 +l +/ +給 +謢 +強 +觸 +衛 +與 +⊙ +$ +緯 +變 +⑴ +⑵ +⑶ +㎏ +殺 +∩ +幚 +─ +價 +▲ +離 +ú +ó +飄 +烏 +関 +閟 +﹝ +﹞ +邏 +輯 +鍵 +驗 +訣 +導 +歷 +屆 +層 +▼ +儱 +錄 +熳 +ē +艦 +吋 +錶 +辧 +飼 +顯 +④ +禦 +販 +気 +対 +枰 +閩 +紀 +幹 +瞓 +貊 +淚 +△ +眞 +墊 +Ω +獻 +褲 +縫 +緑 +亜 +鉅 +餠 +{ +} +◆ +蘆 +薈 +█ +◇ +溫 +彈 +晳 +粧 +犸 +穩 +訊 +崬 +凖 +熥 +П +舊 +條 +紋 +圍 +Ⅳ +筆 +尷 +難 +雜 +錯 +綁 +識 +頰 +鎖 +艶 +□ +殁 +殼 +⑧ +├ +▕ +鵬 +ǐ +ō +ǒ +糝 +綱 +▎ +μ +盜 +饅 +醬 +籤 +蓋 +釀 +鹽 +據 +à +ɡ +辦 +◥ +彐 +┌ +婦 +獸 +鲩 +伱 +ī +蒟 +蒻 +齊 +袆 +腦 +寧 +凈 +妳 +煥 +詢 +偽 +謹 +啫 +鯽 +騷 +鱸 +損 +傷 +鎻 +髮 +買 +冏 +儥 +両 +﹢ +∞ +載 +喰 +z +羙 +悵 +燙 +曉 +員 +組 +徹 +艷 +痠 +鋼 +鼙 +縮 +細 +嚒 +爯 +≠ +維 +" +鱻 +壇 +厍 +帰 +浥 +犇 +薡 +軎 +² +應 +醜 +刪 +緻 +鶴 +賜 +噁 +軌 +尨 +镔 +鷺 +槗 +彌 +葚 +濛 +請 +溇 +緹 +賢 +訪 +獴 +瑅 +資 +縤 +陣 +蕟 +栢 +韻 +祼 +恁 +伢 +謝 +劃 +涑 +總 +衖 +踺 +砋 +凉 +籃 +駿 +苼 +瘋 +昽 +紡 +驊 +腎 +﹗ +響 +杋 +剛 +嚴 +禪 +歓 +槍 +傘 +檸 +檫 +炣 +勢 +鏜 +鎢 +銑 +尐 +減 +奪 +惡 +θ +僮 +婭 +臘 +ū +ì +殻 +鉄 +∑ +蛲 +焼 +緖 +續 +紹 +懮 diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java new file mode 100644 index 0000000000..9ce3b38765 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java @@ -0,0 +1,500 @@ +package com.baidu.paddle.fastdeploy.app.examples.ocr; + +import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.os.SystemClock; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import com.baidu.paddle.fastdeploy.RuntimeOption; +import com.baidu.paddle.fastdeploy.app.examples.R; +import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.app.ui.Utils; +import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter; +import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.pipeline.PPOCRv3; +import com.baidu.paddle.fastdeploy.vision.OCRResult; +import com.baidu.paddle.fastdeploy.vision.Visualize; +import com.baidu.paddle.fastdeploy.vision.ocr.Classifier; +import com.baidu.paddle.fastdeploy.vision.ocr.DBDetector; +import com.baidu.paddle.fastdeploy.vision.ocr.Recognizer; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class OcrMainActivity extends Activity implements View.OnClickListener, CameraSurfaceView.OnTextureChangedListener { + private static final String TAG = OcrMainActivity.class.getSimpleName(); + + CameraSurfaceView svPreview; + TextView tvStatus; + ImageButton btnSwitch; + ImageButton btnShutter; + ImageButton btnSettings; + ImageView realtimeToggleButton; + boolean isRealtimeStatusRunning = false; + ImageView backInPreview; + private ImageView albumSelectButton; + private View cameraPageView; + private ViewGroup resultPageView; + private ImageView resultImage; + private ImageView backInResult; + private SeekBar confidenceSeekbar; + private TextView seekbarText; + private float resultNum = 1.0f; + private ResultListView resultView; + private Bitmap picBitmap; + private Bitmap shutterBitmap; + private Bitmap originPicBitmap; + private Bitmap originShutterBitmap; + private boolean isShutterBitmapCopied = false; + + public static final int TYPE_UNKNOWN = -1; + public static final int BTN_SHUTTER = 0; + public static final int ALBUM_SELECT = 1; + public static final int REALTIME_DETECT = 2; + private static int TYPE = REALTIME_DETECT; + + private static final int REQUEST_PERMISSION_CODE_STORAGE = 101; + private static final int INTENT_CODE_PICK_IMAGE = 100; + private static final int TIME_SLEEP_INTERVAL = 50; // ms + + long timeElapsed = 0; + long frameCounter = 0; + + // Call 'init' and 'release' manually later + PPOCRv3 predictor = new PPOCRv3(); + + private String[] texts; + private float[] recScores; + private boolean initialized; + private List results = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Fullscreen + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.ocr_activity_main); + + // Clear all setting items to avoid app crashing due to the incorrect settings + initSettings(); + + // Check and request CAMERA and WRITE_EXTERNAL_STORAGE permissions + if (!checkAllPermissions()) { + requestAllPermissions(); + } + + // Init the camera preview and UI components + initView(); + } + + @SuppressLint("NonConstantResourceId") + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_switch: + svPreview.switchCamera(); + break; + case R.id.btn_shutter: + TYPE = BTN_SHUTTER; + shutterAndPauseCamera(); + resultView.setAdapter(null); + break; + case R.id.btn_settings: + startActivity(new Intent(OcrMainActivity.this, OcrSettingsActivity.class)); + break; + case R.id.realtime_toggle_btn: + toggleRealtimeStyle(); + break; + case R.id.back_in_preview: + finish(); + break; + case R.id.iv_select: + TYPE = ALBUM_SELECT; + // Judge whether authority has been granted. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + // If this permission was requested before the application but the user refused the request, this method will return true. + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE_STORAGE); + } else { + Intent intent = new Intent(Intent.ACTION_PICK); + intent.setType("image/*"); + startActivityForResult(intent, INTENT_CODE_PICK_IMAGE); + } + resultView.setAdapter(null); + break; + case R.id.back_in_result: + back(); + break; + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + back(); + } + + private void back() { + resultPageView.setVisibility(View.GONE); + cameraPageView.setVisibility(View.VISIBLE); + TYPE = REALTIME_DETECT; + isShutterBitmapCopied = false; + svPreview.onResume(); + results.clear(); + if (texts != null) { + texts = null; + } + if (recScores != null) { + recScores = null; + } + } + + private void shutterAndPauseCamera() { + new Thread(new Runnable() { + @Override + public void run() { + try { + // Sleep some times to ensure picture has been correctly shut. + Thread.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms + } catch (InterruptedException e) { + e.printStackTrace(); + } + runOnUiThread(new Runnable() { + @SuppressLint("SetTextI18n") + public void run() { + // These code will run in main thread. + svPreview.onPause(); + cameraPageView.setVisibility(View.GONE); + resultPageView.setVisibility(View.VISIBLE); + seekbarText.setText(resultNum + ""); + confidenceSeekbar.setProgress((int) (resultNum * 100)); + if (shutterBitmap != null && !shutterBitmap.isRecycled()) { + resultImage.setImageBitmap(shutterBitmap); + } else { + new AlertDialog.Builder(OcrMainActivity.this) + .setTitle("Empty Result!") + .setMessage("Current picture is empty, please shutting it again!") + .setCancelable(true) + .show(); + } + } + }); + + } + }).start(); + } + + private void copyBitmapFromCamera(Bitmap ARGB8888ImageBitmap) { + if (isShutterBitmapCopied || ARGB8888ImageBitmap == null) { + return; + } + if (!ARGB8888ImageBitmap.isRecycled()) { + synchronized (this) { + shutterBitmap = ARGB8888ImageBitmap.copy(Bitmap.Config.ARGB_8888, true); + originShutterBitmap = ARGB8888ImageBitmap.copy(Bitmap.Config.ARGB_8888, true); + } + SystemClock.sleep(TIME_SLEEP_INTERVAL); + isShutterBitmapCopied = true; + } + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == INTENT_CODE_PICK_IMAGE) { + if (resultCode == Activity.RESULT_OK) { + cameraPageView.setVisibility(View.GONE); + resultPageView.setVisibility(View.VISIBLE); + seekbarText.setText(resultNum + ""); + confidenceSeekbar.setProgress((int) (resultNum * 100)); + Uri uri = data.getData(); + String path = getRealPathFromURI(this, uri); + picBitmap = decodeBitmap(path, 720, 1280); + originPicBitmap = picBitmap.copy(Bitmap.Config.ARGB_8888, true); + resultImage.setImageBitmap(picBitmap); + } + } + } + + private void toggleRealtimeStyle() { + if (isRealtimeStatusRunning) { + isRealtimeStatusRunning = false; + realtimeToggleButton.setImageResource(R.drawable.realtime_stop_btn); + svPreview.setOnTextureChangedListener(this); + tvStatus.setVisibility(View.VISIBLE); + } else { + isRealtimeStatusRunning = true; + realtimeToggleButton.setImageResource(R.drawable.realtime_start_btn); + tvStatus.setVisibility(View.GONE); + isShutterBitmapCopied = false; + svPreview.setOnTextureChangedListener(new CameraSurfaceView.OnTextureChangedListener() { + @Override + public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) { + if (TYPE == BTN_SHUTTER) { + copyBitmapFromCamera(ARGB8888ImageBitmap); + } + return false; + } + }); + } + } + + @Override + public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) { + if (TYPE == BTN_SHUTTER) { + copyBitmapFromCamera(ARGB8888ImageBitmap); + return false; + } + + boolean modified = false; + + long tc = System.currentTimeMillis(); + OCRResult result = predictor.predict(ARGB8888ImageBitmap); + timeElapsed += (System.currentTimeMillis() - tc); + + Visualize.visOcr(ARGB8888ImageBitmap, result); + modified = result.initialized(); + + frameCounter++; + if (frameCounter >= 30) { + final int fps = (int) (1000 / (timeElapsed / 30)); + runOnUiThread(new Runnable() { + @SuppressLint("SetTextI18n") + public void run() { + tvStatus.setText(Integer.toString(fps) + "fps"); + } + }); + frameCounter = 0; + timeElapsed = 0; + } + return modified; + } + + @Override + protected void onResume() { + super.onResume(); + // Reload settings and re-initialize the predictor + checkAndUpdateSettings(); + // Open camera until the permissions have been granted + if (!checkAllPermissions()) { + svPreview.disableCamera(); + } else { + svPreview.enableCamera(); + } + svPreview.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + svPreview.onPause(); + } + + @Override + protected void onDestroy() { + if (predictor != null) { + predictor.release(); + } + super.onDestroy(); + } + + public void initView() { + TYPE = REALTIME_DETECT; + svPreview = (CameraSurfaceView) findViewById(R.id.sv_preview); + svPreview.setOnTextureChangedListener(this); + tvStatus = (TextView) findViewById(R.id.tv_status); + btnSwitch = (ImageButton) findViewById(R.id.btn_switch); + btnSwitch.setOnClickListener(this); + btnShutter = (ImageButton) findViewById(R.id.btn_shutter); + btnShutter.setOnClickListener(this); + btnSettings = (ImageButton) findViewById(R.id.btn_settings); + btnSettings.setOnClickListener(this); + realtimeToggleButton = findViewById(R.id.realtime_toggle_btn); + realtimeToggleButton.setOnClickListener(this); + backInPreview = findViewById(R.id.back_in_preview); + backInPreview.setOnClickListener(this); + albumSelectButton = findViewById(R.id.iv_select); + albumSelectButton.setOnClickListener(this); + cameraPageView = findViewById(R.id.camera_page); + resultPageView = findViewById(R.id.result_page); + resultImage = findViewById(R.id.result_image); + backInResult = findViewById(R.id.back_in_result); + backInResult.setOnClickListener(this); + confidenceSeekbar = findViewById(R.id.confidence_seekbar); + seekbarText = findViewById(R.id.seekbar_text); + resultView = findViewById(R.id.result_list_view); + + confidenceSeekbar.setMax(100); + confidenceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + float resultConfidence = seekBar.getProgress() / 100f; + BigDecimal bd = new BigDecimal(resultConfidence); + resultNum = bd.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); + seekbarText.setText(resultNum + ""); + confidenceSeekbar.setProgress((int) (resultNum * 100)); + results.clear(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (TYPE == ALBUM_SELECT) { + SystemClock.sleep(TIME_SLEEP_INTERVAL * 10); + detail(picBitmap); + picBitmap = originPicBitmap.copy(Bitmap.Config.ARGB_8888, true); + } else { + SystemClock.sleep(TIME_SLEEP_INTERVAL * 10); + detail(shutterBitmap); + shutterBitmap = originShutterBitmap.copy(Bitmap.Config.ARGB_8888, true); + } + } + }); + } + }); + } + + private void detail(Bitmap bitmap) { + OCRResult result = predictor.predict(bitmap, true); + + texts = result.mText; + recScores = result.mRecScores; + + initialized = result.initialized(); + if (initialized) { + for (int i = 0; i < texts.length; i++) { + if (recScores[i] > resultNum) { + results.add(new BaseResultModel(i + 1, texts[i], recScores[i])); + } + } + } + BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.ocr_result_page_item, results); + resultView.setAdapter(adapter); + resultView.invalidate(); + + resultImage.setImageBitmap(bitmap); + resultNum = 1.0f; + } + + @SuppressLint("ApplySharedPref") + public void initSettings() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.clear(); + editor.commit(); + OcrSettingsActivity.resetSettings(); + } + + public void checkAndUpdateSettings() { + if (OcrSettingsActivity.checkAndUpdateSettings(this)) { + String realModelDir = getCacheDir() + "/" + OcrSettingsActivity.modelDir; + String detModelName = "ch_PP-OCRv3_det_infer"; + // String detModelName = "ch_ppocr_mobile_v2.0_det_infer"; + String clsModelName = "ch_ppocr_mobile_v2.0_cls_infer"; + // String recModelName = "ch_ppocr_mobile_v2.0_rec_infer"; + String recModelName = "ch_PP-OCRv3_rec_infer"; + String realDetModelDir = realModelDir + "/" + detModelName; + String realClsModelDir = realModelDir + "/" + clsModelName; + String realRecModelDir = realModelDir + "/" + recModelName; + String srcDetModelDir = OcrSettingsActivity.modelDir + "/" + detModelName; + String srcClsModelDir = OcrSettingsActivity.modelDir + "/" + clsModelName; + String srcRecModelDir = OcrSettingsActivity.modelDir + "/" + recModelName; + Utils.copyDirectoryFromAssets(this, srcDetModelDir, realDetModelDir); + Utils.copyDirectoryFromAssets(this, srcClsModelDir, realClsModelDir); + Utils.copyDirectoryFromAssets(this, srcRecModelDir, realRecModelDir); + String realLabelPath = getCacheDir() + "/" + OcrSettingsActivity.labelPath; + Utils.copyFileFromAssets(this, OcrSettingsActivity.labelPath, realLabelPath); + + String detModelFile = realDetModelDir + "/" + "inference.pdmodel"; + String detParamsFile = realDetModelDir + "/" + "inference.pdiparams"; + String clsModelFile = realClsModelDir + "/" + "inference.pdmodel"; + String clsParamsFile = realClsModelDir + "/" + "inference.pdiparams"; + String recModelFile = realRecModelDir + "/" + "inference.pdmodel"; + String recParamsFile = realRecModelDir + "/" + "inference.pdiparams"; + String recLabelFilePath = realLabelPath; // ppocr_keys_v1.txt + RuntimeOption detOption = new RuntimeOption(); + RuntimeOption clsOption = new RuntimeOption(); + RuntimeOption recOption = new RuntimeOption(); + detOption.setCpuThreadNum(OcrSettingsActivity.cpuThreadNum); + clsOption.setCpuThreadNum(OcrSettingsActivity.cpuThreadNum); + recOption.setCpuThreadNum(OcrSettingsActivity.cpuThreadNum); + detOption.setLitePowerMode(OcrSettingsActivity.cpuPowerMode); + clsOption.setLitePowerMode(OcrSettingsActivity.cpuPowerMode); + recOption.setLitePowerMode(OcrSettingsActivity.cpuPowerMode); + if (Boolean.parseBoolean(OcrSettingsActivity.enableLiteFp16)) { + detOption.enableLiteFp16(); + clsOption.enableLiteFp16(); + recOption.enableLiteFp16(); + } + DBDetector detModel = new DBDetector(detModelFile, detParamsFile, detOption); + Classifier clsModel = new Classifier(clsModelFile, clsParamsFile, clsOption); + Recognizer recModel = new Recognizer(recModelFile, recParamsFile, recLabelFilePath, recOption); + predictor.init(detModel, clsModel, recModel); + + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) { + new AlertDialog.Builder(OcrMainActivity.this) + .setTitle("Permission denied") + .setMessage("Click to force quit the app, then open Settings->Apps & notifications->Target " + + "App->Permissions to grant all of the permissions.") + .setCancelable(false) + .setPositiveButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + OcrMainActivity.this.finish(); + } + }).show(); + } + } + + private void requestAllPermissions() { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA}, 0); + } + + private boolean checkAllPermissions() { + return ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + && ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; + } +} diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java new file mode 100644 index 0000000000..6f8c45ff4f --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java @@ -0,0 +1,198 @@ +package com.baidu.paddle.fastdeploy.app.examples.ocr; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.PreferenceManager; +import android.support.v7.app.ActionBar; + +import com.baidu.paddle.fastdeploy.app.examples.R; +import com.baidu.paddle.fastdeploy.app.ui.Utils; +import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; + +import java.util.ArrayList; +import java.util.List; + +public class OcrSettingsActivity extends AppCompatPreferenceActivity implements + SharedPreferences.OnSharedPreferenceChangeListener { + private static final String TAG = OcrSettingsActivity.class.getSimpleName(); + + static public int selectedModelIdx = -1; + static public String modelDir = ""; + static public String labelPath = ""; + static public int cpuThreadNum = 2; + static public String cpuPowerMode = ""; + static public float scoreThreshold = 0.4f; + static public String enableLiteFp16 = "true"; + + ListPreference lpChoosePreInstalledModel = null; + EditTextPreference etModelDir = null; + EditTextPreference etLabelPath = null; + ListPreference lpCPUThreadNum = null; + ListPreference lpCPUPowerMode = null; + EditTextPreference etScoreThreshold = null; + ListPreference lpEnableLiteFp16 = null; + + List preInstalledModelDirs = null; + List preInstalledLabelPaths = null; + List preInstalledCPUThreadNums = null; + List preInstalledCPUPowerModes = null; + List preInstalledScoreThresholds = null; + List preInstalledEnableLiteFp16s = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.ocr_settings); + ActionBar supportActionBar = getSupportActionBar(); + if (supportActionBar != null) { + supportActionBar.setDisplayHomeAsUpEnabled(true); + } + + // Initialize pre-installed models + preInstalledModelDirs = new ArrayList(); + preInstalledLabelPaths = new ArrayList(); + preInstalledCPUThreadNums = new ArrayList(); + preInstalledCPUPowerModes = new ArrayList(); + preInstalledScoreThresholds = new ArrayList(); + preInstalledEnableLiteFp16s = new ArrayList(); + preInstalledModelDirs.add(getString(R.string.OCR_MODEL_DIR_DEFAULT)); + preInstalledLabelPaths.add(getString(R.string.OCR_REC_LABEL_DEFAULT)); + preInstalledCPUThreadNums.add(getString(R.string.CPU_THREAD_NUM_DEFAULT)); + preInstalledCPUPowerModes.add(getString(R.string.CPU_POWER_MODE_DEFAULT)); + preInstalledScoreThresholds.add(getString(R.string.SCORE_THRESHOLD_DEFAULT)); + preInstalledEnableLiteFp16s.add(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + + // Setup UI components + lpChoosePreInstalledModel = + (ListPreference) findPreference(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY)); + String[] preInstalledModelNames = new String[preInstalledModelDirs.size()]; + for (int i = 0; i < preInstalledModelDirs.size(); i++) { + preInstalledModelNames[i] = preInstalledModelDirs.get(i).substring(preInstalledModelDirs.get(i).lastIndexOf("/") + 1); + } + lpChoosePreInstalledModel.setEntries(preInstalledModelNames); + lpChoosePreInstalledModel.setEntryValues(preInstalledModelDirs.toArray(new String[preInstalledModelDirs.size()])); + lpCPUThreadNum = (ListPreference) findPreference(getString(R.string.CPU_THREAD_NUM_KEY)); + lpCPUPowerMode = (ListPreference) findPreference(getString(R.string.CPU_POWER_MODE_KEY)); + etModelDir = (EditTextPreference) findPreference(getString(R.string.MODEL_DIR_KEY)); + etModelDir.setTitle("Model dir (SDCard: " + Utils.getSDCardDirectory() + ")"); + etLabelPath = (EditTextPreference) findPreference(getString(R.string.LABEL_PATH_KEY)); + etLabelPath.setTitle("Label path (SDCard: " + Utils.getSDCardDirectory() + ")"); + etScoreThreshold = (EditTextPreference) findPreference(getString(R.string.SCORE_THRESHOLD_KEY)); + lpEnableLiteFp16 = (ListPreference) findPreference(getString(R.string.ENABLE_LITE_FP16_MODE_KEY)); + } + + @SuppressLint("ApplySharedPref") + private void reloadSettingsAndUpdateUI() { + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + + String selected_model_dir = sharedPreferences.getString(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY), + getString(R.string.OCR_MODEL_DIR_DEFAULT)); + int selected_model_idx = lpChoosePreInstalledModel.findIndexOfValue(selected_model_dir); + if (selected_model_idx >= 0 && selected_model_idx < preInstalledModelDirs.size() && selected_model_idx != selectedModelIdx) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(getString(R.string.MODEL_DIR_KEY), preInstalledModelDirs.get(selected_model_idx)); + editor.putString(getString(R.string.LABEL_PATH_KEY), preInstalledLabelPaths.get(selected_model_idx)); + editor.putString(getString(R.string.CPU_THREAD_NUM_KEY), preInstalledCPUThreadNums.get(selected_model_idx)); + editor.putString(getString(R.string.CPU_POWER_MODE_KEY), preInstalledCPUPowerModes.get(selected_model_idx)); + editor.putString(getString(R.string.SCORE_THRESHOLD_KEY), preInstalledScoreThresholds.get(selected_model_idx)); + editor.putString(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT), preInstalledEnableLiteFp16s.get(selected_model_idx)); + editor.commit(); + lpChoosePreInstalledModel.setSummary(selected_model_dir); + selectedModelIdx = selected_model_idx; + } + + String model_dir = sharedPreferences.getString(getString(R.string.MODEL_DIR_KEY), + getString(R.string.OCR_MODEL_DIR_DEFAULT)); + String label_path = sharedPreferences.getString(getString(R.string.LABEL_PATH_KEY), + getString(R.string.OCR_REC_LABEL_DEFAULT)); + String cpu_thread_num = sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY), + getString(R.string.CPU_THREAD_NUM_DEFAULT)); + String cpu_power_mode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY), + getString(R.string.CPU_POWER_MODE_DEFAULT)); + String score_threshold = sharedPreferences.getString(getString(R.string.SCORE_THRESHOLD_KEY), + getString(R.string.SCORE_THRESHOLD_DEFAULT)); + String enable_lite_fp16 = sharedPreferences.getString(getString(R.string.ENABLE_LITE_FP16_MODE_KEY), + getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + + etModelDir.setSummary(model_dir); + etLabelPath.setSummary(label_path); + lpCPUThreadNum.setValue(cpu_thread_num); + lpCPUThreadNum.setSummary(cpu_thread_num); + lpCPUPowerMode.setValue(cpu_power_mode); + lpCPUPowerMode.setSummary(cpu_power_mode); + etScoreThreshold.setSummary(score_threshold); + etScoreThreshold.setText(score_threshold); + lpEnableLiteFp16.setValue(enable_lite_fp16); + lpEnableLiteFp16.setSummary(enable_lite_fp16); + + } + + static boolean checkAndUpdateSettings(Context ctx) { + boolean settingsChanged = false; + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); + + String model_dir = sharedPreferences.getString(ctx.getString(R.string.MODEL_DIR_KEY), + ctx.getString(R.string.OCR_MODEL_DIR_DEFAULT)); + settingsChanged |= !modelDir.equalsIgnoreCase(model_dir); + modelDir = model_dir; + + String label_path = sharedPreferences.getString(ctx.getString(R.string.LABEL_PATH_KEY), + ctx.getString(R.string.OCR_REC_LABEL_DEFAULT)); + settingsChanged |= !labelPath.equalsIgnoreCase(label_path); + labelPath = label_path; + + String cpu_thread_num = sharedPreferences.getString(ctx.getString(R.string.CPU_THREAD_NUM_KEY), + ctx.getString(R.string.CPU_THREAD_NUM_DEFAULT)); + settingsChanged |= cpuThreadNum != Integer.parseInt(cpu_thread_num); + cpuThreadNum = Integer.parseInt(cpu_thread_num); + + String cpu_power_mode = sharedPreferences.getString(ctx.getString(R.string.CPU_POWER_MODE_KEY), + ctx.getString(R.string.CPU_POWER_MODE_DEFAULT)); + settingsChanged |= !cpuPowerMode.equalsIgnoreCase(cpu_power_mode); + cpuPowerMode = cpu_power_mode; + + String score_threshold = sharedPreferences.getString(ctx.getString(R.string.SCORE_THRESHOLD_KEY), + ctx.getString(R.string.SCORE_THRESHOLD_DEFAULT)); + settingsChanged |= scoreThreshold != Float.parseFloat(score_threshold); + scoreThreshold = Float.parseFloat(score_threshold); + + String enable_lite_fp16 = sharedPreferences.getString(ctx.getString(R.string.ENABLE_LITE_FP16_MODE_KEY), + ctx.getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + settingsChanged |= !enableLiteFp16.equalsIgnoreCase(enable_lite_fp16); + enableLiteFp16 = enable_lite_fp16; + + return settingsChanged; + } + + static void resetSettings() { + selectedModelIdx = -1; + modelDir = ""; + labelPath = ""; + cpuThreadNum = 2; + cpuPowerMode = ""; + scoreThreshold = 0.4f; + enableLiteFp16 = "true"; + } + + @Override + protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + reloadSettingsAndUpdateUI(); + } + + @Override + protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + reloadSettingsAndUpdateUI(); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/Utils.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/Utils.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/Utils.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/Utils.java diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/layout/ActionBarLayout.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/layout/ActionBarLayout.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/layout/ActionBarLayout.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/layout/ActionBarLayout.java diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/AppCompatPreferenceActivity.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/AppCompatPreferenceActivity.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/AppCompatPreferenceActivity.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/AppCompatPreferenceActivity.java diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java similarity index 99% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java index 14217181d3..e90874c627 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java @@ -12,6 +12,7 @@ import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLUtils; import android.opengl.Matrix; +import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; @@ -305,7 +306,6 @@ public void openCamera() { boolean rotate = degree == 90 || degree == 270; textureWidth = rotate ? previewSize.height : previewSize.width; textureHeight = rotate ? previewSize.width : previewSize.height; - // Destroy FBO and draw textures GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); GLES20.glDeleteFramebuffers(1, fbo, 0); diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/ResultListView.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/ResultListView.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/ResultListView.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/ResultListView.java diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/adapter/BaseResultAdapter.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/adapter/BaseResultAdapter.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/adapter/BaseResultAdapter.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/adapter/BaseResultAdapter.java diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/model/BaseResultModel.java b/examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/model/BaseResultModel.java similarity index 100% rename from java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/model/BaseResultModel.java rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/model/BaseResultModel.java diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/action_button_layer.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/action_button_layer.xml new file mode 100644 index 0000000000..a0d2e76bfa --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/action_button_layer.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/album_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/album_btn.xml new file mode 100644 index 0000000000..26d01c5841 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/album_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000000..1f6bb29060 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_start_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_start_btn.xml new file mode 100644 index 0000000000..6641344530 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_start_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_stop_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_stop_btn.xml new file mode 100644 index 0000000000..8869a1b2bf --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/realtime_stop_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/result_page_border_section_bk.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/result_page_border_section_bk.xml new file mode 100644 index 0000000000..bd068f169f --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/result_page_border_section_bk.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/round_corner_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/round_corner_btn.xml new file mode 100644 index 0000000000..c5dcc45d56 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/round_corner_btn.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_realtime.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_realtime.xml new file mode 100644 index 0000000000..b349d15a6a --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_realtime.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_result.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_result.xml new file mode 100644 index 0000000000..17cb68ed80 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_progress_result.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb.xml new file mode 100644 index 0000000000..96bd95e0a1 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb_shape.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb_shape.xml new file mode 100644 index 0000000000..26d033b6df --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/seekbar_thumb_shape.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/switch_side_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/switch_side_btn.xml new file mode 100644 index 0000000000..b9b2edfb6a --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/switch_side_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/take_picture_btn.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/take_picture_btn.xml new file mode 100644 index 0000000000..4966675c35 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-v24/take_picture_btn.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album.png new file mode 100644 index 0000000000..3a6fdedaee Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album_pressed.png new file mode 100644 index 0000000000..aa873424eb Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/album_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/back_btn.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/back_btn.png new file mode 100644 index 0000000000..ff121e85f5 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/back_btn.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/more_menu.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/more_menu.png new file mode 100644 index 0000000000..edf9f3ccce Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/more_menu.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start.png new file mode 100644 index 0000000000..94ab081724 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start_pressed.png new file mode 100644 index 0000000000..feef0fea62 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_start_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop.png new file mode 100644 index 0000000000..8c926367db Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop_pressed.png new file mode 100644 index 0000000000..309082788b Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/realtime_stop_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/scan_icon.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/scan_icon.png new file mode 100644 index 0000000000..7517d99d09 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/scan_icon.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_handle.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_handle.png new file mode 100644 index 0000000000..55f5f73991 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_handle.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_progress_dotted.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_progress_dotted.png new file mode 100644 index 0000000000..e6241d12e6 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_progress_dotted.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_thumb_invisible.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_thumb_invisible.png new file mode 100644 index 0000000000..acfe8d374a Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/seekbar_thumb_invisible.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side.png new file mode 100644 index 0000000000..3e6ae9a947 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side_pressed.png new file mode 100644 index 0000000000..25e1522768 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/switch_side_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture.png new file mode 100644 index 0000000000..d6ced986e8 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture_pressed.png new file mode 100644 index 0000000000..5f9c8ee3b5 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xhdpi/take_picture_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_default.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_default.png new file mode 100644 index 0000000000..b9e66c7f60 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_default.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_pressed.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_pressed.png new file mode 100644 index 0000000000..9544133bda Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable-xxhdpi-v4/btn_switch_pressed.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings.xml new file mode 100644 index 0000000000..917897b999 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_default.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_default.xml new file mode 100644 index 0000000000..e19589a97e --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_default.xml @@ -0,0 +1,13 @@ + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_pressed.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_pressed.xml new file mode 100644 index 0000000000..c4af2a042d --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_settings_pressed.xml @@ -0,0 +1,13 @@ + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter.xml new file mode 100644 index 0000000000..4f9826d3ae --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_default.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_default.xml new file mode 100644 index 0000000000..234ca014a7 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_default.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_pressed.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_pressed.xml new file mode 100644 index 0000000000..accc7acedb --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_shutter_pressed.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_switch.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_switch.xml new file mode 100644 index 0000000000..691e8c2e97 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/btn_switch.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/ic_launcher_background.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000..0d025f9bf6 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout-land/ocr_activity_main.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout-land/ocr_activity_main.xml new file mode 100644 index 0000000000..b30f35edf7 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout-land/ocr_activity_main.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_activity_main.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_activity_main.xml new file mode 100644 index 0000000000..b30f35edf7 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_activity_main.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_camera_page.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_camera_page.xml new file mode 100644 index 0000000000..6f31c2c7e4 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_camera_page.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_result_page.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_result_page.xml new file mode 100644 index 0000000000..958a859401 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_result_page.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/android/app/src/main/res/layout/ocr_result_page_item.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_result_page_item.xml similarity index 100% rename from java/android/app/src/main/res/layout/ocr_result_page_item.xml rename to examples/vision/ocr/PP-OCRv3/android/app/src/main/res/layout/ocr_result_page_item.xml diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..eca70cfe52 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000000..eca70cfe52 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..898f3ed59a Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..dffca3601e Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..64ba76f75e Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..dae5e08234 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..e5ed46597e Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..14ed0af350 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..b0907cac3b Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..d8ae031549 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..2c18de9e66 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..beed3cdd2c Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/arrays.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000000..c7cf123788 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/arrays.xml @@ -0,0 +1,39 @@ + + + + 1 threads + 2 threads + 4 threads + 8 threads + + + 1 + 2 + 4 + 8 + + + HIGH(only big cores) + LOW(only LITTLE cores) + FULL(all cores) + NO_BIND(depends on system) + RAND_HIGH + RAND_LOW + + + LITE_POWER_HIGH + LITE_POWER_LOW + LITE_POWER_FULL + LITE_POWER_NO_BIND + LITE_POWER_RAND_HIGH + LITE_POWER_RAND_LOW + + + true + false + + + true + false + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/colors.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000000..f8ec1f0c3b --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/colors.xml @@ -0,0 +1,22 @@ + + + #008577 + #00574B + #D81B60 + #FF000000 + #00000000 + #00000000 + #FFFFFFFF + + #000000 + #3B85F5 + #F5A623 + #FFFFFF + + #EEEEEE + + #3B85F5 + #333333 + #E5E5E5 + #3b85f5 + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/dimens.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000000..2df89499da --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/dimens.xml @@ -0,0 +1,17 @@ + + + 26dp + 36dp + 34dp + 60dp + 16dp + 67dp + 67dp + 56dp + 56dp + 46dp + 46dp + 32dp + 24dp + 16dp + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/strings.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..b5c396f5f7 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/strings.xml @@ -0,0 +1,51 @@ + + + EasyEdge + + EasyEdge + EasyEdge + EasyEdge + EasyEdge + EasyEdge + + CHOOSE_INSTALLED_MODEL_KEY + MODEL_DIR_KEY + LABEL_PATH_KEY + CPU_THREAD_NUM_KEY + CPU_POWER_MODE_KEY + SCORE_THRESHOLD_KEY + ENABLE_LITE_FP16_MODE_KEY + + 2 + LITE_POWER_HIGH + 0.4 + 0.1 + 0.25 + true + + + models/picodet_s_320_coco_lcnet + labels/coco_label_list.txt + + models + labels/ppocr_keys_v1.txt + + models/MobileNetV1_x0_25_infer + labels/imagenet1k_label_list.txt + + models/scrfd_500m_bnkps_shape320x320_pd + + models/human_pp_humansegv1_lite_192x192_inference_model + + 拍照识别 + 实时识别 + < + 模型名称 + 识别结果 + 序号 + 名称 + 置信度 + 阈值控制 + 重新识别 + 保存结果 + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/styles.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..67c1475944 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/styles.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/values.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/values.xml new file mode 100644 index 0000000000..156146d9ad --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/values/values.xml @@ -0,0 +1,17 @@ + + + 120dp + 46px + + 126px + 136px + + 46px + + 36px + + 15dp + + 15dp + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/xml/ocr_settings.xml b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/xml/ocr_settings.xml new file mode 100644 index 0000000000..692b74b4cd --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/app/src/main/res/xml/ocr_settings.xml @@ -0,0 +1,45 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/android/build.gradle b/examples/vision/ocr/PP-OCRv3/android/build.gradle new file mode 100644 index 0000000000..d8d678b3ff --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/build.gradle @@ -0,0 +1,37 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +//plugins { +// id 'com.android.application' version '7.2.2' apply false +// id 'com.android.library' version '7.2.2' apply false +//} +// +//task clean(type: Delete) { +// delete rootProject.buildDir +//} + +buildscript { + repositories { + google() + jcenter() + // mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:7.2.2' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + // mavenCentral() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/examples/vision/ocr/PP-OCRv3/android/gradle.properties b/examples/vision/ocr/PP-OCRv3/android/gradle.properties new file mode 100644 index 0000000000..ae995d47cc --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/gradle.properties @@ -0,0 +1,13 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx3096m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.jar b/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..e708b1c023 Binary files /dev/null and b/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.properties b/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..7855fafe49 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Oct 08 17:24:34 CST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/examples/vision/ocr/PP-OCRv3/android/gradlew b/examples/vision/ocr/PP-OCRv3/android/gradlew new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/vision/ocr/PP-OCRv3/android/gradlew.bat b/examples/vision/ocr/PP-OCRv3/android/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/vision/ocr/PP-OCRv3/android/local.properties b/examples/vision/ocr/PP-OCRv3/android/local.properties new file mode 100644 index 0000000000..aaa0de9aa3 --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Tue Nov 29 18:47:20 CST 2022 +sdk.dir=D\:\\androidsdk diff --git a/examples/vision/ocr/PP-OCRv3/android/settings.gradle b/examples/vision/ocr/PP-OCRv3/android/settings.gradle new file mode 100644 index 0000000000..e7b4def49c --- /dev/null +++ b/examples/vision/ocr/PP-OCRv3/android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/examples/vision/ocr/PP-OCRv3/cpp/README.md b/examples/vision/ocr/PP-OCRv3/cpp/README.md index 3692658090..bfbc0fc4a2 100644 --- a/examples/vision/ocr/PP-OCRv3/cpp/README.md +++ b/examples/vision/ocr/PP-OCRv3/cpp/README.md @@ -48,103 +48,9 @@ wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.6/ppocr/utils/ppocr_ - -## PPOCRv3 C++接口 - -### PPOCRv3类 - -``` -fastdeploy::pipeline::PPOCRv3(fastdeploy::vision::ocr::DBDetector* det_model, - fastdeploy::vision::ocr::Classifier* cls_model, - fastdeploy::vision::ocr::Recognizer* rec_model); -``` - -PPOCRv3 的初始化,由检测,分类和识别模型串联构成 - -**参数** - -> * **DBDetector**(model): OCR中的检测模型 -> * **Classifier**(model): OCR中的分类模型 -> * **Recognizer**(model): OCR中的识别模型 - -``` -fastdeploy::pipeline::PPOCRv3(fastdeploy::vision::ocr::DBDetector* det_model, - fastdeploy::vision::ocr::Recognizer* rec_model); -``` -PPOCRv3 的初始化,由检测,识别模型串联构成(无分类器) - -**参数** - -> * **DBDetector**(model): OCR中的检测模型 -> * **Recognizer**(model): OCR中的识别模型 - -#### Predict函数 - -> ``` -> bool Predict(cv::Mat* img, fastdeploy::vision::OCRResult* result); -> ``` -> -> 模型预测接口,输入一张图片,返回OCR预测结果 -> -> **参数** -> -> > * **img**: 输入图像,注意需为HWC,BGR格式 -> > * **result**: OCR预测结果,包括由检测模型输出的检测框位置,分类模型输出的方向分类,以及识别模型输出的识别结果, OCRResult说明参考[视觉模型预测结果](../../../../../docs/api/vision_results/) - - -## DBDetector C++接口 - -### DBDetector类 - -``` -fastdeploy::vision::ocr::DBDetector(const std::string& model_file, const std::string& params_file = "", - const RuntimeOption& custom_option = RuntimeOption(), - const ModelFormat& model_format = ModelFormat::PADDLE); -``` - -DBDetector模型加载和初始化,其中模型为paddle模型格式。 - -**参数** - -> * **model_file**(str): 模型文件路径 -> * **params_file**(str): 参数文件路径,当模型格式为ONNX时,此参数传入空字符串即可 -> * **runtime_option**(RuntimeOption): 后端推理配置,默认为None,即采用默认配置 -> * **model_format**(ModelFormat): 模型格式,默认为Paddle格式 - -### Classifier类与DBDetector类相同 - -### Recognizer类 -``` - Recognizer(const std::string& model_file, - const std::string& params_file = "", - const std::string& label_path = "", - const RuntimeOption& custom_option = RuntimeOption(), - const ModelFormat& model_format = ModelFormat::PADDLE); -``` -Recognizer类初始化时,需要在label_path参数中,输入识别模型所需的label文件,其他参数均与DBDetector类相同 - -**参数** -> * **label_path**(str): 识别模型的label文件路径 - - -### 类成员变量 -#### DBDetector预处理参数 -用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 - -> > * **max_side_len**(int): 检测算法前向时图片长边的最大尺寸,当长边超出这个值时会将长边resize到这个大小,短边等比例缩放,默认为960 -> > * **det_db_thresh**(double): DB模型输出预测图的二值化阈值,默认为0.3 -> > * **det_db_box_thresh**(double): DB模型输出框的阈值,低于此值的预测框会被丢弃,默认为0.6 -> > * **det_db_unclip_ratio**(double): DB模型输出框扩大的比例,默认为1.5 -> > * **det_db_score_mode**(string):DB后处理中计算文本框平均得分的方式,默认为slow,即求polygon区域的平均分数的方式 -> > * **use_dilation**(bool):是否对检测输出的feature map做膨胀处理,默认为Fasle - -#### Classifier预处理参数 -用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 - -> > * **cls_thresh**(double): 当分类模型输出的得分超过此阈值,输入的图片将被翻转,默认为0.9 - ## 其它文档 +- [C++ API查阅](https://baidu-paddle.github.io/fastdeploy-api/cpp/html/) - [PPOCR 系列模型介绍](../../) - [PPOCRv3 Python部署](../python) - [模型预测结果说明](../../../../../docs/cn/faq/how_to_change_backend.md) diff --git a/examples/vision/ocr/PP-OCRv3/python/README.md b/examples/vision/ocr/PP-OCRv3/python/README.md index a51abba98a..280ae7016c 100644 --- a/examples/vision/ocr/PP-OCRv3/python/README.md +++ b/examples/vision/ocr/PP-OCRv3/python/README.md @@ -38,89 +38,12 @@ python infer.py --det_model ch_PP-OCRv3_det_infer --cls_model ch_ppocr_mobile_v2 运行完成可视化结果如下图所示 -## PPOCRv3 Python接口 - -``` -fd.vision.ocr.PPOCRv3(det_model=det_model, cls_model=cls_model, rec_model=rec_model) -``` -PPOCRv3的初始化,输入的参数是检测模型,分类模型和识别模型,其中cls_model可选,如无需求,可设置为None - -**参数** - -> * **det_model**(model): OCR中的检测模型 -> * **cls_model**(model): OCR中的分类模型 -> * **rec_model**(model): OCR中的识别模型 - -### predict函数 - -> ``` -> result = ppocr_v3.predict(im) -> ``` -> -> 模型预测接口,输入是一张图片 -> -> **参数** -> -> > * **im**(np.ndarray): 输入数据,每张图片注意需为HWC,BGR格式 - -> **返回** -> -> > 返回`fastdeploy.vision.OCRResult`结构体,结构体说明参考文档[视觉模型预测结果](../../../../../docs/api/vision_results/) - - - -## DBDetector Python接口 - -### DBDetector类 - -``` -fastdeploy.vision.ocr.DBDetector(model_file, params_file, runtime_option=None, model_format=ModelFormat.PADDLE) -``` - -DBDetector模型加载和初始化,其中模型为paddle模型格式。 - -**参数** - -> * **model_file**(str): 模型文件路径 -> * **params_file**(str): 参数文件路径,当模型格式为ONNX时,此参数传入空字符串即可 -> * **runtime_option**(RuntimeOption): 后端推理配置,默认为None,即采用默认配置 -> * **model_format**(ModelFormat): 模型格式,默认为PADDLE格式 - -### Classifier类与DBDetector类相同 - -### Recognizer类 -``` -fastdeploy.vision.ocr.Recognizer(rec_model_file,rec_params_file,rec_label_file, - runtime_option=rec_runtime_option,model_format=ModelFormat.PADDLE) -``` -Recognizer类初始化时,需要在rec_label_file参数中,输入识别模型所需的label文件路径,其他参数均与DBDetector类相同 - -**参数** -> * **label_path**(str): 识别模型的label文件路径 - - - -### 类成员变量 - -#### DBDetector预处理参数 -用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 - -> > * **max_side_len**(int): 检测算法前向时图片长边的最大尺寸,当长边超出这个值时会将长边resize到这个大小,短边等比例缩放,默认为960 -> > * **det_db_thresh**(double): DB模型输出预测图的二值化阈值,默认为0.3 -> > * **det_db_box_thresh**(double): DB模型输出框的阈值,低于此值的预测框会被丢弃,默认为0.6 -> > * **det_db_unclip_ratio**(double): DB模型输出框扩大的比例,默认为1.5 -> > * **det_db_score_mode**(string):DB后处理中计算文本框平均得分的方式,默认为slow,即求polygon区域的平均分数的方式 -> > * **use_dilation**(bool):是否对检测输出的feature map做膨胀处理,默认为Fasle - -#### Classifier预处理参数 -用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 - -> > * **cls_thresh**(double): 当分类模型输出的得分超过此阈值,输入的图片将被翻转,默认为0.9 ## 其它文档 +- [Python API文档查阅](https://baidu-paddle.github.io/fastdeploy-api/python/html/) - [PPOCR 系列模型介绍](../../) - [PPOCRv3 C++部署](../cpp) - [模型预测结果说明](../../../../../docs/api/vision_results/) diff --git a/examples/vision/ocr/PP-OCRv3/serving/README.md b/examples/vision/ocr/PP-OCRv3/serving/README.md old mode 100644 new mode 100755 index ec53fb8d6a..31db5a72cc --- a/examples/vision/ocr/PP-OCRv3/serving/README.md +++ b/examples/vision/ocr/PP-OCRv3/serving/README.md @@ -1,5 +1,9 @@ # PP-OCR服务化部署示例 +在服务化部署前,需确认 + +- 1. 服务化镜像的软硬件环境要求和镜像拉取命令请参考[FastDeploy服务化部署](../../../../../serving/README_CN.md) + ## 介绍 本文介绍了使用FastDeploy搭建OCR文字识别服务的方法. @@ -43,14 +47,16 @@ tar xvf ch_PP-OCRv3_rec_infer.tar && mv ch_PP-OCRv3_rec_infer 1 mv 1/inference.pdiparams 1/model.pdiparams && mv 1/inference.pdmodel 1/model.pdmodel mv 1 models/rec_runtime/ && rm -rf ch_PP-OCRv3_rec_infer.tar +mkdir models/pp_ocr/1 && mkdir models/rec_pp/1 && mkdir models/cls_pp/1 + wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.6/ppocr/utils/ppocr_keys_v1.txt mv ppocr_keys_v1.txt models/rec_postprocess/1/ wget https://gitee.com/paddlepaddle/PaddleOCR/raw/release/2.6/doc/imgs/12.jpg - -docker pull paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 -docker run -dit --net=host --name fastdeploy --shm-size="1g" -v $PWD:/ocr_serving paddlepaddle/fastdeploy:0.6.0-gpu-cuda11.4-trt8.4-21.10 bash +# x.y.z为镜像版本号,需参照serving文档替换为数字 +docker pull paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 +docker run -dit --net=host --name fastdeploy --shm-size="1g" -v $PWD:/ocr_serving paddlepaddle/fastdeploy:x.y.z-gpu-cuda11.4-trt8.4-21.10 bash docker exec -it -u root fastdeploy bash ``` diff --git a/examples/vision/ocr/PP-OCRv3/serving/client.py b/examples/vision/ocr/PP-OCRv3/serving/client.py old mode 100644 new mode 100755 index b7b20644fa..1b150b7d09 --- a/examples/vision/ocr/PP-OCRv3/serving/client.py +++ b/examples/vision/ocr/PP-OCRv3/serving/client.py @@ -91,7 +91,7 @@ def _verify_triton_state(self, triton_client): if __name__ == "__main__": model_name = "pp_ocr" model_version = "1" - url = "localhost:9001" + url = "localhost:8001" runner = SyncGRPCTritonRunner(url, model_name, model_version) im = cv2.imread("12.jpg") im = np.array([im, ]) diff --git a/examples/vision/ocr/PP-OCRv3/serving/models/cls_runtime/config.pbtxt b/examples/vision/ocr/PP-OCRv3/serving/models/cls_runtime/config.pbtxt old mode 100644 new mode 100755 index aa66b1f9b2..eb7b255036 --- a/examples/vision/ocr/PP-OCRv3/serving/models/cls_runtime/config.pbtxt +++ b/examples/vision/ocr/PP-OCRv3/serving/models/cls_runtime/config.pbtxt @@ -35,3 +35,18 @@ instance_group [ gpus: [0] } ] + +optimization { + execution_accelerators { + # GPU推理配置, 配合KIND_GPU使用 + gpu_execution_accelerator : [ + { + name : "paddle" + # 设置推理并行计算线程数为4 + parameters { key: "cpu_threads" value: "4" } + # 开启mkldnn加速,设置为0关闭mkldnn + parameters { key: "use_mkldnn" value: "1" } + } + ] + } +} diff --git a/examples/vision/ocr/PP-OCRv3/serving/models/det_runtime/config.pbtxt b/examples/vision/ocr/PP-OCRv3/serving/models/det_runtime/config.pbtxt old mode 100644 new mode 100755 index c3ffe15c11..96d85e3e19 --- a/examples/vision/ocr/PP-OCRv3/serving/models/det_runtime/config.pbtxt +++ b/examples/vision/ocr/PP-OCRv3/serving/models/det_runtime/config.pbtxt @@ -35,3 +35,18 @@ instance_group [ gpus: [0] } ] + +optimization { + execution_accelerators { + # GPU推理配置, 配合KIND_GPU使用 + gpu_execution_accelerator : [ + { + name : "paddle" + # 设置推理并行计算线程数为4 + parameters { key: "cpu_threads" value: "4" } + # 开启mkldnn加速,设置为0关闭mkldnn + parameters { key: "use_mkldnn" value: "1" } + } + ] + } +} \ No newline at end of file diff --git a/examples/vision/ocr/PP-OCRv3/serving/models/rec_postprocess/1/model.py b/examples/vision/ocr/PP-OCRv3/serving/models/rec_postprocess/1/model.py old mode 100644 new mode 100755 index 049173382d..fe66e8c3f3 --- a/examples/vision/ocr/PP-OCRv3/serving/models/rec_postprocess/1/model.py +++ b/examples/vision/ocr/PP-OCRv3/serving/models/rec_postprocess/1/model.py @@ -47,8 +47,6 @@ def initialize(self, args): * model_version: Model version * model_name: Model name """ - sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach()) - print(sys.getdefaultencoding()) # You must parse model_config. JSON string is not parsed here self.model_config = json.loads(args['model_config']) print("model_config:", self.model_config) diff --git a/examples/vision/ocr/PP-OCRv3/serving/models/rec_runtime/config.pbtxt b/examples/vision/ocr/PP-OCRv3/serving/models/rec_runtime/config.pbtxt old mode 100644 new mode 100755 index d4b3b12126..037d7a9f28 --- a/examples/vision/ocr/PP-OCRv3/serving/models/rec_runtime/config.pbtxt +++ b/examples/vision/ocr/PP-OCRv3/serving/models/rec_runtime/config.pbtxt @@ -35,3 +35,18 @@ instance_group [ gpus: [0] } ] + +optimization { + execution_accelerators { + # GPU推理配置, 配合KIND_GPU使用 + gpu_execution_accelerator : [ + { + name : "paddle" + # 设置推理并行计算线程数为4 + parameters { key: "cpu_threads" value: "4" } + # 开启mkldnn加速,设置为0关闭mkldnn + parameters { key: "use_mkldnn" value: "1" } + } + ] + } +} \ No newline at end of file diff --git a/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java b/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java index 08ecda611e..88b3c3a5b4 100644 --- a/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java +++ b/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java @@ -287,6 +287,8 @@ protected void onResume() { // Open camera until the permissions have been granted if (!checkAllPermissions()) { svPreview.disableCamera(); + } else { + svPreview.enableCamera(); } svPreview.onResume(); } diff --git a/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java b/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java index 94a5fdbd0e..14217181d3 100644 --- a/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java +++ b/examples/vision/segmentation/paddleseg/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/ui/view/CameraSurfaceView.java @@ -278,6 +278,10 @@ public void disableCamera() { disableCamera = true; } + public void enableCamera() { + disableCamera = false; + } + public void switchCamera() { releaseCamera(); selectedCameraId = (selectedCameraId + 1) % numberOfCameras; diff --git a/examples/vision/segmentation/paddleseg/cpp/README.md b/examples/vision/segmentation/paddleseg/cpp/README.md index 926452ad02..e7b9dc5bf5 100644 --- a/examples/vision/segmentation/paddleseg/cpp/README.md +++ b/examples/vision/segmentation/paddleseg/cpp/README.md @@ -9,7 +9,7 @@ 【注意】如你部署的为**PP-Matting**、**PP-HumanMatting**以及**ModNet**请参考[Matting模型部署](../../../matting) -以Linux上推理为例,在本目录执行如下命令即可完成编译测试,支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) +以Linux上推理为例,在本目录执行如下命令即可完成编译测试,支持此模型需保证FastDeploy版本1.0.0以上(x.x.x>=1.0.0) ```bash mkdir build @@ -85,7 +85,7 @@ PaddleSegModel模型加载和初始化,其中model_file为导出的Paddle模 > > * **is_vertical_screen**(bool): PP-HumanSeg系列模型通过设置此参数为`true`表明输入图片是竖屏,即height大于width的图片 #### 后处理参数 -> > * **appy_softmax**(bool): 当模型导出时,并未指定`apply_softmax`参数,可通过此设置此参数为`true`,将预测的输出分割标签(label_map)对应的概率结果(score_map)做softmax归一化处理 +> > * **apply_softmax**(bool): 当模型导出时,并未指定`apply_softmax`参数,可通过此设置此参数为`true`,将预测的输出分割标签(label_map)对应的概率结果(score_map)做softmax归一化处理 - [模型介绍](../../) - [Python部署](../python) diff --git a/examples/vision/segmentation/paddleseg/cpp/infer.cc b/examples/vision/segmentation/paddleseg/cpp/infer.cc index d3c4627043..28bb560091 100644 --- a/examples/vision/segmentation/paddleseg/cpp/infer.cc +++ b/examples/vision/segmentation/paddleseg/cpp/infer.cc @@ -37,7 +37,7 @@ void CpuInfer(const std::string& model_dir, const std::string& image_file) { auto im = cv::imread(image_file); fastdeploy::vision::SegmentationResult res; - if (!model.Predict(&im, &res)) { + if (!model.Predict(im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } @@ -66,7 +66,7 @@ void GpuInfer(const std::string& model_dir, const std::string& image_file) { auto im = cv::imread(image_file); fastdeploy::vision::SegmentationResult res; - if (!model.Predict(&im, &res)) { + if (!model.Predict(im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } @@ -96,7 +96,7 @@ void TrtInfer(const std::string& model_dir, const std::string& image_file) { auto im = cv::imread(image_file); fastdeploy::vision::SegmentationResult res; - if (!model.Predict(&im, &res)) { + if (!model.Predict(im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } diff --git a/examples/vision/segmentation/paddleseg/quantize/README.md b/examples/vision/segmentation/paddleseg/quantize/README.md old mode 100644 new mode 100755 index 6199c653ac..83a76e3846 --- a/examples/vision/segmentation/paddleseg/quantize/README.md +++ b/examples/vision/segmentation/paddleseg/quantize/README.md @@ -4,14 +4,14 @@ FastDeploy已支持部署量化模型,并提供一键模型自动化压缩的工 ## FastDeploy一键模型自动化压缩工具 FastDeploy 提供了一键模型自动化压缩工具, 能够简单地通过输入一个配置文件, 对模型进行量化. -详细教程请见: [一键模型自动化压缩工具](../../../../../tools/auto_compression/) +详细教程请见: [一键模型自动化压缩工具](../../../../../tools/common_tools/auto_compression/) 注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的deploy.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可。 ## 下载量化完成的PaddleSeg模型 用户也可以直接下载下表中的量化模型进行部署.(点击模型名字即可下载) Benchmark表格说明: -- Rtuntime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. +- Runtime时延为模型在各种Runtime上的推理时延,包含CPU->GPU数据拷贝,GPU推理,GPU->CPU数据拷贝时间. 不包含模型各自的前后处理时间. - 端到端时延为模型在实际推理场景中的时延, 包含模型的前后处理. - 所测时延均为推理1000次后求得的平均值, 单位是毫秒. - INT8 + FP16 为在推理INT8量化模型的同时, 给Runtime 开启FP16推理选项 @@ -26,7 +26,7 @@ Benchmark表格说明: | [PP-LiteSeg-T(STDC1)-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/PP_LiteSeg_T_STDC1_cityscapes_without_argmax_infer_QAT_new.tar)) | Paddle Inference | CPU | 1138.04| 602.62 |None|None | 1.89 |77.37 | 71.62 |量化蒸馏训练 | #### 端到端 Benchmark -| 模型 |推理后端 |部署硬件 | FP32 Runtime时延 | INT8 Runtime时延 | INT8 + FP16 Runtime时延 | INT8+FP16+PM Runtime时延 | 最大加速比 | FP32 mIoU | INT8 mIoU | 量化方式 | +| 模型 |推理后端 |部署硬件 | FP32 End2End时延 | INT8 End2End时延 | INT8 + FP16 End2End时延 | INT8+FP16+PM End2End时延 | 最大加速比 | FP32 mIoU | INT8 mIoU | 量化方式 | | ------------------- | -----------------|-----------| -------- |-------- |-------- | --------- |-------- |----- |----- |----- | | [PP-LiteSeg-T(STDC1)-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/PP_LiteSeg_T_STDC1_cityscapes_without_argmax_infer_QAT_new.tar)) | Paddle Inference | CPU | 4726.65| 4134.91|None|None | 1.14 |77.37 | 71.62 |量化蒸馏训练 | diff --git a/examples/vision/segmentation/paddleseg/quantize/cpp/README.md b/examples/vision/segmentation/paddleseg/quantize/cpp/README.md old mode 100644 new mode 100755 index 0fbaac173d..bd17ec634e --- a/examples/vision/segmentation/paddleseg/quantize/cpp/README.md +++ b/examples/vision/segmentation/paddleseg/quantize/cpp/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的deploy.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的deploy.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的PP_LiteSeg_T_STDC1_cityscapes模型为例, 进行部署 在本目录执行如下命令即可完成编译,以及量化模型部署.支持此模型需保证FastDeploy版本0.7.0以上(x.x.x>=0.7.0) diff --git a/examples/vision/segmentation/paddleseg/quantize/cpp/infer.cc b/examples/vision/segmentation/paddleseg/quantize/cpp/infer.cc index 2611e2456a..158a302636 100644 --- a/examples/vision/segmentation/paddleseg/quantize/cpp/infer.cc +++ b/examples/vision/segmentation/paddleseg/quantize/cpp/infer.cc @@ -34,7 +34,7 @@ void InitAndInfer(const std::string& model_dir, const std::string& image_file, auto im_bak = im.clone(); fastdeploy::vision::SegmentationResult res; - if (!model.Predict(&im, &res)) { + if (!model.Predict(im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } diff --git a/examples/vision/segmentation/paddleseg/quantize/python/README.md b/examples/vision/segmentation/paddleseg/quantize/python/README.md old mode 100644 new mode 100755 index 2e06ae145c..b9cc1c6c4a --- a/examples/vision/segmentation/paddleseg/quantize/python/README.md +++ b/examples/vision/segmentation/paddleseg/quantize/python/README.md @@ -8,7 +8,7 @@ ### 量化模型准备 - 1. 用户可以直接使用由FastDeploy提供的量化模型进行部署. -- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的deploy.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 2. 用户可以使用FastDeploy提供的[一键模型自动化压缩工具](../../../../../../tools/common_tools/auto_compression/),自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的deploy.yaml文件, 自行量化的模型文件夹内不包含此yaml文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) ## 以量化后的PP_LiteSeg_T_STDC1_cityscapes模型为例, 进行部署 diff --git a/examples/vision/segmentation/paddleseg/rknpu2/cpp/infer.cc b/examples/vision/segmentation/paddleseg/rknpu2/cpp/infer.cc index 9004828b77..bfc108d058 100644 --- a/examples/vision/segmentation/paddleseg/rknpu2/cpp/infer.cc +++ b/examples/vision/segmentation/paddleseg/rknpu2/cpp/infer.cc @@ -74,12 +74,12 @@ void InferHumanPPHumansegv2Lite(const std::string& device) { auto im = cv::imread(image_file); if (device == "npu") { - model.DisableNormalizeAndPermute(); + model.GetPreprocessor().DisableNormalizeAndPermute(); } fastdeploy::vision::SegmentationResult res; clock_t start = clock(); - if (!model.Predict(&im, &res)) { + if (!model.Predict(im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } diff --git a/examples/vision/segmentation/paddleseg/rv1126/README.md b/examples/vision/segmentation/paddleseg/rv1126/README.md new file mode 100755 index 0000000000..ed5d150807 --- /dev/null +++ b/examples/vision/segmentation/paddleseg/rv1126/README.md @@ -0,0 +1,11 @@ +# PP-LiteSeg 量化模型在 RV1126 上的部署 +目前 FastDeploy 已经支持基于 PaddleLite 部署 PP-LiteSeg 量化模型到 RV1126 上。 + +模型的量化和量化模型的下载请参考:[模型量化](../quantize/README.md) + + +## 详细部署文档 + +在 RV1126 上只支持 C++ 的部署。 + +- [C++部署](cpp) diff --git a/examples/vision/segmentation/paddleseg/rv1126/cpp/CMakeLists.txt b/examples/vision/segmentation/paddleseg/rv1126/cpp/CMakeLists.txt new file mode 100755 index 0000000000..baaf8331f1 --- /dev/null +++ b/examples/vision/segmentation/paddleseg/rv1126/cpp/CMakeLists.txt @@ -0,0 +1,38 @@ +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10) + +# 指定下载解压后的fastdeploy库路径 +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +# 添加FastDeploy依赖头文件 +include_directories(${FASTDEPLOY_INCS}) +include_directories(${FastDeploy_INCLUDE_DIRS}) + +add_executable(infer_demo ${PROJECT_SOURCE_DIR}/infer.cc) +# 添加FastDeploy库依赖 +target_link_libraries(infer_demo ${FASTDEPLOY_LIBS}) + +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/build/install) + +install(TARGETS infer_demo DESTINATION ./) + +install(DIRECTORY models DESTINATION ./) +install(DIRECTORY images DESTINATION ./) +# install(DIRECTORY run_with_adb.sh DESTINATION ./) + +file(GLOB FASTDEPLOY_LIBS ${FASTDEPLOY_INSTALL_DIR}/lib/*) +install(PROGRAMS ${FASTDEPLOY_LIBS} DESTINATION lib) + +file(GLOB OPENCV_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/opencv/lib/lib*) +install(PROGRAMS ${OPENCV_LIBS} DESTINATION lib) + +file(GLOB PADDLELITE_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/lib*) +install(PROGRAMS ${PADDLELITE_LIBS} DESTINATION lib) + +file(GLOB TIMVX_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddlelite/lib/verisilicon_timvx/*) +install(PROGRAMS ${TIMVX_LIBS} DESTINATION lib) + +file(GLOB ADB_TOOLS run_with_adb.sh) +install(PROGRAMS ${ADB_TOOLS} DESTINATION ./) diff --git a/examples/vision/segmentation/paddleseg/rv1126/cpp/README.md b/examples/vision/segmentation/paddleseg/rv1126/cpp/README.md new file mode 100755 index 0000000000..6295fa728e --- /dev/null +++ b/examples/vision/segmentation/paddleseg/rv1126/cpp/README.md @@ -0,0 +1,54 @@ +# PP-LiteSeg 量化模型 C++ 部署示例 + +本目录下提供的 `infer.cc`,可以帮助用户快速完成 PP-LiteSeg 量化模型在 RV1126 上的部署推理加速。 + +## 部署准备 +### FastDeploy 交叉编译环境准备 +- 1. 软硬件环境满足要求,以及交叉编译环境的准备,请参考:[FastDeploy 交叉编译环境准备](../../../../../../docs/cn/build_and_install/rv1126.md#交叉编译环境搭建) + +### 模型准备 +- 1. 用户可以直接使用由 FastDeploy 提供的量化模型进行部署。 +- 2. 用户可以使用 FastDeploy 提供的一键模型自动化压缩工具,自行进行模型量化, 并使用产出的量化模型进行部署.(注意: 推理量化后的分类模型仍然需要FP32模型文件夹下的 deploy.yaml 文件, 自行量化的模型文件夹内不包含此 yaml 文件, 用户从FP32模型文件夹下复制此yaml文件到量化后的模型文件夹内即可.) +- 更多量化相关相关信息可查阅[模型量化](../../quantize/README.md) + +## 在 RV1126 上部署量化后的 PP-LiteSeg 分割模型 +请按照以下步骤完成在 RV1126 上部署 PP-LiteSeg 量化模型: +1. 交叉编译编译 FastDeploy 库,具体请参考:[交叉编译 FastDeploy](../../../../../../docs/cn/build_and_install/rv1126.md#基于-paddlelite-的-fastdeploy-交叉编译库编译) + +2. 将编译后的库拷贝到当前目录,可使用如下命令: +```bash +cp -r FastDeploy/build/fastdeploy-tmivx/ FastDeploy/examples/vision/segmentation/paddleseg/rv1126/cpp +``` + +3. 在当前路径下载部署所需的模型和示例图片: +```bash +mkdir models && mkdir images +wget https://bj.bcebos.com/fastdeploy/models/rk1/ppliteseg.tar.gz +tar -xvf ppliteseg.tar.gz +cp -r ppliteseg models +wget https://paddleseg.bj.bcebos.com/dygraph/demo/cityscapes_demo.png +cp -r cityscapes_demo.png images +``` + +4. 编译部署示例,可使入如下命令: +```bash +mkdir build && cd build +cmake -DCMAKE_TOOLCHAIN_FILE=${PWD}/../fastdeploy-tmivx/timvx.cmake -DFASTDEPLOY_INSTALL_DIR=${PWD}/../fastdeploy-tmivx .. +make -j8 +make install +# 成功编译之后,会生成 install 文件夹,里面有一个运行 demo 和部署所需的库 +``` + +5. 基于 adb 工具部署 PP-LiteSeg 分割模型到 Rockchip RV1126,可使用如下命令: +```bash +# 进入 install 目录 +cd FastDeploy/examples/vision/segmentation/paddleseg/rv1126/cpp/build/install/ +# 如下命令表示:bash run_with_adb.sh 需要运行的demo 模型路径 图片路径 设备的DEVICE_ID +bash run_with_adb.sh infer_demo ppliteseg cityscapes_demo.png $DEVICE_ID +``` + +部署成功后运行结果如下: + + + +需要特别注意的是,在 RV1126 上部署的模型需要是量化后的模型,模型的量化请参考:[模型量化](../../../../../../docs/cn/quantize.md) diff --git a/examples/vision/segmentation/paddleseg/rv1126/cpp/infer.cc b/examples/vision/segmentation/paddleseg/rv1126/cpp/infer.cc new file mode 100755 index 0000000000..8c9c7456ce --- /dev/null +++ b/examples/vision/segmentation/paddleseg/rv1126/cpp/infer.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2022 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. + +#include "fastdeploy/vision.h" +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void InitAndInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto config_file = model_dir + sep + "deploy.yaml"; + auto subgraph_file = model_dir + sep + "subgraph.txt"; + + fastdeploy::RuntimeOption option; + option.UseTimVX(); + option.SetLiteSubgraphPartitionPath(subgraph_file); + + auto model = fastdeploy::vision::segmentation::PaddleSegModel( + model_file, params_file, config_file,option); + + assert(model.Initialized()); + + auto im = cv::imread(image_file); + + fastdeploy::vision::SegmentationResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + + std::cout << res.Str() << std::endl; + + auto vis_im = fastdeploy::vision::VisSegmentation(im, res, 0.5); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + std::cout << "Usage: infer_demo path/to/quant_model " + "path/to/image " + "run_option, " + "e.g ./infer_demo ./ResNet50_vd_quant ./test.jpeg" + << std::endl; + return -1; + } + + std::string model_dir = argv[1]; + std::string test_image = argv[2]; + InitAndInfer(model_dir, test_image); + return 0; +} \ No newline at end of file diff --git a/examples/vision/segmentation/paddleseg/rv1126/cpp/run_with_adb.sh b/examples/vision/segmentation/paddleseg/rv1126/cpp/run_with_adb.sh new file mode 100755 index 0000000000..aacaed4c51 --- /dev/null +++ b/examples/vision/segmentation/paddleseg/rv1126/cpp/run_with_adb.sh @@ -0,0 +1,47 @@ +#!/bin/bash +HOST_SPACE=${PWD} +echo ${HOST_SPACE} +WORK_SPACE=/data/local/tmp/test + +# The first parameter represents the demo name +DEMO_NAME=image_classification_demo +if [ -n "$1" ]; then + DEMO_NAME=$1 +fi + +# The second parameter represents the model name +MODEL_NAME=mobilenet_v1_fp32_224 +if [ -n "$2" ]; then + MODEL_NAME=$2 +fi + +# The third parameter indicates the name of the image to be tested +IMAGE_NAME=0001.jpg +if [ -n "$3" ]; then + IMAGE_NAME=$3 +fi + +# The fourth parameter represents the ID of the device +ADB_DEVICE_NAME= +if [ -n "$4" ]; then + ADB_DEVICE_NAME="-s $4" +fi + +# Set the environment variables required during the running process +EXPORT_ENVIRONMENT_VARIABLES="export GLOG_v=5; export VIV_VX_ENABLE_GRAPH_TRANSFORM=-pcq:1; export VIV_VX_SET_PER_CHANNEL_ENTROPY=100; export TIMVX_BATCHNORM_FUSION_MAX_ALLOWED_QUANT_SCALE_DEVIATION=300000; export VSI_NN_LOG_LEVEL=5;" + +EXPORT_ENVIRONMENT_VARIABLES="${EXPORT_ENVIRONMENT_VARIABLES}export LD_LIBRARY_PATH=${WORK_SPACE}/lib:\$LD_LIBRARY_PATH;" + +# Please install adb, and DON'T run this in the docker. +set -e +adb $ADB_DEVICE_NAME shell "rm -rf $WORK_SPACE" +adb $ADB_DEVICE_NAME shell "mkdir -p $WORK_SPACE" + +# Upload the demo, librarys, model and test images to the device +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/lib $WORK_SPACE +adb $ADB_DEVICE_NAME push ${HOST_SPACE}/${DEMO_NAME} $WORK_SPACE +adb $ADB_DEVICE_NAME push models $WORK_SPACE +adb $ADB_DEVICE_NAME push images $WORK_SPACE + +# Execute the deployment demo +adb $ADB_DEVICE_NAME shell "cd $WORK_SPACE; ${EXPORT_ENVIRONMENT_VARIABLES} chmod +x ./${DEMO_NAME}; ./${DEMO_NAME} ./models/${MODEL_NAME} ./images/$IMAGE_NAME" diff --git a/fastdeploy/backends/lite/lite_backend.cc b/fastdeploy/backends/lite/lite_backend.cc index e3c87aabd1..04f1392568 100755 --- a/fastdeploy/backends/lite/lite_backend.cc +++ b/fastdeploy/backends/lite/lite_backend.cc @@ -72,7 +72,7 @@ void LiteBackend::BuildOption(const LiteBackendOption& option) { } } } - if(option_.enable_timvx){ + if(option_.enable_timvx) { config_.set_nnadapter_device_names({"verisilicon_timvx"}); valid_places.push_back( paddle::lite_api::Place{TARGET(kNNAdapter), PRECISION(kInt8)}); @@ -221,6 +221,14 @@ bool LiteBackend::Infer(std::vector& inputs, tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); + } else if (inputs[i].dtype == FDDataType::INT64) { +#ifdef __aarch64__ + tensor->CopyFromCpu( + reinterpret_cast(const_cast( + inputs[i].CpuData()))); +#else + FDASSERT(false, "FDDataType::INT64 is not support for Arm v7 now!"); +#endif } else { FDASSERT(false, "Unexpected data type of %d.", inputs[i].dtype); } diff --git a/fastdeploy/backends/openvino/ov_backend.cc b/fastdeploy/backends/openvino/ov_backend.cc old mode 100644 new mode 100755 index 9e8c2571ab..6858f85471 --- a/fastdeploy/backends/openvino/ov_backend.cc +++ b/fastdeploy/backends/openvino/ov_backend.cc @@ -176,7 +176,7 @@ bool OpenVINOBackend::InitFromPaddle(const std::string& model_file, } ov::AnyMap properties; - if (option_.cpu_thread_num > 0) { + if (option_.device == "CPU" && option_.cpu_thread_num > 0) { properties["INFERENCE_NUM_THREADS"] = option_.cpu_thread_num; } if (option_.device == "CPU") { @@ -306,7 +306,7 @@ bool OpenVINOBackend::InitFromOnnx(const std::string& model_file, } ov::AnyMap properties; - if (option_.cpu_thread_num > 0) { + if (option_.device == "CPU" && option_.cpu_thread_num > 0) { properties["INFERENCE_NUM_THREADS"] = option_.cpu_thread_num; } if (option_.device == "CPU") { diff --git a/fastdeploy/backends/ort/ops/adaptive_pool2d.cc b/fastdeploy/backends/ort/ops/adaptive_pool2d.cc index 7b4ec7ad48..045b42eb62 100755 --- a/fastdeploy/backends/ort/ops/adaptive_pool2d.cc +++ b/fastdeploy/backends/ort/ops/adaptive_pool2d.cc @@ -76,7 +76,7 @@ void AdaptivePool2dKernel::Compute(OrtKernelContext* context) { context, 0, output_size_.data(), output_size_.size()); float* output_data = ort_.GetTensorMutableData(output); - if(this->provider_ == "CUDAExecutionProvider"){ + if(!strcmp(this->provider_, "CUDAExecutionProvider")){ #ifdef WITH_GPU auto compute_stream = ort_.KernelContext_GetGPUComputeStream(context); CudaAdaptivePool(input_size, output_size_, output_data, input_data, compute_stream, pooling_type_); @@ -85,7 +85,7 @@ void AdaptivePool2dKernel::Compute(OrtKernelContext* context) { << "Will force to use CPU to run." << std::endl; CpuAdaptivePool(input_size, output_size_, input_data, output_data); #endif - }else{ + } else { CpuAdaptivePool(input_size, output_size_, input_data, output_data); } } diff --git a/fastdeploy/backends/paddle/paddle_backend.cc b/fastdeploy/backends/paddle/paddle_backend.cc index 866bf578e2..49abf02b11 100644 --- a/fastdeploy/backends/paddle/paddle_backend.cc +++ b/fastdeploy/backends/paddle/paddle_backend.cc @@ -22,24 +22,34 @@ void PaddleBackend::BuildOption(const PaddleBackendOption& option) { option_ = option; if (option.use_gpu) { config_.EnableUseGpu(option.gpu_mem_init_size, option.gpu_id); - if(option_.external_stream_) { + if (option_.external_stream_) { config_.SetExecStream(option_.external_stream_); } if (option.enable_trt) { #ifdef ENABLE_TRT_BACKEND + config_.Exp_DisableTensorRtOPs(option.trt_disabled_ops_); auto precision = paddle_infer::PrecisionType::kFloat32; if (option.trt_option.enable_fp16) { precision = paddle_infer::PrecisionType::kHalf; } bool use_static = false; if (option.trt_option.serialize_file != "") { - FDWARNING << "Detect that tensorrt cache file has been set to " << option.trt_option.serialize_file << ", but while enable paddle2trt, please notice that the cache file will save to the directory where paddle model saved." << std::endl; + FDWARNING + << "Detect that tensorrt cache file has been set to " + << option.trt_option.serialize_file + << ", but while enable paddle2trt, please notice that the cache " + "file will save to the directory where paddle model saved." + << std::endl; use_static = true; } - config_.EnableTensorRtEngine(option.trt_option.max_workspace_size, option.trt_option.max_batch_size, 3, precision, use_static); + config_.EnableTensorRtEngine(option.trt_option.max_workspace_size, + option.trt_option.max_batch_size, 3, + precision, use_static); SetTRTDynamicShapeToConfig(option); #else - FDWARNING << "The FastDeploy is not compiled with TensorRT backend, so will fallback to GPU with Paddle Inference Backend." << std::endl; + FDWARNING << "The FastDeploy is not compiled with TensorRT backend, so " + "will fallback to GPU with Paddle Inference Backend." + << std::endl; #endif } } else if (option.use_ipu) { @@ -98,39 +108,48 @@ bool PaddleBackend::InitFromPaddle(const std::string& model_file, if (!ReadBinaryFromFile(model_file, &contents)) { return false; } - auto reader = - paddle2onnx::PaddleReader(contents.c_str(), contents.size()); + auto reader = paddle2onnx::PaddleReader(contents.c_str(), contents.size()); // If it's a quantized model, and use cpu with mkldnn, automaticaly switch to int8 mode if (reader.is_quantize_model) { if (option.use_gpu) { - FDWARNING << "The loaded model is a quantized model, while inference on GPU, please use TensorRT backend to get better performance." << std::endl; + FDWARNING << "The loaded model is a quantized model, while inference on " + "GPU, please use TensorRT backend to get better performance." + << std::endl; if (option.enable_trt) { #ifdef ENABLE_TRT_BACKEND bool use_static = false; if (option.trt_option.serialize_file != "") { - FDWARNING << "Detect that tensorrt cache file has been set to " << option.trt_option.serialize_file << ", but while enable paddle2trt, please notice that the cache file will save to the directory where paddle model saved." << std::endl; + FDWARNING + << "Detect that tensorrt cache file has been set to " + << option.trt_option.serialize_file + << ", but while enable paddle2trt, please notice that the cache " + "file will save to the directory where paddle model saved." + << std::endl; use_static = true; } - config_.EnableTensorRtEngine(option.trt_option.max_workspace_size, option.trt_option.max_batch_size, 3, paddle_infer::PrecisionType::kInt8, use_static, false); + config_.EnableTensorRtEngine(option.trt_option.max_workspace_size, + option.trt_option.max_batch_size, 3, + paddle_infer::PrecisionType::kInt8, + use_static, false); SetTRTDynamicShapeToConfig(option); - #endif } } if (option.enable_mkldnn) { config_.EnableMkldnnInt8(); } else { - FDWARNING << "The loaded model is a quantized model, while inference on CPU, please enable MKLDNN to get better performance." << std::endl; + FDWARNING << "The loaded model is a quantized model, while inference on " + "CPU, please enable MKLDNN to get better performance." + << std::endl; } } inputs_desc_.resize(reader.num_inputs); for (int i = 0; i < reader.num_inputs; ++i) { std::string name(reader.inputs[i].name); - std::vector shape( - reader.inputs[i].shape, - reader.inputs[i].shape + reader.inputs[i].rank); + std::vector shape(reader.inputs[i].shape, + reader.inputs[i].shape + reader.inputs[i].rank); inputs_desc_[i].name = name; inputs_desc_[i].shape.assign(shape.begin(), shape.end()); inputs_desc_[i].dtype = ReaderDataTypeToFD(reader.inputs[i].dtype); @@ -138,7 +157,9 @@ bool PaddleBackend::InitFromPaddle(const std::string& model_file, outputs_desc_.resize(reader.num_outputs); for (int i = 0; i < reader.num_outputs; ++i) { std::string name(reader.outputs[i].name); - std::vector shape(reader.outputs[i].shape, reader.outputs[i].shape + reader.outputs[i].rank); + std::vector shape(reader.outputs[i].shape, + reader.outputs[i].shape + + reader.outputs[i].rank); outputs_desc_[i].name = name; outputs_desc_[i].shape.assign(shape.begin(), shape.end()); outputs_desc_[i].dtype = ReaderDataTypeToFD(reader.outputs[i].dtype); @@ -147,7 +168,8 @@ bool PaddleBackend::InitFromPaddle(const std::string& model_file, if (option.collect_shape) { // Set the shape info file. auto curr_model_dir = GetDirFromPath(model_file); - std::string shape_range_info = PathJoin(curr_model_dir, "shape_range_info.pbtxt"); + std::string shape_range_info = + PathJoin(curr_model_dir, "shape_range_info.pbtxt"); if (!CheckFileExists(shape_range_info)) { FDINFO << "Start generating shape range info file." << std::endl; paddle_infer::Config analysis_config; @@ -164,7 +186,8 @@ bool PaddleBackend::InitFromPaddle(const std::string& model_file, CollectShapeRun(predictor_tmp.get(), opt_shape); FDINFO << "Finish generating shape range info file." << std::endl; } - FDINFO << "Start loading shape range info file "<< shape_range_info << " to set TensorRT dynamic shape." << std::endl; + FDINFO << "Start loading shape range info file " << shape_range_info + << " to set TensorRT dynamic shape." << std::endl; config_.EnableTunedTensorRtDynamicShape(shape_range_info, false); } #endif @@ -194,8 +217,7 @@ std::vector PaddleBackend::GetOutputInfos() { } bool PaddleBackend::Infer(std::vector& inputs, - std::vector* outputs, - bool copy_to_fd) { + std::vector* outputs, bool copy_to_fd) { if (inputs.size() != inputs_desc_.size()) { FDERROR << "[PaddleBackend] Size of inputs(" << inputs.size() << ") should keep same with the inputs of this model(" @@ -211,13 +233,13 @@ bool PaddleBackend::Infer(std::vector& inputs, predictor_->Run(); // output share backend memory only support CPU or GPU - if(option_.use_ipu) { + if (option_.use_ipu) { copy_to_fd = true; } outputs->resize(outputs_desc_.size()); for (size_t i = 0; i < outputs_desc_.size(); ++i) { auto handle = predictor_->GetOutputHandle(outputs_desc_[i].name); - if(copy_to_fd) { + if (copy_to_fd) { (*outputs)[i].is_pinned_memory = option_.enable_pinned_memory; } PaddleTensorToFDTensor(handle, &((*outputs)[i]), copy_to_fd); @@ -225,47 +247,47 @@ bool PaddleBackend::Infer(std::vector& inputs, return true; } -std::unique_ptr PaddleBackend::Clone(void *stream, int device_id) { - std::unique_ptr new_backend = utils::make_unique(); +std::unique_ptr PaddleBackend::Clone(void* stream, int device_id) { + std::unique_ptr new_backend = + utils::make_unique(); auto casted_backend = dynamic_cast(new_backend.get()); - if(device_id > 0 && option_.use_gpu == true && device_id != option_.gpu_id) { + if (device_id > 0 && option_.use_gpu == true && device_id != option_.gpu_id) { auto clone_option = option_; clone_option.gpu_id = device_id; clone_option.external_stream_ = stream; casted_backend->InitFromPaddle(clone_option.model_file, - clone_option.params_file, - clone_option); - FDWARNING << "The target device id:" - << device_id - << " is different from current device id:" - << option_.gpu_id - << ", cannot share memory with current engine." - << std::endl; + clone_option.params_file, clone_option); + FDWARNING << "The target device id:" << device_id + << " is different from current device id:" << option_.gpu_id + << ", cannot share memory with current engine." << std::endl; return new_backend; } casted_backend->inputs_desc_.assign(inputs_desc_.begin(), inputs_desc_.end()); - casted_backend->outputs_desc_.assign(outputs_desc_.begin(), outputs_desc_.end()); + casted_backend->outputs_desc_.assign(outputs_desc_.begin(), + outputs_desc_.end()); casted_backend->predictor_ = std::move(predictor_->Clone(stream)); return new_backend; } #ifdef ENABLE_TRT_BACKEND -void PaddleBackend::SetTRTDynamicShapeToConfig(const PaddleBackendOption& option) { - std::map> max_shape; - std::map> min_shape; - std::map> opt_shape; - GetDynamicShapeFromOption(option, &max_shape, &min_shape, &opt_shape); +void PaddleBackend::SetTRTDynamicShapeToConfig( + const PaddleBackendOption& option) { + std::map> max_shape; + std::map> min_shape; + std::map> opt_shape; + GetDynamicShapeFromOption(option, &max_shape, &min_shape, &opt_shape); + if (min_shape.size() > 0) { FDINFO << "Start setting trt dynamic shape." << std::endl; - if (min_shape.size() > 0) { - config_.SetTRTDynamicShapeInfo(min_shape, max_shape, opt_shape); - } + config_.SetTRTDynamicShapeInfo(min_shape, max_shape, opt_shape); FDINFO << "Finish setting trt dynamic shape." << std::endl; + } } -void PaddleBackend::GetDynamicShapeFromOption(const PaddleBackendOption& option, - std::map>* max_shape, - std::map>* min_shape, - std::map>* opt_shape) const { +void PaddleBackend::GetDynamicShapeFromOption( + const PaddleBackendOption& option, + std::map>* max_shape, + std::map>* min_shape, + std::map>* opt_shape) const { auto print_shape = [](const std::vector& shape) -> std::string { std::ostringstream oss; oss << "["; @@ -281,24 +303,35 @@ void PaddleBackend::GetDynamicShapeFromOption(const PaddleBackendOption& option, for (const auto& item : option.trt_option.min_shape) { auto max_iter = option.trt_option.max_shape.find(item.first); auto opt_iter = option.trt_option.opt_shape.find(item.first); - FDASSERT(max_iter != option.trt_option.max_shape.end(), "Cannot find %s in TrtBackendOption::min_shape.", item.first.c_str()); - FDASSERT(opt_iter != option.trt_option.opt_shape.end(), "Cannot find %s in TrtBackendOption::opt_shape.", item.first.c_str()); - (*max_shape)[item.first].assign(max_iter->second.begin(), max_iter->second.end()); - (*opt_shape)[item.first].assign(opt_iter->second.begin(), opt_iter->second.end()); + FDASSERT(max_iter != option.trt_option.max_shape.end(), + "Cannot find %s in TrtBackendOption::min_shape.", + item.first.c_str()); + FDASSERT(opt_iter != option.trt_option.opt_shape.end(), + "Cannot find %s in TrtBackendOption::opt_shape.", + item.first.c_str()); + (*max_shape)[item.first].assign(max_iter->second.begin(), + max_iter->second.end()); + (*opt_shape)[item.first].assign(opt_iter->second.begin(), + opt_iter->second.end()); (*min_shape)[item.first].assign(item.second.begin(), item.second.end()); - FDINFO << item.first << ": the max shape = " << print_shape(max_iter->second) + FDINFO << item.first + << ": the max shape = " << print_shape(max_iter->second) << ", the min shape = " << print_shape(item.second) - << ", the opt shape = " << print_shape(opt_iter->second) << std::endl; + << ", the opt shape = " << print_shape(opt_iter->second) + << std::endl; } } -void PaddleBackend::CollectShapeRun(paddle_infer::Predictor* predictor, +void PaddleBackend::CollectShapeRun( + paddle_infer::Predictor* predictor, const std::map>& shape) const { auto input_names = predictor->GetInputNames(); auto input_type = predictor->GetInputTypes(); - for(auto name : input_names) { - FDASSERT(shape.find(name) != shape.end() && input_type.find(name) != input_type.end(), - "Paddle Input name [%s] is not one of the trt dynamic shape.", name.c_str()); + for (auto name : input_names) { + FDASSERT(shape.find(name) != shape.end() && + input_type.find(name) != input_type.end(), + "Paddle Input name [%s] is not one of the trt dynamic shape.", + name.c_str()); auto tensor = predictor->GetInputHandle(name); auto shape_value = shape.at(name); int shape_num = std::accumulate(shape_value.begin(), shape_value.end(), 1, @@ -306,30 +339,30 @@ void PaddleBackend::CollectShapeRun(paddle_infer::Predictor* predictor, tensor->Reshape(shape_value); auto dtype = input_type[name]; switch (dtype) { - case paddle_infer::DataType::FLOAT32: { - std::vector input_data(shape_num, 1.0); - tensor->CopyFromCpu(input_data.data()); - break; - } - case paddle_infer::DataType::INT32: { - std::vector input_data(shape_num, 1); - tensor->CopyFromCpu(input_data.data()); - break; - } - case paddle_infer::DataType::INT64: { - std::vector input_data(shape_num, 1); - tensor->CopyFromCpu(input_data.data()); - break; - } - default: { - FDASSERT(false, "Input data Paddle backend only supports FP32/INT32/INT64 currently."); - break; - } + case paddle_infer::DataType::FLOAT32: { + std::vector input_data(shape_num, 1.0); + tensor->CopyFromCpu(input_data.data()); + break; + } + case paddle_infer::DataType::INT32: { + std::vector input_data(shape_num, 1); + tensor->CopyFromCpu(input_data.data()); + break; + } + case paddle_infer::DataType::INT64: { + std::vector input_data(shape_num, 1); + tensor->CopyFromCpu(input_data.data()); + break; + } + default: { + FDASSERT(false, "Input data Paddle backend only supports " + "FP32/INT32/INT64 currently."); + break; + } } } predictor->Run(); } #endif - } // namespace fastdeploy diff --git a/fastdeploy/backends/paddle/paddle_backend.h b/fastdeploy/backends/paddle/paddle_backend.h old mode 100755 new mode 100644 index ba083ae431..2df0c67399 --- a/fastdeploy/backends/paddle/paddle_backend.h +++ b/fastdeploy/backends/paddle/paddle_backend.h @@ -23,8 +23,8 @@ #ifdef ENABLE_PADDLE_FRONTEND #include "paddle2onnx/converter.h" #endif -#include "paddle_inference_api.h" // NOLINT #include "fastdeploy/utils/unique_ptr.h" +#include "paddle_inference_api.h" // NOLINT #ifdef ENABLE_TRT_BACKEND #include "fastdeploy/backends/tensorrt/trt_backend.h" @@ -60,6 +60,7 @@ struct PaddleBackendOption { #ifdef ENABLE_TRT_BACKEND TrtBackendOption trt_option; bool collect_shape = false; + std::vector trt_disabled_ops_{}; #endif #ifdef WITH_IPU @@ -91,8 +92,7 @@ void ShareTensorFromFDTensor(paddle_infer::Tensor* tensor, FDTensor& fd_tensor); // if copy_to_fd is true, copy memory data to FDTensor /// else share memory to FDTensor void PaddleTensorToFDTensor(std::unique_ptr& tensor, - FDTensor* fd_tensor, - bool copy_to_fd); + FDTensor* fd_tensor, bool copy_to_fd); // Convert data type from paddle inference to fastdeploy FDDataType PaddleDataTypeToFD(const paddle_infer::DataType& dtype); @@ -106,20 +106,18 @@ class PaddleBackend : public BaseBackend { virtual ~PaddleBackend() = default; void BuildOption(const PaddleBackendOption& option); - bool InitFromPaddle( - const std::string& model_file, const std::string& params_file, - const PaddleBackendOption& option = PaddleBackendOption()); + bool + InitFromPaddle(const std::string& model_file, const std::string& params_file, + const PaddleBackendOption& option = PaddleBackendOption()); - bool Infer(std::vector& inputs, - std::vector* outputs, + bool Infer(std::vector& inputs, std::vector* outputs, bool copy_to_fd = true) override; - int NumInputs() const override { return inputs_desc_.size(); } int NumOutputs() const override { return outputs_desc_.size(); } - std::unique_ptr Clone(void *stream = nullptr, + std::unique_ptr Clone(void* stream = nullptr, int device_id = -1) override; TensorInfo GetInputInfo(int index) override; @@ -129,9 +127,11 @@ class PaddleBackend : public BaseBackend { private: #ifdef ENABLE_TRT_BACKEND - void CollectShapeRun(paddle_infer::Predictor* predictor, - const std::map>& shape) const; - void GetDynamicShapeFromOption(const PaddleBackendOption& option, + void + CollectShapeRun(paddle_infer::Predictor* predictor, + const std::map>& shape) const; + void GetDynamicShapeFromOption( + const PaddleBackendOption& option, std::map>* max_shape, std::map>* min_shape, std::map>* opt_shape) const; diff --git a/fastdeploy/core/fd_tensor.cc b/fastdeploy/core/fd_tensor.cc index 896f2ff3be..e84535ac90 100644 --- a/fastdeploy/core/fd_tensor.cc +++ b/fastdeploy/core/fd_tensor.cc @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. #include "fastdeploy/core/fd_tensor.h" -#include "fastdeploy/core/fd_scalar.h" #include "fastdeploy/core/float16.h" #include "fastdeploy/utils/utils.h" @@ -81,8 +80,7 @@ const void* FDTensor::CpuData() const { void FDTensor::SetExternalData(const std::vector& new_shape, const FDDataType& data_type, void* data_buffer, - const Device& new_device, - int new_device_id) { + const Device& new_device, int new_device_id) { dtype = data_type; shape.assign(new_shape.begin(), new_shape.end()); external_data_ptr = data_buffer; diff --git a/fastdeploy/core/fd_tensor.h b/fastdeploy/core/fd_tensor.h index ef9ff3796d..3c79b0c88c 100644 --- a/fastdeploy/core/fd_tensor.h +++ b/fastdeploy/core/fd_tensor.h @@ -19,12 +19,11 @@ #include #include "fastdeploy/core/allocate.h" +#include "fastdeploy/core/fd_scalar.h" #include "fastdeploy/core/fd_type.h" namespace fastdeploy { -struct Scalar; - struct FASTDEPLOY_DECL FDTensor { // std::vector data; void* buffer_ = nullptr; diff --git a/fastdeploy/function/clip.cc b/fastdeploy/function/clip.cc index bede9e56aa..c4b2fa9e0d 100644 --- a/fastdeploy/function/clip.cc +++ b/fastdeploy/function/clip.cc @@ -39,14 +39,15 @@ void ClipKernel(const FDTensor& x, double min, double max, FDTensor* out) { "max should be greater than or equal to min. But received min = %f, " "max = %f", static_cast(min_), static_cast(max_)); - - out->Allocate(x.Shape(), x.Dtype()); + FDTensor tmp; + tmp.Allocate(x.Shape(), x.Dtype()); const T* x_data = reinterpret_cast(x.Data()); int64_t numel = x.Numel(); - T* out_data = reinterpret_cast(out->Data()); + T* out_data = reinterpret_cast(tmp.Data()); std::transform(x_data, x_data + numel, out_data, ClipFunctor(min_, max_)); + *out = std::move(tmp); } void Clip(const FDTensor& x, double min, double max, FDTensor* out) { diff --git a/fastdeploy/function/concat.cc b/fastdeploy/function/concat.cc index 295c3c25a4..4f07743942 100644 --- a/fastdeploy/function/concat.cc +++ b/fastdeploy/function/concat.cc @@ -88,11 +88,13 @@ template void ConcatKernel(const std::vector& input, FDTensor* output, int axis) { auto output_shape = ComputeAndCheckConcatOutputShape(input, axis); - output->Resize(output_shape, TypeToDataType::dtype, output->name, - input[0].device); + FDTensor output_tmp; + output_tmp.Resize(output_shape, TypeToDataType::dtype, output->name, + input[0].device); ConcatFunctor functor; - functor(input, axis, output); + functor(input, axis, &output_tmp); + *output = std::move(output_tmp); } void Concat(const std::vector& x, FDTensor* out, int axis) { diff --git a/fastdeploy/function/elementwise.cc b/fastdeploy/function/elementwise.cc index 120fe1678c..5d94764de9 100644 --- a/fastdeploy/function/elementwise.cc +++ b/fastdeploy/function/elementwise.cc @@ -86,4 +86,25 @@ FDTensor operator/(const FDTensor& x, const FDTensor& y) { return out; } +#define INSTANTIATE_OPERATOR(operation_type) \ + template FDTensor operator operation_type(const FDTensor& x, bool y); \ + template FDTensor operator operation_type(const FDTensor& x, uint8_t y); \ + template FDTensor operator operation_type(const FDTensor& x, int16_t y); \ + template FDTensor operator operation_type(const FDTensor& x, int y); \ + template FDTensor operator operation_type(const FDTensor& x, int64_t y); \ + template FDTensor operator operation_type(const FDTensor& x, float y); \ + template FDTensor operator operation_type(const FDTensor& x, double y); \ + template FDTensor operator operation_type(bool x, const FDTensor& y); \ + template FDTensor operator operation_type(uint8_t x, const FDTensor& y); \ + template FDTensor operator operation_type(int16_t x, const FDTensor& y); \ + template FDTensor operator operation_type(int x, const FDTensor& y); \ + template FDTensor operator operation_type(int64_t x, const FDTensor& y); \ + template FDTensor operator operation_type(float x, const FDTensor& y); \ + template FDTensor operator operation_type(double x, const FDTensor& y) + +INSTANTIATE_OPERATOR(+); +INSTANTIATE_OPERATOR(-); +INSTANTIATE_OPERATOR(*); +INSTANTIATE_OPERATOR(/); + } // namespace fastdeploy diff --git a/fastdeploy/function/elementwise.h b/fastdeploy/function/elementwise.h index fd0a9c44b0..53d34da6e5 100644 --- a/fastdeploy/function/elementwise.h +++ b/fastdeploy/function/elementwise.h @@ -14,9 +14,11 @@ #pragma once +#include "fastdeploy/core/fd_scalar.h" #include "fastdeploy/core/fd_tensor.h" namespace fastdeploy { + namespace function { /** Excute the add operation for input FDTensors. *out = x + y. @@ -62,10 +64,42 @@ FASTDEPLOY_DECL void Maximum(const FDTensor& x, const FDTensor& y, FASTDEPLOY_DECL FDTensor operator+(const FDTensor& x, const FDTensor& y); +template FDTensor operator+(const FDTensor& x, T y) { + return x + FDTensor(Scalar(y)); +} + +template FDTensor operator+(T x, const FDTensor& y) { + return FDTensor(Scalar(x)) + y; +} + FASTDEPLOY_DECL FDTensor operator-(const FDTensor& x, const FDTensor& y); +template FDTensor operator-(const FDTensor& x, T y) { + return x - FDTensor(Scalar(y)); +} + +template FDTensor operator-(T x, const FDTensor& y) { + return FDTensor(Scalar(x)) - y; +} + FASTDEPLOY_DECL FDTensor operator*(const FDTensor& x, const FDTensor& y); +template FDTensor operator*(const FDTensor& x, T y) { + return x * FDTensor(Scalar(y)); +} + +template FDTensor operator*(T x, const FDTensor& y) { + return FDTensor(Scalar(x)) * y; +} + FASTDEPLOY_DECL FDTensor operator/(const FDTensor& x, const FDTensor& y); +template FDTensor operator/(const FDTensor& x, T y) { + return x / FDTensor(Scalar(y)); +} + +template FDTensor operator/(T x, const FDTensor& y) { + return FDTensor(Scalar(x)) / y; +} + } // namespace fastdeploy diff --git a/fastdeploy/function/elementwise_base.h b/fastdeploy/function/elementwise_base.h index e2fab684e5..7ce1a694d2 100644 --- a/fastdeploy/function/elementwise_base.h +++ b/fastdeploy/function/elementwise_base.h @@ -213,10 +213,12 @@ void CommonElementwiseBroadcastForward(const FDTensor& x, const FDTensor& y, GetBroadcastDimsArrays(x_dims, y_dims, x_dims_array.data(), y_dims_array.data(), out_dims_array.data(), max_dim, axis); - z->Allocate(out_dims_array, TypeToDataType::dtype); + FDTensor tmp; + tmp.Allocate(out_dims_array, TypeToDataType::dtype); CommonForwardBroadcastCPU( - x, y, z, x_dims_array.data(), y_dims_array.data(), out_dims_array.data(), - max_dim, func, is_xsize_larger); + x, y, &tmp, x_dims_array.data(), y_dims_array.data(), + out_dims_array.data(), max_dim, func, is_xsize_larger); + *z = std::move(tmp); } template diff --git a/fastdeploy/function/functions.h b/fastdeploy/function/functions.h index d2ffe6a0c1..a43407839f 100644 --- a/fastdeploy/function/functions.h +++ b/fastdeploy/function/functions.h @@ -21,6 +21,7 @@ #include "fastdeploy/function/elementwise.h" #include "fastdeploy/function/full.h" #include "fastdeploy/function/gather_scatter_along_axis.h" +#include "fastdeploy/function/gaussian_random.h" #include "fastdeploy/function/isfinite.h" #include "fastdeploy/function/linspace.h" #include "fastdeploy/function/math.h" diff --git a/fastdeploy/function/gaussian_random.cc b/fastdeploy/function/gaussian_random.cc new file mode 100644 index 0000000000..18657c4f2a --- /dev/null +++ b/fastdeploy/function/gaussian_random.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2022 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. + +#include "fastdeploy/function/gaussian_random.h" +#include +#include +#include + +namespace fastdeploy { +namespace function { + +template +void GaussianRandomKernel(const std::vector& shape, float mean, + float std, int seed, FDTensor* out) { + std::normal_distribution dist(mean, std); + + out->Allocate(shape, TypeToDataType::dtype); + int64_t size = out->Numel(); + T* data = reinterpret_cast(out->Data()); + std::mt19937_64 engine; + engine.seed(seed); + for (int64_t i = 0; i < size; ++i) { + data[i] = dist(engine); + } +} + +void GaussianRandom(const std::vector& shape, FDTensor* out, + FDDataType dtype, float mean, float std, int seed) { + FD_VISIT_FLOAT_TYPES(dtype, "GaussianRandomKernel", [&]() { + GaussianRandomKernel(shape, mean, std, seed, out); + }); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/function/gaussian_random.h b/fastdeploy/function/gaussian_random.h new file mode 100644 index 0000000000..85a4ff8a63 --- /dev/null +++ b/fastdeploy/function/gaussian_random.h @@ -0,0 +1,36 @@ +// Copyright (c) 2022 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. + +#pragma once + +#include "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { +namespace function { + +/** Output is obtained by gathering entries of axis of x indexed by index and + * concatenate them together. + @param shape The output tensor shape. + @param out the output tensor. + @param mean mean value of gaussian random + @param std standard value of gaussian random + @param seed The seed of random generator. + @param dtype The data type of the output Tensor. +*/ +void GaussianRandom(const std::vector& shape, FDTensor* out, + FDDataType dtype = FDDataType::FP32, float mean = 0.0f, + float std = 1.0f, int seed = 0); + +} // namespace function +} // namespace fastdeploy diff --git a/fastdeploy/function/slice.cc b/fastdeploy/function/slice.cc index f374034f29..dab0ea0232 100644 --- a/fastdeploy/function/slice.cc +++ b/fastdeploy/function/slice.cc @@ -163,5 +163,20 @@ void Slice(const FDTensor& x, const std::vector& axes, })); } +void Slice(const FDTensor& x, const std::vector& axes, + const std::vector& index, FDTensor* out) { + std::vector ends = index; + for (int i = 0; i < ends.size(); ++i) { + ends[i] += 1; + } + Slice(x, axes, index, ends, out); + for (int i = 0; i < axes.size(); ++i) { + if (out->Shape().size() <= 1) { + break; + } + out->Squeeze(axes[i]); + } +} + } // namespace function } // namespace fastdeploy diff --git a/fastdeploy/function/slice.h b/fastdeploy/function/slice.h index d676a232e3..e35ee57627 100644 --- a/fastdeploy/function/slice.h +++ b/fastdeploy/function/slice.h @@ -37,5 +37,8 @@ FASTDEPLOY_DECL void Slice(const FDTensor& x, const std::vector& axes, const std::vector& starts, const std::vector& ends, FDTensor* out); +FASTDEPLOY_DECL void Slice(const FDTensor& x, const std::vector& axes, + const std::vector& index, FDTensor* out); + } // namespace function } // namespace fastdeploy diff --git a/fastdeploy/function/sort.cc b/fastdeploy/function/sort.cc index 23f66b8086..5b81a631cb 100644 --- a/fastdeploy/function/sort.cc +++ b/fastdeploy/function/sort.cc @@ -73,8 +73,9 @@ void SortKernel(const FDTensor& x, FDTensor* out, FDTensor* indices, axis = (axis < 0) ? (rank + axis) : axis; // Do full sort if (axis == -1 || axis + 1 == rank) { - const int64_t input_width = input_shape[rank - 1]; - const int64_t input_height = x.Numel() / input_width; + int64_t numel = x.Numel(); + int64_t input_width = input_shape[axis]; + int64_t input_height = numel / input_width; FD_VISIT_INT_TYPES(indices_type, "FullSort", ([&] { FullSort(input_height, input_width, rank, &x, out, indices, descending); @@ -93,8 +94,9 @@ void SortKernel(const FDTensor& x, FDTensor* out, FDTensor* indices, FDTensor trans_inp; Transpose(x, &trans_inp, trans); - const int64_t input_width = input_shape[axis]; - const int64_t input_height = x.Numel() / input_width; + int64_t numel = x.Numel(); + int64_t input_width = input_shape[axis]; + int64_t input_height = numel / input_width; FD_VISIT_INT_TYPES(indices_type, "FullSort", ([&] { FullSort(input_height, input_width, rank, &trans_inp, out, indices, @@ -115,4 +117,4 @@ void Sort(const FDTensor& x, FDTensor* out, FDTensor* indices, int axis, } } // namespace function -} // namespace fastdeploy \ No newline at end of file +} // namespace fastdeploy diff --git a/fastdeploy/function/tile.cc b/fastdeploy/function/tile.cc index 6437b4ec60..c6e3095c6f 100644 --- a/fastdeploy/function/tile.cc +++ b/fastdeploy/function/tile.cc @@ -49,6 +49,7 @@ void TileFunctor(const FDTensor& x, return; } + FDTensor out_tmp; Eigen::DSizes bcast_dims; for (size_t i = 0; i < repeat_times.size(); ++i) { bcast_dims[i] = repeat_times[i]; @@ -59,12 +60,14 @@ void TileFunctor(const FDTensor& x, out_shape[i] *= repeat_times[i]; } - out->Allocate(out_shape, x.Dtype()); + out_tmp.Allocate(out_shape, x.Dtype()); auto eigen_x = EigenTensor::From(x, x_shape); - auto eigen_out = EigenTensor::From(*out, out_shape); + auto eigen_out = EigenTensor::From(out_tmp, out_shape); const auto& dev = *EigenDeviceWrapper::GetInstance()->GetDevice(); eigen_out.device(dev) = eigen_x.broadcast(bcast_dims); + + *out = std::move(out_tmp); } template diff --git a/fastdeploy/pybind/runtime.cc b/fastdeploy/pybind/runtime.cc index 502c030fcf..75767c6657 100644 --- a/fastdeploy/pybind/runtime.cc +++ b/fastdeploy/pybind/runtime.cc @@ -35,7 +35,8 @@ void BindRuntime(pybind11::module& m) { .def("set_paddle_mkldnn", &RuntimeOption::SetPaddleMKLDNN) .def("set_openvino_device", &RuntimeOption::SetOpenVINODevice) .def("set_openvino_shape_info", &RuntimeOption::SetOpenVINOShapeInfo) - .def("set_openvino_cpu_operators", &RuntimeOption::SetOpenVINOCpuOperators) + .def("set_openvino_cpu_operators", + &RuntimeOption::SetOpenVINOCpuOperators) .def("enable_paddle_log_info", &RuntimeOption::EnablePaddleLogInfo) .def("disable_paddle_log_info", &RuntimeOption::DisablePaddleLogInfo) .def("set_paddle_mkldnn_cache_size", @@ -52,10 +53,15 @@ void BindRuntime(pybind11::module& m) { .def("set_trt_cache_file", &RuntimeOption::SetTrtCacheFile) .def("enable_pinned_memory", &RuntimeOption::EnablePinnedMemory) .def("disable_pinned_memory", &RuntimeOption::DisablePinnedMemory) - .def("enable_paddle_trt_collect_shape", &RuntimeOption::EnablePaddleTrtCollectShape) - .def("disable_paddle_trt_collect_shape", &RuntimeOption::DisablePaddleTrtCollectShape) + .def("enable_paddle_trt_collect_shape", + &RuntimeOption::EnablePaddleTrtCollectShape) + .def("disable_paddle_trt_collect_shape", + &RuntimeOption::DisablePaddleTrtCollectShape) .def("use_ipu", &RuntimeOption::UseIpu) .def("set_ipu_config", &RuntimeOption::SetIpuConfig) + .def("delete_paddle_backend_pass", + &RuntimeOption::DeletePaddleBackendPass) + .def("disable_paddle_trt_ops", &RuntimeOption::DisablePaddleTrtOPs) .def_readwrite("model_file", &RuntimeOption::model_file) .def_readwrite("params_file", &RuntimeOption::params_file) .def_readwrite("model_format", &RuntimeOption::model_format) @@ -117,9 +123,9 @@ void BindRuntime(pybind11::module& m) { auto dtype = NumpyDataTypeToFDDataType(warm_datas[i][j].dtype()); std::vector data_shape; - data_shape.insert( - data_shape.begin(), warm_datas[i][j].shape(), - warm_datas[i][j].shape() + warm_datas[i][j].ndim()); + data_shape.insert(data_shape.begin(), warm_datas[i][j].shape(), + warm_datas[i][j].shape() + + warm_datas[i][j].ndim()); warm_tensors[i][j].Resize(data_shape, dtype); memcpy(warm_tensors[i][j].MutableData(), warm_datas[i][j].mutable_data(), @@ -160,36 +166,39 @@ void BindRuntime(pybind11::module& m) { } return results; }) - .def("infer", [](Runtime& self, std::map& data) { - std::vector inputs; - inputs.reserve(data.size()); - for (auto iter = data.begin(); iter != data.end(); ++iter) { - FDTensor tensor; - tensor.SetExternalData(iter->second.Shape(), iter->second.Dtype(), iter->second.Data(), iter->second.device); - tensor.name = iter->first; - inputs.push_back(tensor); - } - std::vector outputs; - if (!self.Infer(inputs, &outputs)) { - throw std::runtime_error("Failed to inference with Runtime."); - } - return outputs; - }) - .def("infer", [](Runtime& self, std::vector& inputs) { - std::vector outputs; - return self.Infer(inputs, &outputs); - }) + .def("infer", + [](Runtime& self, std::map& data) { + std::vector inputs; + inputs.reserve(data.size()); + for (auto iter = data.begin(); iter != data.end(); ++iter) { + FDTensor tensor; + tensor.SetExternalData(iter->second.Shape(), + iter->second.Dtype(), iter->second.Data(), + iter->second.device); + tensor.name = iter->first; + inputs.push_back(tensor); + } + std::vector outputs; + if (!self.Infer(inputs, &outputs)) { + throw std::runtime_error("Failed to inference with Runtime."); + } + return outputs; + }) + .def("infer", + [](Runtime& self, std::vector& inputs) { + std::vector outputs; + return self.Infer(inputs, &outputs); + }) .def("bind_input_tensor", &Runtime::BindInputTensor) - .def("infer", [](Runtime& self) { - self.Infer(); - }) - .def("get_output_tensor", [](Runtime& self, const std::string& name) { - FDTensor* output = self.GetOutputTensor(name); - if(output == nullptr) { - return pybind11::cast(nullptr); - } - return pybind11::cast(*output); - }) + .def("infer", [](Runtime& self) { self.Infer(); }) + .def("get_output_tensor", + [](Runtime& self, const std::string& name) { + FDTensor* output = self.GetOutputTensor(name); + if (output == nullptr) { + return pybind11::cast(nullptr); + } + return pybind11::cast(*output); + }) .def("num_inputs", &Runtime::NumInputs) .def("num_outputs", &Runtime::NumOutputs) .def("get_input_info", &Runtime::GetInputInfo) diff --git a/fastdeploy/runtime.cc b/fastdeploy/runtime.cc old mode 100755 new mode 100644 index 088cf273ba..1a51cebea8 --- a/fastdeploy/runtime.cc +++ b/fastdeploy/runtime.cc @@ -94,7 +94,7 @@ std::string Str(const Backend& b) { return "Backend::POROS"; } else if (b == Backend::RKNPU2) { return "Backend::RKNPU2"; - }else if (b == Backend::OPENVINO) { + } else if (b == Backend::OPENVINO) { return "Backend::OPENVINO"; } else if (b == Backend::LITE) { return "Backend::PDLITE"; @@ -113,7 +113,7 @@ std::ostream& operator<<(std::ostream& out, const Backend& backend) { out << "Backend::OPENVINO"; } else if (backend == Backend::RKNPU2) { out << "Backend::RKNPU2"; - }else if (backend == Backend::POROS) { + } else if (backend == Backend::POROS) { out << "Backend::POROS"; } else if (backend == Backend::LITE) { out << "Backend::PDLITE"; @@ -152,15 +152,17 @@ bool CheckModelFormat(const std::string& model_file, } else if (model_format == ModelFormat::TORCHSCRIPT) { if (model_file.size() < 3 || model_file.substr(model_file.size() - 3, 3) != ".pt") { - FDERROR << "With model format of ModelFormat::TORCHSCRIPT, the model file " - "should ends with `.pt`, but now it's " - << model_file << std::endl; + FDERROR + << "With model format of ModelFormat::TORCHSCRIPT, the model file " + "should ends with `.pt`, but now it's " + << model_file << std::endl; return false; } } else { - FDERROR << "Only support model format with frontend ModelFormat::PADDLE / " - "ModelFormat::ONNX / ModelFormat::RKNN / ModelFormat::TORCHSCRIPT." - << std::endl; + FDERROR + << "Only support model format with frontend ModelFormat::PADDLE / " + "ModelFormat::ONNX / ModelFormat::RKNN / ModelFormat::TORCHSCRIPT." + << std::endl; return false; } return true; @@ -205,9 +207,9 @@ void RuntimeOption::SetModelPath(const std::string& model_path, model_file = model_path; model_format = ModelFormat::TORCHSCRIPT; } else { - FDASSERT( - false, - "The model format only can be ModelFormat::PADDLE/ModelFormat::ONNX/ModelFormat::TORCHSCRIPT."); + FDASSERT(false, + "The model format only can be " + "ModelFormat::PADDLE/ModelFormat::ONNX/ModelFormat::TORCHSCRIPT."); } } @@ -317,13 +319,18 @@ void RuntimeOption::EnablePaddleLogInfo() { pd_enable_log_info = true; } void RuntimeOption::DisablePaddleLogInfo() { pd_enable_log_info = false; } void RuntimeOption::EnablePaddleToTrt() { - FDASSERT(backend == Backend::TRT, "Should call UseTrtBackend() before call EnablePaddleToTrt()."); + FDASSERT(backend == Backend::TRT, + "Should call UseTrtBackend() before call EnablePaddleToTrt()."); #ifdef ENABLE_PADDLE_BACKEND - FDINFO << "While using TrtBackend with EnablePaddleToTrt, FastDeploy will change to use Paddle Inference Backend." << std::endl; + FDINFO << "While using TrtBackend with EnablePaddleToTrt, FastDeploy will " + "change to use Paddle Inference Backend." + << std::endl; backend = Backend::PDINFER; pd_enable_trt = true; #else - FDASSERT(false, "While using TrtBackend with EnablePaddleToTrt, require the FastDeploy is compiled with Paddle Inference Backend, please rebuild your FastDeploy."); + FDASSERT(false, "While using TrtBackend with EnablePaddleToTrt, require the " + "FastDeploy is compiled with Paddle Inference Backend, " + "please rebuild your FastDeploy."); #endif } @@ -336,20 +343,12 @@ void RuntimeOption::SetOpenVINODevice(const std::string& name) { openvino_device = name; } -void RuntimeOption::EnableLiteFP16() { - lite_enable_fp16 = true; -} +void RuntimeOption::EnableLiteFP16() { lite_enable_fp16 = true; } -void RuntimeOption::DisableLiteFP16() { - lite_enable_fp16 = false; -} -void RuntimeOption::EnableLiteInt8() { - lite_enable_int8 = true; -} +void RuntimeOption::DisableLiteFP16() { lite_enable_fp16 = false; } +void RuntimeOption::EnableLiteInt8() { lite_enable_int8 = true; } -void RuntimeOption::DisableLiteInt8() { - lite_enable_int8 = false; -} +void RuntimeOption::DisableLiteInt8() { lite_enable_int8 = false; } void RuntimeOption::SetLitePowerMode(LitePowerMode mode) { lite_power_mode = mode; } @@ -361,7 +360,8 @@ void RuntimeOption::SetLiteOptimizedModelDir( void RuntimeOption::SetLiteSubgraphPartitionPath( const std::string& nnadapter_subgraph_partition_config_path) { - lite_nnadapter_subgraph_partition_config_path = nnadapter_subgraph_partition_config_path; + lite_nnadapter_subgraph_partition_config_path = + nnadapter_subgraph_partition_config_path; } void RuntimeOption::SetTrtInputShape(const std::string& input_name, @@ -387,8 +387,8 @@ void RuntimeOption::SetTrtInputShape(const std::string& input_name, void RuntimeOption::SetTrtMaxWorkspaceSize(size_t max_workspace_size) { trt_max_workspace_size = max_workspace_size; } -void RuntimeOption::SetTrtMaxBatchSize(size_t max_batch_size){ - trt_max_batch_size = max_batch_size; +void RuntimeOption::SetTrtMaxBatchSize(size_t max_batch_size) { + trt_max_batch_size = max_batch_size; } void RuntimeOption::EnableTrtFP16() { trt_enable_fp16 = true; } @@ -422,27 +422,27 @@ bool Runtime::Compile(std::vector>& prewarm_tensors, poros_option.enable_fp16 = option.trt_enable_fp16; poros_option.max_batch_size = option.trt_max_batch_size; poros_option.max_workspace_size = option.trt_max_workspace_size; - FDASSERT(option.model_format == ModelFormat::TORCHSCRIPT, - "PorosBackend only support model format of ModelFormat::TORCHSCRIPT."); + FDASSERT( + option.model_format == ModelFormat::TORCHSCRIPT, + "PorosBackend only support model format of ModelFormat::TORCHSCRIPT."); backend_ = utils::make_unique(); auto casted_backend = dynamic_cast(backend_.get()); FDASSERT( casted_backend->Compile(option.model_file, prewarm_tensors, poros_option), "Load model from Torchscript failed while initliazing PorosBackend."); #else - FDASSERT(false, - "PorosBackend is not available, please compiled with " - "ENABLE_POROS_BACKEND=ON."); + FDASSERT(false, "PorosBackend is not available, please compiled with " + "ENABLE_POROS_BACKEND=ON."); #endif return true; } -void RuntimeOption::EnablePaddleTrtCollectShape() { - pd_collect_shape = true; -} +void RuntimeOption::EnablePaddleTrtCollectShape() { pd_collect_shape = true; } -void RuntimeOption::DisablePaddleTrtCollectShape() { - pd_collect_shape = false; +void RuntimeOption::DisablePaddleTrtCollectShape() { pd_collect_shape = false; } + +void RuntimeOption::DisablePaddleTrtOPs(const std::vector& ops) { + trt_disabled_ops_.insert(trt_disabled_ops_.end(), ops.begin(), ops.end()); } void RuntimeOption::UseIpu(int device_num, int micro_batch_size, @@ -519,9 +519,9 @@ bool Runtime::Init(const RuntimeOption& _option) { } else if (option.backend == Backend::POROS) { FDASSERT(option.device == Device::CPU || option.device == Device::GPU, "Backend::POROS only supports Device::CPU/Device::GPU."); - FDASSERT( - option.model_format == ModelFormat::TORCHSCRIPT, - "Backend::POROS only supports model format of ModelFormat::TORCHSCRIPT."); + FDASSERT(option.model_format == ModelFormat::TORCHSCRIPT, + "Backend::POROS only supports model format of " + "ModelFormat::TORCHSCRIPT."); FDINFO << "Runtime initialized with Backend::POROS in " << Str(option.device) << "." << std::endl; return true; @@ -572,7 +572,7 @@ std::vector Runtime::GetOutputInfos() { bool Runtime::Infer(std::vector& input_tensors, std::vector* output_tensors) { - for (auto& tensor: input_tensors) { + for (auto& tensor : input_tensors) { FDASSERT(tensor.device_id < 0 || tensor.device_id == option.device_id, "Device id of input tensor(%d) and runtime(%d) are not same.", tensor.device_id, option.device_id); @@ -589,17 +589,15 @@ void Runtime::BindInputTensor(const std::string& name, FDTensor& input) { for (auto& t : input_tensors_) { if (t.name == name) { is_exist = true; - t.SetExternalData(input.shape, input.dtype, - input.MutableData(), input.device, - input.device_id); + t.SetExternalData(input.shape, input.dtype, input.MutableData(), + input.device, input.device_id); break; } } - if(!is_exist) { + if (!is_exist) { FDTensor new_tensor(name); - new_tensor.SetExternalData(input.shape, input.dtype, - input.MutableData(), input.device, - input.device_id); + new_tensor.SetExternalData(input.shape, input.dtype, input.MutableData(), + input.device, input.device_id); input_tensors_.emplace_back(std::move(new_tensor)); } } @@ -644,6 +642,7 @@ void Runtime::CreatePaddleBackend() { trt_option.serialize_file = option.trt_serialize_file; trt_option.enable_pinned_memory = option.enable_pinned_memory; pd_option.trt_option = trt_option; + pd_option.trt_disabled_ops_ = option.trt_disabled_ops_; } #endif #ifdef WITH_IPU @@ -669,9 +668,8 @@ void Runtime::CreatePaddleBackend() { pd_option), "Load model from Paddle failed while initliazing PaddleBackend."); #else - FDASSERT(false, - "PaddleBackend is not available, please compiled with " - "ENABLE_PADDLE_BACKEND=ON."); + FDASSERT(false, "PaddleBackend is not available, please compiled with " + "ENABLE_PADDLE_BACKEND=ON."); #endif } @@ -701,9 +699,8 @@ void Runtime::CreateOpenVINOBackend() { "Load model from Paddle failed while initliazing OrtBackend."); } #else - FDASSERT(false, - "OpenVINOBackend is not available, please compiled with " - "ENABLE_OPENVINO_BACKEND=ON."); + FDASSERT(false, "OpenVINOBackend is not available, please compiled with " + "ENABLE_OPENVINO_BACKEND=ON."); #endif } @@ -733,9 +730,8 @@ void Runtime::CreateOrtBackend() { "Load model from Paddle failed while initliazing OrtBackend."); } #else - FDASSERT(false, - "OrtBackend is not available, please compiled with " - "ENABLE_ORT_BACKEND=ON."); + FDASSERT(false, "OrtBackend is not available, please compiled with " + "ENABLE_ORT_BACKEND=ON."); #endif } @@ -772,9 +768,8 @@ void Runtime::CreateTrtBackend() { "Load model from Paddle failed while initliazing TrtBackend."); } #else - FDASSERT(false, - "TrtBackend is not available, please compiled with " - "ENABLE_TRT_BACKEND=ON."); + FDASSERT(false, "TrtBackend is not available, please compiled with " + "ENABLE_TRT_BACKEND=ON."); #endif } @@ -786,7 +781,8 @@ void Runtime::CreateLiteBackend() { lite_option.enable_fp16 = option.lite_enable_fp16; lite_option.power_mode = static_cast(option.lite_power_mode); lite_option.optimized_model_dir = option.lite_optimized_model_dir; - lite_option.nnadapter_subgraph_partition_config_path = option.lite_nnadapter_subgraph_partition_config_path; + lite_option.nnadapter_subgraph_partition_config_path = + option.lite_nnadapter_subgraph_partition_config_path; lite_option.enable_timvx = option.enable_timvx; FDASSERT(option.model_format == ModelFormat::PADDLE, "LiteBackend only support model format of ModelFormat::PADDLE"); @@ -796,9 +792,8 @@ void Runtime::CreateLiteBackend() { lite_option), "Load model from nb file failed while initializing LiteBackend."); #else - FDASSERT(false, - "LiteBackend is not available, please compiled with " - "ENABLE_LITE_BACKEND=ON."); + FDASSERT(false, "LiteBackend is not available, please compiled with " + "ENABLE_LITE_BACKEND=ON."); #endif } @@ -821,10 +816,8 @@ void Runtime::CreateRKNPU2Backend() { Runtime* Runtime::Clone(void* stream, int device_id) { Runtime* runtime = new Runtime(); - if (option.backend != Backend::OPENVINO - && option.backend != Backend::PDINFER - && option.backend != Backend::TRT - ) { + if (option.backend != Backend::OPENVINO && + option.backend != Backend::PDINFER && option.backend != Backend::TRT) { runtime->Init(option); FDWARNING << "Only OpenVINO/Paddle Inference/TensorRT support \ clone engine to reduce CPU/GPU memory usage now. For " @@ -834,8 +827,8 @@ Runtime* Runtime::Clone(void* stream, int device_id) { << std::endl; return runtime; } - FDINFO << "Runtime Clone with Backend:: " << Str(option.backend) << " in " << Str(option.device) - << "." << std::endl; + FDINFO << "Runtime Clone with Backend:: " << Str(option.backend) << " in " + << Str(option.device) << "." << std::endl; runtime->option = option; runtime->backend_ = backend_->Clone(stream, device_id); return runtime; diff --git a/fastdeploy/runtime.h b/fastdeploy/runtime.h index e96643345b..e53c7ca1ed 100644 --- a/fastdeploy/runtime.h +++ b/fastdeploy/runtime.h @@ -24,9 +24,9 @@ #include #include +#include "backends/rknpu/rknpu2/rknpu2_config.h" #include "fastdeploy/backends/backend.h" #include "fastdeploy/utils/perf.h" -#include "backends/rknpu/rknpu2/rknpu2_config.h" /** \brief All C++ FastDeploy APIs are defined inside this namespace * @@ -35,14 +35,14 @@ namespace fastdeploy { /*! Inference backend supported in FastDeploy */ enum Backend { - UNKNOWN, ///< Unknown inference backend - ORT, ///< ONNX Runtime, support Paddle/ONNX format model, CPU / Nvidia GPU - TRT, ///< TensorRT, support Paddle/ONNX format model, Nvidia GPU only + UNKNOWN, ///< Unknown inference backend + ORT, ///< ONNX Runtime, support Paddle/ONNX format model, CPU / Nvidia GPU + TRT, ///< TensorRT, support Paddle/ONNX format model, Nvidia GPU only PDINFER, ///< Paddle Inference, support Paddle format model, CPU / Nvidia GPU POROS, ///< Poros, support TorchScript format model, CPU / Nvidia GPU OPENVINO, ///< Intel OpenVINO, support Paddle/ONNX format, CPU only - LITE, ///< Paddle Lite, support Paddle format model, ARM CPU only - RKNPU2, ///< RKNPU2, support RKNN format model, Rockchip NPU only + LITE, ///< Paddle Lite, support Paddle format model, ARM CPU only + RKNPU2, ///< RKNPU2, support RKNN format model, Rockchip NPU only }; FASTDEPLOY_DECL std::ostream& operator<<(std::ostream& out, @@ -94,10 +94,10 @@ struct FASTDEPLOY_DECL RuntimeOption { /// Use Nvidia GPU to inference void UseGpu(int gpu_id = 0); - void UseRKNPU2(fastdeploy::rknpu2::CpuName rknpu2_name - = fastdeploy::rknpu2::CpuName::RK3588, - fastdeploy::rknpu2::CoreMask rknpu2_core - = fastdeploy::rknpu2::CoreMask::RKNN_NPU_CORE_0); + void UseRKNPU2(fastdeploy::rknpu2::CpuName rknpu2_name = + fastdeploy::rknpu2::CpuName::RK3588, + fastdeploy::rknpu2::CoreMask rknpu2_core = + fastdeploy::rknpu2::CoreMask::RKNN_NPU_CORE_0); /// Use TimVX to inference void UseTimVX(); @@ -116,9 +116,7 @@ struct FASTDEPLOY_DECL RuntimeOption { void UsePaddleBackend(); /// Wrapper function of UsePaddleBackend() - void UsePaddleInferBackend() { - return UsePaddleBackend(); - } + void UsePaddleInferBackend() { return UsePaddleBackend(); } /// Set ONNX Runtime as inference backend, support CPU/GPU void UseOrtBackend(); @@ -136,9 +134,7 @@ struct FASTDEPLOY_DECL RuntimeOption { void UseLiteBackend(); /// Wrapper function of UseLiteBackend() - void UsePaddleLiteBackend() { - return UseLiteBackend(); - } + void UsePaddleLiteBackend() { return UseLiteBackend(); } /// Set mkldnn switch while using Paddle Inference as inference backend void SetPaddleMKLDNN(bool pd_mkldnn = true); @@ -177,7 +173,7 @@ struct FASTDEPLOY_DECL RuntimeOption { * @brief Set shape info for OpenVINO */ void SetOpenVINOShapeInfo( - const std::map>& shape_info) { + const std::map>& shape_info) { ov_shape_infos = shape_info; } @@ -197,7 +193,7 @@ struct FASTDEPLOY_DECL RuntimeOption { * @brief Set nnadapter subgraph partition path for Paddle Lite backend. */ void SetLiteSubgraphPartitionPath( - const std::string& nnadapter_subgraph_partition_config_path); + const std::string& nnadapter_subgraph_partition_config_path); /** * @brief enable half precision while use paddle lite backend @@ -275,6 +271,11 @@ struct FASTDEPLOY_DECL RuntimeOption { */ void DisablePaddleTrtCollectShape(); + /** + * @brief Prevent ops running in paddle trt backend + */ + void DisablePaddleTrtOPs(const std::vector& ops); + /* * @brief Set number of streams by the OpenVINO backends */ @@ -363,6 +364,8 @@ struct FASTDEPLOY_DECL RuntimeOption { bool trt_enable_int8 = false; size_t trt_max_batch_size = 32; size_t trt_max_workspace_size = 1 << 30; + // ======Only for PaddleTrt Backend======= + std::vector trt_disabled_ops_{}; // ======Only for Poros Backend======= bool is_dynamic = false; @@ -378,12 +381,12 @@ struct FASTDEPLOY_DECL RuntimeOption { std::vector ov_cpu_operators; // ======Only for RKNPU2 Backend======= - fastdeploy::rknpu2::CpuName rknpu2_cpu_name_ - = fastdeploy::rknpu2::CpuName::RK3588; - fastdeploy::rknpu2::CoreMask rknpu2_core_mask_ - = fastdeploy::rknpu2::CoreMask::RKNN_NPU_CORE_AUTO; + fastdeploy::rknpu2::CpuName rknpu2_cpu_name_ = + fastdeploy::rknpu2::CpuName::RK3588; + fastdeploy::rknpu2::CoreMask rknpu2_core_mask_ = + fastdeploy::rknpu2::CoreMask::RKNN_NPU_CORE_AUTO; - std::string model_file = ""; // Path of model file + std::string model_file = ""; // Path of model file std::string params_file = ""; // Path of parameters file, can be empty // format of input model ModelFormat model_format = ModelFormat::AUTOREC; @@ -450,8 +453,7 @@ struct FASTDEPLOY_DECL Runtime { * \param[in] stream CUDA Stream, defualt param is nullptr * \return new Runtime* by this clone */ - Runtime* Clone(void* stream = nullptr, - int device_id = -1); + Runtime* Clone(void* stream = nullptr, int device_id = -1); RuntimeOption option; diff --git a/fastdeploy/text/uie/model.cc b/fastdeploy/text/uie/model.cc index 490a4a0fbe..cd90db4f11 100644 --- a/fastdeploy/text/uie/model.cc +++ b/fastdeploy/text/uie/model.cc @@ -230,7 +230,7 @@ bool UIEModel::Initialize() { void UIEModel::SetValidBackend() { // TODO(zhoushunjie): Add lite backend in future - valid_cpu_backends = {Backend::ORT, Backend::OPENVINO, Backend::PDINFER}; + valid_cpu_backends = {Backend::ORT, Backend::OPENVINO, Backend::PDINFER, Backend::LITE}; valid_gpu_backends = {Backend::ORT, Backend::PDINFER, Backend::TRT}; } diff --git a/fastdeploy/utils/utils.h b/fastdeploy/utils/utils.h index 9b2a0fe201..0dff28f8be 100644 --- a/fastdeploy/utils/utils.h +++ b/fastdeploy/utils/utils.h @@ -66,7 +66,8 @@ class FASTDEPLOY_DECL FDLogger { if (!verbose_ && line_ != "") { std::cout << line_ << std::endl; #ifdef __ANDROID__ - __android_log_print(ANDROID_LOG_INFO, prefix_.c_str(), "%s", line_.c_str()); + __android_log_print(ANDROID_LOG_INFO, prefix_.c_str(), "%s", + line_.c_str()); #endif } } @@ -122,6 +123,8 @@ FASTDEPLOY_DECL bool ReadBinaryFromFile(const std::string& file, [&] { \ const auto& __dtype__ = TYPE; \ switch (__dtype__) { \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::UINT8, uint8_t, \ + __VA_ARGS__) \ FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::BOOL, bool, \ __VA_ARGS__) \ FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT32, int32_t, \ @@ -141,26 +144,26 @@ FASTDEPLOY_DECL bool ReadBinaryFromFile(const std::string& file, } \ }() -#define FD_VISIT_INT_FLOAT_TYPES(TYPE, NAME, ...) \ - [&] { \ - const auto& __dtype__ = TYPE; \ - switch (__dtype__) { \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT32, int32_t, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT64, int64_t, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::FP32, float, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::FP64, double, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::UINT8, uint8_t, \ - __VA_ARGS__) \ - default: \ - FDASSERT(false, \ - "Invalid enum data type. Expect to accept data type INT32, " \ - "INT64, FP32, FP64, UINT8 but receive type %s.", \ - Str(__dtype__).c_str()); \ - } \ +#define FD_VISIT_INT_FLOAT_TYPES(TYPE, NAME, ...) \ + [&] { \ + const auto& __dtype__ = TYPE; \ + switch (__dtype__) { \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT32, int32_t, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT64, int64_t, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::FP32, float, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::FP64, double, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::UINT8, uint8_t, \ + __VA_ARGS__) \ + default: \ + FDASSERT(false, \ + "Invalid enum data type. Expect to accept data type INT32, " \ + "INT64, FP32, FP64, UINT8 but receive type %s.", \ + Str(__dtype__).c_str()); \ + } \ }() #define FD_VISIT_FLOAT_TYPES(TYPE, NAME, ...) \ @@ -179,22 +182,22 @@ FASTDEPLOY_DECL bool ReadBinaryFromFile(const std::string& file, } \ }() -#define FD_VISIT_INT_TYPES(TYPE, NAME, ...) \ - [&] { \ - const auto& __dtype__ = TYPE; \ - switch (__dtype__) { \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT32, int32_t, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT64, int64_t, \ - __VA_ARGS__) \ - FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::UINT8, uint8_t, \ - __VA_ARGS__) \ - default: \ - FDASSERT(false, \ - "Invalid enum data type. Expect to accept data type INT32, " \ - "INT64, UINT8 but receive type %s.", \ - Str(__dtype__).c_str()); \ - } \ +#define FD_VISIT_INT_TYPES(TYPE, NAME, ...) \ + [&] { \ + const auto& __dtype__ = TYPE; \ + switch (__dtype__) { \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT32, int32_t, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::INT64, int64_t, \ + __VA_ARGS__) \ + FD_PRIVATE_CASE_TYPE(NAME, ::fastdeploy::FDDataType::UINT8, uint8_t, \ + __VA_ARGS__) \ + default: \ + FDASSERT(false, \ + "Invalid enum data type. Expect to accept data type INT32, " \ + "INT64, UINT8 but receive type %s.", \ + Str(__dtype__).c_str()); \ + } \ }() FASTDEPLOY_DECL std::vector diff --git a/fastdeploy/vision/detection/contrib/yolov5/yolov5.cc b/fastdeploy/vision/detection/contrib/yolov5/yolov5.cc index 422cf501c4..92d53dd107 100755 --- a/fastdeploy/vision/detection/contrib/yolov5/yolov5.cc +++ b/fastdeploy/vision/detection/contrib/yolov5/yolov5.cc @@ -27,6 +27,7 @@ YOLOv5::YOLOv5(const std::string& model_file, const std::string& params_file, } else { valid_cpu_backends = {Backend::PDINFER, Backend::ORT, Backend::LITE}; valid_gpu_backends = {Backend::PDINFER, Backend::ORT, Backend::TRT}; + valid_timvx_backends = {Backend::LITE}; } runtime_option = custom_option; runtime_option.model_format = model_format; diff --git a/fastdeploy/vision/detection/ppdet/model.h b/fastdeploy/vision/detection/ppdet/model.h old mode 100644 new mode 100755 index a686198ebe..44f574435d --- a/fastdeploy/vision/detection/ppdet/model.h +++ b/fastdeploy/vision/detection/ppdet/model.h @@ -64,6 +64,7 @@ class FASTDEPLOY_DECL PPYOLOE : public PPDetBase { valid_cpu_backends = {Backend::OPENVINO, Backend::ORT, Backend::PDINFER, Backend::LITE}; valid_gpu_backends = {Backend::ORT, Backend::PDINFER, Backend::TRT}; + valid_timvx_backends = {Backend::LITE}; initialized = Initialize(); } diff --git a/fastdeploy/vision/ocr/ppocr/classifier.cc b/fastdeploy/vision/ocr/ppocr/classifier.cc index 130329735e..4be9a3556a 100755 --- a/fastdeploy/vision/ocr/ppocr/classifier.cc +++ b/fastdeploy/vision/ocr/ppocr/classifier.cc @@ -50,10 +50,29 @@ bool Classifier::Initialize() { return true; } +bool Classifier::Predict(cv::Mat& img, int32_t* cls_label, float* cls_score) { + std::vector cls_labels(1); + std::vector cls_scores(1); + bool success = BatchPredict({img}, &cls_labels, &cls_scores); + if(!success){ + return success; + } + *cls_label = cls_labels[0]; + *cls_score = cls_scores[0]; + return true; +} + bool Classifier::BatchPredict(const std::vector& images, std::vector* cls_labels, std::vector* cls_scores) { + return BatchPredict(images, cls_labels, cls_scores, 0, images.size()); +} + +bool Classifier::BatchPredict(const std::vector& images, + std::vector* cls_labels, std::vector* cls_scores, + size_t start_index, size_t end_index) { + size_t total_size = images.size(); std::vector fd_images = WrapMat(images); - if (!preprocessor_.Run(&fd_images, &reused_input_tensors_)) { + if (!preprocessor_.Run(&fd_images, &reused_input_tensors_, start_index, end_index)) { FDERROR << "Failed to preprocess the input image." << std::endl; return false; } @@ -63,7 +82,7 @@ bool Classifier::BatchPredict(const std::vector& images, return false; } - if (!postprocessor_.Run(reused_output_tensors_, cls_labels, cls_scores)) { + if (!postprocessor_.Run(reused_output_tensors_, cls_labels, cls_scores, start_index, total_size)) { FDERROR << "Failed to postprocess the inference cls_results by runtime." << std::endl; return false; } diff --git a/fastdeploy/vision/ocr/ppocr/classifier.h b/fastdeploy/vision/ocr/ppocr/classifier.h index d3430e4e02..ddc4db27ac 100755 --- a/fastdeploy/vision/ocr/ppocr/classifier.h +++ b/fastdeploy/vision/ocr/ppocr/classifier.h @@ -43,7 +43,7 @@ class FASTDEPLOY_DECL Classifier : public FastDeployModel { const ModelFormat& model_format = ModelFormat::PADDLE); /// Get model's name std::string ModelName() const { return "ppocr/ocr_cls"; } - + virtual bool Predict(cv::Mat& img, int32_t* cls_label, float* cls_score); /** \brief BatchPredict the input image and get OCR classification model cls_result. * * \param[in] images The list of input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. @@ -53,6 +53,10 @@ class FASTDEPLOY_DECL Classifier : public FastDeployModel { virtual bool BatchPredict(const std::vector& images, std::vector* cls_labels, std::vector* cls_scores); + virtual bool BatchPredict(const std::vector& images, + std::vector* cls_labels, + std::vector* cls_scores, + size_t start_index, size_t end_index); ClassifierPreprocessor preprocessor_; ClassifierPostprocessor postprocessor_; diff --git a/fastdeploy/vision/ocr/ppocr/cls_postprocessor.cc b/fastdeploy/vision/ocr/ppocr/cls_postprocessor.cc index 5eb6b5d690..c19bcc3a6f 100644 --- a/fastdeploy/vision/ocr/ppocr/cls_postprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/cls_postprocessor.cc @@ -20,10 +20,6 @@ namespace fastdeploy { namespace vision { namespace ocr { -ClassifierPostprocessor::ClassifierPostprocessor() { - initialized_ = true; -} - bool SingleBatchPostprocessor(const float* out_data, const size_t& length, int* cls_label, float* cls_score) { *cls_label = std::distance( @@ -37,10 +33,14 @@ bool SingleBatchPostprocessor(const float* out_data, const size_t& length, int* bool ClassifierPostprocessor::Run(const std::vector& tensors, std::vector* cls_labels, std::vector* cls_scores) { - if (!initialized_) { - FDERROR << "Postprocessor is not initialized." << std::endl; - return false; - } + size_t total_size = tensors[0].shape[0]; + return Run(tensors, cls_labels, cls_scores, 0, total_size); +} + +bool ClassifierPostprocessor::Run(const std::vector& tensors, + std::vector* cls_labels, + std::vector* cls_scores, + size_t start_index, size_t total_size) { // Classifier have only 1 output tensor. const FDTensor& tensor = tensors[0]; @@ -48,13 +48,29 @@ bool ClassifierPostprocessor::Run(const std::vector& tensors, size_t batch = tensor.shape[0]; size_t length = accumulate(tensor.shape.begin()+1, tensor.shape.end(), 1, std::multiplies()); - cls_labels->resize(batch); - cls_scores->resize(batch); + if (batch <= 0) { + FDERROR << "The infer outputTensor.shape[0] <=0, wrong infer result." << std::endl; + return false; + } + if (start_index < 0 || total_size <= 0) { + FDERROR << "start_index or total_size error. Correct is: 0 <= start_index < total_size" << std::endl; + return false; + } + if ((start_index + batch) > total_size) { + FDERROR << "start_index or total_size error. Correct is: start_index + batch(outputTensor.shape[0]) <= total_size" << std::endl; + return false; + } + + cls_labels->resize(total_size); + cls_scores->resize(total_size); const float* tensor_data = reinterpret_cast(tensor.Data()); - for (int i_batch = 0; i_batch < batch; ++i_batch) { - if(!SingleBatchPostprocessor(tensor_data, length, &cls_labels->at(i_batch),&cls_scores->at(i_batch))) return false; - tensor_data = tensor_data + length; + if(!SingleBatchPostprocessor(tensor_data+ i_batch * length, + length, + &cls_labels->at(i_batch + start_index), + &cls_scores->at(i_batch + start_index))) { + return false; + } } return true; diff --git a/fastdeploy/vision/ocr/ppocr/cls_postprocessor.h b/fastdeploy/vision/ocr/ppocr/cls_postprocessor.h index 15bf098c70..a755e12948 100644 --- a/fastdeploy/vision/ocr/ppocr/cls_postprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/cls_postprocessor.h @@ -25,11 +25,6 @@ namespace ocr { */ class FASTDEPLOY_DECL ClassifierPostprocessor { public: - /** \brief Create a postprocessor instance for Classifier serials model - * - */ - ClassifierPostprocessor(); - /** \brief Process the result of runtime and fill to ClassifyResult structure * * \param[in] tensors The inference result from runtime @@ -40,10 +35,11 @@ class FASTDEPLOY_DECL ClassifierPostprocessor { bool Run(const std::vector& tensors, std::vector* cls_labels, std::vector* cls_scores); - float cls_thresh_ = 0.9; + bool Run(const std::vector& tensors, + std::vector* cls_labels, std::vector* cls_scores, + size_t start_index, size_t total_size); - private: - bool initialized_ = false; + float cls_thresh_ = 0.9; }; } // namespace ocr diff --git a/fastdeploy/vision/ocr/ppocr/cls_preprocessor.cc b/fastdeploy/vision/ocr/ppocr/cls_preprocessor.cc old mode 100644 new mode 100755 index 1f09936905..dcd76c168a --- a/fastdeploy/vision/ocr/ppocr/cls_preprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/cls_preprocessor.cc @@ -21,58 +21,53 @@ namespace fastdeploy { namespace vision { namespace ocr { -ClassifierPreprocessor::ClassifierPreprocessor() { - initialized_ = true; -} - void OcrClassifierResizeImage(FDMat* mat, const std::vector& cls_image_shape) { - int imgC = cls_image_shape[0]; - int imgH = cls_image_shape[1]; - int imgW = cls_image_shape[2]; + int img_c = cls_image_shape[0]; + int img_h = cls_image_shape[1]; + int img_w = cls_image_shape[2]; float ratio = float(mat->Width()) / float(mat->Height()); int resize_w; - if (ceilf(imgH * ratio) > imgW) - resize_w = imgW; + if (ceilf(img_h * ratio) > img_w) + resize_w = img_w; else - resize_w = int(ceilf(imgH * ratio)); - - Resize::Run(mat, resize_w, imgH); + resize_w = int(ceilf(img_h * ratio)); - std::vector value = {0, 0, 0}; - if (resize_w < imgW) { - Pad::Run(mat, 0, 0, 0, imgW - resize_w, value); - } + Resize::Run(mat, resize_w, img_h); } bool ClassifierPreprocessor::Run(std::vector* images, std::vector* outputs) { - if (!initialized_) { - FDERROR << "The preprocessor is not initialized." << std::endl; - return false; - } - if (images->size() == 0) { - FDERROR << "The size of input images should be greater than 0." << std::endl; + return Run(images, outputs, 0, images->size()); +} + +bool ClassifierPreprocessor::Run(std::vector* images, std::vector* outputs, + size_t start_index, size_t end_index) { + + if (images->size() == 0 || start_index <0 || end_index <= start_index || end_index > images->size()) { + FDERROR << "images->size() or index error. Correct is: 0 <= start_index < end_index <= images->size()" << std::endl; return false; } - for (size_t i = 0; i < images->size(); ++i) { + for (size_t i = start_index; i < end_index; ++i) { FDMat* mat = &(images->at(i)); OcrClassifierResizeImage(mat, cls_image_shape_); - NormalizeAndPermute::Run(mat, mean_, scale_, is_scale_); - /* Normalize::Run(mat, mean_, scale_, is_scale_); + std::vector value = {0, 0, 0}; + if (mat->Width() < cls_image_shape_[2]) { + Pad::Run(mat, 0, 0, 0, cls_image_shape_[2] - mat->Width(), value); + } HWC2CHW::Run(mat); Cast::Run(mat, "float"); - */ } // Only have 1 output Tensor. outputs->resize(1); // Concat all the preprocessed data to a batch tensor - std::vector tensors(images->size()); - for (size_t i = 0; i < images->size(); ++i) { - (*images)[i].ShareWithTensor(&(tensors[i])); + size_t tensor_size = end_index - start_index; + std::vector tensors(tensor_size); + for (size_t i = 0; i < tensor_size; ++i) { + (*images)[i + start_index].ShareWithTensor(&(tensors[i])); tensors[i].ExpandDim(0); } if (tensors.size() == 1) { diff --git a/fastdeploy/vision/ocr/ppocr/cls_preprocessor.h b/fastdeploy/vision/ocr/ppocr/cls_preprocessor.h index a701e7e3ae..ed75d55b28 100644 --- a/fastdeploy/vision/ocr/ppocr/cls_preprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/cls_preprocessor.h @@ -24,11 +24,6 @@ namespace ocr { */ class FASTDEPLOY_DECL ClassifierPreprocessor { public: - /** \brief Create a preprocessor instance for Classifier serials model - * - */ - ClassifierPreprocessor(); - /** \brief Process the input image and prepare input tensors for runtime * * \param[in] images The input image data list, all the elements are returned by cv::imread() @@ -36,14 +31,13 @@ class FASTDEPLOY_DECL ClassifierPreprocessor { * \return true if the preprocess successed, otherwise false */ bool Run(std::vector* images, std::vector* outputs); + bool Run(std::vector* images, std::vector* outputs, + size_t start_index, size_t end_index); std::vector mean_ = {0.5f, 0.5f, 0.5f}; std::vector scale_ = {0.5f, 0.5f, 0.5f}; bool is_scale_ = true; std::vector cls_image_shape_ = {3, 48, 192}; - - private: - bool initialized_ = false; }; } // namespace ocr diff --git a/fastdeploy/vision/ocr/ppocr/dbdetector.cc b/fastdeploy/vision/ocr/ppocr/dbdetector.cc index 68a994afcb..b490e88d9d 100755 --- a/fastdeploy/vision/ocr/ppocr/dbdetector.cc +++ b/fastdeploy/vision/ocr/ppocr/dbdetector.cc @@ -50,14 +50,6 @@ bool DBDetector::Initialize() { return true; } -bool DBDetector::Predict(cv::Mat* img, - std::vector>* boxes_result) { - if (!Predict(*img, boxes_result)) { - return false; - } - return true; -} - bool DBDetector::Predict(const cv::Mat& img, std::vector>* boxes_result) { std::vector>> det_results; diff --git a/fastdeploy/vision/ocr/ppocr/dbdetector.h b/fastdeploy/vision/ocr/ppocr/dbdetector.h index d3b99d598f..d2305abd7c 100755 --- a/fastdeploy/vision/ocr/ppocr/dbdetector.h +++ b/fastdeploy/vision/ocr/ppocr/dbdetector.h @@ -44,14 +44,6 @@ class FASTDEPLOY_DECL DBDetector : public FastDeployModel { const ModelFormat& model_format = ModelFormat::PADDLE); /// Get model's name std::string ModelName() const { return "ppocr/ocr_det"; } - /** \brief Predict the input image and get OCR detection model result. - * - * \param[in] img The input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. - * \param[in] boxes_result The output of OCR detection model result will be writen to this structure. - * \return true if the prediction is successed, otherwise false. - */ - virtual bool Predict(cv::Mat* img, - std::vector>* boxes_result); /** \brief Predict the input image and get OCR detection model result. * * \param[in] img The input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. diff --git a/fastdeploy/vision/ocr/ppocr/det_postprocessor.cc b/fastdeploy/vision/ocr/ppocr/det_postprocessor.cc index 34a88c0111..e83dac5e58 100644 --- a/fastdeploy/vision/ocr/ppocr/det_postprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/det_postprocessor.cc @@ -20,10 +20,6 @@ namespace fastdeploy { namespace vision { namespace ocr { -DBDetectorPostprocessor::DBDetectorPostprocessor() { - initialized_ = true; -} - bool DBDetectorPostprocessor::SingleBatchPostprocessor( const float* out_data, int n2, @@ -57,10 +53,10 @@ bool DBDetectorPostprocessor::SingleBatchPostprocessor( std::vector>> boxes; boxes = - post_processor_.BoxesFromBitmap(pred_map, bit_map, det_db_box_thresh_, + util_post_processor_.BoxesFromBitmap(pred_map, bit_map, det_db_box_thresh_, det_db_unclip_ratio_, det_db_score_mode_); - boxes = post_processor_.FilterTagDetRes(boxes, det_img_info); + boxes = util_post_processor_.FilterTagDetRes(boxes, det_img_info); // boxes to boxes_result for (int i = 0; i < boxes.size(); i++) { @@ -80,10 +76,6 @@ bool DBDetectorPostprocessor::SingleBatchPostprocessor( bool DBDetectorPostprocessor::Run(const std::vector& tensors, std::vector>>* results, const std::vector>& batch_det_img_info) { - if (!initialized_) { - FDERROR << "Postprocessor is not initialized." << std::endl; - return false; - } // DBDetector have only 1 output tensor. const FDTensor& tensor = tensors[0]; diff --git a/fastdeploy/vision/ocr/ppocr/det_postprocessor.h b/fastdeploy/vision/ocr/ppocr/det_postprocessor.h index f98b89b028..1152288439 100644 --- a/fastdeploy/vision/ocr/ppocr/det_postprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/det_postprocessor.h @@ -25,11 +25,6 @@ namespace ocr { */ class FASTDEPLOY_DECL DBDetectorPostprocessor { public: - /** \brief Create a postprocessor instance for DBDetector serials model - * - */ - DBDetectorPostprocessor(); - /** \brief Process the result of runtime and fill to results structure * * \param[in] tensors The inference result from runtime @@ -48,8 +43,7 @@ class FASTDEPLOY_DECL DBDetectorPostprocessor { bool use_dilation_ = false; private: - bool initialized_ = false; - PostProcessor post_processor_; + PostProcessor util_post_processor_; bool SingleBatchPostprocessor(const float* out_data, int n2, int n3, diff --git a/fastdeploy/vision/ocr/ppocr/det_preprocessor.cc b/fastdeploy/vision/ocr/ppocr/det_preprocessor.cc index 89a8d6d39c..28b7e47afc 100644 --- a/fastdeploy/vision/ocr/ppocr/det_preprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/det_preprocessor.cc @@ -21,10 +21,6 @@ namespace fastdeploy { namespace vision { namespace ocr { -DBDetectorPreprocessor::DBDetectorPreprocessor() { - initialized_ = true; -} - std::array OcrDetectorGetInfo(FDMat* img, int max_size_len) { int w = img->Width(); int h = img->Height(); @@ -63,10 +59,6 @@ bool OcrDetectorResizeImage(FDMat* img, bool DBDetectorPreprocessor::Run(std::vector* images, std::vector* outputs, std::vector>* batch_det_img_info_ptr) { - if (!initialized_) { - FDERROR << "The preprocessor is not initialized." << std::endl; - return false; - } if (images->size() == 0) { FDERROR << "The size of input images should be greater than 0." << std::endl; return false; diff --git a/fastdeploy/vision/ocr/ppocr/det_preprocessor.h b/fastdeploy/vision/ocr/ppocr/det_preprocessor.h index 39c48691d7..d66e785d38 100644 --- a/fastdeploy/vision/ocr/ppocr/det_preprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/det_preprocessor.h @@ -24,11 +24,6 @@ namespace ocr { */ class FASTDEPLOY_DECL DBDetectorPreprocessor { public: - /** \brief Create a preprocessor instance for DBDetector serials model - * - */ - DBDetectorPreprocessor(); - /** \brief Process the input image and prepare input tensors for runtime * * \param[in] images The input image data list, all the elements are returned by cv::imread() @@ -44,9 +39,6 @@ class FASTDEPLOY_DECL DBDetectorPreprocessor { std::vector mean_ = {0.485f, 0.456f, 0.406f}; std::vector scale_ = {0.229f, 0.224f, 0.225f}; bool is_scale_ = true; - - private: - bool initialized_ = false; }; } // namespace ocr diff --git a/fastdeploy/vision/ocr/ppocr/ocrmodel_pybind.cc b/fastdeploy/vision/ocr/ppocr/ocrmodel_pybind.cc index b7e7dcbf3b..f84e99ed5e 100755 --- a/fastdeploy/vision/ocr/ppocr/ocrmodel_pybind.cc +++ b/fastdeploy/vision/ocr/ppocr/ocrmodel_pybind.cc @@ -20,14 +20,8 @@ void BindPPOCRModel(pybind11::module& m) { vision::ocr::SortBoxes(&boxes); return boxes; }); + // DBDetector - pybind11::class_(m, "DBDetector") - .def(pybind11::init()) - .def(pybind11::init<>()) - .def_readwrite("preprocessor", &vision::ocr::DBDetector::preprocessor_) - .def_readwrite("postprocessor", &vision::ocr::DBDetector::postprocessor_); - pybind11::class_(m, "DBDetectorPreprocessor") .def(pybind11::init<>()) .def_readwrite("max_side_len", &vision::ocr::DBDetectorPreprocessor::max_side_len_) @@ -45,7 +39,7 @@ void BindPPOCRModel(pybind11::module& m) { for(size_t i = 0; i< outputs.size(); ++i){ outputs[i].StopSharing(); } - return make_pair(outputs, batch_det_img_info); + return std::make_pair(outputs, batch_det_img_info); }); pybind11::class_(m, "DBDetectorPostprocessor") @@ -77,15 +71,31 @@ void BindPPOCRModel(pybind11::module& m) { return results; }); - // Classifier - pybind11::class_(m, "Classifier") + pybind11::class_(m, "DBDetector") .def(pybind11::init()) .def(pybind11::init<>()) - .def_readwrite("preprocessor", &vision::ocr::Classifier::preprocessor_) - .def_readwrite("postprocessor", &vision::ocr::Classifier::postprocessor_); + .def_readwrite("preprocessor", &vision::ocr::DBDetector::preprocessor_) + .def_readwrite("postprocessor", &vision::ocr::DBDetector::postprocessor_) + .def("predict", [](vision::ocr::DBDetector& self, + pybind11::array& data) { + auto mat = PyArrayToCvMat(data); + std::vector> boxes_result; + self.Predict(mat, &boxes_result); + return boxes_result; + }) + .def("batch_predict", [](vision::ocr::DBDetector& self, std::vector& data) { + std::vector images; + std::vector>> det_results; + for (size_t i = 0; i < data.size(); ++i) { + images.push_back(PyArrayToCvMat(data[i])); + } + self.BatchPredict(images, &det_results); + return det_results; + }); - pybind11::class_(m, "ClassifierPreprocessor") + // Classifier + pybind11::class_(m, "ClassifierPreprocessor") .def(pybind11::init<>()) .def_readwrite("cls_image_shape", &vision::ocr::ClassifierPreprocessor::cls_image_shape_) .def_readwrite("mean", &vision::ocr::ClassifierPreprocessor::mean_) @@ -116,7 +126,7 @@ void BindPPOCRModel(pybind11::module& m) { if (!self.Run(inputs, &cls_labels, &cls_scores)) { throw std::runtime_error("Failed to preprocess the input data in ClassifierPostprocessor."); } - return make_pair(cls_labels,cls_scores); + return std::make_pair(cls_labels,cls_scores); }) .def("run", [](vision::ocr::ClassifierPostprocessor& self, std::vector& input_array) { @@ -127,39 +137,56 @@ void BindPPOCRModel(pybind11::module& m) { if (!self.Run(inputs, &cls_labels, &cls_scores)) { throw std::runtime_error("Failed to preprocess the input data in ClassifierPostprocessor."); } - return make_pair(cls_labels,cls_scores); + return std::make_pair(cls_labels,cls_scores); }); - - - // Recognizer - pybind11::class_(m, "Recognizer") - .def(pybind11::init(m, "Classifier") + .def(pybind11::init()) .def(pybind11::init<>()) - .def_readwrite("preprocessor", &vision::ocr::Recognizer::preprocessor_) - .def_readwrite("postprocessor", &vision::ocr::Recognizer::postprocessor_); - - pybind11::class_(m, "RecognizerPreprocessor") - .def(pybind11::init<>()) - .def_readwrite("rec_image_shape", &vision::ocr::RecognizerPreprocessor::rec_image_shape_) - .def_readwrite("mean", &vision::ocr::RecognizerPreprocessor::mean_) - .def_readwrite("scale", &vision::ocr::RecognizerPreprocessor::scale_) - .def_readwrite("is_scale", &vision::ocr::RecognizerPreprocessor::is_scale_) - .def("run", [](vision::ocr::RecognizerPreprocessor& self, std::vector& im_list) { - std::vector images; - for (size_t i = 0; i < im_list.size(); ++i) { - images.push_back(vision::WrapMat(PyArrayToCvMat(im_list[i]))); - } - std::vector outputs; - if (!self.Run(&images, &outputs)) { - throw std::runtime_error("Failed to preprocess the input data in RecognizerPreprocessor."); - } - for(size_t i = 0; i< outputs.size(); ++i){ - outputs[i].StopSharing(); + .def_readwrite("preprocessor", &vision::ocr::Classifier::preprocessor_) + .def_readwrite("postprocessor", &vision::ocr::Classifier::postprocessor_) + .def("predict", [](vision::ocr::Classifier& self, + pybind11::array& data) { + auto mat = PyArrayToCvMat(data); + int32_t cls_label; + float cls_score; + self.Predict(mat, &cls_label, &cls_score); + return std::make_pair(cls_label, cls_score); + }) + .def("batch_predict", [](vision::ocr::Classifier& self, std::vector& data) { + std::vector images; + std::vector cls_labels; + std::vector cls_scores; + for (size_t i = 0; i < data.size(); ++i) { + images.push_back(PyArrayToCvMat(data[i])); } - return outputs; + self.BatchPredict(images, &cls_labels, &cls_scores); + return std::make_pair(cls_labels, cls_scores); }); + // Recognizer + pybind11::class_(m, "RecognizerPreprocessor") + .def(pybind11::init<>()) + .def_readwrite("rec_image_shape", &vision::ocr::RecognizerPreprocessor::rec_image_shape_) + .def_readwrite("mean", &vision::ocr::RecognizerPreprocessor::mean_) + .def_readwrite("scale", &vision::ocr::RecognizerPreprocessor::scale_) + .def_readwrite("is_scale", &vision::ocr::RecognizerPreprocessor::is_scale_) + .def("run", [](vision::ocr::RecognizerPreprocessor& self, std::vector& im_list) { + std::vector images; + for (size_t i = 0; i < im_list.size(); ++i) { + images.push_back(vision::WrapMat(PyArrayToCvMat(im_list[i]))); + } + std::vector outputs; + if (!self.Run(&images, &outputs)) { + throw std::runtime_error("Failed to preprocess the input data in RecognizerPreprocessor."); + } + for(size_t i = 0; i< outputs.size(); ++i){ + outputs[i].StopSharing(); + } + return outputs; + }); + pybind11::class_(m, "RecognizerPostprocessor") .def(pybind11::init()) .def("run", [](vision::ocr::RecognizerPostprocessor& self, @@ -169,7 +196,7 @@ void BindPPOCRModel(pybind11::module& m) { if (!self.Run(inputs, &texts, &rec_scores)) { throw std::runtime_error("Failed to preprocess the input data in RecognizerPostprocessor."); } - return make_pair(texts, rec_scores); + return std::make_pair(texts, rec_scores); }) .def("run", [](vision::ocr::RecognizerPostprocessor& self, std::vector& input_array) { @@ -180,7 +207,32 @@ void BindPPOCRModel(pybind11::module& m) { if (!self.Run(inputs, &texts, &rec_scores)) { throw std::runtime_error("Failed to preprocess the input data in RecognizerPostprocessor."); } - return make_pair(texts, rec_scores); + return std::make_pair(texts, rec_scores); + }); + + pybind11::class_(m, "Recognizer") + .def(pybind11::init()) + .def(pybind11::init<>()) + .def_readwrite("preprocessor", &vision::ocr::Recognizer::preprocessor_) + .def_readwrite("postprocessor", &vision::ocr::Recognizer::postprocessor_) + .def("predict", [](vision::ocr::Recognizer& self, + pybind11::array& data) { + auto mat = PyArrayToCvMat(data); + std::string text; + float rec_score; + self.Predict(mat, &text, &rec_score); + return std::make_pair(text, rec_score); + }) + .def("batch_predict", [](vision::ocr::Recognizer& self, std::vector& data) { + std::vector images; + std::vector texts; + std::vector rec_scores; + for (size_t i = 0; i < data.size(); ++i) { + images.push_back(PyArrayToCvMat(data[i])); + } + self.BatchPredict(images, &texts, &rec_scores); + return std::make_pair(texts, rec_scores); }); } } // namespace fastdeploy diff --git a/fastdeploy/vision/ocr/ppocr/ppocr_pybind.cc b/fastdeploy/vision/ocr/ppocr/ppocr_pybind.cc index fcbbe02242..7542793fe7 100755 --- a/fastdeploy/vision/ocr/ppocr/ppocr_pybind.cc +++ b/fastdeploy/vision/ocr/ppocr/ppocr_pybind.cc @@ -25,6 +25,8 @@ void BindPPOCRv3(pybind11::module& m) { fastdeploy::vision::ocr::Recognizer*>()) .def(pybind11::init()) + .def_property("cls_batch_size", &pipeline::PPOCRv3::GetClsBatchSize, &pipeline::PPOCRv3::SetClsBatchSize) + .def_property("rec_batch_size", &pipeline::PPOCRv3::GetRecBatchSize, &pipeline::PPOCRv3::SetRecBatchSize) .def("predict", [](pipeline::PPOCRv3& self, pybind11::array& data) { auto mat = PyArrayToCvMat(data); @@ -52,6 +54,8 @@ void BindPPOCRv2(pybind11::module& m) { fastdeploy::vision::ocr::Recognizer*>()) .def(pybind11::init()) + .def_property("cls_batch_size", &pipeline::PPOCRv2::GetClsBatchSize, &pipeline::PPOCRv2::SetClsBatchSize) + .def_property("rec_batch_size", &pipeline::PPOCRv2::GetRecBatchSize, &pipeline::PPOCRv2::SetRecBatchSize) .def("predict", [](pipeline::PPOCRv2& self, pybind11::array& data) { auto mat = PyArrayToCvMat(data); diff --git a/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc b/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc index daa40692d4..2ee2f903f6 100755 --- a/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc +++ b/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc @@ -33,6 +33,32 @@ PPOCRv2::PPOCRv2(fastdeploy::vision::ocr::DBDetector* det_model, recognizer_->preprocessor_.rec_image_shape_[1] = 32; } +bool PPOCRv2::SetClsBatchSize(int cls_batch_size) { + if (cls_batch_size < -1 || cls_batch_size == 0) { + FDERROR << "batch_size > 0 or batch_size == -1." << std::endl; + return false; + } + cls_batch_size_ = cls_batch_size; + return true; +} + +int PPOCRv2::GetClsBatchSize() { + return cls_batch_size_; +} + +bool PPOCRv2::SetRecBatchSize(int rec_batch_size) { + if (rec_batch_size < -1 || rec_batch_size == 0) { + FDERROR << "batch_size > 0 or batch_size == -1." << std::endl; + return false; + } + rec_batch_size_ = rec_batch_size; + return true; +} + +int PPOCRv2::GetRecBatchSize() { + return rec_batch_size_; +} + bool PPOCRv2::Initialized() const { if (detector_ != nullptr && !detector_->Initialized()) { @@ -52,7 +78,10 @@ bool PPOCRv2::Initialized() const { bool PPOCRv2::Predict(cv::Mat* img, fastdeploy::vision::OCRResult* result) { std::vector batch_result(1); - BatchPredict({*img},&batch_result); + bool success = BatchPredict({*img},&batch_result); + if(!success){ + return success; + } *result = std::move(batch_result[0]); return true; }; @@ -67,12 +96,12 @@ bool PPOCRv2::BatchPredict(const std::vector& images, FDERROR << "There's error while detecting image in PPOCR." << std::endl; return false; } + for(int i_batch = 0; i_batch < batch_boxes.size(); ++i_batch) { vision::ocr::SortBoxes(&(batch_boxes[i_batch])); (*batch_result)[i_batch].boxes = batch_boxes[i_batch]; } - for(int i_batch = 0; i_batch < images.size(); ++i_batch) { fastdeploy::vision::OCRResult& ocr_result = (*batch_result)[i_batch]; // Get croped images by detection result @@ -93,22 +122,34 @@ bool PPOCRv2::BatchPredict(const std::vector& images, std::vector* text_ptr = &ocr_result.text; std::vector* rec_scores_ptr = &ocr_result.rec_scores; - if (nullptr != classifier_){ - if (!classifier_->BatchPredict(image_list, cls_labels_ptr, cls_scores_ptr)) { - FDERROR << "There's error while recognizing image in PPOCR." << std::endl; - return false; - }else{ - for (size_t i_img = 0; i_img < image_list.size(); ++i_img) { - if(cls_labels_ptr->at(i_img) % 2 == 1 && cls_scores_ptr->at(i_img) > classifier_->postprocessor_.cls_thresh_) { - cv::rotate(image_list[i_img], image_list[i_img], 1); + if (nullptr != classifier_) { + for(size_t start_index = 0; start_index < image_list.size(); start_index+=cls_batch_size_) { + size_t end_index = std::min(start_index + cls_batch_size_, image_list.size()); + if (!classifier_->BatchPredict(image_list, cls_labels_ptr, cls_scores_ptr, start_index, end_index)) { + FDERROR << "There's error while recognizing image in PPOCR." << std::endl; + return false; + }else{ + for (size_t i_img = start_index; i_img < end_index; ++i_img) { + if(cls_labels_ptr->at(i_img) % 2 == 1 && cls_scores_ptr->at(i_img) > classifier_->postprocessor_.cls_thresh_) { + cv::rotate(image_list[i_img], image_list[i_img], 1); + } } } } } - - if (!recognizer_->BatchPredict(image_list, text_ptr, rec_scores_ptr)) { - FDERROR << "There's error while recognizing image in PPOCR." << std::endl; - return false; + + std::vector width_list; + for (int i = 0; i < image_list.size(); i++) { + width_list.push_back(float(image_list[i].cols) / image_list[i].rows); + } + std::vector indices = vision::ocr::ArgSort(width_list); + + for(size_t start_index = 0; start_index < image_list.size(); start_index+=rec_batch_size_) { + size_t end_index = std::min(start_index + rec_batch_size_, image_list.size()); + if (!recognizer_->BatchPredict(image_list, text_ptr, rec_scores_ptr, start_index, end_index, indices)) { + FDERROR << "There's error while recognizing image in PPOCR." << std::endl; + return false; + } } } return true; diff --git a/fastdeploy/vision/ocr/ppocr/ppocr_v2.h b/fastdeploy/vision/ocr/ppocr/ppocr_v2.h index d021d6c32d..05f2b9309f 100755 --- a/fastdeploy/vision/ocr/ppocr/ppocr_v2.h +++ b/fastdeploy/vision/ocr/ppocr/ppocr_v2.h @@ -68,11 +68,19 @@ class FASTDEPLOY_DECL PPOCRv2 : public FastDeployModel { virtual bool BatchPredict(const std::vector& images, std::vector* batch_result); bool Initialized() const override; + bool SetClsBatchSize(int cls_batch_size); + int GetClsBatchSize(); + bool SetRecBatchSize(int rec_batch_size); + int GetRecBatchSize(); protected: fastdeploy::vision::ocr::DBDetector* detector_ = nullptr; fastdeploy::vision::ocr::Classifier* classifier_ = nullptr; fastdeploy::vision::ocr::Recognizer* recognizer_ = nullptr; + + private: + int cls_batch_size_ = 1; + int rec_batch_size_ = 6; /// Launch the detection process in OCR. }; diff --git a/fastdeploy/vision/ocr/ppocr/rec_postprocessor.cc b/fastdeploy/vision/ocr/ppocr/rec_postprocessor.cc index cdc302e28c..d93c16907a 100644 --- a/fastdeploy/vision/ocr/ppocr/rec_postprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/rec_postprocessor.cc @@ -34,7 +34,7 @@ std::vector ReadDict(const std::string& path) { } RecognizerPostprocessor::RecognizerPostprocessor(){ - initialized_ = true; + initialized_ = false; } RecognizerPostprocessor::RecognizerPostprocessor(const std::string& label_path) { @@ -84,24 +84,53 @@ bool RecognizerPostprocessor::SingleBatchPostprocessor(const float* out_data, bool RecognizerPostprocessor::Run(const std::vector& tensors, std::vector* texts, std::vector* rec_scores) { + // Recognizer have only 1 output tensor. + // For Recognizer, the output tensor shape = [batch, ?, 6625] + size_t total_size = tensors[0].shape[0]; + return Run(tensors, texts, rec_scores, 0, total_size, {}); +} + +bool RecognizerPostprocessor::Run(const std::vector& tensors, + std::vector* texts, std::vector* rec_scores, + size_t start_index, size_t total_size, const std::vector& indices) { if (!initialized_) { FDERROR << "Postprocessor is not initialized." << std::endl; return false; } + // Recognizer have only 1 output tensor. const FDTensor& tensor = tensors[0]; // For Recognizer, the output tensor shape = [batch, ?, 6625] size_t batch = tensor.shape[0]; size_t length = accumulate(tensor.shape.begin()+1, tensor.shape.end(), 1, std::multiplies()); - texts->resize(batch); - rec_scores->resize(batch); + if (batch <= 0) { + FDERROR << "The infer outputTensor.shape[0] <=0, wrong infer result." << std::endl; + return false; + } + if (start_index < 0 || total_size <= 0) { + FDERROR << "start_index or total_size error. Correct is: 0 <= start_index < total_size" << std::endl; + return false; + } + if ((start_index + batch) > total_size) { + FDERROR << "start_index or total_size error. Correct is: start_index + batch(outputTensor.shape[0]) <= total_size" << std::endl; + return false; + } + texts->resize(total_size); + rec_scores->resize(total_size); + const float* tensor_data = reinterpret_cast(tensor.Data()); - for (int i_batch = 0; i_batch < batch; ++i_batch) { - if(!SingleBatchPostprocessor(tensor_data, tensor.shape, &texts->at(i_batch), &rec_scores->at(i_batch))) { + for (int i_batch = 0; i_batch < batch; ++i_batch) { + size_t real_index = i_batch+start_index; + if (indices.size() != 0) { + real_index = indices[i_batch+start_index]; + } + if(!SingleBatchPostprocessor(tensor_data + i_batch * length, + tensor.shape, + &texts->at(real_index), + &rec_scores->at(real_index))) { return false; } - tensor_data = tensor_data + length; } return true; diff --git a/fastdeploy/vision/ocr/ppocr/rec_postprocessor.h b/fastdeploy/vision/ocr/ppocr/rec_postprocessor.h index d1aa0124b4..711ae3a014 100644 --- a/fastdeploy/vision/ocr/ppocr/rec_postprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/rec_postprocessor.h @@ -32,7 +32,7 @@ class FASTDEPLOY_DECL RecognizerPostprocessor { */ explicit RecognizerPostprocessor(const std::string& label_path); - /** \brief Process the result of runtime and fill to ClassifyResult structure + /** \brief Process the result of runtime and fill to RecognizerResult * * \param[in] tensors The inference result from runtime * \param[in] texts The output result of recognizer @@ -42,6 +42,11 @@ class FASTDEPLOY_DECL RecognizerPostprocessor { bool Run(const std::vector& tensors, std::vector* texts, std::vector* rec_scores); + bool Run(const std::vector& tensors, + std::vector* texts, std::vector* rec_scores, + size_t start_index, size_t total_size, + const std::vector& indices); + private: bool SingleBatchPostprocessor(const float* out_data, const std::vector& output_shape, diff --git a/fastdeploy/vision/ocr/ppocr/rec_preprocessor.cc b/fastdeploy/vision/ocr/ppocr/rec_preprocessor.cc index 858578d690..a965eb7624 100644 --- a/fastdeploy/vision/ocr/ppocr/rec_preprocessor.cc +++ b/fastdeploy/vision/ocr/ppocr/rec_preprocessor.cc @@ -21,69 +21,75 @@ namespace fastdeploy { namespace vision { namespace ocr { -RecognizerPreprocessor::RecognizerPreprocessor() { - initialized_ = true; -} - void OcrRecognizerResizeImage(FDMat* mat, float max_wh_ratio, const std::vector& rec_image_shape) { - int imgC, imgH, imgW; - imgC = rec_image_shape[0]; - imgH = rec_image_shape[1]; - imgW = rec_image_shape[2]; + int img_c, img_h, img_w; + img_c = rec_image_shape[0]; + img_h = rec_image_shape[1]; + img_w = rec_image_shape[2]; - imgW = int(imgH * max_wh_ratio); + img_w = int(img_h * max_wh_ratio); float ratio = float(mat->Width()) / float(mat->Height()); int resize_w; - if (ceilf(imgH * ratio) > imgW) { - resize_w = imgW; + if (ceilf(img_h * ratio) > img_w) { + resize_w = img_w; }else{ - resize_w = int(ceilf(imgH * ratio)); + resize_w = int(ceilf(img_h * ratio)); } - Resize::Run(mat, resize_w, imgH); + Resize::Run(mat, resize_w, img_h); std::vector value = {0, 0, 0}; - Pad::Run(mat, 0, 0, 0, int(imgW - mat->Width()), value); + Pad::Run(mat, 0, 0, 0, int(img_w - mat->Width()), value); } bool RecognizerPreprocessor::Run(std::vector* images, std::vector* outputs) { - if (!initialized_) { - FDERROR << "The preprocessor is not initialized." << std::endl; - return false; - } - if (images->size() == 0) { - FDERROR << "The size of input images should be greater than 0." << std::endl; + return Run(images, outputs, 0, images->size(), {}); +} + +bool RecognizerPreprocessor::Run(std::vector* images, std::vector* outputs, + size_t start_index, size_t end_index, const std::vector& indices) { + if (images->size() == 0 || end_index <= start_index || end_index > images->size()) { + FDERROR << "images->size() or index error. Correct is: 0 <= start_index < end_index <= images->size()" << std::endl; return false; } - int imgH = rec_image_shape_[1]; - int imgW = rec_image_shape_[2]; - float max_wh_ratio = imgW * 1.0 / imgH; + int img_h = rec_image_shape_[1]; + int img_w = rec_image_shape_[2]; + float max_wh_ratio = img_w * 1.0 / img_h; float ori_wh_ratio; - for (size_t i = 0; i < images->size(); ++i) { - FDMat* mat = &(images->at(i)); + for (size_t i = start_index; i < end_index; ++i) { + size_t real_index = i; + if (indices.size() != 0) { + real_index = indices[i]; + } + FDMat* mat = &(images->at(real_index)); ori_wh_ratio = mat->Width() * 1.0 / mat->Height(); max_wh_ratio = std::max(max_wh_ratio, ori_wh_ratio); } - for (size_t i = 0; i < images->size(); ++i) { - FDMat* mat = &(images->at(i)); + for (size_t i = start_index; i < end_index; ++i) { + size_t real_index = i; + if (indices.size() != 0) { + real_index = indices[i]; + } + FDMat* mat = &(images->at(real_index)); OcrRecognizerResizeImage(mat, max_wh_ratio, rec_image_shape_); NormalizeAndPermute::Run(mat, mean_, scale_, is_scale_); - /* - Normalize::Run(mat, mean_, scale_, is_scale_); - HWC2CHW::Run(mat); - Cast::Run(mat, "float"); - */ } // Only have 1 output Tensor. outputs->resize(1); + size_t tensor_size = end_index-start_index; // Concat all the preprocessed data to a batch tensor - std::vector tensors(images->size()); - for (size_t i = 0; i < images->size(); ++i) { - (*images)[i].ShareWithTensor(&(tensors[i])); + std::vector tensors(tensor_size); + for (size_t i = 0; i < tensor_size; ++i) { + size_t real_index = i + start_index; + if (indices.size() != 0) { + real_index = indices[i + start_index]; + } + + (*images)[real_index].ShareWithTensor(&(tensors[i])); tensors[i].ExpandDim(0); } if (tensors.size() == 1) { diff --git a/fastdeploy/vision/ocr/ppocr/rec_preprocessor.h b/fastdeploy/vision/ocr/ppocr/rec_preprocessor.h index 3e5c7de824..1dad75870b 100644 --- a/fastdeploy/vision/ocr/ppocr/rec_preprocessor.h +++ b/fastdeploy/vision/ocr/ppocr/rec_preprocessor.h @@ -24,12 +24,6 @@ namespace ocr { */ class FASTDEPLOY_DECL RecognizerPreprocessor { public: - /** \brief Create a preprocessor instance for PaddleClas serials model - * - * \param[in] config_file Path of configuration file for deployment, e.g resnet/infer_cfg.yml - */ - RecognizerPreprocessor(); - /** \brief Process the input image and prepare input tensors for runtime * * \param[in] images The input image data list, all the elements are returned by cv::imread() @@ -37,14 +31,14 @@ class FASTDEPLOY_DECL RecognizerPreprocessor { * \return true if the preprocess successed, otherwise false */ bool Run(std::vector* images, std::vector* outputs); + bool Run(std::vector* images, std::vector* outputs, + size_t start_index, size_t end_index, + const std::vector& indices); std::vector rec_image_shape_ = {3, 48, 320}; std::vector mean_ = {0.5f, 0.5f, 0.5f}; std::vector scale_ = {0.5f, 0.5f, 0.5f}; bool is_scale_ = true; - - private: - bool initialized_ = false; }; } // namespace ocr diff --git a/fastdeploy/vision/ocr/ppocr/recognizer.cc b/fastdeploy/vision/ocr/ppocr/recognizer.cc index 59d64a6c45..a20f312c27 100755 --- a/fastdeploy/vision/ocr/ppocr/recognizer.cc +++ b/fastdeploy/vision/ocr/ppocr/recognizer.cc @@ -53,10 +53,33 @@ bool Recognizer::Initialize() { return true; } +bool Recognizer::Predict(cv::Mat& img, std::string* text, float* rec_score) { + std::vector texts(1); + std::vector rec_scores(1); + bool success = BatchPredict({img}, &texts, &rec_scores); + if (!success) { + return success; + } + *text = std::move(texts[0]); + *rec_score = rec_scores[0]; + return true; +} + bool Recognizer::BatchPredict(const std::vector& images, std::vector* texts, std::vector* rec_scores) { + return BatchPredict(images, texts, rec_scores, 0, images.size(), {}); +} + +bool Recognizer::BatchPredict(const std::vector& images, + std::vector* texts, std::vector* rec_scores, + size_t start_index, size_t end_index, const std::vector& indices) { + size_t total_size = images.size(); + if (indices.size() != 0 && indices.size() != total_size) { + FDERROR << "indices.size() should be 0 or images.size()." << std::endl; + return false; + } std::vector fd_images = WrapMat(images); - if (!preprocessor_.Run(&fd_images, &reused_input_tensors_)) { + if (!preprocessor_.Run(&fd_images, &reused_input_tensors_, start_index, end_index, indices)) { FDERROR << "Failed to preprocess the input image." << std::endl; return false; } @@ -66,7 +89,7 @@ bool Recognizer::BatchPredict(const std::vector& images, return false; } - if (!postprocessor_.Run(reused_output_tensors_, texts, rec_scores)) { + if (!postprocessor_.Run(reused_output_tensors_, texts, rec_scores, start_index, total_size, indices)) { FDERROR << "Failed to postprocess the inference cls_results by runtime." << std::endl; return false; } diff --git a/fastdeploy/vision/ocr/ppocr/recognizer.h b/fastdeploy/vision/ocr/ppocr/recognizer.h index 1cd841eb45..4ee12bb6a5 100755 --- a/fastdeploy/vision/ocr/ppocr/recognizer.h +++ b/fastdeploy/vision/ocr/ppocr/recognizer.h @@ -45,6 +45,7 @@ class FASTDEPLOY_DECL Recognizer : public FastDeployModel { const ModelFormat& model_format = ModelFormat::PADDLE); /// Get model's name std::string ModelName() const { return "ppocr/ocr_rec"; } + virtual bool Predict(cv::Mat& img, std::string* text, float* rec_score); /** \brief BatchPredict the input image and get OCR recognition model result. * * \param[in] images The list of input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. @@ -53,6 +54,10 @@ class FASTDEPLOY_DECL Recognizer : public FastDeployModel { */ virtual bool BatchPredict(const std::vector& images, std::vector* texts, std::vector* rec_scores); + virtual bool BatchPredict(const std::vector& images, + std::vector* texts, std::vector* rec_scores, + size_t start_index, size_t end_index, + const std::vector& indices); RecognizerPreprocessor preprocessor_; RecognizerPostprocessor postprocessor_; diff --git a/fastdeploy/vision/ocr/ppocr/utils/ocr_utils.h b/fastdeploy/vision/ocr/ppocr/utils/ocr_utils.h old mode 100644 new mode 100755 index 0e5c040eb8..f12f40f71f --- a/fastdeploy/vision/ocr/ppocr/utils/ocr_utils.h +++ b/fastdeploy/vision/ocr/ppocr/utils/ocr_utils.h @@ -33,6 +33,8 @@ FASTDEPLOY_DECL cv::Mat GetRotateCropImage(const cv::Mat& srcimage, FASTDEPLOY_DECL void SortBoxes(std::vector>* boxes); +FASTDEPLOY_DECL std::vector ArgSort(const std::vector &array); + } // namespace ocr } // namespace vision } // namespace fastdeploy diff --git a/fastdeploy/vision/ocr/ppocr/utils/sorted_boxes.cc b/fastdeploy/vision/ocr/ppocr/utils/sorted_boxes.cc old mode 100644 new mode 100755 index b55d2a9eb9..053215e4a6 --- a/fastdeploy/vision/ocr/ppocr/utils/sorted_boxes.cc +++ b/fastdeploy/vision/ocr/ppocr/utils/sorted_boxes.cc @@ -35,13 +35,29 @@ void SortBoxes(std::vector>* boxes) { if (boxes->size() == 0) { return; } - + for (int i = 0; i < boxes->size() - 1; i++) { - if (std::abs((*boxes)[i + 1][1] - (*boxes)[i][1]) < 10 && - ((*boxes)[i + 1][0] < (*boxes)[i][0])) { - std::swap((*boxes)[i], (*boxes)[i + 1]); + for (int j = i; j >=0 ; j--){ + if (std::abs((*boxes)[j + 1][1] - (*boxes)[j][1]) < 10 && + ((*boxes)[j + 1][0] < (*boxes)[j][0])) { + std::swap((*boxes)[i], (*boxes)[i + 1]); + } } } + +} + +std::vector ArgSort(const std::vector &array) { + const int array_len(array.size()); + std::vector array_index(array_len, 0); + for (int i = 0; i < array_len; ++i) + array_index[i] = i; + + std::sort( + array_index.begin(), array_index.end(), + [&array](int pos1, int pos2) { return (array[pos1] < array[pos2]); }); + + return array_index; } } // namespace ocr diff --git a/fastdeploy/vision/segmentation/ppseg/model.cc b/fastdeploy/vision/segmentation/ppseg/model.cc old mode 100644 new mode 100755 index 1bf83131cf..ad2a7773a9 --- a/fastdeploy/vision/segmentation/ppseg/model.cc +++ b/fastdeploy/vision/segmentation/ppseg/model.cc @@ -27,6 +27,7 @@ PaddleSegModel::PaddleSegModel(const std::string& model_file, valid_cpu_backends = {Backend::OPENVINO, Backend::PDINFER, Backend::ORT, Backend::LITE}; valid_gpu_backends = {Backend::PDINFER, Backend::ORT, Backend::TRT}; valid_rknpu_backends = {Backend::RKNPU2}; + valid_timvx_backends = {Backend::LITE}; runtime_option = custom_option; runtime_option.model_format = model_format; runtime_option.model_file = model_file; diff --git a/fastdeploy/vision/segmentation/ppseg/postprocessor.cc b/fastdeploy/vision/segmentation/ppseg/postprocessor.cc index a2acb8ef7a..953cf2c687 100644 --- a/fastdeploy/vision/segmentation/ppseg/postprocessor.cc +++ b/fastdeploy/vision/segmentation/ppseg/postprocessor.cc @@ -280,13 +280,17 @@ bool PaddleSegPostprocessor::Run( FDMat mat; std::vector uint8_result_buffer; + // Resize interpration + int interpolation = cv::INTER_LINEAR; if (is_resized) { if (infer_results_dtype == FDDataType::INT64 || infer_results_dtype == FDDataType::INT32 ){ - FDTensorCast2Uint8(&infer_result, infer_chw, &uint8_result_buffer); - } + FDTensorCast2Uint8(&infer_result, infer_chw, &uint8_result_buffer); + // label map resize with nearest interpolation + interpolation = cv::INTER_NEAREST; + } mat = std::move(Mat::Create(infer_result, ProcLib::OPENCV)); - Resize::Run(&mat, input_width, input_height, -1.0f, -1.0f, 1, false, ProcLib::OPENCV); + Resize::Run(&mat, input_width, input_height, -1.0f, -1.0f, interpolation, false, ProcLib::OPENCV); mat.ShareWithTensor(&infer_result); } result->shape = infer_result.shape; diff --git a/fastdeploy/vision/segmentation/ppseg/postprocessor.h b/fastdeploy/vision/segmentation/ppseg/postprocessor.h index a42e253974..89c8371ee7 100644 --- a/fastdeploy/vision/segmentation/ppseg/postprocessor.h +++ b/fastdeploy/vision/segmentation/ppseg/postprocessor.h @@ -20,7 +20,8 @@ namespace fastdeploy { namespace vision { namespace segmentation { - +/*! @brief Postprocessor object for PaddleSeg serials model. + */ class FASTDEPLOY_DECL PaddleSegPostprocessor { public: /** \brief Create a postprocessor instance for PaddleSeg serials model diff --git a/fastdeploy/vision/segmentation/ppseg/preprocessor.h b/fastdeploy/vision/segmentation/ppseg/preprocessor.h index 77ac36d93e..faa7fb8de5 100644 --- a/fastdeploy/vision/segmentation/ppseg/preprocessor.h +++ b/fastdeploy/vision/segmentation/ppseg/preprocessor.h @@ -18,7 +18,8 @@ namespace fastdeploy { namespace vision { namespace segmentation { - +/*! @brief Preprocessor object for PaddleSeg serials model. + */ class FASTDEPLOY_DECL PaddleSegPreprocessor { public: /** \brief Create a preprocessor instance for PaddleSeg serials model diff --git a/fastdeploy/vision/visualize/segmentation.cc b/fastdeploy/vision/visualize/segmentation.cc index 43f8572507..9e4fe41494 100644 --- a/fastdeploy/vision/visualize/segmentation.cc +++ b/fastdeploy/vision/visualize/segmentation.cc @@ -25,6 +25,8 @@ namespace fastdeploy { namespace vision { #ifdef __ARM_NEON +static constexpr int VIS_SEG_OMP_NUM_THREADS=2; + static inline void QuantizeBlendingWeight8( float weight, uint8_t* old_multi_factor, uint8_t* new_multi_factor) { // Quantize the weight to boost blending performance. @@ -53,7 +55,8 @@ static cv::Mat FastVisSegmentationNEON( const uint8_t *im_ptr = static_cast(im.data); if (!quantize_weight) { - #pragma omp parallel for num_threads(2) schedule(static) + #pragma omp parallel for proc_bind(close) \ + num_threads(VIS_SEG_OMP_NUM_THREADS) schedule(static) for (int i = 0; i < size - 15; i += 16) { uint8x16_t labelx16 = vld1q_u8(label_ptr + i); // 16 bytes // e.g 0b00000001 << 7 -> 0b10000000 128; @@ -87,7 +90,8 @@ static cv::Mat FastVisSegmentationNEON( if (new_multi_factor == 8) { // Only keep mask, no need to blending with origin image. - #pragma omp parallel for num_threads(2) schedule(static) + #pragma omp parallel for proc_bind(close) \ + num_threads(VIS_SEG_OMP_NUM_THREADS) schedule(static) for (int i = 0; i < size - 15; i += 16) { uint8x16_t labelx16 = vld1q_u8(label_ptr + i); // 16 bytes // e.g 0b00000001 << 7 -> 0b10000000 128; @@ -112,7 +116,8 @@ static cv::Mat FastVisSegmentationNEON( uint8x16_t old_mulx16 = vdupq_n_u8(old_multi_factor); uint8x16_t new_mulx16 = vdupq_n_u8(new_multi_factor); // Blend the two colors together with quantize 'weight'. - #pragma omp parallel for num_threads(2) schedule(static) + #pragma omp parallel for proc_bind(close) \ + num_threads(VIS_SEG_OMP_NUM_THREADS) schedule(static) for (int i = 0; i < size - 15; i += 16) { uint8x16x3_t bgrx16x3 = vld3q_u8(im_ptr + i * 3); // 48 bytes uint8x16_t labelx16 = vld1q_u8(label_ptr + i); // 16 bytes diff --git a/fastdeploy/vision/visualize/visualize.h b/fastdeploy/vision/visualize/visualize.h index ea543553fa..498944c231 100755 --- a/fastdeploy/vision/visualize/visualize.h +++ b/fastdeploy/vision/visualize/visualize.h @@ -20,9 +20,11 @@ #include "fastdeploy/vision/tracking/pptracking/model.h" namespace fastdeploy { +/** \brief All C++ FastDeploy Vision Models APIs are defined inside this namespace +* +*/ namespace vision { -// This class will deprecated, please not use it class FASTDEPLOY_DECL Visualize { public: static int num_classes_; @@ -52,35 +54,108 @@ class FASTDEPLOY_DECL Visualize { std::vector GenerateColorMap(int num_classes = 1000); cv::Mat RemoveSmallConnectedArea(const cv::Mat& alpha_pred, float threshold); +/** \brief Show the visualized results for detection models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] score_threshold threshold for result scores, the bounding box will not be shown if the score is less than score_threshold + * \param[in] line_size line size for bounding boxes + * \param[in] font_size font size for text + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisDetection(const cv::Mat& im, const DetectionResult& result, float score_threshold = 0.0, int line_size = 1, float font_size = 0.5f); +/** \brief Show the visualized results with custom labels for detection models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] labels the visualized result will show the bounding box contain class label + * \param[in] score_threshold threshold for result scores, the bounding box will not be shown if the score is less than score_threshold + * \param[in] line_size line size for bounding boxes + * \param[in] font_size font size for text + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisDetection(const cv::Mat& im, const DetectionResult& result, const std::vector& labels, float score_threshold = 0.0, int line_size = 1, float font_size = 0.5f); +/** \brief Show the visualized results for classification models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] top_k the length of return values, e.g., if topk==2, the result will include the 2 most possible class label for input image. + * \param[in] score_threshold threshold for top_k scores, the class will not be shown if the score is less than score_threshold + * \param[in] font_size font size + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisClassification( const cv::Mat& im, const ClassifyResult& result, int top_k = 5, float score_threshold = 0.0f, float font_size = 0.5f); +/** \brief Show the visualized results with custom labels for classification models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] labels custom labels for user, the visualized result will show the corresponding custom labels + * \param[in] top_k the length of return values, e.g., if topk==2, the result will include the 2 most possible class label for input image. + * \param[in] score_threshold threshold for top_k scores, the class will not be shown if the score is less than score_threshold + * \param[in] font_size font size + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisClassification( const cv::Mat& im, const ClassifyResult& result, const std::vector& labels, int top_k = 5, float score_threshold = 0.0f, float font_size = 0.5f); +/** \brief Show the visualized results for face detection models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] line_size line size for bounding boxes + * \param[in] font_size font size for text + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisFaceDetection(const cv::Mat& im, const FaceDetectionResult& result, int line_size = 1, float font_size = 0.5f); +/** \brief Show the visualized results for face alignment models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] line_size line size for circle point + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisFaceAlignment(const cv::Mat& im, const FaceAlignmentResult& result, int line_size = 1); +/** \brief Show the visualized results for segmentation models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] weight transparent weight of visualized result image + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisSegmentation(const cv::Mat& im, const SegmentationResult& result, float weight = 0.5); +/** \brief Show the visualized results for matting models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \param[in] remove_small_connected_area if remove_small_connected_area==true, the visualized result will not include the small connected areas + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisMatting(const cv::Mat& im, const MattingResult& result, bool remove_small_connected_area = false); +/** \brief Show the visualized results for Ocr models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result the result produced by model + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisOcr(const cv::Mat& im, const OCRResult& ocr_result); FASTDEPLOY_DECL cv::Mat VisMOT(const cv::Mat& img, const MOTResult& results, @@ -93,6 +168,13 @@ FASTDEPLOY_DECL cv::Mat SwapBackground(const cv::Mat& im, const cv::Mat& background, const SegmentationResult& result, int background_label); +/** \brief Show the visualized results for key point detection models + * + * \param[in] im the input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] results the result produced by model + * \param[in] conf_threshold threshold for result scores, the result will not be shown if the score is less than conf_threshold + * \return cv::Mat type stores the visualized results + */ FASTDEPLOY_DECL cv::Mat VisKeypointDetection(const cv::Mat& im, const KeyPointDetectionResult& results, float conf_threshold = 0.5f); diff --git a/java/android/README.md b/java/android/README.md index 4647d916be..d3328f344d 100644 --- a/java/android/README.md +++ b/java/android/README.md @@ -26,11 +26,11 @@ FastDeploy Android SDK 目前支持图像分类、目标检测、OCR文字识别
### 下载 FastDeploy Android SDK -Release版本(Java SDK 目前仅支持Android,当前版本为0.8.0 pre-release) +Release版本(Java SDK 目前仅支持Android,当前版本为 1.0.0) | 平台 | 文件 | 说明 | | :--- | :--- | :---- | -| Android Java SDK | [fastdeploy-android-sdk-0.8.0.aar](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-sdk-0.8.0.aar) | NDK 20 编译产出, minSdkVersion 15,targetSdkVersion 28 | +| Android Java SDK | [fastdeploy-android-sdk-1.0.0.aar](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-sdk-1.0.0.aar) | NDK 20 编译产出, minSdkVersion 15,targetSdkVersion 28 | 更多预编译库信息,请参考: [download_prebuilt_libraries.md](../../docs/cn/build_and_install/download_prebuilt_libraries.md) @@ -349,6 +349,8 @@ public class FaceDetectionResult { public class RuntimeOption { public void enableLiteFp16(); // 开启fp16精度推理 public void disableLiteFP16(); // 关闭fp16精度推理 + public void enableLiteInt8(); // 开启int8精度推理,针对量化模型 + public void disableLiteInt8(); // 关闭int8精度推理 public void setCpuThreadNum(int threadNum); // 设置线程数 public void setLitePowerMode(LitePowerMode mode); // 设置能耗模式 public void setLitePowerMode(String modeStr); // 通过字符串形式设置能耗模式 diff --git a/java/android/app/build.gradle b/java/android/app/build.gradle index a92d0a13c7..d58cb3dd57 100644 --- a/java/android/app/build.gradle +++ b/java/android/app/build.gradle @@ -19,7 +19,6 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - } dependencies { @@ -30,6 +29,7 @@ dependencies { implementation 'com.android.support:design:28.0.0' implementation 'org.jetbrains:annotations:15.0' // implementation project(path: ':fastdeploy') + implementation project(path: ':ui') //noinspection GradleDependency testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' @@ -68,6 +68,10 @@ def FD_MODEL = [ [ 'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/portrait_pp_humansegv2_lite_256x144_inference_model.tgz', 'dest': 'src/main/assets/models' + ], + [ + 'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/PP_TinyPose_128x96_infer.tgz', + 'dest': 'src/main/assets/models' ] ] @@ -80,7 +84,7 @@ def FD_JAVA_SDK = [ task downloadAndExtractModels(type: DefaultTask) { doFirst { - println "Downloading and extracting fastdeploy models ..." + println "[INFO] Downloading and extracting fastdeploy models ..." } doLast { String cachePath = "cache" @@ -90,19 +94,22 @@ task downloadAndExtractModels(type: DefaultTask) { FD_MODEL.eachWithIndex { model, index -> String[] modelPaths = model.src.split("/") String modelName = modelPaths[modelPaths.length - 1] + String modelPrefix = modelName.substring(0, modelName.length() - 4) // Download the target model if not exists - boolean copyFiles = !file("${model.dest}").exists() + boolean copyFiles = !file("${model.dest}/${modelPrefix}").exists() if (!file("${cachePath}/${modelName}").exists()) { - println "Downloading ${model.src} -> ${cachePath}/${modelName}" + println "[INFO] Downloading ${model.src} -> ${cachePath}/${modelName}" ant.get(src: model.src, dest: file("${cachePath}/${modelName}")) copyFiles = true } if (copyFiles) { - println "Coping ${cachePath}/${modelName} -> ${model.dest}" + println "[INFO] Taring ${cachePath}/${modelName} -> ${model.dest}/${modelPrefix}" copy { from tarTree("${cachePath}/${modelName}") into "${model.dest}" } + } else { + println "[INFO] ${model.dest}/${modelPrefix} already exists!" } } } @@ -110,7 +117,7 @@ task downloadAndExtractModels(type: DefaultTask) { task downloadAndExtractSDKs(type: DefaultTask) { doFirst { - println "Downloading and extracting fastdeploy android java sdk ..." + println "[INFO] Downloading and extracting fastdeploy android java sdk ..." } doLast { String cachePath = "cache" @@ -123,16 +130,18 @@ task downloadAndExtractSDKs(type: DefaultTask) { // Download the target SDK if not exists boolean copyFiles = !file("${sdk.dest}/${sdkName}").exists() if (!file("${cachePath}/${sdkName}").exists()) { - println "Downloading ${sdk.src} -> ${cachePath}/${sdkName}" + println "[INFO] Downloading ${sdk.src} -> ${cachePath}/${sdkName}" ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}")) copyFiles = true } if (copyFiles) { - println "Coping ${cachePath}/${sdkName} -> ${sdk.dest}/${sdkName}" + println "[INFO] Coping ${cachePath}/${sdkName} -> ${sdk.dest}/${sdkName}" copy { from "${cachePath}/${sdkName}" into "${sdk.dest}" } + } else { + println "[INFO] ${sdk.dest}/${sdkName} already exists!" } } } diff --git a/java/android/app/src/main/AndroidManifest.xml b/java/android/app/src/main/AndroidManifest.xml index 858ef04f62..9a809c9a43 100644 --- a/java/android/app/src/main/AndroidManifest.xml +++ b/java/android/app/src/main/AndroidManifest.xml @@ -15,12 +15,16 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + + diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationMainActivity.java index 54fece396c..7992a7f89f 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationMainActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationMainActivity.java @@ -1,8 +1,8 @@ package com.baidu.paddle.fastdeploy.app.examples.classification; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.readTxt; +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; +import static com.baidu.paddle.fastdeploy.ui.Utils.readTxt; import android.Manifest; import android.annotation.SuppressLint; @@ -20,7 +20,6 @@ import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -32,13 +31,12 @@ import com.baidu.paddle.fastdeploy.RuntimeOption; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; -import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter; -import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.adapter.BaseResultAdapter; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.vision.ClassifyResult; -import com.baidu.paddle.fastdeploy.vision.Visualize; import com.baidu.paddle.fastdeploy.vision.classification.PaddleClasModel; import java.math.BigDecimal; @@ -407,7 +405,7 @@ private void detail(Bitmap bitmap) { } } } - BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.classification_result_page_item, results); + BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.base_result_page_item, results); resultView.setAdapter(adapter); resultView.invalidate(); diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationSettingsActivity.java index 23ab16f9aa..2f5000195e 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationSettingsActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationSettingsActivity.java @@ -10,8 +10,8 @@ import android.support.v7.app.ActionBar; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; import java.util.ArrayList; import java.util.List; diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationWelcomeActivity.java new file mode 100644 index 0000000000..05396dfdd8 --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/classification/ClassificationWelcomeActivity.java @@ -0,0 +1,31 @@ +package com.baidu.paddle.fastdeploy.app.examples.classification; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class ClassificationWelcomeActivity extends Activity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.classification_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(ClassificationWelcomeActivity.this, ClassificationMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java index 1277117672..33e4acea19 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionMainActivity.java @@ -1,5 +1,9 @@ package com.baidu.paddle.fastdeploy.app.examples.detection; +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; +import static com.baidu.paddle.fastdeploy.ui.Utils.readTxt; + import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; @@ -16,7 +20,6 @@ import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -28,19 +31,15 @@ import com.baidu.paddle.fastdeploy.RuntimeOption; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; -import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter; -import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.adapter.BaseResultAdapter; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.vision.DetectionResult; import com.baidu.paddle.fastdeploy.vision.Visualize; import com.baidu.paddle.fastdeploy.vision.detection.PicoDet; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.readTxt; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -406,7 +405,7 @@ private void detail(Bitmap bitmap) { } } } - BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.detection_result_page_item, results); + BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.base_result_page_item, results); resultView.setAdapter(adapter); resultView.invalidate(); diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionSettingsActivity.java index 21984fdcc8..510a5a691f 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionSettingsActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionSettingsActivity.java @@ -10,8 +10,8 @@ import android.support.v7.app.ActionBar; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; -import com.baidu.paddle.fastdeploy.app.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; import java.util.ArrayList; import java.util.List; diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionWelcomeActivity.java new file mode 100644 index 0000000000..a5764a7378 --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/detection/DetectionWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.detection; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class DetectionWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.detection_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(DetectionWelcomeActivity.this, DetectionMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java index 1891f99e39..e92c9998e4 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java @@ -1,5 +1,8 @@ package com.baidu.paddle.fastdeploy.app.examples.facedet; +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; + import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; @@ -16,7 +19,6 @@ import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -28,18 +30,15 @@ import com.baidu.paddle.fastdeploy.RuntimeOption; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; -import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter; -import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.adapter.BaseResultAdapter; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.vision.FaceDetectionResult; import com.baidu.paddle.fastdeploy.vision.Visualize; import com.baidu.paddle.fastdeploy.vision.facedet.SCRFD; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -405,7 +404,7 @@ private void detail(Bitmap bitmap) { } } } - BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.facedet_result_page_item, results); + BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.base_result_page_item, results); resultView.setAdapter(adapter); resultView.invalidate(); diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetSettingsActivity.java index ed82c5b59f..d56251b734 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetSettingsActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetSettingsActivity.java @@ -10,8 +10,8 @@ import android.support.v7.app.ActionBar; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; import java.util.ArrayList; import java.util.List; diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetWelcomeActivity.java new file mode 100644 index 0000000000..f2fd6c53ef --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.facedet; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class FaceDetWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.facedet_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(FaceDetWelcomeActivity.this, FaceDetMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionMainActivity.java new file mode 100644 index 0000000000..ab7acc6245 --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionMainActivity.java @@ -0,0 +1,403 @@ +package com.baidu.paddle.fastdeploy.app.examples.keypointdetection; + +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.os.SystemClock; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import com.baidu.paddle.fastdeploy.RuntimeOption; +import com.baidu.paddle.fastdeploy.app.examples.R; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.vision.SegmentationResult; +import com.baidu.paddle.fastdeploy.vision.Visualize; +import com.baidu.paddle.fastdeploy.vision.KeyPointDetectionResult; +import com.baidu.paddle.fastdeploy.vision.keypointdetection.PPTinyPose; + +import java.util.ArrayList; +import java.util.List; + + +public class KeyPointDetectionMainActivity extends Activity implements View.OnClickListener, CameraSurfaceView.OnTextureChangedListener { + private static final String TAG = KeyPointDetectionMainActivity.class.getSimpleName(); + + CameraSurfaceView svPreview; + TextView tvStatus; + ImageButton btnSwitch; + ImageButton btnShutter; + ImageButton btnSettings; + ImageView realtimeToggleButton; + boolean isRealtimeStatusRunning = false; + ImageView backInPreview; + private ImageView albumSelectButton; + private View cameraPageView; + private ViewGroup resultPageView; + private ImageView resultImage; + private ImageView backInResult; + private ResultListView resultView; + private Bitmap shutterBitmap; + private Bitmap picBitmap; + private boolean isShutterBitmapCopied = false; + + public static final int TYPE_UNKNOWN = -1; + public static final int BTN_SHUTTER = 0; + public static final int ALBUM_SELECT = 1; + public static final int REALTIME_DETECT = 2; + private static int TYPE = REALTIME_DETECT; + + private static final int REQUEST_PERMISSION_CODE_STORAGE = 101; + private static final int INTENT_CODE_PICK_IMAGE = 100; + private static final int TIME_SLEEP_INTERVAL = 50; // ms + + long timeElapsed = 0; + long frameCounter = 0; + + // Call 'init' and 'release' manually later + PPTinyPose predictor = new PPTinyPose(); + private List results = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Fullscreen + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.keypointdetection_activity_main); + + // Clear all setting items to avoid app crashing due to the incorrect settings + initSettings(); + + // Check and request CAMERA and WRITE_EXTERNAL_STORAGE permissions + if (!checkAllPermissions()) { + requestAllPermissions(); + } + + // Init the camera preview and UI components + initView(); + } + + @SuppressLint("NonConstantResourceId") + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_switch: + svPreview.switchCamera(); + break; + case R.id.btn_shutter: + TYPE = BTN_SHUTTER; + shutterAndPauseCamera(); + resultView.setAdapter(null); + break; + case R.id.btn_settings: + startActivity(new Intent(this, KeyPointDetectionSettingsActivity.class)); + break; + case R.id.realtime_toggle_btn: + toggleRealtimeStyle(); + break; + case R.id.back_in_preview: + finish(); + break; + case R.id.album_select: + TYPE = ALBUM_SELECT; + // Judge whether authority has been granted. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + // If this permission was requested before the application but the user refused the request, this method will return true. + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE_STORAGE); + } else { + Intent intent = new Intent(Intent.ACTION_PICK); + intent.setType("image/*"); + startActivityForResult(intent, INTENT_CODE_PICK_IMAGE); + } + resultView.setAdapter(null); + break; + case R.id.back_in_result: + back(); + break; + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + back(); + } + + private void back() { + resultPageView.setVisibility(View.GONE); + cameraPageView.setVisibility(View.VISIBLE); + TYPE = REALTIME_DETECT; + isShutterBitmapCopied = false; + svPreview.onResume(); + results.clear(); + } + + private void shutterAndPauseCamera() { + new Thread(new Runnable() { + @Override + public void run() { + try { + // Sleep some times to ensure picture has been correctly shut. + Thread.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms + } catch (InterruptedException e) { + e.printStackTrace(); + } + runOnUiThread(new Runnable() { + @SuppressLint("SetTextI18n") + public void run() { + // These codes will run in main thread. + svPreview.onPause(); + cameraPageView.setVisibility(View.GONE); + resultPageView.setVisibility(View.VISIBLE); + if (shutterBitmap != null && !shutterBitmap.isRecycled()) { + detail(shutterBitmap); + } else { + new AlertDialog.Builder(KeyPointDetectionMainActivity.this) + .setTitle("Empty Result!") + .setMessage("Current picture is empty, please shutting it again!") + .setCancelable(true) + .show(); + } + } + }); + } + }).start(); + } + + private void copyBitmapFromCamera(Bitmap ARGB8888ImageBitmap) { + if (isShutterBitmapCopied || ARGB8888ImageBitmap == null) { + return; + } + if (!ARGB8888ImageBitmap.isRecycled()) { + synchronized (this) { + shutterBitmap = ARGB8888ImageBitmap.copy(Bitmap.Config.ARGB_8888, true); + } + SystemClock.sleep(TIME_SLEEP_INTERVAL); + isShutterBitmapCopied = true; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == INTENT_CODE_PICK_IMAGE) { + if (resultCode == Activity.RESULT_OK) { + cameraPageView.setVisibility(View.GONE); + resultPageView.setVisibility(View.VISIBLE); + Uri uri = data.getData(); + String path = getRealPathFromURI(this, uri); + Bitmap bitmap = decodeBitmap(path, 720, 1280); + picBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); + SystemClock.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms + detail(picBitmap); + } + } + } + + private void toggleRealtimeStyle() { + if (isRealtimeStatusRunning) { + isRealtimeStatusRunning = false; + realtimeToggleButton.setImageResource(R.drawable.realtime_stop_btn); + svPreview.setOnTextureChangedListener(this); + tvStatus.setVisibility(View.VISIBLE); + } else { + isRealtimeStatusRunning = true; + realtimeToggleButton.setImageResource(R.drawable.realtime_start_btn); + tvStatus.setVisibility(View.GONE); + isShutterBitmapCopied = false; + // Camera is still working but detecting loop is on pause. + svPreview.setOnTextureChangedListener(new CameraSurfaceView.OnTextureChangedListener() { + @Override + public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) { + if (TYPE == BTN_SHUTTER) { + copyBitmapFromCamera(ARGB8888ImageBitmap); + } + return false; + } + }); + } + } + + @Override + public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) { + if (TYPE == BTN_SHUTTER) { + copyBitmapFromCamera(ARGB8888ImageBitmap); + return false; + } + + boolean modified = false; + + long tc = System.currentTimeMillis(); + KeyPointDetectionResult result = predictor.predict(ARGB8888ImageBitmap); + timeElapsed += (System.currentTimeMillis() - tc); + + Visualize.visKeypointDetection(ARGB8888ImageBitmap, result, 0.f); + + modified = result.initialized(); + + frameCounter++; + if (frameCounter >= 30) { + final int fps = (int) (1000 / (timeElapsed / 30)); + runOnUiThread(new Runnable() { + @SuppressLint("SetTextI18n") + public void run() { + tvStatus.setText(Integer.toString(fps) + "fps"); + } + }); + frameCounter = 0; + timeElapsed = 0; + } + return modified; + } + + @Override + protected void onResume() { + super.onResume(); + // Reload settings and re-initialize the predictor + checkAndUpdateSettings(); + // Open camera until the permissions have been granted + if (!checkAllPermissions()) { + svPreview.disableCamera(); + } else { + svPreview.enableCamera(); + } + svPreview.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + svPreview.onPause(); + } + + @Override + protected void onDestroy() { + if (predictor != null) { + predictor.release(); + } + super.onDestroy(); + } + + public void initView() { + TYPE = REALTIME_DETECT; + // (1) EXPECTED_PREVIEW_WIDTH should mean 'height' and EXPECTED_PREVIEW_HEIGHT + // should mean 'width' if the camera display orientation is 90 | 270 degree + // (Hold the phone upright to record video) + // (2) Smaller resolution is more suitable for Human Pose detection on mobile + // device. So, we set this preview size (720,480) here. Reference: + // https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.5/configs/keypoint/tiny_pose + CameraSurfaceView.EXPECTED_PREVIEW_WIDTH = 720; + CameraSurfaceView.EXPECTED_PREVIEW_HEIGHT = 480; + svPreview = (CameraSurfaceView) findViewById(R.id.sv_preview); + svPreview.setOnTextureChangedListener(this); + + tvStatus = (TextView) findViewById(R.id.tv_status); + btnSwitch = (ImageButton) findViewById(R.id.btn_switch); + btnSwitch.setOnClickListener(this); + btnShutter = (ImageButton) findViewById(R.id.btn_shutter); + btnShutter.setOnClickListener(this); + btnSettings = (ImageButton) findViewById(R.id.btn_settings); + btnSettings.setOnClickListener(this); + realtimeToggleButton = findViewById(R.id.realtime_toggle_btn); + realtimeToggleButton.setOnClickListener(this); + backInPreview = findViewById(R.id.back_in_preview); + backInPreview.setOnClickListener(this); + albumSelectButton = findViewById(R.id.album_select); + albumSelectButton.setOnClickListener(this); + cameraPageView = findViewById(R.id.camera_page); + resultPageView = findViewById(R.id.result_page); + resultImage = findViewById(R.id.result_image); + backInResult = findViewById(R.id.back_in_result); + backInResult.setOnClickListener(this); + resultView = findViewById(R.id.result_list_view); + } + + private void detail(Bitmap bitmap) { + predictor.predict(bitmap, true, 5.f); + resultImage.setImageBitmap(bitmap); + } + + @SuppressLint("ApplySharedPref") + public void initSettings() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.clear(); + editor.commit(); + KeyPointDetectionSettingsActivity.resetSettings(); + } + + public void checkAndUpdateSettings() { + if (KeyPointDetectionSettingsActivity.checkAndUpdateSettings(this)) { + String realModelDir = getCacheDir() + "/" + KeyPointDetectionSettingsActivity.modelDir; + Utils.copyDirectoryFromAssets(this, KeyPointDetectionSettingsActivity.modelDir, realModelDir); + + String modelFile = realModelDir + "/" + "model.pdmodel"; + String paramsFile = realModelDir + "/" + "model.pdiparams"; + String configFile = realModelDir + "/" + "infer_cfg.yml"; + RuntimeOption option = new RuntimeOption(); + option.setCpuThreadNum(KeyPointDetectionSettingsActivity.cpuThreadNum); + option.setLitePowerMode(KeyPointDetectionSettingsActivity.cpuPowerMode); + if (Boolean.parseBoolean(KeyPointDetectionSettingsActivity.enableLiteFp16)) { + option.enableLiteFp16(); + } + predictor.setUseDark(true); + predictor.init(modelFile, paramsFile, configFile, option); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) { + new AlertDialog.Builder(KeyPointDetectionMainActivity.this) + .setTitle("Permission denied") + .setMessage("Click to force quit the app, then open Settings->Apps & notifications->Target " + + "App->Permissions to grant all of the permissions.") + .setCancelable(false) + .setPositiveButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + KeyPointDetectionMainActivity.this.finish(); + } + }).show(); + } + } + + private void requestAllPermissions() { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA}, 0); + } + + private boolean checkAllPermissions() { + return ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + && ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; + } + +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionSettingsActivity.java new file mode 100644 index 0000000000..d80abd7bdc --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionSettingsActivity.java @@ -0,0 +1,164 @@ +package com.baidu.paddle.fastdeploy.app.examples.keypointdetection; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.PreferenceManager; +import android.support.v7.app.ActionBar; + +import com.baidu.paddle.fastdeploy.app.examples.R; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; + +import java.util.ArrayList; +import java.util.List; + + +public class KeyPointDetectionSettingsActivity extends AppCompatPreferenceActivity implements + SharedPreferences.OnSharedPreferenceChangeListener { + private static final String TAG = KeyPointDetectionSettingsActivity.class.getSimpleName(); + + static public int selectedModelIdx = -1; + static public String modelDir = ""; + static public int cpuThreadNum = 2; + static public String cpuPowerMode = ""; + static public String enableLiteFp16 = "true"; + + ListPreference lpChoosePreInstalledModel = null; + EditTextPreference etModelDir = null; + ListPreference lpCPUThreadNum = null; + ListPreference lpCPUPowerMode = null; + ListPreference lpEnableLiteFp16 = null; + + List preInstalledModelDirs = null; + List preInstalledCPUThreadNums = null; + List preInstalledCPUPowerModes = null; + List preInstalledEnableLiteFp16s = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.keypointdetection_settting); + ActionBar supportActionBar = getSupportActionBar(); + if (supportActionBar != null) { + supportActionBar.setDisplayHomeAsUpEnabled(true); + } + + // Initialize pre-installed models + preInstalledModelDirs = new ArrayList(); + preInstalledCPUThreadNums = new ArrayList(); + preInstalledCPUPowerModes = new ArrayList(); + preInstalledEnableLiteFp16s = new ArrayList(); + preInstalledModelDirs.add(getString(R.string.KEYPOINT_DETECTION_MODEL_DIR_DEFAULT)); + preInstalledCPUThreadNums.add(getString(R.string.CPU_THREAD_NUM_DEFAULT)); + preInstalledCPUPowerModes.add(getString(R.string.CPU_POWER_MODE_DEFAULT)); + preInstalledEnableLiteFp16s.add(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + + // Setup UI components + lpChoosePreInstalledModel = + (ListPreference) findPreference(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY)); + String[] preInstalledModelNames = new String[preInstalledModelDirs.size()]; + for (int i = 0; i < preInstalledModelDirs.size(); i++) { + preInstalledModelNames[i] = preInstalledModelDirs.get(i).substring(preInstalledModelDirs.get(i).lastIndexOf("/") + 1); + } + lpChoosePreInstalledModel.setEntries(preInstalledModelNames); + lpChoosePreInstalledModel.setEntryValues(preInstalledModelDirs.toArray(new String[preInstalledModelDirs.size()])); + lpCPUThreadNum = (ListPreference) findPreference(getString(R.string.CPU_THREAD_NUM_KEY)); + lpCPUPowerMode = (ListPreference) findPreference(getString(R.string.CPU_POWER_MODE_KEY)); + etModelDir = (EditTextPreference) findPreference(getString(R.string.MODEL_DIR_KEY)); + etModelDir.setTitle("Model dir (SDCard: " + Utils.getSDCardDirectory() + ")"); + lpEnableLiteFp16 = (ListPreference) findPreference(getString(R.string.ENABLE_LITE_FP16_MODE_KEY)); + } + + @SuppressLint("ApplySharedPref") + private void reloadSettingsAndUpdateUI() { + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + + String selected_model_dir = sharedPreferences.getString(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY), + getString(R.string.KEYPOINT_DETECTION_MODEL_DIR_DEFAULT)); + int selected_model_idx = lpChoosePreInstalledModel.findIndexOfValue(selected_model_dir); + if (selected_model_idx >= 0 && selected_model_idx < preInstalledModelDirs.size() && selected_model_idx != selectedModelIdx) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(getString(R.string.MODEL_DIR_KEY), preInstalledModelDirs.get(selected_model_idx)); + editor.putString(getString(R.string.CPU_THREAD_NUM_KEY), preInstalledCPUThreadNums.get(selected_model_idx)); + editor.putString(getString(R.string.CPU_POWER_MODE_KEY), preInstalledCPUPowerModes.get(selected_model_idx)); + editor.putString(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT), preInstalledEnableLiteFp16s.get(selected_model_idx)); + editor.commit(); + lpChoosePreInstalledModel.setSummary(selected_model_dir); + selectedModelIdx = selected_model_idx; + } + + String model_dir = sharedPreferences.getString(getString(R.string.MODEL_DIR_KEY), + getString(R.string.KEYPOINT_DETECTION_MODEL_DIR_DEFAULT)); + String cpu_thread_num = sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY), + getString(R.string.CPU_THREAD_NUM_DEFAULT)); + String cpu_power_mode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY), + getString(R.string.CPU_POWER_MODE_DEFAULT)); + String enable_lite_fp16 = sharedPreferences.getString(getString(R.string.ENABLE_LITE_FP16_MODE_KEY), + getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + + etModelDir.setSummary(model_dir); + lpCPUThreadNum.setValue(cpu_thread_num); + lpCPUThreadNum.setSummary(cpu_thread_num); + lpCPUPowerMode.setValue(cpu_power_mode); + lpCPUPowerMode.setSummary(cpu_power_mode); + lpEnableLiteFp16.setValue(enable_lite_fp16); + lpEnableLiteFp16.setSummary(enable_lite_fp16); + } + + static boolean checkAndUpdateSettings(Context ctx) { + boolean settingsChanged = false; + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx); + + String model_dir = sharedPreferences.getString(ctx.getString(R.string.MODEL_DIR_KEY), + ctx.getString(R.string.KEYPOINT_DETECTION_MODEL_DIR_DEFAULT)); + settingsChanged |= !modelDir.equalsIgnoreCase(model_dir); + modelDir = model_dir; + + String cpu_thread_num = sharedPreferences.getString(ctx.getString(R.string.CPU_THREAD_NUM_KEY), + ctx.getString(R.string.CPU_THREAD_NUM_DEFAULT)); + settingsChanged |= cpuThreadNum != Integer.parseInt(cpu_thread_num); + cpuThreadNum = Integer.parseInt(cpu_thread_num); + + String cpu_power_mode = sharedPreferences.getString(ctx.getString(R.string.CPU_POWER_MODE_KEY), + ctx.getString(R.string.CPU_POWER_MODE_DEFAULT)); + settingsChanged |= !cpuPowerMode.equalsIgnoreCase(cpu_power_mode); + cpuPowerMode = cpu_power_mode; + + String enable_lite_fp16 = sharedPreferences.getString(ctx.getString(R.string.ENABLE_LITE_FP16_MODE_KEY), + ctx.getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); + settingsChanged |= !enableLiteFp16.equalsIgnoreCase(enable_lite_fp16); + enableLiteFp16 = enable_lite_fp16; + + return settingsChanged; + } + + static void resetSettings() { + selectedModelIdx = -1; + modelDir = ""; + cpuThreadNum = 2; + cpuPowerMode = ""; + enableLiteFp16 = "true"; + } + + @Override + protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + reloadSettingsAndUpdateUI(); + } + + @Override + protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + reloadSettingsAndUpdateUI(); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionWelcomeActivity.java new file mode 100644 index 0000000000..19da5d3fdc --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/keypointdetection/KeyPointDetectionWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.keypointdetection; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class KeyPointDetectionWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.keypointdetection_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(KeyPointDetectionWelcomeActivity.this, KeyPointDetectionMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java index 4dc1885b3b..e66d3e9ffe 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrMainActivity.java @@ -1,7 +1,7 @@ package com.baidu.paddle.fastdeploy.app.examples.ocr; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; import android.Manifest; import android.annotation.SuppressLint; @@ -30,12 +30,13 @@ import com.baidu.paddle.fastdeploy.RuntimeOption; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; -import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter; -import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.pipeline.PPOCRv2; +import com.baidu.paddle.fastdeploy.pipeline.PPOCRv3; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.adapter.BaseResultAdapter; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.vision.OCRResult; import com.baidu.paddle.fastdeploy.vision.Visualize; import com.baidu.paddle.fastdeploy.vision.ocr.Classifier; @@ -403,7 +404,7 @@ private void detail(Bitmap bitmap) { } } } - BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.ocr_result_page_item, results); + BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.base_result_page_item, results); resultView.setAdapter(adapter); resultView.invalidate(); @@ -424,9 +425,7 @@ public void checkAndUpdateSettings() { if (OcrSettingsActivity.checkAndUpdateSettings(this)) { String realModelDir = getCacheDir() + "/" + OcrSettingsActivity.modelDir; String detModelName = "ch_PP-OCRv2_det_infer"; - // String detModelName = "ch_ppocr_mobile_v2.0_det_infer"; String clsModelName = "ch_ppocr_mobile_v2.0_cls_infer"; - // String recModelName = "ch_ppocr_mobile_v2.0_rec_infer"; String recModelName = "ch_PP-OCRv2_rec_infer"; String realDetModelDir = realModelDir + "/" + detModelName; String realClsModelDir = realModelDir + "/" + clsModelName; @@ -461,11 +460,11 @@ public void checkAndUpdateSettings() { clsOption.enableLiteFp16(); recOption.enableLiteFp16(); } + DBDetector detModel = new DBDetector(detModelFile, detParamsFile, detOption); Classifier clsModel = new Classifier(clsModelFile, clsParamsFile, clsOption); Recognizer recModel = new Recognizer(recModelFile, recParamsFile, recLabelFilePath, recOption); predictor.init(detModel, clsModel, recModel); - } } diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java index 6f8c45ff4f..f359b65930 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrSettingsActivity.java @@ -10,8 +10,8 @@ import android.support.v7.app.ActionBar; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; import java.util.ArrayList; import java.util.List; diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrWelcomeActivity.java new file mode 100644 index 0000000000..553cc093cb --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ocr/OcrWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.ocr; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class OcrWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.ocr_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(OcrWelcomeActivity.this, OcrMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java index 3223fc07fc..ec2ebbffad 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationMainActivity.java @@ -1,7 +1,7 @@ package com.baidu.paddle.fastdeploy.app.examples.segmentation; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap; -import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI; +import static com.baidu.paddle.fastdeploy.ui.Utils.decodeBitmap; +import static com.baidu.paddle.fastdeploy.ui.Utils.getRealPathFromURI; import android.Manifest; import android.annotation.SuppressLint; @@ -19,7 +19,6 @@ import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -30,10 +29,10 @@ import com.baidu.paddle.fastdeploy.RuntimeOption; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView; -import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView; -import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.CameraSurfaceView; +import com.baidu.paddle.fastdeploy.ui.view.ResultListView; +import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel; import com.baidu.paddle.fastdeploy.vision.SegmentationResult; import com.baidu.paddle.fastdeploy.vision.Visualize; import com.baidu.paddle.fastdeploy.vision.segmentation.PaddleSegModel; @@ -341,7 +340,7 @@ public void initView() { } private void detail(Bitmap bitmap) { - predictor.predict(bitmap, true, 0.4f); + predictor.predict(bitmap, true, 0.7f); resultImage.setImageBitmap(bitmap); } @@ -368,7 +367,7 @@ public void checkAndUpdateSettings() { if (Boolean.parseBoolean(SegmentationSettingsActivity.enableLiteFp16)) { option.enableLiteFp16(); } - predictor.setVerticalScreenFlag(true); + predictor.setIsVerticalScreen(true); predictor.init(modelFile, paramsFile, configFile, option); } } diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationSettingsActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationSettingsActivity.java index 866c2c712f..ae32e960aa 100644 --- a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationSettingsActivity.java +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationSettingsActivity.java @@ -10,8 +10,8 @@ import android.support.v7.app.ActionBar; import com.baidu.paddle.fastdeploy.app.examples.R; -import com.baidu.paddle.fastdeploy.app.ui.Utils; -import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity; +import com.baidu.paddle.fastdeploy.ui.Utils; +import com.baidu.paddle.fastdeploy.ui.view.AppCompatPreferenceActivity; import java.util.ArrayList; import java.util.List; @@ -96,8 +96,6 @@ private void reloadSettingsAndUpdateUI() { getString(R.string.CPU_THREAD_NUM_DEFAULT)); String cpu_power_mode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY), getString(R.string.CPU_POWER_MODE_DEFAULT)); - String score_threshold = sharedPreferences.getString(getString(R.string.SCORE_THRESHOLD_KEY), - getString(R.string.SCORE_THRESHOLD_FACEDET)); String enable_lite_fp16 = sharedPreferences.getString(getString(R.string.ENABLE_LITE_FP16_MODE_KEY), getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT)); diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationWelcomeActivity.java new file mode 100644 index 0000000000..16ba8bf9d1 --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/segmentation/SegmentationWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.segmentation; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class SegmentationWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.segmentation_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(SegmentationWelcomeActivity.this, SegmentationMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/res/drawable/main_bk.png b/java/android/app/src/main/res/drawable/main_bk.png new file mode 100644 index 0000000000..1ff9457d4d Binary files /dev/null and b/java/android/app/src/main/res/drawable/main_bk.png differ diff --git a/java/android/app/src/main/res/drawable/paddle_logo.png b/java/android/app/src/main/res/drawable/paddle_logo.png new file mode 100644 index 0000000000..bc1135abfa Binary files /dev/null and b/java/android/app/src/main/res/drawable/paddle_logo.png differ diff --git a/java/android/app/src/main/res/layout/classification_camera_page.xml b/java/android/app/src/main/res/layout/classification_camera_page.xml index 441c3e5911..fd760b4853 100644 --- a/java/android/app/src/main/res/layout/classification_camera_page.xml +++ b/java/android/app/src/main/res/layout/classification_camera_page.xml @@ -12,7 +12,7 @@ android:layout_height="match_parent" android:background="@color/colorWindow"> - @@ -53,9 +53,9 @@ android:textAlignment="center" android:textSize="15sp"/> - + - - - + - + android:dividerHeight="@dimen/result_list_gap_width"> diff --git a/java/android/app/src/main/res/layout/classification_welcome.xml b/java/android/app/src/main/res/layout/classification_welcome.xml new file mode 100644 index 0000000000..7adb91dfb5 --- /dev/null +++ b/java/android/app/src/main/res/layout/classification_welcome.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + +