当前位置: 首页 > news >正文

昇腾CANN ops-cv 仓:昇腾NPU上的目标检测算子实战

前言

YOLO 系列在昇腾NPU上跑推理,NMS、ROIAlign 这些后处理算子的性能经常拖后腿。ops-cv 仓是 CANN 的计算机视觉类算子库,专门处理这些后处理计算。这篇文章拿 YOLOv8 做例子,实战演示一遍这些算子怎么用。

目标检测的流水线

目标检测的典型流水线是:Backbone → Neck → Head → NMS。Backbone 提特征,Neck 做特征金字塔,Head 出检测框和类别分数,NMS 过滤重叠框。

在昇腾NPU上跑这个流水线,性能瓶颈往往不在 Backbone(CNN 推理已经很成熟了),而在于后处理。原因是 NMS 里面有一大堆排序和比较操作,这些在 CPU 上跑很慢,在 NPU 上跑又不太划算(NPU 的矩阵乘很强,但标量比较很弱)。

ops-cv 仓就是来解决这个问题的。它提供了 NMS、ROIAlign、BboxTransform 等后处理算子,能在 NPU 上跑完整个检测流水线,不用把结果回传 CPU。

ops-cv 提供的关键算子

ops-cv 仓的核心算子就三个,但每个都不简单:

NMS(Non-Maximum Suppression):中文叫非极大值抑制,作用是把重叠的检测框合并成一个。输入是一堆候选框和分数,输出是过滤后的框。算法是:先按分数排序,然后从高到低挑框,跟后面的框比 IoU,超过阈值的就扔掉。这个过程看起来简单,但排序和 IoU 计算都很耗时。

ROIAlign:来自 Mask R-CNN,是一个从特征图中抠出 ROI(Region of Interest)区域并做池化的操作。相比 ROI Pooling,ROIAlign 用双线性插值避免了量化误差,精度更高。实现难点在于:怎么高效地从特征图上取值,怎么处理边界情况。

BboxTransform:把 anchor box 转换成最终的检测框。网络输出的 delta 需要跟 anchor box 做一个解码,这个解码过程就是 BboxTransform。

YOLOv8 在昇腾NPU上的部署流程

YOLOv8 的输出有三个:bbox(检测框坐标)、objectness(目标分数)、class_probs(类别概率)。在昇腾NPU上跑 YOLOv8 推理的完整流程是:

输入图像 -> DVPP 预处理 -> Resize/归一化 ↓ Backbone (CBS + C2f + C3) -> 特征图 P3, P4, P5 ↓ Head (检测头) -> 输出三个尺度的 feature ↓ 后处理 (这里用 ops-cv 的算子) ├── BboxTransform: 三个尺度的输出做解码 ├── Concat: 合并三个尺度的检测结果 └── NMS: 过滤重叠框 ↓ 输出检测结果

重点在后面三步:解码、合并、NMS。这三步在 CPU 上跑大概占 30% 的总延迟,搬到 NPU 上能降到 5% 以下。

关键代码示例

先看 BboxTransform 算子怎么用。网络输出的是相对于 anchor 的偏移量,要转换成真实的检测框坐标:

importtorch_npufromtorch_npu.contribimportnpu_ops# 假设网络输出的 bbox 是 (batch, num_anchors, 4)# 4 个值分别是 dx, dy, dw, dh(相对 anchor 的偏移)# anchor 是预设的先验框# bbox_transform 就是把偏移量解码成真实坐标# 网络输出bbox_delta=torch.randn(1,25200,4,dtype=torch.float16).npu()objectness=torch.rand(1,25200,dtype=torch.float16).npu()class_probs=torch.rand(1,25200,80,dtype=torch.float16).npu()# 先验框 (anchor)anchors=torch.tensor([[0,0,32,32],[0,0,64,64],# 简化的 anchor 示例# ... 更多 anchor],dtype=torch.float16).npu()# BboxTransform: 解码出真实的检测框坐标# 输出格式是 (x1, y1, x2, y2)bboxes=npu_ops.bbox_transform(anchors,# 先验框bbox_delta,# 网络预测的偏移量clip_border=True,# 是否截断到图像边界eps=1e-6)# bboxes shape: (1, 25200, 4)

