已关闭
[Requirement|需求建议]: 新增算子check_valid的ascend950 实现 #777
wuao创建于  8月19日关闭于  8月21日
wuao成员
8月19日 创建

Thanks for sending an requirement! Please fill in the following template to help quickly solve your problem.

Backgroud(背景信息)

check_valid(算子注册名 CheckValid,aclnn 函数 aclnnCheckValid)是目标检测后处理阶段的边界框合法性校验算子。
anchor-based 检测器(Faster R-CNN、Mask R-CNN、RetinaNet、SSD、YOLOv3 等)在 RPN 或 bbox head 阶段会批量生成大量
候选框(anchor / proposal),其中相当一部分会落在图像有效区域之外;后续 IoU 计算、NMS、RoIAlign 等环节要求输入框
必须落在图像范围内,否则会产生越界访问或无意义结果。CheckValid 即对每个候选框做一次逐框越界判定,输出长度为 N
的 0/1 掩码(1=合法、0=非法),供下游按掩码过滤。CANN 内置 proto 注释将其明确标注为 "customized FasterRcnn operator"。

Origin(信息来源)

NA

Benefit / Necessity (价值/作用)

check_valid(算子注册名 CheckValid,aclnn 函数 aclnnCheckValid)是 anchor-based 目标检测后处理阶段的
边界框合法性校验算子。检测器(Faster R-CNN / Mask R-CNN / RetinaNet / SSD 等)在 RPN 或 bbox head 阶段会
批量生成大量候选框(anchor 或 proposal),其中相当一部分会落在图像有效区域之外;后续 IoU 计算、NMS、RoI Align 等
环节要求输入框必须落在图像范围内,否则会产生越界访问或无意义结果。CheckValid 即在此环节对每个候选框做一次
逐框越界判定,输出一个长度为 N 的 0/1 掩码(1=合法、0=非法),供下游按掩码过滤。

Design(设计方案)

1 CANN 方案分析

source.md

研究模式:未接入源码仓(reference/ 不存在)。CANN 侧结论基于本地安装包 cann-9.1.0 实证搜索
($ASCEND_OPP_PATH/built-in/op_proto/inc/ 内置 proto + 全包 aclnnCheckValid 符号检索);MindSpore 参考实现
走读基于 github.com/mindspore-ai/mindspore 仓库 master 公开源码。未杜撰本仓本地文件行号。

1.1 算子概述

CheckValid 是 CANN nn_detect_ops(检测算子族)中的边界框合法性校验算子,CANN 内置 proto 注释明确标注为
"customized FasterRcnn operator"。其语义源自 MindSpore mindspore.ops.CheckValid,对 (N,4) 候选框逐框判定
是否落在 img_metas 给定的图像有效边界内,输出 (N,1) 的 int8 0/1 掩码。

算子名映射:

命名风格 形式
目录 / snake_case check_valid
注册名 / PascalCase CheckValid
aclnn 函数 aclnnCheckValid(待新建)

1.2 交付件覆盖总览

按 CANN 交付件类别逐项在本地安装包 cann-9.1.0 内实证检索:

交付件 状态 证据 / 说明
GEIR 原型(REG_OP) ✅ 已找到 $ASCEND_OPP_PATH/built-in/op_proto/inc/nn_detect_ops.h:126 REG_OP(CheckValid);ops_proto_legacy.h:24960 同名(legacy)
OpDef(自定义算子定义) ❌ 未找到 本地无 check_valid 自定义 OpDef 工程,需新建
信息库(op_info_cfg) ❌ 未找到 本地 opp/built-in/op_impl/ 未检出 CheckValid 信息库配置
aclnn API ❌ 未找到 全包检索 aclnnCheckValid 无命中(无 aclnn_check_valid.h / 符号)
Shape 推导(InferShape) ❌ 未找到 无对应推导实现,需新建
Tiling ❌ 未找到 无对应 tiling 实现,需新建
Kernel(Ascend950 / arch35) ❌ 未找到 无对应 kernel 产物,需新建
融合 PASS ❌ 未找到 无 CheckValid 相关融合规则
框架注册(MindSpore Ascend) ⚠ 仅 MindSpore 侧 MindSpore mindspore.ops.CheckValid 已注册(含 CPU kernel);Ascend 后端 kernel 未在本地公开仓交付
Torchair ❌ 未找到 无 torchair 适配(算子无 PyTorch 原生对应)
op-plugin(PyTorch) ❌ 未找到 PyTorch 无原生 check_valid,op-plugin 无适配需求

