一、摘要

Two‑Stage Detector 两阶段目标检测代表算法为 Faster R‑CNN、Mask R‑CNN,分为候选框生成(RPN 区域建议网络)与第二阶段 ROI‑Head 分类回归,检测精度高,适合边缘工业检测、缺陷识别等场景;对比 YOLO 等单阶段算法,计算链路复杂、多输出、Proposal 算子对 NPU 部署有特殊要求。

OrangePi AIpro 搭载昇腾 310B4 AI 处理器,支持 FP16/INT8 离线 om 模型推理,但 Two‑Stage 模型不能直接把 PyTorch/Torch 导出 ONNX 直接运行,存在几个部署难点:

  1. RPN Proposal 候选框生成包含大量动态 shape 逻辑,ATC 转换容易出现动态算子报错;

  2. 多输出:RPN 输出 anchors、proposal,ROI 输出类别、框偏移;

  3. ROI Align 算子需要 CANN 算子库支持;

  4. 后处理 NMS、坐标还原需要 CPU 侧实现,无法全部放入模型内部。

区分两种部署形态:

  • 完整端到端模型:网络内部集成 Proposal、NMS;

  • 拆分式部署:RPN 网络输出交给 CPU 做 Proposal 后,再送入 ROI Head,降低模型转换难度。

适用场景

  1. 工业缺陷检测,对检测框精度要求高,允许中等推理时延;

  2. 边缘摄像头场景,基于 OrangePi AIpro 做本地高精度目标检测;

  3. 教学实验,学习两阶段检测器在昇腾边缘硬件完整部署链路。

前置约束:开发板预先部署 CANN 驱动、AscendCL 运行时环境;原始模型优先导出去掉后处理的 ONNX,NMS、坐标解码放到应用代码中实现。

二、Two‑Stage Detector 开发模式

2.1 三种开发接入模式

开发模式

适用场景

OrangePi AIpro 接入方式

核心特点

端到端 om 模型模式(优先尝试)

算子全部兼容,动态 shape 可控

MMDeploy 导出 ONNX,ATC 转换 om,AIPP 做图像预处理

代码简洁;Proposal、ROIAlign 算子兼容性要求高,转换失败概率较高

模型拆分推理模式(推荐生产)

Proposal 算子转换报错,边缘部署

拆分为 Backbone+RPN、ROI‑Head 两个 om 模型;CPU 做 Proposal 处理

稳定性高;两次推理,应用层逻辑复杂

MindSpore 在线推理模式

算法调试、教学原型

MindSpore 加载 FasterRCNN 网络,昇腾在线推理

不适合高吞吐业务,适合算法验证

注意:Two‑Stage 模型尽量避免把 NMS 算子嵌入 ONNX 内部,建议移到 Python 应用层,降低模型转换失败概率。

2.2 整体数据流

原始图像 → OpenCV读取预处理缩放归一化 → AIPP/CPU预处理
→ 送入Backbone+RPN离线om推理 → 获取RPN输出anchors、box delta
→ CPU执行Proposal筛选候选框 → 候选框与特征图送入ROI‑Head om推理
→ CPU后处理:坐标解码、NMS过滤 → 绘制检测框输出结果

2.3 关键约束(OrangePi AIpro 部署重点)

  1. soc_version 必须指定Ascend310B4,否则 om 无法在香橙派 AIpro 上加载运行;

  2. ROIAlign、Proposal 对动态输入敏感,转换时合理设置--dynamic_dims;

  3. 两阶段两次推理之间候选框数据在 CPU 内存交互,候选框数量需要限制;

  4. INT8 量化会对两阶段检测精度带来明显损失,优先 FP16 推理;

  5. 开发板内存有限,输入分辨率不宜设置过高,防止内存 OOM。

三、核心模块内容详解

3.1 Two‑Stage 网络结构

  • Backbone+FPN:图像提取多尺度特征;

  • RPN Head:生成锚框、前景背景分类、框偏移,输出大量候选 Proposal;

  • ROI Align:根据 Proposal 从特征图抠取 ROI 特征;

  • ROI‑Head:完成对候选框的分类与坐标回归。

3.2 核心接口与工具

  1. MMDeploy:将 MMDetection 的 Faster‑RCNN 导出拆分式 ONNX 模型;

  2. ATC 工具:ONNX 转 om 离线模型;

  3. AscendCL:开发板侧 Python 接口 aclruntime,加载 om 执行推理;

  4. CPU 侧:Proposal 解码、NMS 非极大抑制、坐标映射还原。

3.3 对接 OrangePi AIpro 要点

预处理可以选择 CPU 做或者 AIPP 配置文件;Two‑Stage 后处理逻辑复杂,大部分逻辑在 ARM CPU 完成,NPU 只负责张量推理计算;可以通过 npu_smi 查看昇腾芯片负载状态。

四、代码实战

环境依赖:OrangePi AIpro,CANN6.3.RC1,AscendCL,opencv‑python,numpy;示例采用拆分式部署模式。

4.1 ATC 模型转换命令(RPN 子网络)

