新闻详情

新闻详情

首页 / 资讯中心 / 详情

RK3588 上从 0 部署 YOLOv5s:我的全链路实践(五)C++ NMS 加速 359 倍

发布时间:2026/11/7 10:41:31来源:尧图网络
RK3588 上从 0 部署 YOLOv5s:我的全链路实践(五)C++ NMS 加速 359 倍
背景同样的 1000 个候选框Python 版 NMS 要跑 6.7 秒C 版只要 18.8 毫秒。这不是改算法是把同一份逻辑从解释器搬到机器码。加速 359 倍结果逐索引完全一致。阶段 5C NMS创建脚本。50_bench_nms.py#!/usr/bin/env python3 ## 阶段5NMS 性能对比——Python 参考实现 vs Cpybind11 # 作用【Python vs C耗时 ms】难点2【X ms → Y ms】 # 用法cd build 旁的目录#python350_bench_nms.py/path/to/build 含 nms_cpp*.so 的目录#python350_bench_nms.py none 只跑 Python 基线也行#importsys,os,json,time,statistics,datetimeimportnumpyas np REPEAT5# 原为100为了不让 Python 双重循环等太久降到5加速比几乎不变 N_BOXES1000# 候选框数量级YOLOv5s640输入 conf0.25后典型几百~上千 deflog_metrics(rec):os.makedirs(metrics,exist_okTrue)pmetrics/metrics.jsonarrjson.load(open(p))ifos.path.exists(p)else[]arr.append(rec)json.dump(arr,open(p,w),ensure_asciiFalse,indent2)defpy_nms(boxes,scores,iou_thresh):Python 参考实现和 C 完全同算法公平对比的前提ordernp.argsort(-scores)keep[]suppressednp.zeros(len(scores),dtypebool)fori in order:ifsuppressed[i]:continuekeep.append(int(i))aboxes[i]forj in order:ifsuppressed[j]orji:continuebboxes[j]x1,y1max(a[0],b[0]),max(a[1],b[1])x2,y2min(a[2],b[2]),min(a[3],b[3])intermax(0.0,x2-x1)*max(0.0,y2-y1)union(a[2]-a[0])*(a[3]-a[1])(b[2]-b[0])*(b[3]-b[1])-interifinter/(union1e-6)iou_thresh:suppressed[j]Truereturnkeep defgen_boxes(n,seed42):合成数据60% 框挤在同一区域高重叠模拟密集检测场景rngnp.random.RandomState(seed)xyrng.rand(n,2)*50060# 顶点集中在画布中央 whrng.rand(n,2)*8010boxesnp.hstack([xy,xywh]).astype(np.float32)scoresrng.rand(n).astype(np.float32)returnboxes,scores defbench(fn,boxes,scores,thr,repeat,label):ts[]fork inrange(repeat):t0time.perf_counter()fn(boxes,scores,thr)dt(time.perf_counter()-t0)*1000ts.append(dt)print( [%s] 第 %d/%d 次: %.3f ms%(label,k1,repeat,dt),flushTrue)returnround(statistics.mean(ts),3)if__name____main__:so_dirsys.argv[1]iflen(sys.argv)1elsebuildprint([1/3] 生成 %d 个模拟框...%N_BOXES,flushTrue)boxes,scoresgen_boxes(N_BOXES)print([2/3] 跑 Python 版 NMS%d 次...%REPEAT,flushTrue)py_msbench(lambda b,s,t:py_nms(b,s,t),boxes,scores,0.45,REPEAT,py )cpp_ms,speedup,agreeNone,None,Noneifso_dir!none:ifos.path.isdir(so_dir):sys.path.insert(0,so_dir)print([3/3] 跑 C 版 NMS ...,flushTrue)importnms_cpp# 正确性验证同输入下两种实现保留的索引集合必须一致 k_pyset(py_nms(boxes,scores,0.45))k_cppset(int(i)fori in nms_cpp.nms(boxes,scores,0.45))agree(k_pyk_cpp)assert agree,C 与 Python 结果不一致——先别谈性能查算法cpp_msbench(lambda b,s,t:nms_cpp.nms(b,s,t),boxes,scores,0.45,REPEAT,cpp)speedupround(py_ms/cpp_ms,1)rec{tag:nms_bench,ts:datetime.datetime.now().isoformat(timespecseconds),n_boxes:N_BOXES,repeat:REPEAT,python_ms:py_ms,cpp_ms:cpp_ms,speedup_x:speedup,result_identical:agree,}log_metrics(rec)print(json.dumps(rec,ensure_asciiFalse,indent2))print(\n[口径] N{} 候选框、重复 {} 次取均值结果一致性必须为 True 再引用速度比.format(N_BOXES,REPEAT))CMakeLists.txtcmake_minimum_required(VERSION3.15)project(nms_cpp LANGUAGES CXX)set(CMAKE_CXX_STANDARD14)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_POSITION_INDEPENDENT_CODE ON)# 用法先 pip install pybind11# cmake -B build -Dpybind11_DIR$(python3 -m pybind11 --cmakedir)# cmake --build build# 产物build/nms_cpp*.sopython 侧把该目录加进 sys.path 即可 importfind_package(pybind11 CONFIG REQUIRED)pybind11_add_module(nms_cpp nms.cpp)nms.cpp//// 阶段5C NMS 后处理pybind11 绑定 Python // 作用【后处理 C 重写】 难点2 证据 // 输入boxes(N,4)float32 xyxy 像素坐标scores(N,)float32iou_thresh // 输出保留框的索引列表按分数降序 // 算法按分数降序贪心——取当前最高分框删除与它 IoUthresh 的所有框 //#include pybind11/pybind11.h#include pybind11/numpy.h#include pybind11/stl.h#include vector#include algorithm#include cmathnamespace pypybind11;// IoUIntersection over Union交并比两框重叠程度1完全重合 static inline float iou_xyxy(const float* a, const float* b){float x1std::max(a[0], b[0]);float y1std::max(a[1], b[1]);float x2std::min(a[2], b[2]);float y2std::min(a[3], b[3]);float wstd::max(0.f, x2 - x1);float hstd::max(0.f, y2 - y1);float interw * h;float area_a(a[2]- a[0])*(a[3]- a[1]);float area_b(b[2]- b[0])*(b[3]- b[1]);returninter /(area_a area_b - inter 1e-6f);}std::vectorint64_tnms(py::array_tfloat, py::array::c_style|py::array::forcecastboxes, py::array_tfloat, py::array::c_style|py::array::forcecastscores, float iou_thresh){if(boxes.ndim()!2||boxes.shape(1)!4)throw std::runtime_error(boxes 必须是 (N,4) xyxy);auto Bboxes.unchecked2();//(N,4)auto Sscores.unchecked1();//(N,)int n(int)B.shape(0);if(n0)return{};const float* bp(const float*)boxes.data();// argsort分数降序这就是按置信度排序 std::vectorintorder(n);for(int i0;in;i)order[i]i;std::sort(order.begin(), order.end(),[](int a, int b){returnS[a]S[b];});std::vectorcharsuppressed(n,0);std::vectorint64_tkeep;for(int i0;in;i){int idxorder[i];if(suppressed[idx])continue;keep.push_back((int64_t)idx);const float* curbp (size_t)idx *4;// 删除所有与当前框高度重叠的候选贪心O(N^2)for(int ji 1;jn;j){int jdxorder[j];if(suppressed[jdx])continue;if(iou_xyxy(cur, bp (size_t)jdx *4)iou_thresh)suppressed[jdx]1;}}returnkeep;// 索引数组Python 侧直接 numpy 索引}PYBIND11_MODULE(nms_cpp, m){m.doc()C NMS (pybind11);m.def(nms,nms, py::arg(boxes), py::arg(scores), py::arg(iou_thresh)0.45f);}生成 CMake 构建配置cmake-Bbuild-Dpybind11_DIR$(python3-mpybind11--cmakedir)编译cmake--buildbuild执行脚本对比前后数据python3 50_bench_nms.py build数据总结要点分析为什么Python这么慢答因为Python版NMS删掉重复框只留最准的那个是“1000*1000“的双重for循环每次迭代都涉及Python解释器开销、numpy索引、max/min调用。100万次迭代光解释器开销就要好几秒。为什么C这么快答C编译后变成机器码loU两个框重叠程度的百分比计算只有几十条汇编指令且用const float*直接指针访问内存零拷贝没有解释器开销。RK3588的A76单核跑1000次框的NMS只用18ms完全合理。“加速的前提是 result_identical: True。 我用了相同的贪心算法C 版返回的保留索引集合与 Python 版完全一致。性能优化绝不能牺牲正确性。”“这个基准测试用的是 1000 个框最坏情况。实际部署中经过 conf0.25 过滤后通常只剩 50-200 个框那时 C NMS 只需 0.2-1 ms完全不会成为瓶颈。”加速的前提是 result_identical: True。我用了相同的贪心算法C 版返回的保留索引集合与 Python 版完全一致。性能优化绝不能牺牲正确性。下一篇讲 mAP 精度评估INT8 量化到底掉多少点5000 张 COCO 图全量实测。更多更详细内容请查看CSDN链接https://blog.csdn.net/2501_92605570?spm1011.2415.3001.5343
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/6 6:37:16

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/7 0:39:20

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/7 6:36:21

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/6 17:25:36

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/6 14:29:05

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/6 14:29:07

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