ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

CANN opbase 动态 Shape 推理实战:SetUnknownRank 接口解析与源码级实现

CANN opbase 动态 Shape 推理实战:SetUnknownRank 接口解析与源码级实现 CANN opbase 动态 Shape 推理实战SetUnknownRank 接口解析与源码级实现【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase本文基于 CANN 算子库基础框架库 opbase 的官方接口文档深入解析Ops::Base::SetUnknownRank接口的功能、原型、使用场景与底层实现。该接口用于在图模式Graph Mode下当输入张量的 rank维度数未知时将输出张量的形状标记为 unknown rank。读完本文你将掌握 SetUnknownRank 的完整调用范式、与 IsUnknownRank 的搭配用法以及它如何通过gert::Shape内部数据结构与 opbase 源码实现动态形状传播。接口定位图模式下的动态形状传播基石在深度学习算子开发中输入张量的形状并不总是静态已知的。CANN 的图模式支持两类动态形态Unknown Rank未知秩连张量的维度数量都不知道形状信息几乎完全缺失Unknown Shape未知形状维度数量rank已知但每个维度的大小未知。当算子在图模式下接收到一个 unknown rank 的输入时其输出张量的形状也无法由常规的 shape 推导规则确定此时开发者需要显式地将输出形状也标记为 unknown rank保证图编译与后续算子调度能够正确识别这一动态性。SetUnknownRank正是为此场景提供的标准接口。接口原型与参数说明函数原型void SetUnknownRank(gert::Shape shape)参数表参数输入/输出说明shapeOutput输出张量的形状Shape对象函数将就地将其标记为 unknown rank。返回值返回类型void无返回值。该接口无特殊限制Restrictions: None。接口所属命名空间为Ops::Base定义于 opbase 仓库的 shape_util.h 声明、shape_util.cpp 实现是算子 Shape 推导InferShape阶段提供给宿主侧Host开发者的基础工具函数。官方示例与调用范式以下代码来自官方文档仅作参考不应直接拷贝执行auto in_shape context-GetInputShape(0); // 0 indicates the first input parameter. OP_CHECK_NULL_WITH_CONTEXT(context, in_shape); auto out_shape context-GetOutputShape(0); // 0 indicates the first output parameter. OP_CHECK_NULL_WITH_CONTEXT(context, out_shape); // Check if the shape of the input tensor is of unknown rank. If yes, the shape of the output tensor is set to unknown rank. if (Ops::Base::IsUnknownRank(*in_shape)) { Ops::Base::SetUnknownRank(*out_shape); }这段代码展示了 SetUnknownRank 的标准使用模式可以拆解为四个步骤获取输入形状通过context-GetInputShape(0)获取第 0 个输入张量的形状指针空指针校验用OP_CHECK_NULL_WITH_CONTEXT宏对指针做判空保护避免后续解引用空指针导致算子异常退出获取输出形状通过context-GetOutputShape(0)获取第 0 个输出张量的形状指针并同样做判空校验判断并传播先用Ops::Base::IsUnknownRank(*in_shape)判断输入是否为 unknown rank若为真则调用Ops::Base::SetUnknownRank(*out_shape)将输出形状标记为 unknown rank。这里体现了一个重要原则SetUnknownRank 通常不单独使用而是与 IsUnknownRank 成对出现先用判定接口确认动态性来源再决定是否传播。这是保证动态 shape 语义在算子链中正确传导的关键。源码级实现unknown rank 在 gert::Shape 中如何表达要深入理解 SetUnknownRank需要看它的底层实现。opbase 中 shape_util.cpp 通过一组常量来区分不同的动态形状语义namespace Ops { namespace Base { constexpr int64_t UNKNOWN_RANK_DIM_VALUE -2LL; constexpr int64_t UNKNOWN_DIM_VALUE -1LL; void SetUnknownRank(gert::Shape shape) { shape.SetDimNum(0); shape.AppendDim(UNKNOWN_RANK_DIM_VALUE); } bool IsUnknownRank(const gert::Shape shape) { return shape.GetDimNum() 1 shape.GetDim(0) UNKNOWN_RANK_DIM_VALUE; }从源码结构可以清晰看到 two 个关键约定-2UNKNOWN_RANK_DIM_VALUE唯一的秩未知标记。SetUnknownRank 的实现非常巧妙——先将维度数量清零SetDimNum(0)再追加一个值为-2的维度。于是1 维且值为 -2这一组合就被定义为 unknown rank 的规范表示。-1UNKNOWN_DIM_VALUE单个维度大小未知的标记用于rank 已知但各维长度未知的 Unknown Shape 场景。相应地IsUnknownRank的判定条件GetDimNum() 1 GetDim(0) UNKNOWN_RANK_DIM_VALUE正是对上述编码的逆运算。这种以特殊维值编码动态语义的设计使得 gert::Shape 无需引入额外的类型字段就能在既有 Shape 数据结构上表达动态形状信息保持了与静态形状的统一内存布局。姊妹接口完整的动态 Shape 工具集SetUnknownRank 并非孤立存在它与另外三个接口共同构成 opbase 的 Unknown Shape 工具集全部声明在 shape_util.h、实现于 shape_util.cpp接口原型功能SetUnknownRankvoid SetUnknownRank(gert::Shape shape)将 shape 标记为 unknown rank1 维且值为 -2IsUnknownRankbool IsUnknownRank(const gert::Shape shape)判断 shape 是否为 unknown rankSetUnknownShapevoid SetUnknownShape(int64_t rank, gert::Shape shape)将 shape 设置为已知 rank、各维长度未知值为 -1IsUnknownShapebool IsUnknownShape(const gert::Shape shape)判断 shape 的各维长度是否未知其中SetUnknownShape的实现shape_util.cpp会先校验rank 0的非法入参并打印错误日志随后将每个维度置为-1。而IsUnknownShape则遍历所有维度只要存在任一维度值为-1即返回trueshape_util.cpp。这套接口在语义上互补一个处理秩未知一个处理秩已知但维长未知共同覆盖了图模式动态形状的两大类场景。典型使用场景场景一动态 rank 输入的透传当算子的输入形状完全动态例如来自动态输入图或数据依赖的 shape 变化且算子本身不改变张量结构时典型做法是直接将输入的 unknown rank 状态透传给输出这正是官方示例的核心逻辑if (Ops::Base::IsUnknownRank(*in_shape)) { Ops::Base::SetUnknownRank(*out_shape); }场景二与 SetUnknownShape 配合处理已知 rank当输入是rank 已知但维长未知Unknown Shape时则应改用SetUnknownShape与IsUnknownShapeauto in_shape context-GetInputShape(0); OP_CHECK_NULL_WITH_CONTEXT(context, in_shape); auto out_shape context-GetOutputShape(0); OP_CHECK_NULL_WITH_CONTEXT(context, out_shape); if (Ops::Base::IsUnknownShape(*in_shape)) { Ops::Base::SetUnknownShape(0, *out_shape); }场景三在具体算子 InferShape 中的落地从 opbase 的公开接口文档示例还可以看到这两个判断接口常被直接嵌入算子的 shape 推导逻辑中例如当输入为 Unknown Shape 时通过output_y_shape-SetDimNum(input_dim_num)显式设置输出维数从而保持动态语义的同时固定已知的秩信息。从 AICPU 侧看 unknown rank 的数据落地在 AICPUAI CPU 算子侧unknown rank 信息同样有对应的承载结构。opbase 的 AICPU 公共组件在 cpu_tensor_shape.h 中为aicpu::TensorShape提供了配套接口bool GetUnknownRank() const;—— 获取 unknown rank 标记void SetUnknownRank(bool unknownRank);—— 设置 unknown rank 标记。其实现位于 tensor_shape_impl.cc最终落到tensor_shape_-set_unknown_rank(...)即通过 cpu_tensor_shape.proto 中 TensorShape 消息的unknown_rank字段持久化。可以看到opbase 在设计上同时提供了 gert 宿主侧与 AICPU 侧两套表达机制保证动态形状信息在 Host 推导与 Device 执行两端语义一致。使用注意事项接口为图模式专用官方文档明确说明该接口用于 Graph Mode 下处理 unknown rank 的动态形状在静态形状场景下调用并无实际意义。成对使用推荐先IsUnknownRank判定、再SetUnknownRank写入避免对已知形状做多余标记影响后续 shape 推导。空指针防护示例中获取 shape 指针后必须使用OP_CHECK_NULL_WITH_CONTEXT判空这是 opbase 算子开发的通用防御性编程规范。就地修改SetUnknownRank通过引用直接修改传入的gert::Shape对象无需返回值调用前请确认 shape 对象有效且可写。总结SetUnknownRank 是 opbase 中处理图模式动态形状的基础接口之一它以-2这一特殊维值编码 unknown rank 语义与 IsUnknownRank 成对使用即可实现动态形状在算子输入输出间的正确传播。结合同组的 SetUnknownShape、IsUnknownShape开发者可以完整覆盖秩未知与维长未知两类动态场景并在 AICPU 侧通过TensorShape::SetUnknownRank(bool)保持语义一致。理解这一接口是编写健壮、可适配动态图算子的关键一步。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表