CANN opbase aclTensor::SetStorageFormat 详解:为张量设置存储格式(StorageFormat)
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
SetStorageFormat是 CANN opbase 框架库中aclTensor类的核心属性设置接口,用于指定张量在设备内存中的实际排布格式(如 NCHW、ND 等)。本文以 docs/en/api/nnopbase/opdev/common_types/SetStorageFormat.md 为骨架,结合仓库内头文件声明、实现源码与算子执行链路中的真实调用,完整讲解该接口的原型、参数语义、可用格式取值、底层实现机制与在算子开发中的典型用法,帮助算子开发者正确读写张量的存储格式元数据。
1. 功能概述:什么是 StorageFormat
在 CANN opbase 中,aclTensor是算子开发过程中传递张量数据的核心对象。一个aclTensor在内存中的实际排布方式由StorageFormat(存储格式)描述,常见的取值包括NCHW、ND等。
从仓库源码结构看,aclTensor对张量格式的管理分为三个相互独立的维度(对应三组 Get/Set 接口):
| 维度 | 语义 | 对应接口 |
|---|---|---|
| StorageFormat | 张量在物理内存中的实际排布格式 | GetStorageFormat、SetStorageFormat |
| OriginalFormat | 张量的原始逻辑格式(数据来源时携带的格式) | GetOriginalFormat、SetOriginalFormat |
| ViewFormat | 当前视图(view)视角下张量的格式 | GetViewFormat、SetViewFormat |
SetStorageFormat专门负责设置其中的StorageFormat维度,即声明该aclTensor在内存中"实际是怎么排的"。
2. 接口原型与参数说明
2.1 原型
SetStorageFormat是aclTensor的公有成员函数,原型如下:
void SetStorageFormat(op::Format format)该声明位于 include/nnopbase/opdev/common_types.h#L162-L163:
op::Format GetStorageFormat() const; void SetStorageFormat(op::Format format);2.2 参数
| 参数 | Input/Output | 说明 |
|---|---|---|
| format | Input | 数据类型为op::Format(即ge::Format),是定义不同格式的枚举类型,例如 NCHW、ND 等 |
关于op::Format的类型来源,include/nnopbase/opdev/common_types.h#L44-L55 中给出了明确的类型别名定义:
namespace op { using Format = ge::Format; using StorageFormat = gert::StorageFormat; // ... } // namespace op也就是说,op::Format与ge::Format是同一枚举类型,二者可以互换使用,文档示例中也直接以ge::FORMAT_ND作为参数传入。
2.3 返回值
该接口无返回值(void),调用失败时也不会抛出异常——它只是纯元数据写入操作(详见第 5 节的源码实现分析)。
2.4 限制
无。
3. 支持的格式取值(op::Format / ge::Format 枚举)
SetStorageFormat的入参是ge::Format枚举。结合 src/nnopbase/common/utils/format_utils.cpp 中ToString(Format)支持的格式映射表,仓库实际识别并支持的格式包括但不限于:
| 格式枚举 | 字符串 | 典型用途 |
|---|---|---|
FORMAT_NCHW | NCHW | 4 维图像数据默认逻辑排布 |
FORMAT_NHWC | NHWC | 通道在最后的图像数据排布 |
FORMAT_ND | ND | 通用 N 维数据排布,未指定特殊排布时使用 |
FORMAT_NC1HWC0 | NC1HWC0 | 昇腾 5D 格式(私有格式) |
FORMAT_FRACTAL_Z | FRACTAL_Z | 分形 Z 格式(私有格式) |
FORMAT_FRACTAL_NZ | FRACTAL_NZ | 分形 NZ 格式(私有格式) |
FORMAT_NC | NC | 2 维矩阵数据排布 |
FORMAT_NCL | NCL | 3 维数据排布 |
FORMAT_NDHWC/FORMAT_NCDHW | NDHWC / NCDHW | 5 维数据排布 |
FORMAT_NDC1HWC0 | NDC1HWC0 | 5D 变体格式 |
FORMAT_FRACTAL_Z_3D | FRACTAL_Z_3D | 3 维分形格式 |
FORMAT_FRACTAL_NZ_C0_16等系列 | FRACTAL_NZ_C0_16/32/2/4/8 | 面向不同 C0 对齐宽度的分形格式 |
说明:上表仅摘录了常用格式;完整的枚举映射可查看 src/nnopbase/common/utils/format_utils.cpp#L103-L171 中的
kFormatToStringMap,它覆盖了 50 余种格式。
3.1 私有格式的注意事项
仓库将部分格式标记为"私有格式"(private format)。src/nnopbase/common/utils/format_utils.cpp#L21-L31 中的op::IsPrivateFormat()会判定FORMAT_NC1HWC0、FORMAT_FRACTAL_Z、FORMAT_NDC1HWC0、FORMAT_FRACTAL_Z_3D、FORMAT_FRACTAL_NZ及FORMAT_FRACTAL_NZ_C0_*等为私有格式。在使用特定构造路径创建aclTensor时,若视图格式为私有格式,框架会打印告警日志(见 src/nnopbase/common/utils/common_types.cpp#L212-L214),提示此类格式不应通过某些普通构造接口创建。因此,在调用SetStorageFormat之前,建议结合算子实际支持的格式合理取值。
4. 使用示例
文档给出的最简示例是将输入张量的存储格式设置为 ND:
// Set the storage format of the input to ND. void Func(const aclTensor *input) { input->SetStorageFormat(ge::FORMAT_ND); }在实际算子开发中,SetStorageFormat常与读取接口配合使用,例如将算子输出张量的存储格式与输入保持一致:
void SetOutputSameAsInput(const aclTensor *input, aclTensor *output) { // 先读取输入张量当前的存储格式 op::Format inputFormat = input->GetStorageFormat(); // 将输出张量的存储格式设置为与输入一致 output->SetStorageFormat(inputFormat); // 同时可配合设置原始格式 output->SetOriginalFormat(input->GetOriginalFormat()); }读取侧对应的实现是 src/nnopbase/common/utils/common_types.cpp#L404 的GetStorageFormat(),它返回底层op::Tensor(gert::TensorV2)中保存的存储格式:
op::Format aclTensor::GetStorageFormat() const { return tensor_->GetFormat().GetStorageFormat(); }5. 源码级实现:SetStorageFormat 做了什么
5.1 实现位置
SetStorageFormat的实现位于 src/nnopbase/common/utils/common_types.cpp#L475:
void aclTensor::SetStorageFormat(op::Format format) { tensor_->SetStorageFormat(format); }5.2 工作原理
从实现看,aclTensor::SetStorageFormat是一个纯元数据写入操作:
aclTensor内部维护一个op::Tensor* tensor_指针(即gert::TensorV2),所有格式、形状、数据类型信息都保存在该底层张量对象中(见 include/nnopbase/opdev/common_types.h#L258-L267 的成员声明);SetStorageFormat将入参透传给底层tensor_->SetStorageFormat(format),更新TensorV2内部Format描述中的 storage 部分;- 该操作不会对张量数据做任何搬运、转置或重排,也不重新分配内存——它只改变"这段内存该如何被解释"的描述信息。如果存储格式与实际内存排布不一致,可能引发算子侧对数据解释错误,因此调用前需要确保值与真实排布相符。
这一点与aclTensor的多种构造函数的行为一致:构造函数内部通过op::StorageFormat format; format.SetStorageFormat(storageFormat);完成初始存储格式的写入(见 src/nnopbase/common/utils/common_types.cpp#L130-L136),SetStorageFormat只是把这一写入能力开放为运行时可调用的公有接口。
6. 在算子执行链路中的实际应用
SetStorageFormat不仅用于算子开发侧的显式调用,也被框架内部多个执行模块使用:
6.1 复合算子(composite op)编译描述构建
在 src/nnopbase/composite_op/aclnn_engine/kernel_context_holder.cpp#L240 与 第 298 行 中,框架在构建算子编译描述时会把输入/输出张量的存储格式直接透传到compileDesc:
compileDesc_[inputNum_].storage_format_.SetStorageFormat(tensor->GetStorageFormat()); // ... compileDesc_[inputNum_ + outputNum_].storage_format_.SetStorageFormat(tensor->GetStorageFormat());可见:aclTensor上设置的 StorageFormat 会作为算子编译(tiling/编译描述)阶段的输入信息,直接影响算子的编译与调度决策。
6.2 独立算子(individual op)运行时张量同步
在 src/nnopbase/individual_op/executor/indv_executor_tensor.cpp#L305-L308 中,框架在构造运行时(runtime)张量时也会调用SetStorageFormat:
rt2Tensor->SetStorageFormat(ge::FORMAT_ND); // ... rt2Tensor->SetStorageFormat(format);这说明在执行器把算子输入转换为 runtime 张量时,会通过SetStorageFormat显式声明张量的存储格式(默认场景使用FORMAT_ND,特殊场景透传原格式),保证下游 kernel 拿到正确的排布信息。
6.3 调试与序列化输出
此外,aclTensor::ToString()(见 src/nnopbase/common/utils/common_types.cpp#L744-L759)在打印张量信息时会同时输出storage_format、ori_format等字段,方便开发者在 dump 调试时核对SetStorageFormat是否生效。
7. 相关辅助工具与配套接口
7.1 格式工具函数
include/nnopbase/opdev/format_utils.h 提供了与op::Format配套的工具函数,在设置存储格式前后可用于格式校验与转换:
| 函数 | 作用 |
|---|---|
op::IsPrivateFormat(Format) | 判断是否为私有格式(NC1HWC0、FRACTAL_Z 等) |
op::ToFormat(const std::string&) | 将字符串(如"ND")转换为Format枚举 |
op::ToString(Format) | 将Format枚举转换为可读字符串 |
op::GetPrimaryFormat(Format) | 提取主格式(低 8 位) |
op::GetSubFormat(Format) | 提取子格式信息 |
op::HasSubFormat(Format) | 判断是否携带子格式 |
op::ToOpFormat(aclFormat) | 将aclFormat转换为op::Format |
op::ToAclFormat(Format) | 将op::Format转换回aclFormat,不支持时返回ACL_FORMAT_UNDEFINED |
其中op::ToFormat与op::ToString的完整字符串-枚举映射见 src/nnopbase/common/utils/format_utils.cpp,可作为设置存储格式时取值范围的权威参考。
7.2 配套接口
SetStorageFormat属于 common_types 接口族 的一员,常用配套接口包括:
- GetStorageFormat:读取存储格式,与
SetStorageFormat互为读写对; - SetOriginalFormat / GetOriginalFormat:设置/读取原始格式;
- SetViewFormat / GetViewFormat:设置/读取视图格式;
- SetStorageShape / GetStorageShape:设置/读取存储形状(存储格式与存储形状共同决定内存布局的完整描述)。
8. 总结
aclTensor::SetStorageFormat(op::Format format)用于设置张量的存储格式元数据,参数类型为op::Format(即ge::Format),无返回值、无限制;- 实现上仅为对底层
gert::TensorV2的元数据写入(src/nnopbase/common/utils/common_types.cpp#L475),不会触发数据搬运或内存重排,调用前需确保与实际排布一致; - 存储格式会沿算子执行链路向下透传:复合算子的编译描述构建(kernel_context_holder.cpp)与独立算子的 runtime 张量构造(indv_executor_tensor.cpp)都会消费该信息,是算子正确编译与执行的关键属性之一。
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考