Closed
[Requirement|需求建议]: AsStrided算子AscendC实现贡献 #2180
Mars_Cheng_cysAdd on  Jul 8Closed at  Jul 30
Mars_Cheng_cys
Mars_Cheng_cys
Jul 8 Create

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

一、背景信息 (必填)

使用 AscendC对TBE实现的 AsStrided 算子进行 AICore 实现重构,适配 Atlas A2 训练系列产品。AsStrided 根据 size、stride 和 storage_offset 从输入 Tensor 的底层存储中按步长取数,生成指定 shape 的输出 Tensor,语义对齐 torch.as_strided 的取数规则。

二、价值/作用 (必填)

AsStrided 是张量视图、切片、滑窗、非连续内存布局访问等场景的基础算子能力。该算子本身不进行数值计算,仅进行按 stride 的数据读取与输出写回,可为 ACLNN 直调及后续上层框架接入提供 NPU 侧实现,减少相关场景回退或低效通用搬运路径。

三、设计方案 (必填)

3.1 使能方式(涉及哪些框架:如Aclnn直调、Pytorch训练等)

当前支持 ACLNN 直调,提供以下接口:

aclnnAsStridedGetWorkspaceSize:根据 x、size、stride、storageOffset、out 生成执行器并返回 workspace 大小。
aclnnAsStrided:提交 AICore 算子执行。

Level 0 接口将 aclIntArray 类型的 size、stride、storageOffset 转换为 INT64 Tensor,执行 shape 推导后进入 AICore 路径;当当前 dtype 或平台不满足 AICore 支持条件时,使用 ViewCopy 作为兜底路径。

3.2 总体设计

AsStrided 的输出 shape 由 size 决定,输出每个元素的输入偏移计算公式为:

input_offset = storage_offset + sum(output_coord[i] * stride[i])

即:

y[coord] = x[input_offset]

算子只进行数据搬运和布局重排,不涉及数值计算,因此不涉及 FP16/BF16 升精度。

3.2.1 算子支持的数据类型
输入/输出 支持的数据类型 数据格式
x / y BOOL、INT8、UINT8、INT16、UINT16、INT32、UINT32、INT64、UINT64、FLOAT16、FLOAT32、BF16、COMPLEX32、COMPLEX64;RegBase 路径覆盖 HIFLOAT8、FLOAT8_E5M2、FLOAT8_E4M3FN ND
size / stride / storage_offset INT32、INT64 ND / 标量
3.2.2 host侧设计

Host 侧完成以下工作:

  1. 注册 x、size、stride、storage_offset、y 及支持的数据类型。
  2. 根据 size 推导输出 shape,输出 dtype 与输入 x 保持一致。
  3. 校验 size 与 stride 的 rank 一致且 rank > 0,当前最大支持 rank 为 8。
  4. 校验 size、stride、storage_offset 均为非负,且 as_strided 访问范围不越过输入 storage。
  5. 获取平台核数、UB 大小、dtype 字节数,计算 32B 对齐 blockElements、UB tile 大小和多核切分参数。
  6. 根据 stride 模式、输入跨度、UB 容量和 shape 特征选择 Tiling Key。

主要 Tiling 策略包括:

路径 设计说明
CONTIGUOUS 连续视图,按线性区间做块搬运
CONTIGUOUS_SMALL_ALIGNED 小 shape 且对齐的连续视图,使用单 UB buffer 降低开销
STRIDE_1 最后一维 stride 为 1,按行连续搬运
STRIDE1_ROW_BATCH 小 shape 的 stride-1 行批量搬运
GENERAL_STRIDE 最后一维 stride > 1,使用 DataCopy srcStride 完成搬运即重排
GENERAL_SMALL_SPAN 小跨度场景,先加载覆盖 span 再打包有效元素
RANK1_STRIDE / RANK1_STRIDE_SPAN rank-1 strided copy,按输出元素切分或加载连续 span 后打包
BROADCAST 最后一维 stride 为 0,读取单元素后在输出行内复制
COMPACT_SPAN / COMPACT_SUFFIX 输入覆盖 span 可放入 UB 时,使用 gather/mask 方式批量打包输出
SCALAR 极小或特殊场景兜底路径

Kernel 总体流程如下:

