首页/新闻资讯/正文详情

CANN ops-nn 稀疏算子 SparseFillEmptyRows 详解:空行回补原理、参数约束与 GEIR 图模式调用实战

发布时间:2026/9/22 11:19:58 来源:云帆数科 栏目:资讯中心
CANN ops-nn 稀疏算子 SparseFillEmptyRows 详解:空行回补原理、参数约束与 GEIR 图模式调用实战
CANN ops-nn 稀疏算子 SparseFillEmptyRows 详解空行回补原理、参数约束与 GEIR 图模式调用实战【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn导读本文基于 CANN ops-nn 开源算子库中 index/sparse_fill_empty_rows 目录的官方算子文档系统讲解SparseFillEmptyRows稀疏算子它专门用于解决稀疏张量Sparse Tensor中整行为空的问题——当稀疏表示中某一行没有任何非零元素时该行在稠密视角下会消失而本算子会在输出中为该空行补充一个取值为default_value的占位元素。读完本文你将掌握该算子的功能语义、全部 8 个输入输出的参数与数据类型约束、AI CPU 内核的 CSR 偏移填充算法原理以及如何通过 GEIR 图模式在 NPU 上完整调用并校验该算子。功能说明稀疏张量的空行补齐稀疏张量与空行问题稀疏张量Sparse Tensor用三个组件表示稠密张量Dense Tensor中少量非零元素indices[N, rank]的二维张量每一行是一个稀疏元素在稠密张量中的坐标values[N]的一维张量与indices逐行对应是各稀疏元素的值dense_shape[rank]的一维张量描述对应的稠密张量形状。由于稀疏表示只记录非零元素稠密张量中某一整行全部为零时该行在indices中不会出现任何条目这就是空行。空行会导致下游依赖逐行数据的算子如嵌入查找、按行规约、批次对齐等得到错误或缺失的行粒度结果。SparseFillEmptyRows 的核心语义按 README.md 的功能说明本算子对稀疏张量的**第 0 维行维度**逐行检查某行在输入中至少有一个稀疏元素 → 原样保留某行为空 → 在输出稀疏张量中为该行补充一个坐标为[row, 0, ..., 0]、取值为default_value的元素。补入的元素坐标除第 0 维为row外其余维度全部取 0。例如稠密形状[3, 4]中第 1 行为空则补入坐标[1, 0]。产品支持情况下表来自 README.md 的产品支持矩阵当前仓库实现所验证/支持的产品如下产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品×Atlas 推理系列产品√Atlas 训练系列产品√需要注意Atlas 200I/500 A2 推理产品当前不支持该算子实际部署前请以目标设备的支持矩阵为准。参数说明输入输出总览SparseFillEmptyRows共4 个输入、4 个输出与算子原型 sparse_fill_empty_rows_proto.h 中REG_OP(SparseFillEmptyRows)的声明一一对应参数名输入/输出/属性描述数据类型数据格式indices输入形状为[N, rank]的二维张量每一行表示一个稀疏元素在 dense tensor 中的坐标。INT64NDvalues输入形状为[N]的一维张量表示indices中每个稀疏元素对应的值。BOOL、COMPLEX128、COMPLEX64、DOUBLE、FLOAT、FLOAT16、INT16、INT32、INT64、INT8、UINT16、UINT32、UINT64、UINT8NDdense_shape输入形状为[rank]的一维张量表示稀疏张量对应 dense tensor 的形状dense_shape[0]表示行数。INT64NDdefault_value输入标量张量表示空行回补时写入y_values的默认值。BOOL、COMPLEX128、COMPLEX64、DOUBLE、FLOAT、FLOAT16、INT16、INT32、INT64、INT8、UINT16、UINT32、UINT64、UINT8NDy_indices输出回补空行后的稀疏索引形状为[N empty_row_count, rank]。INT64NDy_values输出回补空行后的稀疏值形状为[N empty_row_count]数据类型与values一致。BOOL、COMPLEX128、COMPLEX64、DOUBLE、FLOAT、FLOAT16、INT16、INT32、INT64、INT8、UINT16、UINT32、UINT64、UINT8NDempty_row_indicator输出形状为[dense_shape[0]]的一维布尔张量true表示对应行在输入稀疏张量中为空。BOOLNDreverse_index_map输出形状为[N]的一维张量reverse_index_map[i]表示输入第i个元素在输出中的位置。INT64ND关键参数深入解读indicesINT64唯一合法的行坐标类型是int64_t。其第一维N为稀疏元素个数第二维必须等于rank即dense_shape的元素数。注意稀疏表示中的值类型与坐标类型是分离的坐标一律为 INT64值类型则由values决定。values与default_value类型必须一致二者支持同一组数据类型BOOL、COMPLEX128、COMPLEX64、DOUBLE、FLOAT、FLOAT16、INT16、INT32、INT64、INT8、UINT16、UINT32、UINT64、UINT8覆盖了从 8 位整型到复数、半精度浮点的常见数值类型。default_value是标量零维而values是一维[N]。y_indices/y_values输出形状由输入N与空行数empty_row_count共同决定即N empty_row_count。y_values的数据类型与values保持一致。empty_row_indicatorBOOL长度为dense_shape[0]的一维布尔向量逐个标记每一行是否为空是分析稀疏度分布的重要中间结果。reverse_index_mapINT64长度为N建立输入元素 → 输出元素的映射。当有多个空行插入后输出中元素的下标与输入不再一一对应借助该映射可以反推每个原始稀疏元素在回补后的输出中的位置例如用于梯度回传时的 scatter 操作。约束说明以下约束来自 README.md 的约束说明并结合源码确认了其实现依据indices必须是二维张量第二维大小为rank。在 sparse_fill_empty_rows_infershape.cpp 中若indices最大形状的维度数不为 2shape 推导直接返回失败对应的 UT 用例InferShapeRangeFailedWhenIndicesAre1D/InferShapeRangeFailedWhenIndicesAre3D也验证了 1D、3D 输入均被拒绝。values的元素数必须与indices第一维N一致。dense_shape必须是一维张量元素数为rank且元素个数需在[1, gert::Shape::kMaxDimNum]范围内每个维度取值非负。indices[i, 0]必须满足0 indices[i, 0] dense_shape[0]。行坐标越界时AI CPU 内核会记录KERNEL_LOG_ERROR并返回KERNEL_STATUS_PARAM_INVALIDUT 用例row_index_out_of_range_fail覆盖了该场景。当dense_shape[0] 0时N必须为 0。内核中对此有显式校验dense_shape[0] 0 but indices.shape[0] Ndense_rows_zero_with_nonempty_indices_fail与dense_rows_zero_with_empty_indices_success两个用例分别覆盖失败与成功路径。values、default_value、y_values的数据类型需要保持一致。infershape 中对values与default_value的数据类型做了一致性校验不一致时报values and default_value must have the same dtype。本算子为 AI CPU 实现即计算在 Host 侧 CPU 完成而非 NPU 向量/矩阵核。底层实现原理AI CPU 内核的 CSR 偏移填充算法算子注册与入口算子的 AI CPU 实现位于 sparse_fill_empty_rows_aicpu.cpp类SparseFillEmptyRowsCpuKernel继承自CpuKernel通过REGISTER_CPU_KERNEL(SparseFillEmptyRows, ...)注册。入口Compute()首先做输入输出数量校验4 进 4 出随后依据values的数据类型走模板分发SPARSE_FILL_EMPTY_ROWS_DATA_TYPE_CASE宏最终调用模板函数ComputeSparseFillEmptyRowsT()。内核一次处理三个关键步骤第一步合法性检查与行计数。读取dense_shape[0]得到行数denseRows先拒绝负数行数若denseRows 0则要求N 0此时直接置输出形状为[0, rank]/[0]返回。随后遍历indices校验每个indices(i, 0)在[0, denseRows)内统计每行元素个数到csrOffset数组并顺带检测rowsAreOrdered输入行坐标是否按行号非递减有序。第二步生成空行指示与 CSR 前缀和。对每一行rowemptyRowIndicatorData[row] (csrOffset[row] 0)随后把每个计数至少钳到 1 并做前缀和得到每个输出元素应落到的位置区间——这正是 CSRCompressed Sparse Row格式的偏移思想也是补入空行后计算输出位置的关键。第三步填充输出。核心在FillValue()对每个原始元素i其输出位置 该行起始偏移 行内已填充计数随后拷贝该行的rank个坐标、拷贝值并写入reverseIndexMapData[i] outputI对每个空行row在起始偏移处写入坐标[row, 0, ..., 0]与defaultValue。快路径优化内核还内置了一个性能优化分支当allRowsFull rowsAreOrdered所有行都非空且输入行坐标有序时说明没有任何空行需要补入输出与输入完全一致此时直接copy_n批量拷贝indices、values并将reverse_index_map设为恒等映射[0, 1, ..., N-1]跳过逐元素填充显著降低常规场景无空行的开销。UT 用例all_rows_full_*系列覆盖全部 14 种数据类型专门验证了该快路径的输出不变性。数据类型推导与 shape 推导sparse_fill_empty_rows_graph_infer.cpp 完成图模式下输出数据类型推导y_indices固定 INT64、y_values继承values类型、empty_row_indicator固定 BOOL、reverse_index_map固定 INT64。sparse_fill_empty_rows_infershape.cpp 通过InferShapeRange推导输出 shape 范围y_indices/y_values的最大长度为dense_shape的总体元素数elementsNum即极端情况下每行都补入一个元素最小长度在elementsNum 0时为 0、否则为 1empty_row_indicator长度恒等于dense_shape[0]reverse_index_map长度范围与indices第一维范围一致。由于输出长度依赖dense_shape的实际数值推导声明了.InputsDataDependency({kDenseShapeIdx})即 shape 推导依赖第 2 个输入dense_shape的常量数据。调用方式GEIR 图模式调用与完整示例调用方式总览调用方式调用样例说明图模式调用test_geir_sparse_fill_empty_rows.cpp通过算子IR构图方式调用 SparseFillEmptyRows 算子。示例输入与预期输出官方示例 test_geir_sparse_fill_empty_rows.cpp 构造了如下输入indices [[0, 1], [2, 3]]N2, rank2values [10, 20]INT32dense_shape [3, 4]3 行 4 列default_value 1INT32 标量推理过程第 0 行有元素[0,1]第 1 行没有任何元素空行第 2 行有元素[2,3]。因此第 1 行需要回补补入坐标[1, 0]、值1输出排序后得到y_indices [0,1, 1,0, 2,3][N1, 2]y_values [10, 1, 20]第 1 行补入的1位于中间empty_row_indicator [false, true, false]reverse_index_map [0, 2]输入第 0 个元素 → 输出位置 0输入第 1 个元素 → 输出位置 2跳过被插入的空行元素这些期望值在示例的CheckOutput()中被逐一断言也在 test_sparse_fill_empty_rows.cpp 的geir_sample_success用例中复现。构图步骤拆解示例代码完整展示了 GEIR 图模式调用的标准流程核心步骤为构建输入 Tensor用BuildTensorint64_t/BuildScalarTensor构造indices、values、dense_shape与标量default_valueshape 分别为{2,2}、{2}、{2}、{}均指定ge::FORMAT_ND与ge::kPlacementHost。创建 Data 节点用ge::op::Data(name).set_attr_index(i)为每个输入创建图输入节点index从 0 到 3 依次对应indices、values、dense_shape、default_value。创建算子节点并接线ge::op::SparseFillEmptyRows(sparse_fill_empty_rows)后通过set_input_indices/set_input_values/set_input_dense_shape/set_input_default_value连接四个输入同时用update_output_desc_y_*预置 4 个输出的 TensorDesc{3,2}INT64、{3}INT32、{3}BOOL、{2}INT64。构图并运行graph.SetInputs(graphInputs).SetOutputs(graphOutputs)后通过ge::Session的AddGraph(0, graph)与RunGraph(0, inputs, outputs)在设备示例中ge.exec.deviceId0、ge.graphRunMode1在线推理模式上执行最后校验 4 个输出。该示例同时是图模式GEIR下调用本算子的最小可运行模板只需替换CreateGraph()中的输入数据即可复用到其他稀疏场景。测试与验证仓库为算子提供了两层单元测试内核级 UTtests/ut/op_kernel_aicpu/test_sparse_fill_empty_rows.cpp用NodeDefBuilder在 HOST 环境直接RUN_KERNEL覆盖三大类场景——fill_empty_row_*14 种数据类型的空行回补正确性、all_rows_full_*14 种数据类型的无空行快路径、geir_sample_success官方示例输入以及异常路径dense_rows_negative_fail负数行数、dense_rows_zero_with_nonempty_indices_fail0 行却有元素、row_index_out_of_range_fail行坐标越界、unsupported_dtype_fail不支持的数据类型均预期返回KERNEL_STATUS_PARAM_INVALID。infershape 级 UTtests/ut/op_host/test_sparse_fill_empty_rows_infershape.cpp验证 shape 推导的正确输出范围例如输入indices第一维范围[2,5]、dense_shape[3,4]时y_indices长度范围为[1, 12]、empty_row_indicator长度为 3以及 10 余个非法输入被拒绝的用例dtype 不符、indices非 2D、dense_shape空/非 1D/含负维度/超最大 rank/元素乘积溢出 int64 等同时验证dense_shape[0]0且N0时输出全为 0 维度的合法场景。参考资料算子官方文档index/sparse_fill_empty_rows/README.md算子原型GEIR IRop_graph/sparse_fill_empty_rows_proto.hAI CPU 内核实现op_kernel_aicpu/sparse_fill_empty_rows_aicpu.cppshape 推导op_host/sparse_fill_empty_rows_infershape.cpp数据类型推导op_graph/sparse_fill_empty_rows_graph_infer.cppGEIR 调用示例examples/test_geir_sparse_fill_empty_rows.cpp单元测试tests/ut/op_kernel_aicpu/test_sparse_fill_empty_rows.cpp、tests/ut/op_host/test_sparse_fill_empty_rows_infershape.cpp【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

