08-推理性能优化:帧率提升、CPU/NPU 占用优化

📅 2026/8/10 2:28:14
08-推理性能优化:帧率提升、CPU/NPU 占用优化
推理性能优化:帧率提升、CPU/NPU 占用优化为什么要性能优化嵌入式端最大的特点就是算力有限。一块 RK3588,CPU 6 核看着还行,但跑个 YOLOv8n 640 输入,CPU 推理也就 10FPS 出头。放到产品场景,10FPS 可能不够:无人售货柜需要快速响应开门关门,检测慢了用户体验差工业检测流水线上产品快速通过,帧率不够就漏检机械臂抓取需要实时定位反馈,延迟超过 100ms 就影响控制性能优化不是调几个参数就完事,而是从输入尺寸、推理引擎、内存、算法策略多层面系统性优化。输入尺寸优化这是最立竿见影的优化手段。模型输入尺寸从 640 降到 416,计算量直接降到原来的42%(416²/640²≈0.423)。降到 320 更夸张,计算量只有原来的25%。输入尺寸YOLOv8n 计算量RK3588 CPU推理时间mAP精度变化640×6408.7 GFLOPs85ms基准416×4163.7 GFLOPs42ms-2.1%320×3202.2 GFLOPs25ms-5.8%计算量降了,精度也会降。但降幅不是线性的,640→416 只掉 2% 精度,性价比极高。416→320 掉了 3.7%,得看场景能不能接受。选择策略:目标物体大(占画面 20% 以上):320 够用中等目标(占画面 5%-20%):416 最优小目标多(占画面 5% 以下):老老实实用 640智慧农业大棚里检测病害叶片,目标一般较大,320 足够。无人售货柜里商品密集且有些小包装,416 是比较均衡的选择。推理引擎优化NPU 优先有 NPU 就用 NPU,别浪费。RK3588 的 NPU 算力 6 TOPS(INT8),跑 YOLOv8n 640 输入只要15ms,是 CPU 的 5 倍多。# RKNN推理(NPU加速)fromrknnlite.apiimportRKNNLite rknn=RKNNLite()rknn.load_rknn('yolov8n.rknn')rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0)# RK3588有3个NPU核心,可以选NPU_CORE_0/1/2或AUTOoutputs=rknn.inference(inputs=[input_data])RK3588 有 3 个 NPU 核心,NPU_CORE_AUTO会自动负载均衡,但如果只跑一个模型,直接绑定一个核心反而更稳定。CPU 多线程没 NPU 的平台,ONNX Runtime 默认会用多线程。但你可以手动控制线程数,避免和摄像头采集线程抢资源:importonnxruntimeasort# 限制推理线程数,留核心给采集和显示session_options=ort.SessionOptions()session_options.intra_op_num_threads=4# 算子内并行session_options.inter_op_num_threads=1# 算子间并行session=ort.InferenceSession('yolov8n.onnx',sess_options=session_options,providers=['CPUExecutionProvider'])6 核 CPU,建议给推理 4 个线程,剩 2 个留给采集和显示。如果全给推理用,VideoCapture.read()会卡住,帧率反而下降。ONNX Runtime 算子优化session_options=ort.SessionOptions()# 开启内存优化,减少推理过程中的内存碎片session_options.enable_mem_pattern=True# 开启计算图优化(算子融合等)session_options.graph_optimization_level=(ort.GraphOptimizationLevel.ORT_ENABLE_ALL)ORT_ENABLE_ALL会做算子融合、常量折叠等优化,一般能提升 5%-15% 性能。注意这是会话级别的,初始化时设置好就行。内存优化嵌入式端内存紧张,减少内存拷贝在密集推理中很关键。预分配内存不要每次推理都新建 numpy 数组,提前分配好复用:classOptimizedDetector:def__init__(self,model_path,input_size=416):self.input_size=input_size self.session=ort.InferenceSession(model_path)self.input_name=self.session.get_inputs()[0].name