已关闭
[Requirement|需求建议]: TopkV2算子在小k情况下支持双调排序的实现 #5236
cy_hw创建于 8月27日关闭于 9月1日
8月27日 添加了label:requirement
8月27日 关联了pull request:新增aclnnTopkV2接口适配TopkV2算子支持小k场景下的双调排序
8月27日 将 caoyan_huawei 设为负责人
8月29日 修改了issue 的描述
8月29日 修改了issue 的描述
9月1日 关闭了 issue
9月1日 添加了label:resolved
aclnnTopkV2 接口支持TopKV2算子实现双调排序设计
1. 概述
TopK 算子用于沿指定轴取出输入张量的前 K 个极值及其下标。
aclnnTopkV2是对原有aclnnTopk(下称 V1)接口的扩展版本,核心差异是新增int64_t sortPolicy参数,将排序策略选择权上交给调用方,从而支持 Bitonic Sort 等新计算路径。V2 与 V1 共享同一套内部实现(
aclnnTopkGetWorkspaceSizeCommon),二者均遵循 CANN 标准两段式(GetWorkspaceSize + Run)调用模型。2. 接口签名
// 第一段:计算 workspace 并构建 executor aclnnStatus aclnnTopkV2GetWorkspaceSize( const aclTensor* self, int64_t k, int64_t dim, bool largest, bool sorted, int64_t sortPolicy, // ← 相比 V1 新增 aclTensor* valuesOut, aclTensor* indicesOut, uint64_t* workspaceSize, aclOpExecutor** executor); // 第二段:在 stream 上执行计算 aclnnStatus aclnnTopkV2(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream);3. 功能说明
3.1 aclnnTopkV2GetWorkspaceSize(第一段接口)
见
aclnn_topk.cpp:893。负责"编译期"工作:L2_DFX_PHASE_1记录输入(含sortPolicy)与输出张量,用于性能与问题追溯。aclnnTopkGetWorkspaceSizeCommon(aclnn_topk.cpp:672),将sortPolicy透传下去,由公共函数完成全部参数校验、策略选择与图构建。workspaceSize(所需 workspace 大小)与executor(已构建的计算执行器)。公共函数
aclnnTopkGetWorkspaceSizeCommon完成的关键步骤:CheckParams,aclnn_topk.cpp:184)。TopkAdaptInputZeroDimTensor,aclnn_topk.cpp:204)。l0op::Contiguous)与 910 平台 fp32→fp16 的 GE cast 适配(TopkAdaptGeCastTensor,aclnn_topk.cpp:229)。ViewCopy写回用户输出。*workspaceSize = executor->GetWorkspaceSize()。3.2 aclnnTopkV2(第二段接口)
见
aclnn_topk.cpp:902。负责"运行期"工作:L2_DFX_PHASE_2(aclnnTopkV2)标记第二段进入。CommonOpExecutorRun(workspace, workspaceSize, executor, stream),将第一段构建的 executor 在指定aclrtStream上异步执行。实现与
aclnnTopk完全一致,仅 DFX 标签不同(用于区分 V1/V2 的运行统计)。4. 两段式调用关系
第一段不执行真正的数值计算,只做规划与 executor 构建;第二段才在 NPU stream 上执行。这种拆分允许框架在 host 侧完成 Tiling/图融合后再下发设备执行。
5. 与 aclnnTopk(V1)的关系与差异
sortPolicyint64_t sortPolicysortPolicy=0(aclnn_topk.cpp:882)sortPolicy(aclnn_topk.cpp:898)CommonOpExecutorRunCommonOpExecutorRun(仅 DFX 标签不同)aclnnTopkV2(..., sortPolicy=0),是 V2 的子集结论:V2 是 V1 的超集/扩展。V1 = V2(sortPolicy=0)。两者复用同一公共实现,差异仅在于是否向调用方暴露
sortPolicy。6. sortPolicy 参数与策略选择
sortPolicy在公共实现中影响两处:6.1 Bitonic Sort 路径判定
IsBitonicSort(aclnn_topk.cpp:666):return k >= BITONIC_SORT_MIN_K_THRESTHOD // k >= 2 && k <= BITONIC_SORT_MAX_K_THRESTHOD // k <= 32 && sorted // 要求排序 && sortPolicy == TOP_K_BITONIC_SORT_POLICY; // sortPolicy == 1当满足"小 K(2~32)+ 需排序 + sortPolicy=1"时,跳过 Sort/SortAndTopK/RadixTopK 分支,进入默认
l0op::Topk路径,由底层算子按 Bitonic 排序策略执行。该路径针对小 K 排序场景做了优化。6.2 透传至底层 Topk
在 NoTranspose 分支与默认 Topk 分支中,
sortPolicy作为参数传给l0op::Topk(aclnn_topk.cpp:747、aclnn_topk.cpp:785、aclnn_topk.cpp:838),由底层算子决定具体排序实现。V1 因硬编码为 0,底层走默认策略。7. 公共实现的整体策略分支
aclnnTopkGetWorkspaceSizeCommon按以下优先级选择计算路径(顺序即代码判定顺序):aclnn_topk.cpp:718):950 上 K=1 且排序轴=1,直接拷贝 + 索引填 0。aclnn_topk.cpp:732):排序轴==K 且不排序(950),整段拷贝 + 生成连续索引。aclnn_topk.cpp:743):950 且非尾轴、轴长在阈值内、收益可期,直接对非尾轴做 Topk,避免转置开销。positiveDim != lastDim,先转置到尾轴再计算,再转置回去),其内子策略:IsSort,K==轴长且可处理)。IsSortAndTopK,按 dtype/轴长/k 占比阈值)。IsRadixTopKSupported)。l0op::Topk(透传 sortPolicy)。aclnn_topk.cpp:797,先取 PARALLEL_K=32 个候选再取最终 K)。8. 关键常量速查
BITONIC_SORT_MIN_K_THRESTHODBITONIC_SORT_MAX_K_THRESTHODTOP_K_BITONIC_SORT_POLICYPARALLEL_KSORT_WITH_INDEX_THRESHOLDSORT_AND_TOP_K_THRESHOLDRADIX_TOP_K_MIN_K9. 设计小结
aclnnTopkGetWorkspaceSizeCommon与 V1 复用全部校验与策略代码,仅扩展入参。sortPolicy是透传式参数,对已有路径零影响(V1 行为等价 sortPolicy=0)。