3种系拼音库横评,面试必问的坑与选型指南
3种系拼音库横评,面试必问的坑与选型指南

3种系拼音库横评,面试必问的坑与选型指南 看了一堆教程还是不会写项目?别慌,这恰恰是多数应届生的通病。理论背得滚瓜烂熟,真到代码里一动手,连个中文转拼音的轮子都造不好,更别提处理多音字、生僻字这些 面试必问 的脏活累活了。… · 2026/9/22 11:19:52

isfp型人格做性能优化别硬刚 3个工具选对事半功倍
isfp型人格做性能优化别硬刚 3个工具选对事半功倍

isfp型人格做性能优化别硬刚 3个工具选对事半功倍 版本升级后 API 全变了,看着报错日志头皮发麻,想搞性能优化却连参数在哪改都找不到?很多 isfp… · 2026/9/22 11:19:40

美国手游性能优化实战:3个坑让你少熬半个月
美国手游性能优化实战:3个坑让你少熬半个月

美国手游性能优化实战:3个坑让你少熬半个月 配置环境就卡半天,这绝对是开发美国手游项目时的第一道鬼门关。刚拉下代码, npm install 跑了半小时,依赖冲突报错;好不容易跑起来,帧率掉到 20… · 2026/9/22 11:19:39

绿坝-花季护航实战项目:3步搞定版本升级API全变坑
绿坝-花季护航实战项目:3步搞定版本升级API全变坑