结论:CANN 侧仅交付了 GEIR 原型(IR 注册),aclnn API / Kernel / Tiling / 信息库 / Shape 推导均未在公开仓交付。
本工作流即为其补齐 Ascend 950(arch35)实现 + aclnn 两段式接口 + GEIR 推导。

1.3 GEIR 原型(注册信息 + 类型支持矩阵)

1.3.1 注册信息(原文摘录,权威 IR)

来源:/usr/local/Ascend/cann-9.1.0/opp/built-in/op_proto/inc/nn_detect_ops.h 第 106–130 行(本地内置 proto,
最高事实源):

/**
 *@brief Judges whether the bounding box is valid. It is a customized
 * FasterRcnn operator .

 *@par Inputs:
 * Two inputs, including:
 * @li bbox_tensor: Bounding box. A 2D Tensor of type float16 or float32 with shape (N, 4).
 * "N" indicates the number of bounding boxes, the value "4" indicates "x0",
 * "x1", "y0", and "y1".
 * @li img_metas: Valid boundary value of the image. A 1D Tensor of type float16 or float32
 * with shape (16,) \n

 *@par Outputs:
 *valid_tensor: A bool with shape (N, 1), specifying whether an input anchor is
 * in an image. "1" indicates valid, while "0" indicates invalid . \n

 *@attention Constraints:
 * 16 "img_metas" are input. The first three numbers (height, width, ratio) are
 * valid, specifying the valid boundary (heights x ratio, weights x ratio).
 */
REG_OP(CheckValid)
    .INPUT(bbox_tensor, TensorType({DT_FLOAT16, DT_FLOAT}))
    .INPUT(img_metas, TensorType({DT_FLOAT16, DT_FLOAT}))
    .OUTPUT(valid_tensor, TensorType({DT_INT8}))
    .OP_END_FACTORY_REG(CheckValid)

1.3.2 类型支持矩阵(以本地内置 proto 为准)

输入 / 输出 名称 DataType Shape Format
INPUT bbox_tensor DT_FLOAT16 / DT_FLOAT (N, 4) ND
INPUT img_metas DT_FLOAT16 / DT_FLOAT(与 bbox_tensor 一致) (3,) 或 (16,),仅前 3 元素有效 ND
OUTPUT valid_tensor DT_INT8 (N, 1) ND

dtype 组合(aclnn / GEIR 应支持的输入组合,输出固定 DT_INT8):

# bbox_tensor img_metas valid_tensor
1 FLOAT16 FLOAT16 INT8
2 FLOAT FLOAT INT8

MindSpore CPU kernel 额外支持 int16 / uint8 输入、bool 输出;本 Ascend 实现严格对齐 CANN 内置 proto,
仅交付 float16 / float32 输入 → int8 输出两种组合。

1.3.3 文档不一致裁定(见 model_research.md §算子数学背景)

  1. bbox 列序:proto 注释 (x0, x1, y0, y1) vs MindSpore / kernel (x0, y0, x1, y1) → 以 MindSpore / kernel 实证为准。
  2. img_metas 长度:proto 注释 (16,) vs MindSpore 文档 (3,) → 仅读前 3 元素,aclnn/GEIR 兼容两种长度。
  3. 输出 shape:proto 注释 (N, 1) vs MindSpore Python (N,) → aclnn/Ascend 按 proto 输出 (N, 1) int8,框架适配层负责 (N,1) int8 ↔ (N,) bool 转换。

1.4 信息库 / aclnn / Shape / Kernel / op-plugin 适配

1.4.1 信息库

未在本地公开仓检出 CheckValid 信息库配置(aicore_*_infos.json 等)。新建算子工程时需补齐
opp_kernel_info.json / op_info_cfg 条目,dtype 组合与上表一致。

