已关闭
[Requirement|需求建议]: Unique 增加 Regbase values-only AI Core 排序去重支持 #6187
黄晓彬创建于  9月23日关闭于  9月24日
黄晓彬成员
9月23日 创建

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

Backgroud(背景信息)

需要为 Regbase 平台上的 aclnnUnique / aclnnUnique2 提供 values-only 全局去重能力:调用方仅获取去重后的值,不要求返回逆索引和出现次数。面向这类场景,设计专用 AI Core 计算路径,避免完整索引跟踪和多算子组合带来的额外搬运、中间存储及调度开销。

功能要求:

  • 对输入所有元素执行全局去重,多维输入按展平语义处理,输出为一维去重值序列,长度由实际计算结果决定。
  • aclnnUnique 的目标场景为 returnInverse=false;aclnnUnique2 的目标场景为 returnInverse=false && returnCounts=false。
  • 支持 float32、float16、bfloat16、int8/uint8、int16/uint16、int32/uint32、int64/uint64。目标平台为 Regbase,覆盖 Ascend 950
  • sorted=true 输出升序去重结果;sorted=false 不承诺保留输入顺序,允许复用排序去重流程。
  • 保持既有接口签名及非目标场景的调用语义。逆索引、计数和 GE 图模式 AI Core 动态输出不纳入本需求的交付范围。

Origin(信息来源)

内存优化

Benefit / Necessity (价值/作用)

  • 满足集合处理、特征去重等仅消费去重值的业务场景。
  • 省去不需要的原始索引跟踪及搬运,降低大规模输入的内存访问和中间存储开销。
  • 将排序与相邻去重组织为一次 Kernel 调用,减少调度开销,并按阶段复用 UB 和 workspace。
  • 分别为小规模输入与大规模输入选择合适的算法和分核策略。收益需通过精度与性能验收确认,不预设加速比。

Design(设计方案)

1. 总体计算方案

采用“全局升序排序 + 相邻去重”的两阶段融合方案。排序后相同数值相邻,去重阶段为每段相同数值输出一个代表值,并根据实际去重数量回传输出 shape。

输入(按展平语义处理)
  -> 按 dtype、N 和 UB 容量选择排序策略
  -> 各核完成排序并进行全局同步
  -> 复用 UB,执行单核或多核相邻去重
  -> 输出有效 values,并写回实际输出长度

Host 负责准入校验、排序路由、分核、UB 切分和 workspace 规划;Kernel 按 tiling 协议执行,不在设备端重新推导策略。

2. Tiling 设计

2.1 输入约束与规划输入

  • 规划输入包括总元素数 N、dtype/元素字节数、可用 AIV 核数、UB 容量和搬运对齐粒度。
  • 专用路径处理非空输入,不以 2^30 作为统一输入上限。radix 的计数位宽按 N 选择:N < 2^30 使用 uint32,N >= 2^30 使用 int64,以容纳 lookback 状态和累计计数;位宽选择与输入 dtype 无关。空输入交由接口层的空张量流程处理。
  • 大输入仍受可用内存、workspace、tile ID 和 tiling 字段范围约束。总 tile 数需为 uint32 的核步进循环预留余量,每核清零元素数需可用 uint32 表示;地址区间计算需先校验 N × 元素字节数 是否溢出。
  • 输入连续化后进入计算;专用路径要求输入输出为连续、零偏移存储,输入 storage 与 N 一致,输出至少具有 N 个元素的容量。已知输入输出地址时校验其 N 元素区间不重叠。
  • dtype、属性或存储条件不满足时由接口层选择既有计算路径,不把未命中优化路径等同于非法参数。

2.2 排序路由与多核切分