绿坝-花季护航实战项目:3步搞定版本升级API全变坑 版本升级后 API 全变了,你的代码直接报错?别慌,这不是你代码写得烂,而是【绿坝-花季护航】这类底层组件在迭代时,接口规范发生了剧烈震荡。… · 2026/9/22 12:57:05

3步搞定三千越甲可吞吴全诗解析最佳实践
3步搞定三千越甲可吞吴全诗解析最佳实践

3步搞定三千越甲可吞吴全诗解析最佳实践 看了一堆教程还是不会写项目?别急,这通常不是代码能力的问题,而是知识碎片化导致的“断层”。在掘金技术社区的技术博客里,常有资深架构师指出,真正的最佳实践往往隐藏在那些看似无关的跨领域知识中。今天咱们换… · 2026/9/22 12:57:05

两个覆盖导致数据错乱?这份避坑指南救你
两个覆盖导致数据错乱?这份避坑指南救你

两个覆盖导致数据错乱?这份避坑指南救你 复制来的代码跑不通,看着满屏的报错或诡异的输出,你是不是也头大?别急,这不是你的锅,大概率是掉进了“两个覆盖”的陷阱。很多开发者在调试时,往往忽略了变量作用域或引用传递的隐蔽细节,导致逻辑在第二个覆盖… · 2026/9/22 12:56:46

