ARTICLE DETAIL

资讯详情

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

端侧推理引擎全解析:从模型部署到性能优化实战

端侧推理引擎全解析:从模型部署到性能优化实战 做深度学习模型落地我踩过最大的一个坑就是把训练好的模型直接丢到手机上去跑。服务器上延迟挺好看的分类模型一到端侧就单次推理好几秒机身烫得能当暖手宝。后来才搞明白问题不在算法而在于中间少了一层东西——端侧推理引擎。它负责把训练好的深度学习模型翻译成目标硬件能高效执行的指令是模型从机房走到用户手机、摄像头、汽车里的最后一公里。这篇文章就是围绕端侧推理引擎做个整体概述把里面到底有什么、主流引擎怎么选、实际部署会踩哪些坑一次说清楚。不管你是算法工程师要动手部署模型还是客户端开发想接入本地AI能力顺着这条线捋下来基本就能对整个链路有个清晰的判断了。1. 为什么端侧推理在深度学习落地中这么关键1.1 从“训在云端”到“跑在端侧”的转变大部分深度学习项目的起点是训练。训练阶段数据量大、计算密集通常在GPU集群或者带卡的服务器上跑。我们这个阶段更关心精度、收敛速度很少会去考虑“这个模型如果放到一部手机里到底跑不跑得起来”。但真正把一个模型交付给用户时场景变了。人脸解锁不能等网络请求从服务器回来再开锁摄像头里的实时视频分割不可能把每一帧都传到云端处理自动驾驶更是对时延和安全有硬性要求。还有一类场景是隐私医疗影像、用户语音、行为轨迹数据一旦离开设备合规风险立刻上升。于是越来越多模型被推到端侧直接在设备上做推理。所谓端侧不单指手机也包括平板、智能穿戴、门禁设备、边缘工控机、车机。这些设备有一个共同点算力、内存、功耗都有限不能拿训练时那套“先算出来再说”的逻辑去对待。训练时可以随便用FP32、可以堆Batch Size、可以反复试错到端侧就得考虑模型多大、每帧推理多少毫秒、能耗几何、会不会热降频。端侧推理引擎就是专门解决这一层问题的系统软件。1.2 端侧推理引擎到底解决哪三类问题我把它拆成三类核心矛盾理解这三件事你就能明白为什么不能直接用训练框架的mobile版随便跑。首先是兼容性。训练框架五花八门PyTorch、TensorFlow、PaddlePaddle各有各的套路。端侧硬件更杂ARM CPU、Mali GPU、Adreno GPU、各种NPU和DSP。要把一套模型文件在各种硬件上都跑起来必须有统一的东西把模型格式和目标硬件接起来。推理引擎就是这层中间转换和适配。其次是性能。模型计算本质就是大量算子组成的有向图。同样的卷积在X86 CPU上怎么排内存、在ARM CPU上要不要用NEON指令、在GPU上怎么组织线程组、在NPU上怎么量化切成子图差别是数量级的。推理引擎把这些优化固化成算子库、指令调度和计算图优化让算法工程师不用在每一次部署时都重新造轮子。最后是资源约束。手机内存小模型加载几十MB可能直接把App搞爆电池有限推理一次耗多少毫焦耳直接决定能不能商用端侧设备存储紧张模型压缩到几MB还是几百MB产品形态完全不同。推理引擎通过量化、剪枝、内存复用、功耗调度来压低这些开销。一个简单的例子人脸识别常用的MobileNetV3FP32权重在20MB左右INT8量化后不到6MB推理延迟还能再降一半以上这种收益是纯靠优化代码很难拿到的。1.3 端侧与云端的核心差异对照我常跟团队里新同学用下面这张表说事情能省不少解释成本维度云端推理端侧推理计算资源GPU集群、CPU阵列几乎不限手机SoC、嵌入式处理器算力有限网络依赖一般需要连接在线服务可完全离线不依赖网络推理时延受网络RTT影响通常几十上百ms本地执行理想情况几ms几十ms隐私安全数据需上传存在泄露风险数据不出设备隐私性强功耗约束基本不敏感严格受限发热和续航都要考虑存储空间磁盘大模型可以很大存储和内存都紧张模型要尽量小环境一致性硬件相对标准化碎片化严重每个SoC、每版驱动都不同云端推理不是不重要但在深度学习产品化时端侧推理通常才是那个“能不能被用户接受”的决定项。推理引擎本身也不局限在手机上像云端做低延迟推理时同样会用到类似思路只是端侧的限制条件更多所以要把每一个环节做到极致。2. 拆解端侧推理引擎的关键技术模块2.1 模型解析与计算图优化端侧推理引擎拿到手的第一步是把模型文件转成自己的中间表示IR。不管原始格式是ONNX、TensorFlow还是PyTorch导出的TorchScript引擎都会解析成一张算子计算图然后在这张图上做各种优化。计算图优化是端侧推理快慢的分水岭之一。最经典的是算子融合典型例子是“卷积BNReLU”三段融合成一个卷积算子。训练阶段BN必须要因为它能稳定训练分布推理阶段它的参数可以提前折算到卷积的权重和偏置里BN和ReLU就不用再各扫一遍特征图了。少了两次完整内存读写和一个激活内核的启动开销性能提升非常可观。除了融合还有常量折叠。很多形状、索引、归一化参数在转换期就能算出来没必要每次推理都重算。还有死节点消除把图里没有输出引用的节点删除内存优化把不再使用的中间Tensor内存复用到后续节点上。这些都不改变数学结果但能减少实际计算量和内存峰值。引擎的转换工具一般会自动做这些事但你要知道它们存在才能解释为什么同一个模型在不同引擎里跑出完全不同的帧率。另外有一个容易被忽略的步骤图分割。端侧设备有CPU、GPU、NPU、DSP一个大的MobileNet不可能所有算子都交给NPU跑。引擎会把计算图按算子支持情况切成多个子图能放NPU的放NPU放不了的留在CPU中间用数据拷贝连接。子图切得好不好直接决定了异构设备利用率。2.2 量化与压缩模型体积和计算量在端侧从来都是头等问题。FP32模型一个权重占4字节而INT8量化后只占1字节模型体积直接缩到四分之一矩阵乘法的数据搬运量也大幅减少。更重要的是现在很多手机SoC里的NPU/DSP对INT8计算有专门的硬件加速单元同样的卷积速度比CPU上FP32快好几倍。量化按时机分两类。一类是训练后量化Post-Training QuantizationPTQ把训练好的浮点模型拿过来在端侧引擎里统计一下权重和激活的数值范围映射到整数范围。好处是成本低不需要重新训练模型但激活值的范围经常受输入数据分布影响需要喂一小批有代表性的校准数据才能估准。另一类是量化感知训练QAT在训练时就把量化误差模拟进前向计算让权重去适应量化后的取值空间精度通常更稳但需要改动训练流程。在实际部署里我经常用混合精度大部分层走INT8但对量化特别敏感的输出层、检测框回归层、部分激活函数层单独保留FP16或FP32。有一句话叫“量化不是模子压一下就行”不同模型的天数完全不同。我曾经把一个检测模型强行全层INT8结果mAP掉了8个点后来用敏感层隔离恢复了6个点以上体积还控制得很好。量化原理可以粗略类比成压图片一张原图转成低分辨率JPEG后如果关键内容还在肉眼基本看不出区别但文件小了很多。量化校准数据的选择有点像选择“什么光线条件下的照片最能代表用户真实拍摄场景”选偏了压缩后画质就会崩。2.3 算子实现与异构调度计算图优化再好最终还是要落到一个个算子的实现。端侧硬件种类复杂引擎必须在不同后端上提供对应实现CPU后端要利用ARM设备的NEON指令集、x86的SSE/AVX做向量化计算甚至针对L1/L2 Cache大小调整循环分块让数据尽量留在高速缓存里。GPU后端要生成Shader或Compute Kernel组织线程组处理数据排布与内存屏障。OpenCL是通用选择但不同GPU厂商的驱动实现细节差别很大。NPU后端通常由厂商提供特定接口例如通过Android的NNAPI、苹果的Core ML、各家芯片SDK推理引擎需要适配这些通路才能把算子交出去。异构调度不光是“找快的设备跑”还要考虑数据传输代价。CPU和GPU之间的内存拷贝很贵如果某个算子本来在CPU上跑要1ms搬到GPU要花0.8ms搬数据那就没必要搬。引擎会做成本预估然后把算子按性价比分配。有一个相关的概念叫“预算模型”我建议你在调试性能时保留注意看到一个算子耗时突然变高先排查是不是频繁做了异构设备间的数据搬运。而且线程数也不是越多越快。移动端SoC通常有大核和小核8个CPU核全开会造成缓存抖动和功耗暴涨引擎默认的线程策略往往不是性能最优。我自己调NCNN的时候4线程比2线程快不了多少但发热明显上来最后长期运行还是锁在2~3线程。2.4 内存规划与功耗控制端侧推理的内存紧张可能比速度问题更早暴露。一个有几十层卷积的模型中间要保存每层输出的特征图如果每张图都动态分配很快就把内存吃满。成熟的引擎都会采用静态内存池根据计算图把各层输出大小和生命周期摸清楚然后把不相冲突的Tensor分配到同一块内存上复用。这个优化很见功夫一块64MB的缓冲能被压到不到20MB。内存映射也是一个重要手段。模型文件几百MB时要避免一次性读到堆里而用mmap按页映射推理时内核只会把实际访问到的页调入内存能显著降低App常驻内存。功耗控制更难涉及芯片频率管理。引擎内置的性能档位通常有低功耗模式、均衡模式、性能模式。低功耗会限制CPU大核频率、减少线程、GPU降频性能模式则会尽量跑满。实际产品里很少永远用性能模式因为一发热SoC就会降频帧率反而不稳。比较好的做法是让用户能选档位或者根据App前后台状态自动切换推理频率。3. 主流端侧推理引擎选型对比3.1 四款常用开源引擎的核心特点现在开源生态里端侧推理引擎选择很多我挑几个出镜率最高的。TensorFlow LiteTFLite如果整个训练管线都是TensorFlow系的TFLite是最稳的入口。它的算子覆盖广、文档多、部署工具链完整量化体系也成熟。Android上还能通过NNAPI把算子委托给NPU。缺点是有些自定义算子或比较新的模型层要自己写另外它采用“解释执行若干加速内核”的混合模型性能优化上限要花功夫去抠。ONNX Runtime Mobile很多团队今天都是PyTorch训练先导出ONNX再用ONNX Runtime在端侧跑。ONNX Runtime本来很重后来针对移动端拆出了ORT Mobile可以只编译需要的算子做静态库裁剪能明显缩包体。对ONNX生态的支持是它最大的价值特别是当模型里有很多PyTorch自定义模块时。NCNN腾讯开源主打轻量社区里“刷榜”的场景很多。它对ARM CPU的NEON优化做得非常细很多算子都有手工汇编实现CPU推理性能在移动端属于第一梯队。模型体积也比较小适合嵌入式、iOS/Android原生集成。短板是动态图支持和部分新算子的覆盖速度不如大厂生态。MNN阿里开源界面友好跨端覆盖不错。MNN在CPU上的优化也很强同时能接GPU和各家NPU。项目里同时做了很多工程化的东西比如模型加密、内存复用、支持小程序端上运行。如果你要跑在微信小程序或者对包体、加载速度特别敏感的场景MNN是值得优先试的。下表做个摘要引擎开源方主要定位优点注意点TensorFlow LiteGoogleTF生态移动端算子全、工具链成熟、量化好包体偏大部分新算子支持滞后ONNX Runtime MobileMicrosoftONNX跨框架对接PyTorch友好可裁剪需要自己编译定制移动端模板较少NCNN腾讯CPU极致性能ARM汇编优化强、轻量算子覆盖有限GPU/NPU适配偏后期MNN阿里跨端通用 移动端CPU强、支持多种后端、工业落地多模型格式转换和调试工具仍需积累当然还有腾讯的TNN、百度的Paddle Lite以及苹果自家的Core ML。Core ML算比较特殊的在iOS生态内性能和系统兼容性最佳但基本绑定Apple设备项目如果跨Android就要另找方案。3.2 选型决策矩阵很多人在GitHub上看到哪个star多就选哪个或者看性能榜单谁快就跳过去这是不行的。我建议你从五个问题出发第一训练框架和已有资产是什么。TensorFlow项目直接TFLitePyTorch为主先能导出ONNX再考虑ORT Mobile或NCNN/MNN。第二目标硬件有哪些。如果只要跑ARM AndroidNCNN/MNN都很好如果想一套代码多端优先MNN或TFLite。第三算子兼容程度。拿自己的模型挨个引擎试转换一张对比表列出来哪些算子转换失败失败后能否用CPU兜底兜底后性能是否还能接受。第四包体和依赖大小。有些引擎哪怕只跑一个模型也要带两三MB的so在某些小程序/嵌入式场景里很致命。第五团队有没有能力维护C层。如果只是调SDK选文档和示例最全的如果要做算子级定制优化NCNN或MNN的低层代码更适合啃。还有一个容易被低估的点License和商业使用限制。大部分开源引擎可以商用但要注意随附的第三方代码比如部分GPU驱动适配库、第三方卷积实现可能带额外条款。法务上过一遍总比上线后被人找上门好。3.3 我在实际项目中的选型经验我的经验可以总结成几句话。快速出demo、验证产品逻辑首选TFLite因为它最不容易卡在半路上但一旦需要把性能榨到极限比如做实时视频特效或者本地OCRTFLite的默认优化可能不够NCNN/MNN能给你更多手工调校空间。另外我处理过一个项目模型很大包含很多尽量合并到一两个ONNX节点里的自定义算子ORT Mobile可以用它的自定义算子接口接上我们只需要实现这些算子的CPU版本其余自动调度。那一次反而比强行换NCNN省事。所以选型不是“谁性能高选谁”而是看谁的边界离你的模型最近。我现在还养成了一个习惯每选一个新引擎先做一个最小复现实验——用一个小模型跑通然后做三件事测单线程CPU延迟、测多线程CPU延迟、测GPU/NPU后端延迟。三组数字算出来你基本就能知道这个引擎在你的目标设备上还有多少空间可以挖也能避免被纸面上的benchmark误导。4. 端侧推理引擎部署的完整实操流程4.1 准备模型导出ONNX和关键注意事项假设你的模型是用PyTorch训练的现在要接入端侧引擎。通用做法是先导出ONNX再交给推理引擎转换。导出的代码不复杂但有几个细节特别容易踩坑。第一导出前要把模型切到推理模式也就是调用model.eval()否则BN、Dropout的推理逻辑不一致。第二输入要给出样例张量PyTorch用它对模型做一次完整的前向从而记录计算图。第三要明确导出时的opset_version引擎支持的ONNX版本可能不同选太高会报不兼容选太低有的新算子表达不出来。第四如果模型支持动态宽高导出时要指定动态维度比如把高度和宽度设为动态轴。不然端侧每次处理不同分辨率都会报错。代码骨架大致是这样import torch model.eval() x torch.randn(1, 3, 224, 224) torch.onnx.export( model, x, model.onnx, input_names[input], output_names[output], opset_version13, dynamic_axes{input: {0: batch, 2: height, 3: width}, output: {0: batch, 2: height, 3: width}} )导出之后不要急着做转换先做一次数值比对。用ONNX Runtime在本地加载导出的模型和PyTorch原模型的输出对比如果最大误差超过1e-3先查导出过程哪里出了问题。很多端侧部署问题根本不是端侧出来的而是在导出这一步就已经埋了雷。另外很多模型的结构里带着后处理逻辑比如目标检测的NMS。这部分通常不适合放进计算图一是端侧引擎对动态循环、集合操作支持差二是后处理逻辑用原生语言写更灵活。我习惯把后处理移到引擎外面用C/Java/Swift实现非极大值抑制和包围盒还原模型只负责输出一组候选信息。4.2 转换与量化以TFLite为例TFLite的转换流程很适合拿来演示。你先把训练好的TensorFlow模型保存成SavedModel或者直接用Keras模型对象然后交给转换器。基础转换很简单import tensorflow as tf converter tf.lite.TFLiteConverter.from_saved_model(saved_model) tflite_model converter.convert() open(model_fp32.tflite, wb).write(tflite_model)但这只是FP32模型体积大速度也不理想。真正的关键在量化。要给转换器开优化开关并准备一个代表数据集representative dataset它用来统计激活值范围def representative_dataset(): for sample in calibration_samples: # 最好覆盖真实输入分布 yield [sample.reshape(1, 224, 224, 3).astype(np.float32)] converter.optimizations [tf.lite.Optimize.DEFAULT] converter.representative_dataset representative_dataset converter.target_spec.supported_ops [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] converter.inference_input_type tf.uint8 converter.inference_output_type tf.uint8 tflite_quant_model converter.convert()这里要注意校准数据不是随便拿几十张训练图就行得尽量覆盖模型上线后会遇到的光线、角度、目标尺寸分布。选偏了量化后精度会明显波动。还有一个容易犯的错target_spec.supported_ops设置成INT8后如果模型里存在无法量化的算子转换会失败这时候需要改成允许部分算子用float32执行而不是硬着头皮全量量化。转换出来的tflite文件可以直接用Android Studio里的Build Tools跑benchmark也可以在PC上用Python的tflite_runtime快速验证推理结果。我的习惯是在转换完立刻对同一批测试输入比较FP32模型和量化模型的输出偏差超过预期就回去调整校准集。4.3 集成与调用SDK封装思路端侧推理的代码集成通常分三步加载模型、创建推理会话、处理输入输出。以Android TFLite为例加载和调用大概长这样val tflite Interpreter(loadModelFile(context, model_quant.tflite)) val inputShape intArrayOf(1, 224, 224, 3) val inputArray Array(1) { FloatArray(224 * 224 * 3) } val outputArray Array(1) { FloatArray(10) } tflite.run(inputArray, outputArray)不过真实项目不会这么裸我一般会在外层做两件事一是把图像预处理缩放、归一化、通道顺序转换放在独立模块里不进Interpreter这样引擎只管推理二是把Interpreter实例用单例包装起来不要每次调用都重建否则初始化开销会把推理延迟掩盖掉。还要注意端侧引擎的线程安全问题。一个Interpreter实例同时被多个线程调用会崩溃所以常见做法是维护一个对象池每个线程占用一个实例用完归还。如果同一时刻只有一个请求复用一个实例是最省内存的方案。对C引擎比如NCNN需要显式管理Net和Extractor。Extractor每次推理都可以创建但Net要全局复用。输入和输出的Mat对象也要小心生命周期顺手覆写掉就会踩到内存越界的坑。最后封装层一定要把输入大小的校验做掉。用户自拍传上来的是1080x1920但模型入口是224x224如果没有在SDK层做好等比缩放、补边、对齐运行时很容易因为张量形状不匹配直接异常。4.4 性能测试与调优清单性能测试不要只记一个平均耗时。移动端环境很毛糙系统后台任务、CPU调频、温度变化都会影响结果。我只少要记录三个数字p50、p95、运行10分钟后的稳定帧率。p50反映日常典型体验p95覆盖突发卡顿稳定帧率则说明热降频之后会不会掉链子。测完拿到基线后按下面的顺序调优收益从高到低检查输入分支图像解码和缩放是否做到硬件加速看着不起眼却很常见。切换后端从CPU切到GPU或NPU试一次很多卷积类模型能直接翻倍。调整线程数从1到全部核心各跑一遍找到平衡点别迷信“核越多越好”。确认是否量化INT8已经转换但实际有没有走到量化内核要看日志。最后才改模型结构比如把大卷积换成可分离卷积把多分支特征融合简化。还有一条经验首次调用的暖机不能省。GPU和NPU后端第一次执行时要编译内核慢得吓人如果直接在业务回调里测量也会被拖后腿。正确做法是App启动后找个空闲时间预加载模型、跑一次空数据请求之后再进入真实使用流程。5. 端侧推理引擎的常见问题与避坑经验5.1 模型算子不兼容问题怎么排查做端侧部署的人几乎每天都会见到“Unsupported operator”这类报错。前几年还比较频繁现在主流引擎的算子覆盖率已经高了不少但自定义算子、动态控制流、大模型里的奇葩结构还是经常撞上。遇到不兼容我的排查套路是先把报错信息里的算子名拎出来去引擎的算子支持列表里查状态。很多引擎也提供了对应算子转换工具能告诉你哪个算子在哪个Opset版本之后才支持。如果算子很冷门有两条路一是改模型结构尽量用常见的卷积、池化、全连接、激活组合替代二是为该算子写一个自定义实现然后塞进引擎的扩展接口。第二条路成本高但有时候绕不开。实操里还有一个技巧不要等转换工具帮你处理全部算子先在导出ONNX时就把模型拆分把不支持的算子单独从计算图中剥离做成前后处理的预/后处理逻辑。这样模型主链路全兼容性能损失也很小。举个例子某个目标检测模型里用了自定义的Anchor生成和候选框过滤这些完全可以用纯CPU代码写没必要进推理图。5.2 精度漂移和量化敏感层处理量化后精度下降是最磨人的问题。肉眼可见的复原结果错乱、分割mask变毛糙、分类置信度乱飘往往不是模型训得不好而是量化把敏感层的动态范围压缩得太狠了。如果量化后偏差大先确认校准数据对不对。校准数据一定要贴近真实分布并且要有足够的类别覆盖不能拿几十张和上线场景无关的网图凑数。第二个排查点是逐层输出偏差。TFLite有调试工具可以把INT8模型和FP32模型的中间层输出打印出来找出偏差最大的那几个层。通常集中在最后一个卷积层、输出层、或者有复杂激活函数的层。找到敏感层之后在量化配置里给这些层单独指定浮点运算其他层继续使用INT8。这属于混合精度部署能保住大部分体积优势又不会让精度崩掉。还有一种情况是特定输入产生极大或极小的值超出了校准集记录的范围。解决办法不是扩大校准集而是检查模型里是不是有数值不稳定的算子比如某些归一化层在推理阶段没有折叠好导致动态范围跳跃。5.3 内存、发热、启动速度的取舍移动端部署的三角矛盾性能、功耗、包体。不可能三者同时最优。要极致性能往往得用GPU/NPU功耗就上来要小包体量化对精度有压力要低发热就得限制线程和频率性能又打折。我遇到一个典型项目是做本地视频人像分割。最初用GPU双后端跑60fps手机侧温升非常快几分钟就触发降频帧率掉到30fps。后来改成每隔一帧跑一次降到30fps温度和帧率反而稳定了。用户感知到的是“持续流畅比瞬时帧率更重要”。启动速度也是隐蔽的大坑。推理引擎初始化和模型加载可能占几百毫秒特别是几十MB的模型文件。解决方案通常是三步用mmap加载模型文件、把模型加载放到后台线程、在App首屏渲染完再初始化推理引擎。如果你需要做“点击相机马上识别”的功能强烈建议App启动时就预热推理会话否则用户会感觉点完按钮卡了半天。内存方面Android上可以通过Debug.getMemoryInfo拿到native内存和PSS变化。推理引擎的内存峰值经常不在模型本身而在中间特征图。如果模型输入分辨率较高比如实时处理720P画面光第一层卷积的特征图就可能吃掉几十MB这时候适当缩小输入尺寸往往比换任何模型都有效。5.4 碎片化机型兼容性测试技巧端侧开发逃不开机型适配噩梦不同SoC对应不同的GPU驱动和NPU实现。同一个引擎在这台手机上GPU后端飞快换一台可能直接乱输出甚至闪退原因是厂商驱动对OpenCL/NNAPI的实现细节不一样。所以我的兼容性测试原则是高中低端至少各选两部主流机型分别覆盖Android和iOS。高端看性能上限中端看日常体验低端看是否直接没法用。在测试过程中把所有GPU/NPU报错和fallback日志都留到测试机里一旦用户反馈异常就能快速排查。更保险的做法是在代码里加一个“后端健康检测”启动后用一份固定输入跑一次推理校验输出结果是否合理若结果明显异常则自动回退到CPU后端并上报给远程日志。这样即使某个SoC的驱动有bug也能让用户继续使用。版本兼容也不能忽视。Android的NNAPI版本在升级iOS的Core ML版本也在升级同一台设备系统更新后引擎行为可能变化。定期做一次回归测试好过线上突然炸了再去找原因。6. 我最后想分享的几个体会说到这份上想讲几个容易被技术细节盖过的问题。第一个是先想清楚“端侧到底需要什么”。有时候你把一个2BFLOPs的大模型强行量化塞进手机折腾了两个星期性能还是不达标回头想想产品需求本来只要求每帧检测一个目标一个轻量模型就够用。推理引擎优化再强也不如把模型选择做对。第二个体会是别只看跑分。每种引擎都有benchmark工具但benchmark条件跟真实业务差远了。真实业务里有数据读取、预处理、后处理、多线程竞态、内存GC抖动这些都会影响最终帧率。所以我会先搭一个尽量接近真实链路的pipeline再往里面换推理引擎而不是把引擎单独拎出来跑一个纯算子的速度就下结论。第三个体会是要学会读日志和profile数据。很多端侧性能问题用Profiler一看就明白根本不是算子在慢而是某个设备间的数据搬运、锁竞争、内存申请在拖后腿。端侧推理引擎不是黑箱你往下一层一层拆输入处理、模型转换、算子调度、后端执行、硬件驱动每一层都能定位。最后再分享一个通用的小技巧在把模型交给端侧之前先在PC上把整个链路跑通并且保留下每一次转换、量化和性能测试的记录。我在项目里有个deploy_bench目录里面放着模型原始版本、各引擎转换版本、不同设备跑出来的延迟数据。过几个月要加新功能、换引擎或者排查线上问题翻这些记录能省一半时间。这也算是我自己在端侧推理这条路上踩了一堆坑之后最想告诉你的一件事。
返回列表