已合并
【社区任务】aclnnRoll算子设计文档 #711
【社区任务】aclnnRoll算子设计文档 #711
已合并
繁依Fanyi创建于 7月26日
1 个文件变更+275-0
@@ -0,0 +1,275 @@
1+# 需求背景(required)
2+ 
3+## 需求来源
4+ 
5+本需求来源于《7月社区任务-aclnnRoll算子开发任务书》。任务要求在
6+[`cann/ops-math`](https://gitcode.com/cann/ops-math) 已有 `aclnnRoll`
7+实现基础上增加 `complex64` 输入支持,为 PyTorch 侧 `torch.roll`
8+`torch.fft.fftshift``torch.fft.ifftshift` 的复数输入适配提供
9+NPU 算子能力。
10+ 
11+## 背景介绍
12+ 
13+### aclnnRoll算子现有实现
14+ 
15+本任务修改的算子位于:
16+ 
17+```text
18+experimental/math/roll
19+```
20+ 
21+现有实现由 ACLNN API、算子原型、InferShape、Host Tiling 和 Ascend C
22+Kernel 组成。ACLNN API 对非连续输入调用 `l0op::Contiguous`,Kernel
23+根据 Host 下发的 Shape、Stride、位移和分核参数执行数据搬移。
24+ 
25+### aclnnRoll算子实现现状分析
26+ 
27+| 参数 | 参数含义 | 支持数据类型 | 数据格式 | 形状 | 非连续 Tensor |
28+| --- | --- | --- | --- | --- | --- |
29+| `x` | 输入 Tensor | BFLOAT16、FLOAT16、FLOAT32、INT8、UINT8、INT32、UINT32 | ND | 0~8 维 | 支持 |
30+| `shifts` | 各维度循环移动的步数 | int64 数组 | - | `dims` 非空时与 `dims` 等长;`dims` 为空时长度为 1 | - |
31+| `dims` | 指定循环移动的维度 | int64 数组,可空 | - | 非空时与 `shifts` 等长,每项位于 `[-rank, rank)`;0 维 Tensor 时必须为空 | - |
32+| `out` | 输出 Tensor | 与 `x` 相同 | ND | 与 `x` 相同 | - |
33+| `workspaceSize` | Device Workspace 大小 | uint64 指针 | - | - | - |
34+| `executor` | 算子执行器 | `aclOpExecutor` 二级指针 | - | - | - |
35+ 
36+现有 ACLNN API 和 OpDef 未声明 `COMPLEX64`,Host Tiling 也未按
37+8 字节识别 complex64 元素大小;Kernel 需要把实部和虚部作为一个完整的
38+8 字节元素移动。任务同时要求适配 Atlas A2、A3、A5 训练系列产品。
39+ 
40+#### aclnnRoll算子现状流程图
41+ 
42+```mermaid
43+flowchart TD
44+ A["调用 aclnnRoll(x, shifts, dims, out)"] --> B["ACLNN 参数校验"]
45+ B --> C{"x.dtype 是否在现有支持列表中?"}
46+ C -->|"否:COMPLEX64"| D["dtype 校验失败并返回<br/>不进入 OpDef、Host Tiling 和 Kernel"]
47+ C -->|是| E{"x 是否为空 Tensor?"}
48+ E -->|是| F["API 层直接返回"]
49+ E -->|否| G["非连续输入先经 l0op::Contiguous"]
50+ G --> H["l0op::Roll<br/>直接绑定 out 或生成临时 Tensor"]
51+ H --> I["OpDef / InferShape"]
52+ I --> J["Host Tiling<br/>归一化 dims 和 shifts,计算 Shape、Stride 与分核参数"]
53+ J --> K["Kernel<br/>按 DTYPE_X 执行坐标映射和数据搬移"]
54+ K --> L["临时结果按需经 l0op::ViewCopy 写回 out"]
55+ L --> M["返回结果"]
56+```
57+ 
58+### aclnnRoll算子功能分析
59+ 
60+Roll 沿指定维度循环移动 Tensor 元素。设维度长度为 `n`、位移为 `s`
61+归一化后的位移为:
62+ 
63+```text
64+normalizedShift = ((s % n) + n) % n
65+```
66+ 
67+输出坐标 `outputCoord` 对应的输入坐标为:
68+ 
69+```text
70+inputCoord = (outputCoord - normalizedShift + n) % n
71+```
72+ 
73+`dims` 为空时,输入按逻辑顺序展平后执行一维 Roll,再恢复原 Shape。
74+相同维度出现多次时,各次位移在该维度上累加后取模。
75+ 
76+complex64 由相邻的两个 32 位浮点数组成,一个逻辑元素占 8 字节。Roll
77+不进行复数计算,只改变元素位置,因此移动过程必须保持每个 complex64
78+元素的 64 位模式不变。
79+ 
80+# 需求分析(required)
81+ 
82+## 需求描述
83+ 
84+在不改变 `aclnnRoll` 接口语义的前提下,为输入和输出增加
85+`COMPLEX64` 支持。complex64 输入下的结果与 CPU PyTorch
86+`torch.roll` 对齐,并覆盖 `torch.fft.fftshift`
87+`torch.fft.ifftshift` 的调用场景。保持原有 dtype 的功能和性能不变,
88+使用 Ascend C 开发,适配 CANN 8.5.0 及以上版本和 Atlas A2、A3、A5
89+训练系列产品。
90+ 
91+## 需求拆解
92+ 
93+1. ACLNN API 的输入 dtype 支持列表增加 `DT_COMPLEX64`
94+2. OpDef 的输入、输出 dtype 增加 `ge::DT_COMPLEX64`
95+3. Host Tiling 按 8 字节计算 complex64 元素大小。
96+4. Kernel 将 complex64 作为完整的 8 字节存储单元移动。
97+5. 复用现有空 `dims`、负维度、重复维度和正负超大位移处理逻辑。
98+6. 复用现有非连续输入连续化流程。
99+7. Host 继续通过平台接口获取 AIV 核数和 data block 大小,Kernel 使用
100+ 相同的平台 data block 大小进行对齐搬移。
101+8. 注册并构建 `ascend910b``ascend910_93``ascend950`
102+9. 补充 complex64 泛化测试和全部原有 dtype 回归测试。
103+ 
104+# 详细设计(required)
105+ 
106+## 算子分析
107+ 
108+### 数学公式
109+ 
110+对输出位置 `outputCoord`,其来源位置为:
111+ 
112+```text
113+normalizedShift = ((shift % dimSize) + dimSize) % dimSize
114+inputCoord = (outputCoord - normalizedShift + dimSize) % dimSize
115+```
116+ 
117+complex64 只参与数据搬移:
118+ 
119+```text
120+outputBits64[dstIndex] = inputBits64[srcIndex]
121+```
122+ 
123+### 支持数据类型
124+ 
125+BFLOAT16、FLOAT16、FLOAT32、INT8、UINT8、INT32、UINT32、COMPLEX64。
126+ 
127+### 支持形状
128+ 
129+- 输入、输出格式为 ND;
130+- 输入 Rank 为 0~8;
131+- 输出 Shape 与输入 Shape 相同;
132+- 支持空 Tensor 和非连续 Tensor;
133+- 支持空 `dims`、负维度、重复维度和多维度 Roll。
134+ 
135+## 算子实现
136+ 
137+### 实现方案
138+ 
139+#### 3.2.1 host侧设计:
140+ 
141+ACLNN API 设计:
142+ 
143+1.`op_api/aclnn_roll.cpp` 的支持列表中增加
144+ `op::DataType::DT_COMPLEX64`
145+2. 保持现有空指针、dtype、Format、Shape、Rank 和属性合法性校验。
146+3. 非连续输入继续通过 `l0op::Contiguous` 转为连续逻辑 Tensor;非稠密
147+ 输出继续通过 `l0op::ViewCopy` 写回。
148+4. 空 Tensor 继续在 API 层直接返回,不启动 Roll Kernel。
149+ 
150+OpDef 和 InferShape 设计:
151+ 
152+1.`op_host/roll_def.cpp` 的输入和输出中增加
153+ `ge::DT_COMPLEX64`,对应 Format 和 UnknownShapeFormat 增加 ND。
154+2. 注册 `ascend910b``ascend910_93``ascend950`
155+3. `scripts/kernel/binary_config/ascendc_config.json` 中 Roll 的
156+ `compute_units` 与 OpDef 保持一致。
157+4. InferShape 继续把输入 Shape 复制给输出。
158+ 
159+Tiling 策略:
160+ 
161+1. `DT_COMPLEX64` 的元素字节数为 8。
162+2. 负维度加 Rank 转换为非负维度;位移使用正模归一化;重复维度的位移
163+ 累加后取模。
164+3. `dims` 为空时把 Tensor 视为一维;其他场景继续计算连续 Shape 和
165+ Stride。
166+4. 继续使用现有 Roll TilingData 和 TilingKey。
167+ 
168+分核策略:
169+ 
170+1. complex64 复用现有 Roll 分核策略和性能策略。
171+2. 通过平台信息获取可用 AIV 核数和 data block 大小。
172+3. complex64 按 8 字节元素换算一个 data block 包含的元素数。
173+4. 现有每核处理量、尾核和越界保护逻辑保持不变。
174+ 
175+UB 内存和数据分块策略:
176+ 
177+1. 保留现有单缓冲策略,输入 Queue 和输出 Queue 各分配一个 Buffer。
178+2. 每个 Queue 的 `ubElements = 64 KB / elementBytes`;complex64 的
179+ `elementBytes` 为 8,因此每个 Queue 容纳 8192 个元素,两个 Queue
180+ 合计占用约 128 KB UB。
181+3. Host 和 Kernel 均通过平台接口获取 data block 大小。
182+4. data block 大小无效时,Host 记录错误日志并返回失败。
183+ 
184+数据检测:
185+ 
186+1. 复用现有输入、输出、属性、Shape 和 TilingData 判空检查。
187+2. 复用现有 dtype、Format、Shape 和 Rank 校验。
188+3. 复用现有 `dims``shifts` 长度及维度范围检查。
189+ 
190+#### 3.2.2 kernel侧设计:
191+ 
192+1. 参考仓内 `experimental/conversion/as_strided` 的纯搬移算子做法,
193+ 根据构建系统注入的原始数据类型选择 Kernel 存储类型:
194+ 
195+```cpp
196+#if defined(ORIG_DTYPE_X) && ORIG_DTYPE_X == DT_COMPLEX64
197+using RollDataType = uint64_t;
198+#else
199+using RollDataType = DTYPE_X;
200+#endif
201+```
202+ 
203+complex64 路径使用 `uint64_t` 表示 8 字节搬移宽度,不声明或覆盖
204+CANN 的 `complex64` 类型,也不参与整数或复数运算。
205+ 
206+2. 继续复用现有 `Roll<RollDataType>` 及其 identity、展平、一维、多维、
207+ 末维和非末维搬移路径。
208+3. Kernel 通过 `Ops::Base::GetUbBlockSize()` 获取 data block 大小。
209+4. 非对齐尾块继续使用 `DataCopyPad`,实际搬移字节数为:
210+ 
211+```text
212+blockLen = currentElements * sizeof(T)
213+```
214+ 
215+5. 输入 Queue 和输出 Queue 继续按 Host 下发的 `ubElements` 初始化。
216+6. complex64 的实部和虚部始终作为同一个 8 字节元素移动。
217+7. 保留现有批量搬移路径和多核切分。
218+ 
219+#### aclnnRoll算子实现流程图
220+ 
221+```mermaid
222+flowchart TD
223+ A["调用 aclnnRoll(x, shifts, dims, out)"] --> B["ACLNN 支持列表增加 DT_COMPLEX64"]
224+ B --> C{"x 是否为空 Tensor?"}
225+ C -->|是| D["API 层直接返回"]
226+ C -->|否| E["非连续输入先经 l0op::Contiguous"]
227+ E --> F["l0op::Roll<br/>直接绑定 out 或生成临时 Tensor"]
228+ F --> G["OpDef 输入输出增加 ge::DT_COMPLEX64<br/>复用原 InferShape,输出 Shape 与输入一致"]
229+ G --> H["Host Tiling<br/>归一化 dims 和 shifts,complex64 的 elementBytes = 8"]
230+ H --> I["Kernel<br/>complex64 存储类型选择 uint64_t"]
231+ I --> J["复用 identity、展平、一维和多维 Roll 坐标映射路径"]
232+ J --> K["复用 DataCopyPad 按字节搬移<br/>complex64 每个元素按 8 字节整体处理"]
233+ K --> L["临时结果按需经 l0op::ViewCopy 写回 out"]
234+ L --> M["返回结果"]
235+```
236+ 
237+## 支持硬件
238+ 
239+| 支持的芯片版本 | SoC/build 参数 | NpuArch | 涉及勾选 |
240+| --- | --- | --- | --- |
241+| Atlas A2 训练系列产品 | `ascend910b` | DAV_2201 | √ |
242+| Atlas A3 训练系列产品 | `ascend910_93` | DAV_2201 | √ |
243+| Atlas A5 训练系列产品 | `ascend950` | DAV_3510 | √ |
244+ 
245+## 算子约束限制
246+ 
247+无。
248+ 
249+# 可维可测分析
250+ 
251+## 精度标准/性能标准
252+ 
253+| 验收标准 | 描述(不涉及说明原因) | 标准来源 |
254+| --- | --- | --- |
255+| complex64 精度标准 | 与 CPU PyTorch Golden 对齐,采用 AscendOpTest 默认阈值 | 任务书 |
256+| 泛化标准 | 覆盖 0~8 维、空 Tensor、空/负/重复/多维 `dims`、正负超大 `shifts`、非连续输入、奇偶长度和非 data block 对齐数据 | 任务书 |
257+| 框架语义 | `aclnnRoll``torch.roll` 语义对齐,为框架侧 `torch.fft.fftshift``torch.fft.ifftshift` 的 complex64 适配提供算子能力 | 任务书 |
258+| 原 dtype 回归 | BFLOAT16、FLOAT16、FLOAT32、INT8、UINT8、INT32、UINT32 功能保持不变 | 任务书特别注意事项 |
259+| 性能标准 | 无新增性能指标;原有 dtype 不出现性能回退 | 任务书 |
260+| 平台标准 | A2、A3、A5 目标构建通过,真机验证按官方提供的验收资源执行 | 任务书 |
261+ 
262+单元测试覆盖 API、InferShape、Tiling 和 Kernel。Kernel 测试使用不同的
263+64 位模式验证 complex64 元素完整移动;端到端测试以 CPU PyTorch 生成
264+Golden。自测交付件包含自测用例、测试代码和脚本、脚本运行 README,以及
265+覆盖全部用例的结果报告、执行日志/截图、整体通过截图和性能数据截图。
266+ 
267+## 兼容性分析
268+ 
269+本需求是现有算子的 dtype 扩展,`aclnnRoll` 函数签名、属性语义、
270+输出 Shape、TilingKey 和现有 Roll 搬移算法保持兼容。complex64 复用
271+同一套 Host Tiling 和 Kernel 调度,仅增加 8 字节元素类型映射。
272+ 
273+共享修改涉及平台 data block 对齐,因此需要对全部原有 dtype 执行功能和
274+性能回归。非连续输入继续复用 ACLNN 现有连续化流程;空 Tensor、0 维
275+Tensor、重复维度和超大位移继续使用现有语义。