CANN opbase 中 ToContiguousStrides 详解:从 Shape 推导连续 Stride 的底层原理与实战用法

CANN opbase 中 ToContiguousStrides 详解:从 Shape 推导连续 Stride 的底层原理与实战用法 CANN opbase 中 ToContiguousStrides 详解从 Shape 推导连续 Stride 的底层原理与实战用法【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase导读ToContiguousStrides是 CANN opbase 算子库op::shape_utils工具集中用于由形状推导连续内存步长的基础函数给定一个 shape按行主序row-major连续内存布局规则反向推导出对应的 stride 数组。本文以 ToContiguousStrides 官方文档 为主体结合 opbase 仓库中的 源码实现、类型定义 与单元测试完整讲解其函数原型、参数语义、核心算法、边界场景以及在张量视图tensor view与算子 shape 推导中的典型应用帮助算子开发者准确理解并正确使用这一基础工具。一、背景Shape 与 Stride 的关系在多维张量的存储模型中shape描述张量在逻辑上的维度大小例如三维 shape[10, 20, 30]而stride描述沿每个维度前进 1 个元素时在连续内存中需要跨越的元素个数例如对应的 stride 为[600, 30, 1]。两者共同决定了一个逻辑下标(i, j, k)对应的物理内存偏移offset i * strides[0] j * strides[1] k * strides[2]当张量数据在内存中是紧密连续contiguous存放、且按行主序即最右维变化最快排列时stride 可以由 shape 唯一确定这种 stride 称为连续 stride当张量经过切片、转置、扩维等操作后元素在内存中不再紧密排列stride 与 shape 不再保持上述简单关系此时往往需要显式维护视图 strideview strides。ToContiguousStrides解决的就是第一种场景在已知 shape、且确认张量按连续行主序布局时快速推导出对应的 stride供 shape 推导infershape、tensor view 偏移计算、内存搬运与算子调度等环节使用。二、函数原型与参数说明ToContiguousStrides的函数原型来自 官方文档如下void ToContiguousStrides(const op::Shape shape, op::Strides strides)参数语义完整说明参数输入/输出说明shape输入记录了一组 shape 信息例如一个三维 shape[10, 20, 30]类型为op::Shape即gert::Shapestrides输出记录了一组 stride 信息例如针对上述三维 shape 推导出的[600, 30, 1]类型为op::Strides即FVectorint64_t, 25返回值无结果通过输出参数strides返回。约束说明无特殊限制函数对任意维数的 shape 均可调用。关键类型定义在 opbase 的 common_types.h 中相关类型被统一定义在op命名空间下constexpr uint64_t MAX_DIM_NUM 25; // 张量最大维数 using Strides FVectorint64_t, MAX_DIM_NUM; // stride 容器固定容量 25 的小型向量 using ShapeVector FVectorint64_t, MAX_DIM_NUM; // shape 向量容器 using Shape gert::Shape; // shape 类型别名来自 exe_graph 运行时要点op::Shape是gert::Shape的别名来自exe_graph/runtime/shape.h是昇腾图编译框架中的标准 shape 类型op::Strides本质是FVectorint64_t, 25见 fast_vector.h即一个容量上限为 25 的栈上优先的小型动态向量与MAX_DIM_NUM 25对齐既避免了为绝大多数算子维数远小于 25分配堆内存也覆盖了昇腾张量的最大维数场景函数声明位于 common_types.h 第 59 行实现在src/nnopbase/common/utils/下作为算子开发框架的公共基础工具提供给所有算子复用。三、核心算法原理与源码级实现ToContiguousStrides的实现非常精简位于 src/nnopbase/common/utils/shape_utils.cppvoid ToContiguousStrides(const op::Shape shape, op::Strides strides) { strides.assign(shape.GetDimNum(), 1); for (int64_t i static_castint64_t(shape.GetDimNum() - 2); i 0; i--) { strides[i] shape.GetDim(i 1) * strides[i 1]; } }算法解析整个算法只有两步体现了从右向左累乘的经典连续 stride 推导策略初始化strides.assign(shape.GetDimNum(), 1)。先将所有维度的 stride 置为 1。注意assign同时完成了两件事——把strides的规模调整为与 shape 维数一致并为后续累乘提供基准值反向递推从倒数第二维i dimNum - 2开始向左遍历到第 0 维执行strides[i] shape[i 1] * strides[i 1]即某一维的 stride 等于其右邻维度的 size 乘以其右邻维度的 stride。以文档中的三维 shape[10, 20, 30]为例逐步推演初始化strides [1, 1, 1]i 1strides[1] shape[2] * strides[2] 30 * 1 30i 0strides[0] shape[1] * strides[1] 20 * 30 600最终得到strides [600, 30, 1]与文档描述完全一致。该算法成立的前提是行主序C 语言风格连续布局最内层最后一维的元素在内存中连续相邻因此其 stride 恒为 1越靠外的维度stride 越大数值上等于其右侧所有维度 size 的乘积。这一规律与FVector按索引 0~n-1 对应最外维到最内维的约定相匹配。从源码结构可推断的特性对空 shape标量的健壮性当GetDimNum() 0时assign(0, 1)得到空 strides循环初值-2不满足i 0而不执行函数安全返回无越界风险对一维 shape 的正确性当GetDimNum() 1时循环不执行strides [1]即一维连续张量的 stride 恒为 1符合内存语义零维参与的合法 shape若 shape 中存在 0空张量累乘过程中会出现 0 stride这与空张量无有效元素、偏移无意义的语义一致属于合理结果。单元测试中的同源实现该算法在 opbase 测试代码中被原样复刻用于构造基准数据例如 tests/nnopbase/ut/composite_op/test_debug_kernel.cppvectorint64_t ToContiguousStrides(const vectorint64_t shape) { vectorint64_t strides(shape.size(), 1); for (int64_t i static_castint64_t(shape.size() - 2); i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } return strides; }测试代码采用与生产实现完全一致的置 1 反向累乘逻辑用于为test_binary_resuse、test_debug_kernel等场景构造张量的预期 stride可作为验证ToContiguousStrides行为正确性的旁证同一算法在产物代码与测试基准中双重出现确保了算子侧推导结果与测试侧期望的一致性。四、调用示例与结果推演官方文档给出的调用示例如下见 ToContiguousStrides.md// 生成一个 shape 信息为 [1, 2, 3, 4, 5] 的 Shape 对象并生成它的 stride 数据。 void Func() { gert::Shape newShape; for (int64_t i 1; i 5; i) { newShape.AppendDim(i); } FVectorint64_t, 25 strides; ToContiguousStrides(newShape, strides); }示例要点解读使用gert::Shape::AppendDim(i)逐维追加构造出 shape[1, 2, 3, 4, 5]输出容器使用FVectorint64_t, 25——这正好就是op::Strides的底层类型因此也可以直接写op::Strides strides;传入的newShape与strides均按引用传递ToContiguousStrides执行后strides即被填充。对[1, 2, 3, 4, 5]进行逐步推演初始化[1, 1, 1, 1, 1]i 3strides[3] 5 * 1 5i 2strides[2] 4 * 5 20i 1strides[1] 3 * 20 60i 0strides[0] 2 * 60 120最终strides [120, 60, 20, 5, 1]即张量元素总数 120各维 stride 依次为 120、60、20、5、1。读者可据此公式自行验算任意 shape。五、典型应用场景1. 张量视图Tensor View的视图 stride 维护opbase 的张量视图机制在 common_types.h 中提供了视图 stride 的存取接口const op::Strides GetViewStrides() const; void SetViewStrides(const op::Strides strides); void SetViewStrides(op::Strides strides);对于一个未经过切片/转置的原始连续张量其视图 stride 恰好就是ToContiguousStrides(shape)的推导结果只有当张量经历了 ViewCopy、Reshape、切片等特殊操作后参见 common_types.h 中关于 extend_ 指针的注释视图 stride 才需要被显式改写。因此ToContiguousStrides是视图 stride 初始化的标准工具。2. 算子 shape 推导与内存搬移计算在算子 infershape 阶段开发者常需要根据输出 shape 快速得到连续 stride用于计算输出张量的总元素数与内存占用判断输入输出张量是否连续与视图 stride 比较从而决定走直接搬运还是逐元素搬运路径在多输入算子如广播类、二值运算类算子中为各输入统一构造连续 stride 以便对齐计算。3. 测试基准中的 stride 构造如前文所述test_binary_resuse.cpp 在多个用例约第 218、415、495、669、721、764、853 行处中反复使用同源ToContiguousStrides逻辑为不同 shape 计算stridesA / stridesB / stridesResult用于验证二进制张量复用binary reuse场景下内存别名与偏移计算的正确性——这说明该函数是算子内存规划类逻辑中的高频基础件。六、与 shape_utils 工具集的协作关系ToContiguousStrides是 opbase 中 shape_utils 工具集 的一员该工具集还包括ToShape将int64_t*数组或ShapeVector转换为op::ShapeToShapeVector将op::Shape转换为ShapeVectorCheckBroadcastShape校验两个 shape 是否满足广播规则BroadcastInferShape对两个 shape 执行广播并推导广播后的 shape。在实际算子开发中常见的组合链路是先用ToShape/ToShapeVector完成 shape 数据的格式转换再用ToContiguousStrides得到连续 stride最后在需要时用CheckBroadcastShape/BroadcastInferShape处理广播语义。这些工具共同构成了 opbase 为算子开发者提供的 shape/stride 基础能力全部实现在 src/nnopbase/common/utils/shape_utils.cpp 中且均可通过#include opdev/shape_utils.h引入头文件位于 include/nnopbase/opdev/shape_utils.h。七、使用建议与注意事项适用前提ToContiguousStrides推导的是行主序连续布局下的 stride。若张量实际内存布局为列主序或经过了转置/切片导致非连续必须使用张量自身维护的视图 stride而非本函数的结果输出容器复用strides是输出参数函数内部通过assign覆盖其内容因此调用前无需手动 resize多次调用可安全复用同一容器维数上限Strides底层FVectorint64_t, 25的容量与MAX_DIM_NUM 25一致shape 维数不应超过 25这也与昇腾张量模型的最大维数约束一致空 shape 与一维 shape两者均能安全处理分别得到空 strides 与[1]在涉及标量/向量算子的推导中可直接使用无需额外分支。总结ToContiguousStrides是一个仅十余行代码、却承载着由 shape 到连续 stride这一基础内存语义转换的公共工具它通过初始化全 1 从右向左累乘的算法以O(dimNum)的时间复杂度为任意合法 shape 生成行主序连续 stride。其实现位于 shape_utils.cpp类型基础定义于 common_types.h并在 debug kernel 测试 与 binary reuse 测试 中得到了行为印证。无论是编写 shape 推导逻辑、初始化张量视图 stride还是规划内存搬移路径理解并正确使用该函数都是昇腾算子开发中的基本功。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考