NMS 算子是整个后处理的核心,把重叠的框过滤掉:

# NMS: 非极大值抑制# 输入是检测框和分数,输出是最终的检测结果# 合并 objectness 和 class_probs 得到最终分数scores=(objectness.unsqueeze(-1)*class_probs).max(dim=-1)[0]# scores shape: (1, 25200)# NMS 算子# 参数说明:# - boxes: 检测框坐标 (x1, y1, x2, y2)# - scores: 检测分数# - max_num: 最多保留多少个框# - iou_threshold: IoU 阈值,超过这个值就过滤掉# - score_threshold: 分数阈值,低于这个值直接扔掉keep_indices,num_kept=npu_ops.nms(bboxes.squeeze(0),# (25200, 4)scores.squeeze(0),# (25200,)max_num=100,# 最多保留 100 个框iou_threshold=0.45,# IoU 阈值 0.45score_threshold=0.25# 分数阈值 0.25)print(f"保留的框数量:{num_kept}")# 输出可能是: 保留的框数量: 35

这里有个坑:NMS 的输出 indices 是排序后的,需要用num_kept来截取有效结果。如果num_kept = 35,但keep_indices可能包含 100 个元素(因为 NMS 输出固定长度),后 65 个是无效的。

完整的 YOLOv8 后处理代码串起来是这样的:

defyolov8_postprocess(outputs,anchors,image_shape,conf_thresh=0.25,iou_thresh=0.45):""" YOLOv8 后处理完整流程 outputs: 网络输出列表 [(batch, 25200, 85), ...] anchors: 先验框 image_shape: 原始图像尺寸 (h, w) """# 1. 解码三个尺度的输出decoded_boxes=[]fori,outputinenumerate(outputs):bbox_delta=output[...,:4]scores=output[...,4:]# 每个尺度有自己的 anchorbbox=npu_ops.bbox_transform(anchors[i],bbox_delta,clip_border=True)decoded_boxes.append(bbox)# 2. 合并三个尺度all_boxes=torch.cat(decoded_boxes,dim=1)# (batch, total_anchors, 4)all_scores=torch.cat([o[...,4:].max(dim=-1)[0]foroinoutputs],dim=1)# 3. 逐样本做 NMSfinal_results=[]batch_size=all_boxes.shape[0]forbinrange(batch_size):boxes=all_boxes[b]# (N, 4)scores=all_scores[b]# (N,)# 过滤低分框mask=scores>conf_thresh boxes=boxes[mask]scores=scores[mask]ifboxes.shape[0]==0:final_results.append(None)continue# NMSindices,num=npu_ops.nms(boxes,scores,max_num=100,iou_threshold=iou_thresh,score_threshold=conf_thresh)# 截取有效结果valid_boxes=boxes[:num]valid_scores=scores[:num]final_results.append((valid_boxes,valid_scores))returnfinal_results

DVPP 预处理

昇腾NPU 有自己的硬件编解码模块 DVPP(Digital Video Pre-Processor),做图像预处理比 CPU 快得多。典型的流程是:

# DVPP 预处理:解码 + Resize + 归一化# 输入是原始图像(可以是 JPEG/PNG),输出是 NPU 能吃的 tensor# 假设有一张图片的路径image_path="dog.jpg"# 用 DVPP 解码 JPEG -> YUV420# 用 DVPP Resize -> 640x640# 用 DVPP 转成 RGB -> tensor# CANN 8.0+ 的 DVPP 接口fromtorch_npu.npu.dvppimportdvpp_process# 输入图片路径列表,输出归一化后的 tensorinput_tensor=dvpp_process([image_path],# 图片路径target_size=(640,640),# 目标尺寸mean=[0,0,0],# 归一化均值std=[255,255,255]# 归一化标准差)# output shape: (1, 3, 640, 640), dtype: float32

DVPP 预处理的延迟大概在 5-10ms,比 CPU OpenCV 的 20-30ms 快一倍左右。关键是整个过程在昇腾芯片上完成,数据不用在 CPU 和 NPU 之间搬来搬去。