flowchart TD
    A["as_strided Kernel 入口"] --> B["读取 TilingData"]
    B --> C["创建 TPipe 与 AsStridedKernel"]
    C --> D["Init 初始化"]

    D --> D1["加载 tilingKey、shape、stride、storage_offset、UB 与多核切分参数"]
    D1 --> D2["按 tilingKey 确定 splitElements"]
    D2 --> D3["根据 blockIdx 计算 coreBaseIndex 与 currentCoreElements"]
    D3 --> D4["绑定输入 / 输出 GM Buffer"]
    D4 --> D5["按路径申请 UB Buffer"]

    D5 --> E{"currentCoreElements > 0 且 ubElements > 0?"}
    E -- "否" --> Z["当前核无任务,直接返回"]
    E -- "是" --> F{"按 tilingKey 分发"}

    F -- "CONTIGUOUS" --> P0["连续视图:DataCopyPad 双缓冲块搬运"]
    F -- "CONTIGUOUS_SMALL_ALIGNED" --> P9["小对齐连续视图:单 UB DataCopy / DataCopyPad"]
    F -- "COMPACT_SPAN" --> P10["整段输入进 UB:生成 mask / Gather 打包输出"]
    F -- "COMPACT_SUFFIX" --> P11["复用 suffix mask:按 suffix block Gather 打包输出"]
    F -- "STRIDE_1" --> P1["最后一维连续:按行分块搬运"]
    F -- "STRIDE1_ROW_BATCH" --> P6["小行批量:二维 DataCopyPad 后打包输出"]
    F -- "GENERAL_STRIDE" --> P2["通用 stride:DataCopy srcStride 搬运即重排"]
    F -- "GENERAL_SMALL_SPAN" --> P7["小跨度:加载覆盖 span 后按 stride 打包"]
    F -- "RANK1_STRIDE" --> P5["Rank-1 stride:按输出元素多核切分,srcStride 搬运"]
    F -- "RANK1_STRIDE_SPAN" --> P8["Rank-1 小跨度:加载连续 span 后打包"]
    F -- "BROADCAST" --> P3["stride 为 0:读取单元素并在 UB 内复制"]
    F -- "其他 / SCALAR" --> P4["标量兜底:逐元素 ComputeInputOffset 后读写"]

    P0 --> G["写回连续输出 GM"]
    P9 --> G
    P10 --> G
    P11 --> G
    P1 --> G
    P6 --> G
    P2 --> G
    P7 --> G
    P5 --> G
    P8 --> G
    P3 --> G
    P4 --> G

    G --> H["当前核处理完成"]
3.2.3 kernel侧设计

Kernel 根据 Tiling Key 分发到不同处理路径。核心逻辑包括:

  1. 读取 TilingData 中的输出维度、stride、storage_offset、多核切分、UB tile 和 compact suffix 信息。
  2. 通过 ComputeInputOffset 将输出线性下标映射到输入 storage 偏移。
  3. 连续场景使用 DataCopy / DataCopyPad 做块搬运。
  4. 通用 stride 场景使用 DataCopy srcStride 跳过输入间隙并写成连续输出。
  5. compact span/suffix 场景将输入覆盖区搬入 UB,再使用 gather mask 打包有效元素。
  6. broadcast 场景读取单个输入元素并在 UB 中扩展后写回。
  7. 非 32B 对齐尾块使用 DataCopyPad 处理。
3.3 支持硬件
硬件产品 支持情况
Atlas A2 训练系列产品 / ascend910b 支持

3.4 算子约束限制

  1. x、y 数据格式为 ND。
  2. size、stride 长度必须一致,且输出 rank 当前限制为 1 到 8。
  3. size、stride、storage_offset 支持 INT32 / INT64。
  4. storage_offset 必须为非负;stride 当前仅支持非负 stride。
  5. 根据 size、stride、storage_offset 计算出的最大访问偏移必须小于输入元素个数。
  6. size、stride、storage_offset 在 Tiling 阶段需要可取值。
  7. 当前实现为输出 Tensor 拷贝语义,不承诺返回与输入共享 storage 的 alias 视图。
  8. compact/gather 专用路径受 dtype、输入跨度、UB 容量和指令参数限制,不满足时回退到通用路径。

💡 备注(选填)
AsStrided 为访存密集型算子。当前设计通过连续搬运、srcStride 搬运、compact span/suffix gather、小 shape 专用路径、DataCopyPad 尾块处理和多核任务切分提升不同 stride 模式下的有效带宽。后续验证建议覆盖 ACLNN 直调样例、msopst 精度对比(golden 使用 torch.as_strided)、多 dtype / 多 rank / 多 Tiling Key 用例,以及与内置实现的性能对比。

likedislike
Mars_Cheng_cys
Mars_Cheng_cys
Jul 8 Comments:
likedislike
CANN-robotCANN-robotCollaborators
Jul 8 Assign Mars_Cheng_cys as responsible person
Mars_Cheng_cysMars_Cheng_cys
Jul 8 Modify description of issue
Mars_Cheng_cysMars_Cheng_cys
Jul 8 Associated pull request
Mars_Cheng_cysMars_Cheng_cys
Jul 8 Associated pull request
llimwangCollaborators
Jul 30 Comments:

该 Issue 已超过 20 天未更新,先行关闭以便归档;如仍需跟进请评论或重新打开。

likedislike
LllimwangCollaborators
Jul 30 Close issue