场景 拟采用的策略 Tiling 重点
N=1 单元素搬运 搬运 tile 与双缓冲必须落在可用 UB 内
小规模输入 按 dtype 和容量选择小轴排序、单核 merge 或单核 radix 推导单次处理元素数、对齐长度和临时缓冲大小
中等规模输入 根据单核容量选择核内归并或多核排序/归并 分配各核区间,规划分段长度、归并窗口和尾块
大规模输入 compact 多核 radix 推导 radix tile、tile 数、有效核数及 histogram/prefix 布局

以 N=65536 作为 compact radix 的初始分界;小于该值使用通用排序规划。分界需结合各 dtype 的实测结果校准。有效核数不得超过实际任务数,尾核和尾 tile 需单独记录有效长度,避免空任务参与计数和同步协议。

2.3 去重分核与 UB 切分

  • 去重阶段独立判断单核/多核策略,不直接沿用排序算法的单核/多核结论。
  • 初始单核判定为 N <= 8192 且完整单核缓冲预算不超过可用 UB;其余输入采用多核分段去重。
  • 多核按连续区间切分,使用向上取整得到每核处理长度,并显式计算最后一核有效长度。非末核需向后多读一个元素,以相邻比较处理跨核重复值;核内非末 tile 同样预留一个向后比较元素。
  • 单核预算包括两份 values 缓冲、去重辅助缓冲和动态 shape 缓冲;多核预算先扣除核间计数、前缀偏移、边界信息和 shape 等固定空间,再推导流式处理 tile。
  • 需要 SIMT 的排序路径预留 32 KiB UB;Host 的可用容量计算与 runtime local-memory limit 应一致。所有缓冲按实际字节宽度、数量和搬运粒度对齐,禁止把字节数再次乘元素大小。

2.4 Workspace 布局与阶段复用

系统 workspace
排序 values 区(按 512 字节对齐)
阶段复用区:max(排序临时索引 + 排序 scratch, 去重核间辅助区)
  • values-only radix 不保存原始元素索引;排序所需的局部排序位置仍作为内部计算数据处理。
  • radix 拟缓存字节 key、每 tile 的 histogram 和 prefix,避免 scatter 阶段重复计算。全局 histogram/lookback 缓冲按所选 32/64 位 counter 计算 UB 和 workspace,局部 tile histogram/prefix 保持 uint16;两类数据的宽度不得混用。
  • compact radix 的固定 UB 预算为 256 × (3 × counterBytes + 2 × sizeof(uint16_t));扣除固定缓冲和 SIMT 预留后,按 256 元素粒度试算 tile,并同时满足排序临时空间与完整 value tile 的容量要求。
  • 去重前最终输出尚未产生,可借用 valueOut 的 N 元素容量作为排序临时空间。需要 int32 临时索引的排序分支,只有输出字节容量足够时才可借用,否则分配独立索引区。
  • 排序 scratch 与去重核间辅助区按生命周期复用,必须在排序全核同步完成后切换用途。

2.5 Host/Kernel 协议

tiling key 联合编码排序 schedule 和 useInt64Counters,只有多核 radix 选择 64 位计数实例,其余分支使用默认实例。传递排序路由、核数、tile 长度/数量、尾块长度、归并窗口、各 workspace 区域大小,以及去重单多核标志和各队列容量。复用字段需逐分支注明含义,明确元素数、字节数和核数单位。写回前校验容量、整数范围及非零除数。

3. Kernel 设计

3.1 排序阶段

  • 通过 tiling key 静态选择对应排序模板,按 Host 下发的区间进行 CopyIn、排序及 CopyOut。
  • compact radix 按字节轮次进行 key 提取、局部桶统计、全局位置计算和 scatter;通过编译期参数关闭 values-only 场景的原始索引加载、存储和双缓冲切换。
  • 多核 radix 使用 lookback/prefix 协议确定各 tile 的桶起始位置;按 tiling 选择 uint32/int64 的全局计数、histogram 和 scatter 位置。GM 偏移及乘积在运算前提升至 64 位,lookback 回溯使用有符号 64 位索引,避免先发生 32 位截断再赋值。各轮保证生产者数据可见后再供消费者读取。
  • 对有符号整数和浮点数采用与数值顺序一致的 key 编码。浮点 +0/-0 必须按数值相等关系合并,radix 路径设计为恢复输入中首个零的符号;NaN、Inf 的行为需单独对齐接口语义并验收。