1.4.2 aclnn API

未检出 aclnnCheckValid / aclnnCheckValidGetWorkspaceSize 符号。需按 aclnn 两段式约定新建:

aclnnStatus aclnnCheckValidGetWorkspaceSize(
    const aclTensor *bbox_tensor, const aclTensor *img_metas,
    aclTensor *valid_tensor, uint64_t *workspaceSize, aclOpExecutor **executor);
aclnnStatus aclnnCheckValid(void *workspace, uint64_t workspaceSize,
    aclOpExecutor *executor, aclrtStream stream);

1.4.3 Shape 推导

  • 输入:bbox_tensor (N, 4)、img_metas (≥3,)。
  • 输出:valid_tensor (N, 1),dtype INT8。
  • 校验:bbox 必须为 2D 且末维 = 4;img_metas 必须为 1D 且长度 ≥ 3;两输入 dtype 必须相同且 ∈ {FLOAT16, FLOAT};
    否则 InferShape 阶段报错。

1.4.4 Kernel 实现(Ascend 950 / arch35,待新建)

  • 计算范式:纯 Vector(比较 + 一次标量浮点减法),无 Cube / 无 Cube-Vector 混合。
  • 数据流:GM → UB(bbox_tensor 按 N 切分;img_metas 仅 3 元素,广播到各核)→ Vector 比较生成 int8 掩码 → GM。
  • Tiling 要点:按 N 切多核(block 维度切分),单核内按 UB 容量切分 (N,4) 行块;img_metas 小张量全量搬入 UB 或直接走标量寄存器。
  • 边界:N=0 空 bbox 需 kernel 提前 return;输出 int8 按 (N,1) 连续写。
  • workspace:预计仅需极小 workspace(或 0),无中间大张量。

1.4.5 op-plugin / Torchair 适配

PyTorch 无原生 check_valid 算子,op-plugin 无适配对象;torchair 同理。MindSpore 侧经 GEIR 注册即可在 Ascend 后端
dispatch 到本算子,无需额外框架插件。

1.5 参考实现走读(MindSpore CPU kernel,作为 Golden / 语义基准)

来源:github.com/mindspore-ai/mindspore,mindspore/ccsrc/plugin/device/cpu/kernel/check_valid_cpu_kernel.cc
(master 分支公开源码,Apache-2.0)。该实现是本算子 Ascend kernel 与 Golden 的语义基准。

1.5.1 核心计算(LaunchKernel<T>,逐字摘录关键段)

const double offset = 1.0;
auto height = static_cast<double>(img_metas[kIndex0]);   // H
auto width  = static_cast<double>(img_metas[kIndex1]);   // W
auto ratio  = static_cast<double>(img_metas[kIndex2]);   // r
auto img_width_x  = width * ratio - offset;              // W*r - 1
auto img_height_y = height * ratio - offset;             // H*r - 1

auto task = [...](size_t start, size_t end) {
  const T ZERO = static_cast<T>(0);
  for (size_t i = start; i < end; i++) {
    const size_t left_x  = i * 4;      // x0
    const size_t left_y  = i * 4 + 1;  // y0
    const size_t right_x = i * 4 + 2;  // x1
    const size_t right_y = i * 4 + 3;  // y1
    bool valid_flag = false;
    valid_flag = valid_flag || std::less<T>()(anchor_box[left_x], ZERO);            // x0 < 0
    valid_flag = valid_flag || std::less<T>()(anchor_box[left_y], ZERO);            // y0 < 0
    valid_flag = valid_flag || std::less<double>()(img_width_x, anchor_box[right_x]);  // x1 > W*r-1
    valid_flag = valid_flag || std::less<double>()(img_height_y, anchor_box[right_y]); // y1 > H*r-1
    output[i] = !valid_flag;
  }
};
likedislike
liu-weiliu-wei成员
8月19日 将 wow5523 设为负责人
Wwuao成员
8月20日 关联了pull request:check_valid 支持Ascend950
CANN-robotCANN-robot成员
8月21日 关闭了 issue
CANN-robotCANN-robot成员
8月21日 添加了label:resolved