CANN opbase 算子开发指南:aclTensor::SetStorageFormat 接口详解与 StorageFormat 内存排布设置
2026/9/18 13:20:37 网站建设 项目流程

CANN opbase 算子开发指南:aclTensor::SetStorageFormat 接口详解与 StorageFormat 内存排布设置

【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase

导读

本文聚焦 CANN/opbase 算子库中aclTensor对象的核心元数据接口之一 ——SetStorageFormat,讲解如何显式设置张量在设备内存中的排布格式(StorageFormat),并深入源码说明该接口与op::Tensor底层存储格式属性之间的调用关系。阅读本文后,你将掌握op::Format(即ge::Format)枚举的取值约定、aclTensor的 storage/origin/view 三层格式视图的区别,以及如何在算子开发与单测中正确设置和校验张量存储格式。

一、StorageFormat:张量在内存中的排布格式

在算子开发过程中,张量具备逻辑维度(如 NCHW 四维语义)与物理存储排布(数据在内存中的实际存放顺序)两层信息。StorageFormat描述的正是后者 ——aclTensor 在内存中的排布格式,例如NCHWNDNHWCNC1HWC0FRACTAL_NZ等。它决定了算子读取输入、写入输出时如何根据多维索引计算物理内存偏移。

在 common_types.h 中可以看到,op命名空间对底层类型做了别名统一:

namespace op { using Format = ge::Format; using Tensor = gert::TensorV2; using StorageFormat = gert::StorageFormat; using StorageShape = gert::StorageShape; }

其中using Format = ge::Format;明确说明SetStorageFormat的入参类型op::Format本质就是ge::Format枚举。

1.1 aclTensor 的三层格式视图

从 common_types.h 的接口声明可以看到,aclTensor对格式的管理分为三个维度,分别对应三对 Get/Set 接口:

格式视图Get 接口Set 接口语义
StorageFormatGetStorageFormat()SetStorageFormat()张量在内存中的实际排布格式
OriginalFormatGetOriginalFormat()SetOriginalFormat()张量原始的逻辑排布格式(用户视角)
ViewFormatGetViewFormat()SetViewFormat()当前视图(view)下的排布格式

StorageFormat是其中最贴近硬件与底层框架的一层。原始格式(Origin)通常与存储格式一致,但当发生格式转换(如插入 format transform 算子)时,二者就会出现差异;而视图格式(View)则用于描述Reshape、切片等视图操作后张量呈现的格式。

1.2 op::Format 枚举的常见取值

op::Format枚举包含多种格式。结合 format_utils.h 中ToAclFormat的可转换列表,常见取值包括:

枚举值说明
FORMAT_NDN 维通用格式,无特定排布要求
FORMAT_NCHW通道在前(C 维按序排布)的四维格式
FORMAT_NHWC通道在最后(C 维不连续)的四维格式
FORMAT_NC1HWC0Ascend 硬件典型的 5 维分形格式,C 维拆分为 C1/C0
FORMAT_FRACTAL_Z/FORMAT_FRACTAL_NZ面向特定硬件算子(如矩阵运算)的分形排布格式
FORMAT_HWCN与 NCHW 相反的排布
FORMAT_NDHWC/FORMAT_NCDHW5 维数据的 NHWC / NCDHW 排布
FORMAT_NCFORMAT_NCL二维 / 三维的通道格式

此外,format_utils.h 还提供了GetPrimaryFormatGetSubFormatHasSubFormatGetFormatFromSub等工具函数,用于解析带子格式(sub format)与 C0 信息的复合格式编码,说明 Format 枚举值在底层可能是主格式与子格式的位组合。

二、函数原型与参数说明

2.1 函数原型

接口声明位于 common_types.h:

op::Format GetStorageFormat() const; void SetStorageFormat(op::Format format);

2.2 参数说明

参数输入/输出说明
format输入数据类型为op::Format(即ge::Format),是一个枚举,包含多种不同的 Format,例如NCHWNDNHWCNC1HWC0FRACTAL_NZ等。

2.3 返回值说明

无返回值(void)。

2.4 约束说明

接口本身无额外约束。但从实现看,SetStorageFormat只更新元数据中记录的格式信息,不会触发实际的数据重排。若将 StorageFormat 设置为与物理内存实际排布不一致的值,会导致后续算子按错误的索引计算读取数据,因此调用方必须保证设置值与该张量真实的内存排布一致。

三、调用示例:将 StorageFormat 置为 ND 格式

原文档给出的核心用法是将aclTensor的存储格式显式置为ND格式:

// 将input的Storage Format置为ND格式 void Func(const aclTensor *input) { input->SetStorageFormat(ge::FORMAT_ND); }

ge::FORMAT_NDop::Format::FORMAT_ND指向同一枚举值(因op::Formatge::Format),因此在算子实现中也可写作:

void SetToFractalNz(const aclTensor *input) { input->SetStorageFormat(ge::FORMAT_FRACTAL_NZ); }

典型的应用场景包括:

  • 自定义算子 Tiling 前,将输入张量标记为硬件友好的分形格式(如FORMAT_FRACTAL_NZ)以匹配算子 kernel 的读取方式;
  • ReshapeTranspose等算子中,显式修正输出张量的存储格式元数据;
  • 构造用于单测的张量时,模拟指定内存排布,验证格式相关逻辑分支。

四、源码级实现解析:SetStorageFormat 的调用链

4.1 接口实现

SetStorageFormat的实现位于 common_types.cpp:

void aclTensor::SetStorageFormat(op::Format format) { tensor_->SetStorageFormat(format); }