3.2 阶段切换与同步

排序完成后所有参与核执行全局同步,保证完整有序序列可见;再重置 pipeline/UB 分配,将排序缓冲让给去重阶段。单核去重时,其他核只能在该同步点之后退出;多核去重时所有有效核继续参与计数与输出偏移计算。不得在读写未完成时复用 scratch 或 UB。

3.3 相邻去重阶段

  • 单核:读取有序输入,比较相邻元素,压缩保留有效值并累计输出长度。
  • 多核采用两遍扫描:第一遍比较当前元素与后继元素,统计相邻变化点数;非末核/非末 tile 向后多读一个元素,最后一个有效元素由末核尾块处理,避免跨区间重复计数。
  • 各核将计数写入 workspace 并同步,累加前面各核的计数得到输出偏移;第二遍重新扫描并压缩写回有效值,末核根据累计数量回传输出 shape。
  • 每核长度、全局偏移和去重循环次数保留 64 位,循环轮数用 64 位除法与余数求上整,避免调用 uint32 参数的上整辅助函数而截断大输入。
  • 复用 UniqueConsecutive 的单核/多核计算能力,关闭 inverse/counts 的有效数据生成;按实际 dtype 比较,避免窄化转换改变大整数去重结果。

3.4 动态输出与接口衔接

  • 输出先按 N 元素上界分配容量,Kernel 只定义前 K 个有效 values,其中 K 为去重数量;执行结束后回传一维 shape [K]。
  • ACLNN/L0 规划独立 shape buffer,通过计算依赖 shape 回传机制更新输出。shape 存储按 values/inverse/counts 三份记录预留,每份包含 rank 和最多八维信息,共 27 个 int64。
  • inverse/counts 使用内部占位张量,不向调用方禁用输出写入有效 payload 或修改其 shape。
  • GE 图模式的计算依赖输出分配不在本需求内,应保持原有图通路选择,不能仅因新增 AI Core 注册而切入尚未支持的路径。

4. 验收要求

  • 精度:覆盖全部目标 dtype、重复/全相等/全不等输入、多维展平、sorted 两种取值、正负零、Inf/NaN 及大整数;同时检查有效 values 与动态输出长度。
  • 分支:覆盖 N=1、小轴排序、单核/多核切换、8192 附近、65536 附近、2^30 前后的 counter 切换、非对齐尾块,以及 UB 容量临界点。大规模规划需覆盖 tile 数、清零长度和偏移字段的可表示边界;设备资源不足时应区分 Host 边界验证与大输入实跑,不能混称通过。
  • 兼容性:验证 inverse/counts、非目标 dtype、非连续输入和不满足存储准入条件时的既有路径;确认调用方禁用输出不被改写。复用公共排序和去重能力时补充 KthValue、UniqueConsecutive 的回归验证。
  • 稳定性:检查跨核边界重复值、尾 tile、同步、workspace/UB 越界及动态 shape 回传。
  • 性能:对小/中/大规模和不同重复率分别采集耗时与 workspace 占用,与既有路径对比,依据实测确定路由阈值及优化收益。
likedislike
黄黄晓彬成员
9月23日 添加了label:requirement
黄黄晓彬成员
9月23日 修改了issue 的描述
黄黄晓彬成员
9月23日 修改了issue 的描述
黄黄晓彬成员
9月23日 修改了issue 的描述
黄黄晓彬成员
9月23日 修改了issue 的描述
CANN-robotCANN-robot成员
9月24日 关闭了 issue
CANN-robotCANN-robot成员
9月24日 添加了label:resolved