ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

高通SNPE 1.5安装与模型转换踩坑指南:从环境配置到DLC部署

高通SNPE 1.5安装与模型转换踩坑指南:从环境配置到DLC部署 简介高通SNPE 1.5安装包专为在高通骁龙平台上部署深度学习模型而准备适合嵌入式AI工程师、算法移植开发者和边缘计算研究者使用。SNPE作为高通官方神经网络推理引擎常因依赖库众多、环境配置繁琐而令人却步此安装包已预先整理好依赖与工具链下载解压后即可直接安装使用省去大量编译和下载环节。压缩包整体约119.22MB内含1022个文件其中HTML说明文档数量最多其次为Python脚本、JavaScript、PNG图片以及so动态库、C头文件与源文件、Java/XML/JSON等配置资源包中还附带模型转换、量化、精度比对、运行验证等工具脚本和配套Makefile与gradle工程文件基本覆盖从模型转换到目标板部署的完整链路。目前已有209人学习下载。借助这份安装包读者可以绕开繁琐的依赖收集和环境编译步骤在本地或目标设备上快速搭建可用的SNPE开发环境直接验证模型推理效果并参照其中文档理解目录结构对希望快速入门高通平台AI部署的开发者是一份省时省力的可用资源。1. 高通 SNPE 安装包跑不通的焦虑我在 1.5 版本上替你踩完了把训练好的模型塞进骁龙芯片这件事听起来简单实际做起来能把人折腾到怀疑人生。SNPESnapdragon Neural Processing Engine是高通官方的端侧推理工具链负责把 PyTorch、Caffe、ONNX 模型转换成骁龙平台能跑的 DLC 格式并调用 DSP、GPU 或 CPU 加速。但它的安装和部署有个出了名的毛病依赖关系复杂、版本适配苛刻很多人卡在环境配置阶段连模型转换的边都没摸到。这篇笔记围绕 snpe-1.5.zip 这套安装包把从环境准备到模型转换再到板端验证的完整路径写清楚同时把我验证过的依赖组合和踩过的坑一并交代。适合正在做端侧 AI 部署、刚拿到高通气推理模块或者准备把算法移植到骁龙平台的工程师。2. 安装前置条件为什么 snpe-1.5.zip 在你机器上装完照样跑不起来2.1 环境依赖是第一个翻车点Ubuntu、Python 和库版本锁死SNPE 1.5 这个版本的设计年代决定了它的依赖约束。它要求 64 位 Linux 环境Ubuntu 16.04 或 18.04 是最稳的选择CentOS 7 勉强能跑但需要额外处理 glibc 版本。Python 方面官方要求 3.6 到 3.8我实测 3.8.5 配合 Ubuntu 18.04 整套流程最顺如果你用最新的 Python 3.10 或 3.11开箱即报No module named snpe。依赖库主要包括python-dev、numpy、protobuf、libgfortran和libatomic其中protobuf必须锁在 3.8.0 以下新版 protobuf 的运行时和 SNPE 的dlc解析代码不兼容。# Ubuntu 18.04 上验证过的依赖安装序列 sudo apt-get update sudo apt-get install -y python3.8 python3.8-dev python3-pip \ libgfortran4 libatomic1 libtinfo5 unzip wget # 用虚拟环境隔离避免污染系统 Python python3.8 -m venv snpe_env source snpe_env/bin/activate pip install numpy1.17.5 protobuf3.8.0参数说明libgfortran4是 Ubuntu 18.04 对应的版本号如果你用 20.04 或更新版本库名会变成libgfortran5这就是很多人在自带 Python 3.9 的新系统上装完 SNPE 后一运行就崩的原因。libtinfo5是 ncurses 的底层库SNPE 的某些二进制工具链依赖它新系统默认只带libtinfo6需要手动装 5 版本。虚拟环境snpe_env不是必选项但我强烈建议你建一个因为 SNPE 的 Python 包会注入很多路径配置放进系统环境后容易和后续要安装的 TensorFlow 或 PyTorch 打架。2.2 安装包校验拿到 snpe-1.5.zip 后第一步不是解压网上流出的 snpe-1.5.zip 来源不一有人从高通官网申请后搬运有人从内部服务器拷出。无论是哪种渠道解压前一定先做完整性校验。这个安装包大约 1.5 到 2GB包含 SDK 本体、预编译库、示例模型和测试数据。如果校验不通过后续转换模型时会出现各种奇怪的段错误你根本分不清是环境问题还是文件损坏。# 1. 校验 MD5与发布方提供的哈希值对照 md5sum snpe-1.5.zip # 2. 测试压缩包完整性 unzip -t snpe-1.5.zip | tail -n 5 # 3. 解压到固定路径不要放在带空格的目录里 mkdir -p ~/qualcomm/snpe_1.5 unzip snpe-1.5.zip -d ~/qualcomm/snpe_1.5逻辑说明unzip -t会逐文件读取压缩包并做 CRC 校验任何字节级别的错误都会在这一步暴露。解压路径不能有空格——SNPE 的配置脚本会引用$SNPE_ROOT环境变量路径一旦带空格编译原生算子时 GCC 会把路径切碎报错信息三十多行最深处只写了一句recipe for target all failed排查起来极其痛苦。解压完成后目录里应该有一个bin文件夹里面有十几个可执行文件比如snpe-dlc-info、snpe-tensorflow-to-dlc、snpe-net-run这些就是你之后要面对的日常工具。2.3 环境变量配置source 比手动 export 靠谱SNPE 官方安装说明里给了一段环境变量配置脚本路径位于 SDK 根目录下的bin/envsetup.sh。但实际使用中这个脚本有时会漏配某些路径尤其是PYTHONPATH。我一般不直接靠它而是手动补齐确保 Python 解释器能发现 SNPE 的包。export SNPE_ROOT~/qualcomm/snpe_1.5 export PATH$SNPE_ROOT/bin:$PATH export LD_LIBRARY_PATH$SNPE_ROOT/lib:$LD_LIBRARY_PATH export PYTHONPATH$SNPE_ROOT/lib/python:$PYTHONPATH # 把配置写入 .bashrc避免每次开终端重新设 echo # SNPE 1.5 environment ~/.bashrc echo export SNPE_ROOT~/qualcomm/snpe_1.5 ~/.bashrc echo export PATH$SNPE_ROOT/bin:$PATH ~/.bashrc echo export LD_LIBRARY_PATH$SNPE_ROOT/lib:$LD_LIBRARY_PATH ~/.bashrc echo export PYTHONPATH$SNPE_ROOT/lib/python:$PYTHONPATH ~/.bashrc参数说明LD_LIBRARY_PATH指向lib目录预编译的.so文件都集中在这里PYTHONPATH指向lib/python放的是 SNPE 的 Python API 封装。需要注意lib/python这个路径在不同版本的 SNPE 里结构不一样有的版本会把 Python 包放在lib/python有的放在lib/python/snpe如果配置完环境后import snpe失败先ls $SNPE_ROOT/lib/python看看目录结构再微调路径。配置完成后在终端敲一下snpe-dlc-info如果能打印出 usage 信息而不是command not found说明环境基本通了。3. 模型转换实操把 PyTorch 的 YOLO 变成 DLC 的全流程3.1 转换链路选型为什么不直接走 PyTorch 到 DLCSNPE 1.5 的年代还没有官方的 PyTorch 直接转换器。转换到 DLC 有三条路Caffe、TensorFlow、ONNX。其中 ONNX 是效率最高的中间表示因为 PyTorch 导出 ONNX 的生态成熟且 SNPE 1.5 对 ONNX 算子的覆盖度比直接解析 PyTorch 图完整得多。社区热词里提到“高通 kgsl”和“高通 ais”那是图形与 AI 加速的更底层方向这里不展开但说明一件事——高通在 AI 工具链上渲染了很多层东西SNPE 只是最上层应用入口你完全可以只跟 SNPE 打交道不碰底层驱动。我的标准转换链路是PyTorch 模型 → ONNX → DLC。先用 PyTorch 自带的torch.onnx.export导出图结构再用 SNPE 的 ONNX 转换器转成 DLC。这个链路的好处是出了问题容易定位——导出 ONNX 失败大概率是模型里有动态 shape 或自定义算子转 DLC 失败则大概率是算子不受支持。3.2 把 PyTorch 导出为 ONNX shape 固定是第一步import torch import torch.onnx # 假设你有一个训练好的 YOLO 检测模型 from models.yolo import YOLO model YOLO(num_classes80) checkpoint torch.load(yolo_weights.pth, map_locationcpu) model.load_state_dict(checkpoint[model_state_dict]) model.eval() # 固定输入尺寸SNPE 不支持动态 batch 和动态分辨率 dummy_input torch.randn(1, 3, 640, 640) torch.onnx.export( model, dummy_input, yolo.onnx, export_paramsTrue, opset_version11, do_constant_foldingTrue, input_names[input], output_names[output], dynamic_axesNone # 关键必须是 NoneSNPE 不支持动态维度 )参数说明opset_version11是 SNPE 1.5 能处理的较稳版本ONNX 转 DLC 的解析器对 opset 12 以上出现的Resize新属性支持有缺陷会出现坐标偏移检测框错位的问题。dynamic_axesNone是必须显式声明的否则模型里如果有nn.Upsample或torch.nn.functional.interpolate导出时默认会留下动态 shape 的节点转换 DLC 时直接报Unsupported dynamic shape。do_constant_foldingTrue能让权重计算提前折叠减小 ONNX 文件体积同时也减少后续转换器的负担。导出完成后用onnx.checker.check_model校验图结构的合法性但要注意这个校验只查 ONNX 规范层面是否合规查不出 SNPE 是否支持每个算子。我见过不少模型导出的 ONNX 完全合法却在转 DLC 时栽在某个算子上的情况。3.3 ONNX 转 DLC量化前后的两种命令拿到 ONNX 文件后接下来就是用 SNPE 工具链做转换。先做非量化转换跑通流程再决定是否需要做 8 位量化。非量化 DLC 直接上真机跑在 865 上速度尚可但到了 662 这类中端平台就会明显慢。如果是部署到目标设备量化是绕不开的。# 1. 非量化转换生成 FP32 的 DLC snpe-onnx-to-dlc \ --input_network yolo.onnx \ --output_path yolo.dlc \ --input_shape input:1,3,640,640 # 2. 查看 DLC 信息确认图结构完整 snpe-dlc-info -i yolo.dlc | head -n 40参数说明--input_shape input:1,3,640,640的input必须和导出 ONNX 时input_names里定义的名字一致。SNPE 的输入顺序是 NCHW这里1,3,640,640对应 batch 1、通道 3、高度 640、宽度 640。如果你导出的模型是 NHWC 布局这一步会报形状不匹配的错误需要在 PyTorch 导出前就统一成 NCHW不要想着到转换器里再调——SNPE 1.5 对维度顺序的修正能力有限强行改后面跑snpe-net-run时张量形状会错乱。snpe-dlc-info输出里重点看Layer Type列和Output层。如果看到大量Unsupported标记说明这一层的算子没被转换器识别成功但 DLC 文件仍然会生成那些不支持的算子会被标记成空壳推理时直接输出垃圾数据。识别这种假转换的方法是看 DLC 文件大小——如果转换后文件缩水严重模型中大概率有算子被丢弃了。3.4 量化校准8 位定点化的数据准备与命令量化需要准备校准数据SNPE 会根据校准数据集统计各层的激活值范围决定 FP32 到定点 8 位的映射参数。校准数据不需要带标注但必须是从真实分布里抽的样本。常见做法是准备 200 到 500 张图片覆盖各种光照、角度和场景然后打包成 raw 文件列表。# 用 Python 生成校准数据列表文件 import os import cv2 calib_dir calib_images image_list [] for fname in sorted(os.listdir(calib_dir)): img cv2.imread(os.path.join(calib_dir, fname)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (640, 640)) raw_path os.path.join(calib_raw, fname.replace(.jpg, .raw)) img.tofile(raw_path) image_list.append(raw_path) with open(calib_list.txt, w) as f: f.write(\n.join(image_list))# 量化转换命令 snpe-onnx-to-dlc \ --input_network yolo.onnx \ --output_path yolo_quant.dlc \ --input_shape input:1,3,640,640 \ --quantization_type tf_enhanced \ --calibration_data calib_list.txt \ --calibration_cache calib_cache.bin逻辑说明先用 OpenCV 读取图片并缩放到网络输入尺寸然后将像素数据按顺序写入 raw 文件——SNPE 不需要图片文件只需要原始的二进制数据流。tf_enhanced是量化策略它在普通tf量化基础上对激活值做了额外的范围压缩对小数值更敏感的网络比如带有微小回归头的检测模型效果更好。calibration_cache是校准参数缓存第二次运行转换时可以直接读取缓存省去重新跑 200 张图的校准时间。量化完成后建议跑一下精度对比把同一张测试图片分别通过 FP32 DLC 和量化 DLC 推理观察输出的置信度和检测框坐标差多少差异大于 5% 就要考虑是否某些敏感层需要跳过量化。4. 板端部署与 SNPE 运行时真机推理的避坑指南4.1 snpe-net-run 的最小跑通流程在实际设备上验证转换出的 DLC 是否可用一般先用snpe-net-run在 PC 上模拟 CPU 推理再上真机。这里的关键是准备输入数据时要和转换时设定的input_shape严格对应。# 生成单张测试输入与转换时 shape 保持一致 python3 -c import cv2 import numpy as np img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (640, 640)).astype(np.float32) # 归一化到模型训练时的分布通常除以 255 即可 img img / 255.0 # 调整维度到 1,3,640,640 img np.transpose(img, (2, 0, 1))[np.newaxis, ...] img.tofile(input_data/input.raw) # 执行推理 snpe-net-run --container yolo_quant.dlc --input_list input_list.txt参数说明input_list.txt的内容格式是input:input_data/input.raw冒号前是输入层名称冒号后是 raw 文件路径。snpe-net-run会在当前目录生成output文件夹里面是每个输出层的二进制文件。这些文件直接numpy.fromfile读出来就是模型输出可以用来和 PC 上的推理结果做比对。注意这里有个隐藏坑input.raw的数据类型必须是float32不能存成uint8或float16否则运行时张量解析错误且错误信息不明显只显示Failed to read input blob很容易误以为是 DLC 文件损坏。4.2 真机上用 SNPE 库封装的常见问题路径、权限和库依赖真机部署阶段通常是在 Android 应用里通过 JNI 调用 SNPE 的 C API。这一层的坑集中在.so文件的完整性上。SNPE 1.5 的预编译库包含libSNPE.so、libSnpeHtp.so针对 Hexagon DSP和libSnpeGpu.so。如果你的目标平台只用 GPU 加速可以把 DSP 相关的库删掉节省 APK 体积但删之前要确认 SNPE 初始化时没有显式设置Runtime.CPU之外的模式。我在真机部署上遇到过最典型的问题是libgnustl_shared.so缺失导致的崩溃。SNPE 的 C 库编译时用了 GNU STL加载时如果系统里没有这个库进程会在初始化阶段直接退掉logcat 里只打了一行dlopen failed: library libgnustl_shared.so not found。解决方法有两个一是把 SNPE SDK 内置的libgnustl_shared.so一起打进 APK二是在Application初始化里写System.loadLibrary(gnustl_shared)提前加载。// JNI 层初始化代码片段 #include jni.h #include SNPE/SNPE.hpp #include SNPE/SNPEFactory.hpp extern C JNIEXPORT jlong JNICALL Java_com_example_engine_Detector_init(JNIEnv* env, jobject thiz, jstring dlc_path, jstring runtime) { // 先加载 STL 兼容库再加载 SNPE 主库 // 顺序反了会在 dlopen 时报 undefined symbol std::string path env-GetStringUTFChars(dlc_path, nullptr); std::string rt env-GetStringUTFChars(runtime, nullptr); zdl::SNPE::SNPEFactory::initializeLogging(); zdl::SNPE::Runtime_t runtime_type rt GPU ? zdl::SNPE::Runtime::GPU : rt DSP ? zdl::SNPE::Runtime::DSP : zdl::SNPE::Runtime::CPU; if (!zdl::SNPE::SNPEFactory::isRuntimeAvailable(runtime_type)) { return -1; // 设备不支持当前运行时提前返回 } auto container zdl::SNPE::SNPEFactory::loadContainerFromFile(path); auto snpe zdl::SNPE::SNPEFactory::createSNPE(container, runtime_type); return reinterpret_castjlong(snpe.release()); }参数说明isRuntimeAvailable这一步很重要实测在骁龙 660 系列上没有可用的 DSP 加速库直接创建 DSP 运行时会导致空指针。先检查再创建比 try-catch 硬接更稳。loadContainerFromFile要求参数是绝对路径相对路径在 JNI 层会解析失败因为 Java 层和 native 层的工作目录本来就不同别在 Java 端传相对路径过来。4.3 回退策略SNPE 崩溃时保留一条 CPU 提速路径如果真机上遇到 DSP 或 GPU 运行时反复崩溃一个实际可行的方案是退回到 CPU 运行时但用 SNPE 的多线程配置把性能损失压到最低。SNPE 的 CPU 运行时在 1.5 版本上对八核处理器的利用已经做了一轮优化实际推理速度虽比不上 GPU但胜在稳定。// 配置 CPU 线程数追求稳定时不要开满所有核 zdl::SNPE::SNPE::Builder* builder zdl::SNPE::SNPEFactory::createSNPEBuilder(container); builder-setRuntimeProcessor(zdl::SNPE::Runtime::CPU); builder-setCpuFallbackEnabled(true); // 允许自动回退 builder-setPerformanceProfile(zdl::SNPE::PerformanceProfile::HIGH_PERFORMANCE); builder-setCPUFallbackMode(true); auto snpe builder-build(); delete builder;参数说明setCpuFallbackEnabled(true)能让运行时在某些算子无法在 DSP 上执行时自动回退到 CPU而不是整体抛异常。HIGH_PERFORMANCE会把 CPU 频率调到最高档位代价是功耗上升和发热加剧。如果产品对发热敏感建议用DEFAULT档。这里能省一点是一点因为 SNPE CPU 运行时本身比裸跑 NCNN 慢约 30%全指望调参去追 GPU 速度是不现实的保住稳定性才是在量产机上正确的选择。5. 常见坑与排查思路SNPE 1.5 部署失败的五个典型现象5.1 Python import snpe 报错退出码 1现象在虚拟环境里执行import snpe时直接中断退出没有任何 Python tracebackexit code 为 1。原因SNPE 的 Python 包在 import 时会加载libSNPE.so如果系统缺少 zlib 相关依赖动态加载器会 aborted 而不是抛异常。这与常见的ModuleNotFoundError完全不同前者是运行时环境问题后者是PYTHONPATH配置错误。解决先用ldd $SNPE_ROOT/lib/libSNPE.so列出动态依赖逐个补全缺失的库。重点检查libz.so.1是否存在在精简版 Docker 镜像里libz1经常没装。补完后重启 Python 再试 import。5.2 DLC 转换成功但推理结果全是 0 或固定值现象转换过程没有任何报错但snpe-net-run输出文件的内容全为 0 或是一个恒定小数。原因图中有算子被转换器默默丢弃。SNPE 的 ONNX 解析器对某些版本的LeakyReLU或Softmax算子不支持时不会报错而是直接跳过该层导致后续节点收到的输入全是零。解决用snpe-dlc-info -i yolo.dlc -s-s参数会输出各层的详细统计信息对比原 ONNX 图的层数和 DLC 的层数。少了几层就从少的那些节点找原因。常见处理方法是回到 ONNX 导出阶段把不支持的激活函数手动替换为 SNPE 支持的等价组合例如LeakyReLU(0.1)可替换为max(0.1*x, x)用Max算子实现。5.3 量化后精度暴跌检测框全部偏移现象512GB 内存的服务器上训练出来精度正常转成 INT8 DLC 后 mAP 从 65% 跌到 40%且检测框系统性偏移约 10 个像素。原因校准数据数量和分布不够。当校准集只有几十张图时激活值范围统计不充分量化参数偏高或偏低。另外YOLO 这类检测网络的输出头里有小数值回归分量对量化误差极其敏感常被称为“玄学”——调一个随机种子都可能让结果差好几个点。解决把校准集扩大到 500 张以上并按场景切分白天夜晚、室内室外各占一部分。同时尝试--quantization_type tf_enhanced代替默认的tf策略。如果精度仍然不达标就要考虑对敏感层做混合精度处理在 SNPE 中可以通过分段 DLC 来实现把网络切分成两部分前半段用 INT8 量化后半段回归头用 FP32 精度最后在应用层把两个 DLC 串起来。5.4 ARM 真机上 GPU 运行时创建失败返回空指针现象SNPE 初始化时createSNPE返回空指针isRuntimeAvailable(GPU)返回 false。原因设备 GPU 驱动不支持当前 SNPE 版本要求的 OpenCL 扩展或者在系统层面禁用了 GLES 计算。常见于低端设备或者 root 后修改过 GPU 驱动的系统。特别地某些魔改 ROM 加载了不同的 kgsl 驱动会直接破坏格式假设。解决升级目标设备的 GPU 驱动到厂商最新版或者退回 CPU 运行时。先把 CPU 跑通在 CPU 基础上再排查 GPU 驱动不要同时调两块。5.5 转换时报错std::bad_alloc内存不足现象在 8GB 内存的开发机上转换大型模型如 ResNet152时进程直接因内存分配失败终止。原因ONNX 转 DLC 时转换器会在内存中完整加载权重并做图重写内存峰值可能是 DLC 文件大小的 20 倍以上。8GB 内存处理超过 200MB 的 ONNX 文件就吃紧了。解决转到 16GB 以上的机器操作或对 ONNX 做简化——用onnx-simplifier把可折叠的常量节点前移减少冗余计算。还可以在转换命令中加--debug参数观察内存曲线定位是哪个阶段暴涨。6. 性能调优与验证方法把 DLC 的实际吞吐压榨到极致6.1 用 Benchmark 工具跑通速度基线不看单帧延迟量化完 DLC 后很多人习惯直接上真机计时其实 SNPE 自带性能检测工具能更精确地给出各阶段耗时。snpe-benchmark这个工具在bin目录下用法比较简单输入 DLC指定运行帧数它会在被测设备上循环推理并输出平均耗时、P90/P99 延迟、DSP 占用率等指标。我个人习惯用一份固定输入数据跑 20 轮取后 10 轮均值作为标准基线这样能滤掉变频器和温控的干扰——首次运行 DLC 时驱动要做资源分配耗时偏高一倍起步你看单帧数据完全没有参考价值。6.2 按层耗时定位瓶颈输出层时间分布怎么看在性能基线确认不达标后需要知道瓶颈在哪个阶段。SNPE 1.5 的snpe-dlc-info并不直接给出各层耗时要拿到数据得在应用层对execute前后分别打点或者利用 SNPE 的 profiling 回调接口。常见做法是在 JNI 层维护一个耗时表每次execute后读回各层耗时的 API 是getLayerTimeProfile前提是构建 SNPE 时设定了 profiling 开关。// 开启 profiling 后拉取层耗时 zdl::SNPE::SNPE::Builder* builder /* 已有的 Builder 对象 */; builder-setProfilingLevel(zdl::SNPE::ProfilingLevel::LAYER_LEVEL); // 在推理完成后获取耗时记录 zdl::SNPE::SNPE* snpe /* 已创建的 SNPE 对象 */; auto profile snpe-getLayerTimeProfile(); for (auto entry : profile) { // entry.first 是层名entry.second 包含平均时间和累计时间 // 按时间降序排定位前三个最耗时层 }参数说明LAYER_LEVEL会打开逐层计时这会增加推理耗时约 5%只在调优期间使用量产时一定要关掉。拿到层耗时后最典型的瓶颈分布是第一个卷积层和最后的全连接/回归层各占 30% 和 20%中间层反而更分散。对瓶颈层可以做替换SNPE 1.5 支持把模型中的卷积核大小替换为等效的分解组合例如把3x3卷积拆成1x3加3x1在部分设备上能省 10% 左右延迟但精度会有轻微损失。6.3 量化误差验证方法用同一批图跑 FP32 与 INT8 对比量化后的模型到底损失了多少精度需要量化对比。我在实践中用两种方式验证第一种是离线对比把 100 张真实场景图分别喂给 FP32 DLC 和量化 DLC模拟器上用snpe-net-run真机用封装好的 API计算输出的余弦相似度。第二种是业务层验证例如检测模型直接统计 mAP这更稳妥——有些模型输出张量层余弦相似度能到 0.99但实际检测框偏移严重因为坐标回归的微小误差被 NMS 和阈值放大了。# 快速余弦相似度校验脚本 import numpy as np def compare_outputs(fp32_path, int8_path): a np.fromfile(fp32_path, dtypenp.float32).flatten() b np.fromfile(int8_path, dtypenp.float32).flatten() cos np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) return cos cos_sim compare_outputs(output_fp32/result.raw, output_int8/result.raw) print(fCosine similarity: {cos_sim:.4f})如果余弦相似度低于 0.95建议先检查校准集质量而不是急着换量化策略。我遇到过一版模型在自家测试集上量化后准确率只掉了一个点但换了客户提供的图片后暴跌最后发现是客户的图像有严重的噪点而我的校准集全是干净图。所以校准集构建时务必要拿目标设备实际采集的图像不要偷懒用开源数据集代替。6.4 维护一个“能用的安装包”清单版本锁定笔记录入习惯最后分享一个个人习惯每确认一个能跑通的 SNPE 组合就用一个文本文件记录下所有关键依赖的版本号包括操作系统版本、Python 小版本、numpy 版本、protobuf 版本、设备 SoC 型号。这套记录在换机器、换项目时是救命稻草。我现在用的就是 Ubuntu 18.04 Python 3.8.5 numpy 1.17.5 protobuf 3.8.0 SNPE 1.5 这套组合至今没翻过车。如果你的模型算子比较新官方工具链覆盖不了建议尽早评估更换新版本 SNPE而不是在 1.5 上反复打补丁。希望帮到你。本文还有配套的精品资源点击获取
返回列表