
CANN opbase 算子开发指南ToShapeVector 接口解析与实战【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase导读ToShapeVector是 CANN opbase 算子库中 shape 工具集shape_utils的核心转换接口之一用于将算子在形状推导、tiling 等阶段频繁使用的op::Shape即gert::Shape对象中的各维信息提取到ShapeVectorFVectorint64_t, 25容器中。本文将从函数原型、类型体系、源码实现、调用示例与典型应用场景四个层面展开讲解帮助算子在开发 host 侧形状推导、tiling、日志打印时安全、高效地完成 Shape 到向量容器的转换并能够结合仓库源码理解其底层行为。一、功能说明ToShapeVector的功能是提取输入op::Shape对象中的维度信息转换到ShapeVector容器。例如一个三维 shape[10, 20, 30]经过转换后得到的ShapeVector中依次存放10、20、30三个元素分别对应第 0、1、2 维的尺寸。该接口是op::Shape框架侧表示的形状描述对象与算子自定义向量容器之间的桥梁op::Shape提供按维度读写的方法而ShapeVector提供类似标准库std::vector的随机访问、遍历、数据指针等能力二者组合起来可以覆盖算子开发中拿到形状、遍历各维、传递给下游的常见诉求。在仓库中该接口属于 shape 工具集与 ToShape向量转op::Shape即本接口的逆操作、ToContiguousStrides、CheckBroadcastShape、BroadcastInferShape等函数共同组成op命名空间下的 shape 工具族详见 shape_utils 文档首页 与 opdev API 列表。二、函数原型FVectorint64_t, 25 ToShapeVector(const op::Shape shape)所在头文件include/nnopbase/opdev/shape_utils.h命名空间op实现位置src/nnopbase/common/utils/shape_utils.cpp2.1 返回类型解析FVector 与 ShapeVector函数签名中的FVectorint64_t, 25与ShapeVector是同一类型。在 include/nnopbase/opdev/common_types.h 中有如下类型别名定义constexpr uint64_t MAX_DIM_NUM 25; using Strides FVectorint64_t, MAX_DIM_NUM; using ShapeVector FVectorint64_t, MAX_DIM_NUM; using Shape gert::Shape;其中FVector的定义位于 include/nnopbase/opdev/fast_vector.htemplate typename T, size_t N 8 using FVector op::internal::SmallVectorT, N, op::internal::PoolAllocatorT;从源码结构可以推断FVector是基于内部SmallVector与内存池分配器PoolAllocator组合出的高性能小型向量模板参数N 25表示其内联容量与 CANN 算子维度上限MAX_DIM_NUM对齐。也就是说对于维度数不超过 25 的常见算子 shape转换结果可以直接存放在栈上内联缓冲区中无需堆分配从而降低形状推导与 tiling 阶段的内存开销。2.2 参数说明参数输入/输出说明shape输入op::Shape即gert::Shape对象记录了一组 shape 信息例如一个三维 shape[10, 20, 30]。2.3 返回值说明返回一个FVector即ShapeVector对象其中按维度顺序存放着 shape 每一维的大小int64_t类型。2.4 约束说明原文档声明无额外约束。结合源码补充两点使用前提转换前 shape 对象本身应已完成维度设置可通过AppendDim或SetDim填充见下文示例维度数受算子维度上限MAX_DIM_NUM 25约束超出该上限的 shape 无法用ShapeVector完整表达。三、源码实现解析ToShapeVector的实现非常简洁完整源码如下src/nnopbase/common/utils/shape_utils.cppop::ShapeVector ToShapeVector(const op::Shape shape) { op::ShapeVector ret; ret.resize(shape.GetDimNum()); for (size_t i 0; i shape.GetDimNum(); i) { ret[i] shape[i]; } return ret; }整个转换过程分三步确定目标容量通过shape.GetDimNum()获取当前 shape 的维度数并调用ret.resize()将结果容器预分配为对应大小逐维拷贝通过shape[i]下标访问每个维度的大小按序写入ret[i]返回值以值语义返回新构造的ShapeVector。由于ShapeVector是小型内联向量返回值可以直接复用其栈上缓冲区结合SmallVector与PoolAllocator的实现从源码结构看这一设计旨在避免在热路径如逐算子形状推导上产生不必要的堆分配与拷贝。值得留意的是ToShapeVector并非孤立存在同文件中的日志辅助函数 ToString(shape) 正是先调用ToShapeVector得到维度序列再拼接成[1, 2, 3]形式的字符串ge::AscendString ToString(const op::Shape shape) { std::ostringstream oss; auto v ToShapeVector(shape); oss [; ... }这也说明该接口被广泛应用于算子框架的日志输出链路。四、调用示例4.1 原文档示例构造 Shape 并转换以下代码来源于 ToShapeVector 原文档生成一个 shape 信息为[1, 2, 3, 4, 5]的Shape对象并转换为ShapeVector// 生成一个shape信息为[1, 2, 3, 4, 5]的Shape对象并将它转为FVector。 void Func() { gert::Shape newShape; for (int64_t i 1; i 5; i) { newShape.AppendDim(i); } auto shapeVec ToShapeVector(newShape); }示例要点gert::Shape与op::Shape为同一类型见 common_types.h因此可直接作为ToShapeVector入参AppendDim(i)逐次追加维度构造出 5 维 shape转换得到的shapeVec长度为 5依次为1, 2, 3, 4, 5。4.2 完整可运行示例遍历与日志打印结合源码中的ToString与FVector的容器接口可以在算子 host 侧编写如下完整流程#include opdev/shape_utils.h #include opdev/common_types.h void ShowShapeInfo(const op::Shape inputShape) { // 1. 转换为 ShapeVector auto shapeVec ToShapeVector(inputShape); // 2. 遍历每一维 for (size_t i 0; i shapeVec.size(); i) { // 每维大小以 int64_t 存放 int64_t dimSize shapeVec[i]; } // 3. 通过 ToString 直接得到 [1, 2, 3] 形式的可读字符串 ge::AscendString str op::ToString(inputShape); }4.3 与 ToShape 的互逆使用ToShapeVector与 ToShape 是一对互逆接口ToShapeVector负责Shape → ShapeVector而ToShape负责ShapeVector → Shape其实现同样位于 shape_utils.cpp通过SetDimNum/SetDim回填。在需要将 shape 数据作为 int64 数组传给下游 API 的场景中常组合使用// 场景把 shape 转成连续 int64 数组交给下层接口处理 op::Shape shape; // ... 构造 shape ... auto shapeVec ToShapeVector(shape); int64_t* dims shapeVec.data(); // 连续内存可直接传递 uint64_t dimNum shapeVec.size();五、典型应用场景5.1 为下游接口准备连续维度数组在 tests/nnopbase/ut/composite_op/test_dsa.cpp 的测试用例中ToShapeVector被用于将 Tensor 的 shape 转换为连续数组后交给执行器的参数分配接口auto inputShape op::ToShapeVector(tShape); auto inputShapeArray uniqueExecutor.get()-AllocIntArray(inputShape.data(), inputShape.size());这里展示了它的一个关键价值ShapeVector提供了.data()与.size()使得 shape 维度信息可以以int64_t*连续内存的形式传递给诸如AllocIntArray之类的运行时接口。5.2 shape 相关的日志与错误信息格式化如第三节所述ToString内部复用了ToShapeVector。在整个算子库中shape 的可读字符串大量出现在日志输出中例如 aicpu_ext_info_handle.cpp 中打印输入/输出 Tensor 的 ViewShape、StorageShape 与 OriginalShape以及 BroadcastInferShape 在广播推导失败时拼接两个 shape 的字符串构造错误原因。可以推断凡是需要遍历 shape 各维做计算或打印 shape 内容的工具函数都会以ToShapeVector或它的调用链作为基础。5.3 配合其他 shape 工具完成完整流程ToShapeVector所在的 shape_utils.h 还提供了完整的 shape 处理工具链包括ToString(const op::Shape)/ToString(const op::Strides)shape 与 strides 的可读字符串ToShape维度数组/ShapeVector反向构造op::ShapeToContiguousStrides根据 shape 计算连续 stridesCheckBroadcastShape/BroadcastInferShape广播兼容性检查与广播结果推导。算子开发者在编写形状推导InferShape或 tiling 逻辑时通常的组合方式是用ToShapeVector取出各维大小 → 遍历计算如元素个数、stride→ 用ToShape写回新的op::Shape形成一条完整的 shape 处理闭环。六、总结ToShapeVector虽然实现短小却是 CANN opbase 中 shape 处理基础设施的关键一环定位op::Shape → ShapeVectorFVectorint64_t, 25的维度信息提取接口与 ToShape 互逆性能考量基于SmallVector与PoolAllocator在 25 维以内可避免堆分配适合形状推导等高频路径复用价值ToString等工具函数及算子库多处日志、参数下发流程均以其为基础是算子 host 侧处理 shape 的通用入口使用注意转换结果只反映 shape 的维数信息维度上限为MAX_DIM_NUM 25且要求入参 shape 已完成维度设置。掌握该接口即可在算子开发中高效完成 Shape 的遍历、传递与日志输出并在此基础上组合使用 shape_utils 提供的完整工具集。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考