可以看到,aclTensor内部持有一个op::Tensor(即gert::TensorV2)指针tensor_SetStorageFormat是薄封装,将调用直接转发给底层张量的SetStorageFormat方法,写入其StorageFormat属性。与之对应的读取接口在 common_types.cpp:

op::Format aclTensor::GetStorageFormat() const { return tensor_->GetFormat().GetStorageFormat(); }

Get/Set一一对应:写入通过tensor_->SetStorageFormat(),读取通过tensor_->GetFormat().GetStorageFormat(),二者操作的是同一个存储格式字段。

4.2 构造阶段对 StorageFormat 的初始化

从源码看,aclTensor在多种构造路径中都会把传入的storageFormat写入底层gert::StorageFormat对象。例如 common_types.cpp:

aclTensor::aclTensor(const op::Shape& storageShape, const op::Shape& originShape, op::DataType dataType, op::Format storageFormat, op::Format originFormat, void* tensorDataAddr) { ... op::StorageFormat gertFormat; gertFormat.SetStorageFormat(storageFormat); gertFormat.SetOriginFormat(originFormat); ... tensor_ = new (base) op::Tensor(gertShape, gertFormat, op::TensorPlacement::kOnDeviceHbm, dataType, tensorDataAddr); }

类似的初始化逻辑还出现在其他构造函数中(见 common_types.cpp 与 common_types.cpp)。这从侧面印证:aclTensor创建时即可同时指定存储格式与原始格式,SetStorageFormat则用于在张量创建后按需修改存储格式元数据。

4.3 私有格式校验

在 common_types.cpp 中可以看到,aclTensor的视图构造路径会对私有格式(private format)做警告检查:

OP_CHECK(!op::IsPrivateFormat(viewFormat_), OP_LOGW("the private format[%s], should not use this constructor.", op::ToString(viewFormat_).GetString()), ;);

这提示开发者:并非所有 Format 枚举值都适合直接用于公开构造或设置路径,私有格式(如带特定 C0 拆分的内部格式)应通过专门的框架机制处理。

五、配套接口与格式视图协同使用

SetStorageFormat通常与aclTensor的其他格式接口配合使用,以完整刻画张量的格式信息(声明见 common_types.h):

op::Format GetStorageFormat() const; void SetStorageFormat(op::Format format); op::Format GetOriginalFormat() const; void SetOriginalFormat(op::Format format); op::Format GetViewFormat() const; void SetViewFormat(op::Format format);

对应的实现(common_types.cpp):

op::Format aclTensor::GetStorageFormat() const { return tensor_->GetFormat().GetStorageFormat(); } op::Format aclTensor::GetOriginalFormat() const { return tensor_->GetFormat().GetOriginFormat(); } op::Format aclTensor::GetViewFormat() const { return viewFormat_; } void aclTensor::SetStorageFormat(op::Format format) { tensor_->SetStorageFormat(format); } void aclTensor::SetOriginalFormat(op::Format format) { tensor_->SetOriginFormat(format); } void aclTensor::SetViewFormat(op::Format format) { viewFormat_ = format; }

从实现差异可以看出设计意图:

  • StorageFormat / OriginalFormat存储在底层gert::TensorV2的格式对象中,随张量持久化,是算子框架真正消费的元数据;
  • ViewFormat存储在aclTensor自身的viewFormat_成员中,服务于视图层逻辑,viewFormat_的初值在构造时取自originFormat(见 common_types.cpp)。

因此,如果目标是影响算子调度与内存访问,应设置的是SetStorageFormat;而仅表达视图语义的格式偏好,则使用SetViewFormat

六、测试验证:仓库中对该接口的实际使用

仓库的测试代码直接印证了SetStorageFormat的典型用法:

  • 在 composite_op 单测 test_common_types.cpp 中,将张量存储格式设置为分形格式:
a.SetStorageFormat(Format::FORMAT_FRACTAL_NZ);
  • 同样用法出现在 composite_op 系统测试 test_common_types.cpp;
  • 在 individual_op 的 executor 单测中,以ge::FORMAT_ND作为入参调用该接口,例如 executor_utest.cpp 与 indv_args_utest.cpp:
tensor.rt2Tensor.SetStorageFormat(ge::FORMAT_ND);

这些测试一方面验证了op::Formatge::Format)与op::Format::FORMAT_*/ge::FORMAT_*两种写法等价,另一方面也说明SetStorageFormat被广泛用于构造待测张量,是算子级单测中模拟内存排布的标准手段。

七、使用注意事项小结

  1. 只改元数据,不重排数据SetStorageFormat仅更新张量格式元数据,真实数据需由 format transform 算子或显式拷贝完成重排,二者必须保持一致;
  2. 三视图勿混淆:物理排布用SetStorageFormat,逻辑排布用SetOriginalFormat,视图语义用SetViewFormat;底层框架真正消费的是前两者;
  3. 枚举取值op::Formatge::Format,常用值包括FORMAT_NDFORMAT_NCHWFORMAT_NHWCFORMAT_NC1HWC0FORMAT_FRACTAL_NZ等,私有格式应避免在普通构造路径中使用;
  4. 配套读取:设置后可通过GetStorageFormat()校验结果,二者在 common_types.cpp 中操作同一个底层格式字段。

关于aclTensor格式接口的完整集合(含 Shape 视图的 Get/Set 接口、SetData系列数据写入接口、NumelIsEmptyCheckOverflows等),可继续阅读 common_types 接口总览,其中列出了 GetStorageFormat、SetOriginalFormat、SetViewFormat 等全部配套接口文档。

【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询