/**
*@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)
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
1.1 算子概述
CheckValid是 CANNnn_detect_ops(检测算子族)中的边界框合法性校验算子,CANN 内置 proto 注释明确标注为"customized FasterRcnn operator"。其语义源自 MindSpore
mindspore.ops.CheckValid,对(N,4)候选框逐框判定是否落在
img_metas给定的图像有效边界内,输出(N,1)的int80/1 掩码。算子名映射:
check_validCheckValidaclnnCheckValid(待新建)1.2 交付件覆盖总览
按 CANN 交付件类别逐项在本地安装包
cann-9.1.0内实证检索:$ASCEND_OPP_PATH/built-in/op_proto/inc/nn_detect_ops.h:126REG_OP(CheckValid);ops_proto_legacy.h:24960同名(legacy)check_valid自定义 OpDef 工程,需新建opp/built-in/op_impl/未检出CheckValid信息库配置aclnnCheckValid无命中(无aclnn_check_valid.h/ 符号)CheckValid相关融合规则mindspore.ops.CheckValid已注册(含 CPU kernel);Ascend 后端 kernel 未在本地公开仓交付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 为准)
bbox_tensorDT_FLOAT16/DT_FLOAT(N, 4)img_metasDT_FLOAT16/DT_FLOAT(与 bbox_tensor 一致)(3,)或(16,),仅前 3 元素有效valid_tensorDT_INT8(N, 1)dtype 组合(aclnn / GEIR 应支持的输入组合,输出固定
DT_INT8):1.3.3 文档不一致裁定(见 model_research.md §算子数学背景)
(x0, x1, y0, y1)vs MindSpore / kernel(x0, y0, x1, y1)→ 以 MindSpore / kernel 实证为准。(16,)vs MindSpore 文档(3,)→ 仅读前 3 元素,aclnn/GEIR 兼容两种长度。(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),dtypeINT8。否则 InferShape 阶段报错。
1.4.4 Kernel 实现(Ascend 950 / arch35,待新建)
(N,4)行块;img_metas 小张量全量搬入 UB 或直接走标量寄存器。(N,1)连续写。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; } };