尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Paddle-Lite Opt Python API 深度解析:模型离线优化、动态量化与稀疏化实战指南

Paddle-Lite Opt Python API 深度解析:模型离线优化、动态量化与稀疏化实战指南 Paddle-Lite Opt Python API 深度解析模型离线优化、动态量化与稀疏化实战指南【免费下载链接】Paddle-LitePaddlePaddle High Performance Deep Learning Inference Engine for Mobile and Edge (飞桨高性能深度学习端侧推理引擎项目地址: https://gitcode.com/GitHub_Trending/pa/Paddle-Lite本文围绕 Paddle-Lite 的 Python 离线优化接口Opt展开系统讲解如何将 Paddle 原生模型modelparams或 combined 模型转换为 Paddle-Lite 可运行的naive_buffer/protobuf优化模型并结合仓库源码深入剖析set_valid_places的 place 展开机制、动态离线量化INT8/INT16、FP16 与稀疏化等进阶参数在底层OptBase中的真实处理逻辑以及run()的完整执行调用链。读完本文你可以独立完成从模型选择、目标设备指定、量化/稀疏配置到优化产出的全流程并能对照 pybind 绑定源码 与 OptBase 实现 定位常见报错。一、为什么需要opt离线模型优化Paddle-Lite 是飞桨面向移动端与边缘侧的高性能推理引擎其运行时的模型格式与 Paddle 训练/导出的 protobuf 程序并不完全相同。原生 Paddle 模型在导入 Paddle-Lite 之前必须经过一次离线图优化图变换按目标硬件place执行一系列优化 pass算子融合、常量折叠、布局变换、量化改写等生成目标设备可高效执行的计算图格式转换将 protobuf 格式程序转换为移动端常用的naive_buffer.nb单文件格式便于小体积加载目标设备适配依据valid_places为每个算子挑选对应的 kernel 组合不支持的算子会在优化阶段直接报错拦截。Opt正是承载上述流程的 Python 接口。它的底层实现是 C 类lite_api::OptBase定义于 opt_base.hPython 侧通过 pybind11 完成绑定。在 pybind.cc 中可以看到Opt类与 C 方法的完整映射关系void BindLiteOpt(py::module *m) { py::class_OptBase opt_base(*m, Opt); opt_base.def(py::init()) .def(set_model_dir, OptBase::SetModelDir) .def(set_modelset_dir, OptBase::SetModelSetDir) .def(set_model_file, OptBase::SetModelFile) .def(set_param_file, OptBase::SetParamFile) .def(set_valid_places, OptBase::SetValidPlaces) .def(enable_fp16, OptBase::EnableFloat16) .def(set_optimize_out, OptBase::SetOptimizeOut) .def(set_model_type, OptBase::SetModelType) .def(set_quant_model, OptBase::SetQuantModel) .def(set_quant_type, OptBase::SetQuantType) .def(set_sparse_model, OptBase::SetSparseModel) .def(set_sparse_threshold, OptBase::SetSparseThreshold) ... .def(run, OptBase::Run) .def(run_optimize, OptBase::RunOptimize); }需要特别注意的是这段绑定代码位于#ifndef LITE_ON_TINY_PUBLISH宏保护之下见 pybind.cc也就是说Opt接口只在非裁剪发布的预测库编译产物中可用面向开发/优化阶段而端侧运行时预测CxxPredictor/LightPredictor才是推理侧的入口。这也符合opt离线工具 的定位。二、最小可用示例六步完成模型转换以当前文件夹下的mobilenet_v1原生模型modelparams两文件为例标准转换脚本如下完整示例见 opt.md# 引用Paddlelite预测库 from paddlelite.lite import * # 1. 创建opt实例 opt Opt() # 2. 指定输入模型地址 opt.set_model_dir(./mobilenet_v1) # 3. 指定转化类型 arm、x86、opencl、npu opt.set_valid_places(arm) # 4. 指定模型转化类型 naive_buffer、protobuf opt.set_model_type(naive_buffer) # 5. 输出模型地址 opt.set_optimize_out(mobilenetv1_opt) # 6. 执行模型优化 opt.run()执行成功后当前路径下会生成mobilenetv1_opt目录其中的.nb文件即可通过 Paddle-Lite 预测库的CxxConfig::set_model_from_file加载。各接口的详细语义见下文各节。三、模型输入接口目录模型与 combined 模型Opt支持两种输入形式三组接口分别对应接口用途参数set_model_dir(model_dir)设置模型文件夹路径用于从磁盘加载非 combined模型文件夹内含model与paramsmodel_dir(str)set_model_file(model_file)设置模型文件路径用于加载combined形式模型model_file(str)set_param_file(param_file)设置参数文件路径与model_file成对出现时构成 combined 形式param_file(str)三者的实现都极其薄只是把路径转发给内部持有的CxxConfig见 opt_base.ccvoid OptBase::SetModelDir(const std::string model_path) { opt_config_.set_model_dir(model_path); } void OptBase::SetModelFile(const std::string model_path) { opt_config_.set_model_file(model_path); } void OptBase::SetParamFile(const std::string param_path) { opt_config_.set_param_file(param_path); }从源码结构看是否判定为 combined params 形式取决于model_file与param_file是否同时非空该判断逻辑在模型支持性检查CheckIfModelSupported中出现opt_base.ccbool is_combined_params_form false; if (!(opt_config_.model_file()).empty() !(opt_config_.param_file()).empty()) { is_combined_params_form true; } std::string prog_path lite::FindModelFileName(opt_config_.model_dir(), (opt_config_.model_file()), is_combined_params_form);因此使用时注意combined 模型必须同时提供model_file和param_file而普通目录模型只设置model_dir即可。四、set_model_typenaive_buffer与protobuf两种输出格式set_model_type(type)设置优化后模型的输出格式当前仅支持naive_buffer和protobuf两种移动端预测建议转化为naive_buffernaive_buffer优化后模型为以.nb结尾的单个文件结构信息与参数信息合并存储体积与加载开销小是端侧部署的默认选择C 侧默认值即LiteModelType::kNaiveBuffer见 opt_base.hprotobuf优化后模型为输出目录下的model与params两个文件保留标准 protobuf 程序格式便于调试与结构查看。将model重命名为__model__后可用 Netron 等工具可视化打开查看优化后的模型结构。参数解析逻辑非常严格——传入其他值会直接致命报错opt_base.ccvoid OptBase::SetModelType(std::string optimize_out_type) { if (optimize_out_type protobuf) { model_type_ LiteModelType::kProtobuf; } else if (optimize_out_type naive_buffer) { model_type_ LiteModelType::kNaiveBuffer; } else { OPT_LOG_FATAL Unsupported Model type : optimize_out_type; } }五、set_valid_places深度剖析一个字符串背后的 place 展开set_valid_places(valid_places)接收一个以逗号分隔的目标字符串如arm,opencl它决定了优化 pass 面向哪些硬件执行、以及每个算子可选的 kernel 精度/布局组合。源码中SetValidPlacesopt_base.cc会按,拆分字符串再把每个目标别名展开为一组带精度与布局的Place。以arm与opencl为例if (target_repr arm) { if (enable_fp16_) { valid_places_.emplace_back( Place{TARGET(kARM), PRECISION(kFP16), DATALAYOUT(kNCHW)}); } valid_places_.emplace_back( Place{TARGET(kARM), PRECISION(kFloat), DATALAYOUT(kNCHW)}); valid_places_.emplace_back( Place{TARGET(kARM), PRECISION(kInt32), DATALAYOUT(kNCHW)}); valid_places_.emplace_back( Place{TARGET(kARM), PRECISION(kInt64), DATALAYOUT(kNCHW)}); valid_places_.emplace_back( Place{TARGET(kARM), PRECISION(kAny), DATALAYOUT(kNCHW)}); } else if (target_repr opencl) { valid_places_.emplace_back( Place{TARGET(kOpenCL), PRECISION(kFP16), DATALAYOUT(kImageDefault)}); valid_places_.emplace_back( Place{TARGET(kOpenCL), PRECISION(kFP16), DATALAYOUT(kImageFolder)}); ... valid_places_.emplace_back( TARGET(kARM)); // enable kARM CPU kernel when no opencl kernel这段代码揭示了几个实用信息多 place 组合是自动的arm一个词即展开为 FP32/Int32/Int64/Any 等多种 NCHW place无需手动指定精度opencl则展开为 Image 与 Buffer 多种布局组合并额外追加了kARMCPU place——即当某个算子没有 OpenCL kernel 时自动回退到 CPU 执行enable_fp16()与 place 强相关只有当目标包含arm且事先调用了enable_fp16()才会插入kARM kFP16的 place。注意 opt.cc 中命令行版本的顺序也是先EnableFloat16()再SetValidPlaces()Python 侧调用enable_fp16()时应保证在set_valid_places之前支持的完整目标别名从同一函数可确认除arm、opencl、opencl_buffer、metal、arm_metal、x86_metal、x86、x86_opencl、xpu、host外还包含一组 NNAdapter 设备别名imagination_nna、rockchip_npu、mediatek_apu、huawei_kirin_npu、huawei_ascend_npu、amlogic_npu、verisilicon_timvx、eeasytech_npu、android_nnapi、cambricon_mlu、qualcomm_qnn、kunlunxin_xtcl。传入无法识别的字符串会触发Wrong target %s found致命错误至少一个 place 是硬性校验函数末尾有CHECK(!valid_places_.empty())空目标直接终止。多目标组合示例原文档示例from paddlelite.lite import * opt Opt() # 指定转化类型 arm、x86、opencl、npu opt.set_valid_places(arm,opencl) # opt.set_valid_places(arm,npu)六、进阶优化动态离线量化、FP16 与稀疏化Opt除了常规图优化还内置了三类模型瘦身能力三者均为可选开关。6.1 动态离线量化set_quant_modelset_quant_typeset_quant_model(quant_model)bool参数设置是否启用opt中的动态离线量化功能set_quant_type(quant_type)设置量化方式支持QUANT_INT16与QUANT_INT8。量化策略与体积/精度权衡量化类型精度影响体积收益QUANT_INT8对模型精度有一点影响模型体积约减小 4 倍QUANT_INT16对模型精度基本没有影响模型体积约减小 2 倍SetQuantType的解析与SetModelType风格一致非法取值直接致命退出opt_base.ccvoid OptBase::SetQuantType(const std::string quant_type) { if (quant_type QUANT_INT8) { opt_config_.set_quant_type(lite_api::QuantType::QUANT_INT8); } else if (quant_type QUANT_INT16) { opt_config_.set_quant_type(lite_api::QuantType::QUANT_INT16); } else { OPT_LOG_FATAL Unsupported quant type: quant_type; } }其底层优化 pass 实现在 post_quant_dynamic_pass.cc属于 MIR 图优化 pass 体系的一部分开启量化后优化器会在图中对权重插入量化/反量化改写将 FP32 权重转为 INT8/INT16 表示供对应的低精度 kernel 消费。命令行版本中该功能的默认量化类型为QUANT_INT16见 opt.cc 的 gflags 定义Python 侧未显式调用set_quant_type时行为以编译产物配置为准建议显式指定以避免歧义。6.2 FP16 训练后量化enable_fp16()enable_fp16()无参数启用 Float16 训练后量化将模型权重数据量化为 Float16对模型精度有一点影响但运行耗时和内存占用几乎降低一半。结合第五节的源码可见它只对arm目标生效为kARM追加kFP16place本质上是把权重存储精度减半并让 ARM kernel 走 FP16 计算路径。6.3 模型稀疏化set_sparse_modelset_sparse_thresholdset_sparse_model(bool)设置是否使用opt中的模型稀疏化功能。此功能目前只可以在 ARM 平台编译模型时开启set_sparse_threshold(float)设置稀疏化阈值取值区间为[0, 1]。例如设为0.6时对于某层参数若其 0 元素比例小于0.6则该层不走 sparse pass。源码实现印证了这两条约束opt_base.ccvoid OptBase::SetSparseThreshold(float sparse_threshold) { // sparse_model mode only supported on Arm. TargetType target; for (size_t i 0; i valid_places_.size(); i) { target valid_places_[i].target; if (target ! TargetType::kARM) { OPT_LOG sparse_model mode only supported on Arm. The model will be optimized to dense format.; opt_config_.set_sparse_model(false); break; } } // threshold must be between 0 and 1. if (sparse_threshold 0.0 || sparse_threshold 1.0) { OPT_LOG_FATAL Please set sparse_threshold between 0.0 and 1.0.; } else { opt_config_.set_sparse_threshold(sparse_threshold); } }两个值得注意的边界行为非 ARM 目标会静默降级如果valid_places中混入了非 ARM 目标如opencl稀疏化会被自动关闭并打印 The model will be optimized to dense format 日志而不会报错——所以想验证稀疏化是否真正生效应检查该日志阈值越界直接致命退出sparse_threshold超出[0, 1]范围会触发 FATAL而命令行版本中该阈值的默认值即为0.6opt.cc。七、run()与run_optimize()两种执行方式与底层调用链7.1run()分步设置 统一执行run()执行模型优化。在依次设置模型路径、model_type、optimize_out、valid_places之后调用会按配置完成转化优化后模型保存在当前路径下的optimize_out目录中。其 C 实现展示了完整的执行链opt_base.ccvoid OptBase::Run() { CheckIfModelSupported(false); OpKernelInfoCollector::Global().SetKernel2path(kernel2path_map); opt_config_.set_valid_places(valid_places_); if (model_set_dir_ ! ) { RunOptimizeFromModelSet(record_strip_info_); } else { auto opt_predictor lite_api::CreatePaddlePredictor(opt_config_); opt_predictor-SaveOptimizedModel( lite_out_name_, model_type_, record_strip_info_); } }可以归纳为四个关键步骤CheckIfModelSupported(false)——支持性预检加载原始模型程序lite::LoadProgram遍历所有 block 中的 op与目标 place 支持的操作集合求差若存在不支持的算子会打印This model is not supported, because N ops are not supported ... These unsupported ops are: ...后直接终止opt_base.cc。因此大多数 opt 失败 问题的根因是模型中包含了目标硬件不支持的算子kernel 信息注册把编译期收集的kernel2path_map注入OpKernelInfoCollector供裁剪编译记录使用CreatePaddlePredictor(opt_config_)复用运行时预测器的创建入口构建优化器上下文在初始化过程中按 place 执行全部优化 passSaveOptimizedModel(lite_out_name_, model_type_, ...)按naive_buffer或protobuf格式落盘。若设置了模型集合目录set_modelset_dir用于批量定制裁剪则转入RunOptimizeFromModelSet循环优化目录下的每个子模型并在record_model_info(true)时汇总 op/kernel 清单用于后续库裁剪编译。7.2run_optimize()单调用一站式转换run_optimize(model_dir, model_file, param_file, type, valid_places, optimized_model_name)无需逐一分步设置接口直接传入六元组并立即执行转化。其实现就是把六个参数依次灌入对应的Set*方法然后复用与run()完全相同的执行链opt_base.ccvoid OptBase::RunOptimize(const std::string model_dir_path, const std::string model_path, const std::string param_path, const std::string model_type, const std::string valid_places, const std::string optimized_out_path) { SetModelDir(model_dir_path); SetModelFile(model_path); SetParamFile(param_path); SetModelType(model_type); SetValidPlaces(valid_places); SetOptimizeOut(optimized_out_path); ... }目录模型示例model_file与param_file传空字符串即可from paddlelite.lite import * # 1. 创建opt实例 opt Opt() # 2. 执行模型优化目录模型 naive_buffer arm 目标 opt.run_optimize(./mobilenet_v1, , , naive_buffer, arm, mobilenetv1_opt)注意run_optimize不包含量化、FP16、稀疏化参数位若需这些进阶功能请使用分步set_*run()方式。八、配套诊断能力算子查询与模型支持性检查除模型转换外Opt类还暴露了一批只读诊断接口同样见 pybind.cc 的绑定在转换前排查兼容性非常实用Python 接口作用check_if_model_supported()检查输入模型是否被当前valid_places支持并打印模型中各 op 的支持情况print_supported_ops()打印valid_places对应目标上受支持的全部算子print_all_ops()打印 Paddle-Lite 当前编译产物包含的全部有效算子display_kernels_info()打印 kernel 注册表详细信息visualize_optimized_nb_model(model_dir, output_path)加载.nb优化模型按 block 生成.dot可视化文件version()/help()打印 opt 版本号 / 完整帮助信息对应的命令行工具paddle_lite_opt构建产物源码见 opt.cc以 gflags 形式提供等价能力常用参数包括--model_dir、--model_file、--param_file、--optimize_out_type、--optimize_out、--valid_targets、--quant_model、--quant_type、--enable_fp16、--sparse_model、--sparse_threshold、--print_all_ops、--print_supported_ops、--print_model_ops、--optimized_nb_model_path--visualization_file_output_path等参数定义见 opt.cc。命令行与 Python 两个入口最终汇入同一个OptBase类行为一致。典型排障流程先执行opt.set_model_dir(...)opt.set_valid_places(arm)opt.check_if_model_supported()若报not supported再用print_supported_ops()对照模型中缺失的算子确认是否需要切换目标或裁剪模型。九、使用建议与常见注意事项结合源码中的校验逻辑整理如下实战要点接口调用顺序enable_fp16()必须在set_valid_places()之前调用否则不会生成kARM kFP16place见第五节源码非法取值是 FATAL 而非 ValueErrorset_model_type、set_quant_type、set_valid_places、set_sparse_threshold的非法输入都会触发OPT_LOG_FATAL直接终止进程脚本中无需捕获异常但参数应先在本地校验稀疏化对目标有硬约束只有纯 ARM 目标下sparse_modeltrue才会真正走 sparse pass混合目标时自动降级为稠密格式注意检查日志输出位置优化产物写入set_optimize_out指定的、相对当前工作目录的路径naive_buffer模式下产物为.nb单文件naive_buffer不可直接用 Netron 打开需要可视化结构时选择protobuf输出或将.nb模型通过visualize_optimized_nb_model转成.dot文件精度与体积的量化选择对体积敏感、可接受轻微精度损失选QUANT_INT8约 4 倍压缩要求精度几乎无损选QUANT_INT16约 2 倍压缩ARM 场景且希望兼顾耗时与内存时评估enable_fp16()。十、参考文件索引内容路径本文对应的 API 参考文档docs/api_reference/python_api/opt.mdPython 绑定Opt类定义lite/api/python/pybind/pybind.ccOptBase头文件接口签名与默认值lite/api/tools/opt_base.hOptBase实现place 展开、run 调用链、支持性检查lite/api/tools/opt_base.cc命令行工具paddle_lite_opt入口与 gflagslite/api/tools/opt.cc动态离线量化 pass 实现lite/core/optimizer/mir/post_quant_dynamic_pass.cc量化功能 API 测试用例lite/api/test/mobilenetv1_opt_quant_test.cc围绕Opt接口建立选模型 → 定目标 → 配量化/稀疏 → 预检支持性 → 转换 → 验证产物的完整工作流是 Paddle-Lite 端侧部署的第一步掌握valid_places展开机制与run()的四步执行链后绝大多数优化阶段问题都可以在报错信息中快速定位。【免费下载链接】Paddle-LitePaddlePaddle High Performance Deep Learning Inference Engine for Mobile and Edge (飞桨高性能深度学习端侧推理引擎项目地址: https://gitcode.com/GitHub_Trending/pa/Paddle-Lite创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表