新闻详情

新闻详情

首页 / 资讯中心 / 详情

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

发布时间:2026/10/1 7:14:15来源:尧图网络
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

相关资讯

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

较早相关资讯

最新相关资讯

OpenRig:基于Node.js+tmux的Codex CLI本地代理调试框架 2026/10/1 7:14:11

OpenRig:基于Node.js+tmux的Codex CLI本地代理调试框架

1. 项目概述:OpenRig 是什么,它解决的是哪类真实问题?OpenRig 不是一个广为人知的主流开源项目,也不是 Node.js 官方生态中的标准工具。从当前全网公开可查的技术资料、GitHub 仓库、npm 包索引及主流技术社区(Stack O…

阅读更多 →
国内近红外光谱仪公司推荐:数据采集与建模能力考察要点 2026/10/1 7:14:11

国内近红外光谱仪公司推荐:数据采集与建模能力考察要点

国内近红外光谱仪公司推荐:数据采集与建模能力考察要点在化工、精细化工、新材料、医药、生物制药等流程制造行业,近红外光谱仪作为过程分析技术的核心装备之一,其选型决策直接影响着企业的质量管控效率与工艺优化空间。然而,市场…

阅读更多 →
细孔放电加工设备的工艺稳定性难题:从参数沉淀到服务半径的工程化拆解 2026/10/1 7:14:11

细孔放电加工设备的工艺稳定性难题:从参数沉淀到服务半径的工程化拆解

细孔放电加工设备的工艺稳定性难题:从参数沉淀到服务半径的工程化拆解 说明:本文讨论电火花小孔加工设备这一细分领域,从需求结构、供给能力和交付后成本三个维度展开。该细分市场缺少公开且口径统一的权威统计数据,因此本文以加工…

阅读更多 →
统一网关Gateway实战:用Spring Cloud Gateway路由与过滤器搭建TaoToken统一API入口 2026/10/1 7:14:11

统一网关Gateway实战:用Spring Cloud Gateway路由与过滤器搭建TaoToken统一API入口

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
从ProvenanceGuard理解多源RAG的claim-to-source验证 2026/10/1 7:14:11

从ProvenanceGuard理解多源RAG的claim-to-source验证

AI 说“根据账户记录,你有 30 天退款期”,这句话可能事实正确,引用却错了:30 天来自通用政策,账户记录里根本没有。读完本文,你会理解多源 RAG 为什么要保留来源身份,并能用一段 Python 检查“每…

阅读更多 →
企业微信自建机器人对接 OpenClaw 完整创建、授权、调试步骤(含安装包)|TaoToken 统一 Key 通道实践 2026/10/1 7:14:05

企业微信自建机器人对接 OpenClaw 完整创建、授权、调试步骤(含安装包)|TaoToken 统一 Key 通道实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

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

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