3步调通中国电信宽带测速代码 附Python速查手册
3步调通中国电信宽带测速代码 附Python速查手册

3步调通中国电信宽带测速代码 附Python速查手册 刚接手运维脚本或者写自动化测试,最让人头大的就是网络模块。你从网上复制了一段号称“中国电信宽带测速”的代码,本地一跑,要么报错 TimeoutError ,要么测出来的速度只有… · 2026/9/22 12:56:28

2026最新波尔远程控制选型对比,解决代码跑不通的3个坑
2026最新波尔远程控制选型对比,解决代码跑不通的3个坑

2026最新波尔远程控制选型对比,解决代码跑不通的3个坑 复制来的代码跑不通,报错信息满天飞,是不是让你抓狂?别急,这不是你的问题,是工具没选对。2026最新的开发环境里,【波尔远程控制】相关的通信协议与底层控制逻辑已经发生了细微但致命的变… · 2026/9/22 12:56:22

3分钟一文搞懂网站报价,拒绝被培训机构割韭菜
3分钟一文搞懂网站报价,拒绝被培训机构割韭菜

3分钟一文搞懂网站报价,拒绝被培训机构割韭菜 官方文档翻烂了还是不知道一个网站到底该花多少钱?这种“看着一堆参数心里没底”的感觉,每个中小施工企业的负责人都经历过。别慌,今天这篇教程不整虚的,咱们像拆解代码一样, 一文搞懂… · 2026/9/22 12:55:57

5个电影海报图片处理坑,新手避坑指南
5个电影海报图片处理坑,新手避坑指南

5个电影海报图片处理坑,新手避坑指南 刚写完代码,一运行屏幕直接炸了。满屏红色的 StackTrace 滚得比弹幕还快,什么 NullPointerException 、 ImageIO.read() returned null 、… · 2026/9/22 0:00:07

注册微信公众账号:一文搞懂从0到1全流程
注册微信公众账号:一文搞懂从0到1全流程

注册微信公众账号:一文搞懂从0到1全流程 复制来的代码跑不通,报错信息满屏飞,到底卡在哪?别急,咱们先停下手里的调试。很多开发者觉得注册微信公众账号只是填个表单、传个身份证那么简单,真上手才发现坑深不见底。今天这篇 一文搞懂… · 2026/9/22 0:00:07

手写实现图片压缩网站核心:搞定WebP转换与质量调优
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站… · 2026/9/22 0:00:19

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码