atc --model=faster_rcnn_rpn.onnx \
--framework=5 \
--soc_version=Ascend310B4 \
--output=faster_rcnn_rpn.om \
--input_shape="input:1,3,800,1333" \
--dynamic_dims="proposal_num:1~300" \
--insert_op_conf=aipp.cfg
# ROI‑Head子网络转换
atc --model=faster_rcnn_roi.onnx \
--framework=5 \
--soc_version=Ascend310B4 \
--output=faster_rcnn_roi.om

4.2 推理主代码(基于 aclruntime)

import numpy as np
import cv2
from aclruntime import AclModel

def proposal_decode(rpn_bbox, rpn_cls, anchors, conf_threshold=0.5):
    """CPU侧RPN候选框解码,Two‑Stage关键后处理"""
    proposals = []
    num_anchor = anchors.shape[0]
    for i in range(num_anchor):
        score = rpn_cls[i,1]
        if score < conf_threshold:
            continue
        dx, dy, dw, dh = rpn_bbox[i]
        xa, ya, wa, ha = anchors[i]
        x1 = xa + dx * wa
        y1 = ya + dy * ha
        w = np.exp(dw) * wa
        h = np.exp(dh) * ha
        proposals.append([x1,y1,x1+w,y1+h, score])
    return np.array(proposals)

def nms(dets, iou_thresh=0.45):
    """NMS非极大抑制CPU实现"""
    if len(dets)==0:
        return np.empty((0,5))
    x1,y1,x2,y2,scores = dets[:,0],dets[:,1],dets[:,2],dets[:,3],dets[:,4]
    areas = (x2-x1+1)*(y2-y1+1)
    order = scores.argsort()[::-1]
    keep = []
    while order.size>0:
        i = order[0]
        keep.append(i)
        xx1 = np.maximum(x1[i],x1[order[1:]])
        yy1 = np.maximum(y1[i],y1[order[1:]])
        xx2 = np.minimum(x2[i],x2[order[1:]])
        yy2 = np.minimum(y2[i],y2[order[1:]])
        w = np.maximum(0, xx2‑xx1+1)
        h = np.maximum(0, yy2‑yy1+1)
        inter = w*h
        iou = inter/(areas[i]+areas[order[1:]]‑inter)
        idx = np.where(iou<=iou_thresh)[0]
        order = order[idx+1]
    return dets[keep]

if __name__ == "__main__":
    # 加载两个子模型
    rpn_model = AclModel("./faster_rcnn_rpn.om")
    roi_model = AclModel("./faster_rcnn_roi.om")

    img = cv2.imread("test.jpg")
    img_in = cv2.resize(img,(1333,800)).astype(np.float32).transpose(2,0,1)
    img_in = np.expand_dims(img_in,0)

    # 第一阶段推理RPN
    rpn_out = rpn_model.infer([img_in])
    rpn_bbox_pred, rpn_cls_pred, anchors = rpn_out

    # CPU处理Proposal候选框
    proposals = proposal_decode(rpn_bbox_pred[0], rpn_cls_pred[0], anchors[0])
    proposals = nms(proposals, iou_thresh=0.6)
    proposals = proposals[:300,0:4]

    # 第二阶段ROI‑Head推理
    roi_out = roi_model.infer([img_in, proposals.astype(np.float32)])
    roi_cls, roi_bbox = roi_out

    print(f"检测完成,目标数量:{len(proposals)}")

五、常见问题与调优实践

Q1:ATC 转换报错 ROIAlign 算子不支持

  • 根因:CANN 算子版本不匹配,ONNX 算子属性不兼容;

  • 解决:升级 CANN,使用 MMDeploy 指定算子版本导出,拆分模型,ROI 逻辑放到 CPU。

Q2:推理结果框全部偏移、坐标不对

  • 根因:图像预处理归一化、AIPP 参数和训练不匹配;Proposal 解码逻辑错误;

  • 解决:核对均值方差,校验 proposal_decode 坐标变换。

Q3:推理速度慢,FPS 很低

  • 根因:两阶段两次推理;CPU 后处理 Proposal、NMS 占用大量 ARM 时间;

  • 解决:限制候选框最大数量,降低输入分辨率;优化 NMS 代码。

Q4:om 模型加载失败

  • 根因:转换时 soc_version 写错,不是 Ascend310B4;om 是其他昇腾芯片生成;

  • 解决:重新执行 atc,指定正确 soc_version。

六、总结

OrangePi AIpro 部署 Two‑Stage Detector(Faster R‑CNN)分为端到端 om、模型拆分推理、MindSpore 在线推理三种模式,工程实践优先模型拆分推理模式,规避 Proposal、ROIAlign 算子转换风险。

开发关键点:

  1. Two‑Stage 检测器后处理复杂,Proposal 解码、NMS 建议放在 CPU 应用层,不嵌入模型;

  2. ATC 转换必须设置soc_version=Ascend310B4适配香橙派 AIpro 硬件;

  3. 两阶段为两次推理,候选框数量做限制,控制 ARM‑NPU 之间数据交互开销;

  4. 优先 FP16 推理,INT8 量化容易造成检测 mAP 精度下降;

  5. 完成部署后对比 GPU 原始输出,校验坐标、类别、置信度精度对齐。

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