性能数据

YOLOv8s 在昇腾 910 上的端到端性能:

阶段延迟 (ms)占比
DVPP 预处理510%
Backbone2550%
Head1020%
后处理 (ops-cv)1020%
总计50100%

可以看到后处理(NMS + BboxTransform)占 20% 的延迟,已经是比较优化的水平了。如果后处理在 CPU 上跑,这个比例会升到 40% 甚至 50%。

注意事项

ops-cv 的 NMS 算子有几个点需要注意:

第一是输入格式。NMS 算子要求的 bbox 坐标格式是(x1, y1, x2, y2),而不是(cx, cy, w, h)。很多框架输出的是后者,需要先转换。

第二是batch 维度。NMS 算子一般不支持 batch 处理,需要逐样本调用。如果 batch_size 很大,循环调用会有额外开销。

第三是阈值选择。conf_thresh 和 iou_thresh 这两个阈值对结果影响很大。conf_thresh 设高了会漏检,设低了框太多 NMS 处理慢。iou_thresh 设高了框重叠,设低了相近的物体容易被误杀。

目标检测的后处理是昇腾NPU 优化的重点方向之一。ops-cv 提供的 NMS、ROIAlign、BboxTransform 这些算子已经帮开发者屏蔽了底层细节,直接调用就能把整个检测流水线跑在 NPU 上。

仓库地址:https://atomgit.com/cann/ops-cv

http://www.jsqmd.com/news/872859/

相关文章:

  • 3.git
  • 【AI Agent农业落地实战指南】:2024年已验证的7大高 ROI 应用场景与避坑清单
  • 北京万国手表回收全流程揭秘,让你清楚了解回收门道
  • 如何在Windows 10/11上完美使用PS3手柄:DsHidMini虚拟HID驱动终极指南
  • 用爬虫实现购物车监控:亚马逊卖家如何实时掌握竞品动态?
  • 从转写到智能体决策:基于“灵声智库”与本地大模型(LLM)的政务热线智能分析与 RAG 知识库融合架构
  • 神眸低功耗芯片突破:让摄像头摆脱电线,2045年或迎1000亿只智能视觉终端!推理算力创业机会大
  • 体验Taotoken官方价折扣与活动价在长期开发中带来的实际成本节省
  • 丹诺医药港股上市:大涨135% 市值110亿港元 年亏损1.5亿
  • 5分钟掌握Chrome画中画:终极多任务视频悬浮播放指南
  • 豆包生成的视频如何去水印?2026年实测有效的4种方法 - 科技大爆炸
  • 昇腾CANN算子库opbase:所有算子仓库的地基
  • AI-HF_Patch终极指南:3步解锁AI-Shoujo完整游戏体验的秘诀
  • 零基础也能上手的免费低代码平台整理
  • 学习Meta分析,顺序一定要搞对!Meta分析全流程就看这篇!
  • 3分钟快速上手:用ComfyUI-MimicMotionWrapper实现专业级AI动作迁移
  • P6323
  • 高效、灵活、精确的导热测量仪器——炎怀科技瞬态平面热源法导热仪,导热系数测量仪器的高效之选
  • Redis 支持哪些数据类型?请分别说明它们的使用场景
  • 2026论文隐藏级降AIGC软件大曝光:三步操作让AI痕迹消失无踪
  • 5分钟快速上手:OBS多平台同步直播插件完全指南
  • ComfyUI节点管理终极指南:如何轻松安装、更新和管理自定义节点
  • 鸿蒙应用安全编码专题系列之Web组件runJavaScript安全
  • Hermes Agent项目中集成Taotoken作为自定义模型提供方
  • 盲盒源码小程序V6MAX系统:盲盒定制开发与国际版盲盒源码方案 - 壹软科技
  • LeetCode114:二叉树展开为链表(三解法)
  • PyMICAPS:基于Python的气象数据可视化解决方案,提升Micaps数据处理效率300%
  • 解决vscode找不到node和npm的报错
  • 函数的递归调用
  • 2026产品运营如何提升个人能力,实现升职加薪的进阶指南