ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ascend Transformer Boost Transdata 算子详解:ND 与 NZ 数据格式互转的参数约定、形状推导与 Runner 实现

Ascend Transformer Boost Transdata 算子详解:ND 与 NZ 数据格式互转的参数约定、形状推导与 Runner 实现 Ascend Transformer Boost Transdata 算子详解ND 与 NZ 数据格式互转的参数约定、形状推导与 Runner 实现【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库基于华为Ascend AI处理器提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boostTransdata 是 Ascend Transformer Boost以下简称 ATB中负责 ND行主序与 FRACTAL_NZNZ 分块两种数据格式互转的基础算子是 Cube 核上执行 NZ 格式矩阵乘前后完成数据摆位的关键一环。本文基于仓库中的路由知识文件 transdata.md 与对应源码完整梳理 Transdata 算子的文件构成、参数约定transdataType/outCrops、ND↔NZ 维度映射规则、形状推导与合法性校验逻辑以及 OpsRunner 的 Kernel Graph 构建与平台适配细节并给出可复现的最小 Demo 流程帮助你在集成 NZ 格式计算链路时准确使用并排查该算子的问题。一、算子定位与文件构成Transdata 属于推理infer类算子复杂度为 M涉及 6 个核心源文件。按照 路由文件 给出的阅读顺序各文件的角色如下顺序文件重点关注1transdata_operation.h输入输出数量、InferShape 签名2transdata_operation.cppCreateRunner() 决策逻辑3transdata_aclnn_runner.hACLNN API 封装接口4transdata_aclnn_runner.cppWorkspace 计算 ACLNN API 调用5transdata_ops_runner.h原生 Ops 执行接口6transdata_ops_runner.cpp原生 Ops 调用链 平台适配路由文件同时给出了三类关键路径后文均会用到Op 目录:src/ops/ops_infer/transdata/Kernel 目录:src/kernels/kernels/transdata其中 transdata_kernel.cpp 为对应的 Kernel 实现配套tiling/目录存放 Tiling 配置参数头文件: infer_op_params.h从源码结构看TransdataOperation是标准的 ATB Operation 成员继承自OperationBase固定为1 输入 1 输出见 transdata_operation.cpp 中IN_TENSOR_NUM 1、OUT_TENSOR_NUM 1的常量定义因此它没有复杂的多张量编排问题核心逻辑集中在参数校验与形状推导上。二、参数约定TransdataParam参数定义位于 infer_op_params.h这是理解整个算子的入口。2.1 结构体字段struct TransdataParam { enum TransdataType : int { UNDEFINED 0, // 默认 FRACTAL_NZ_TO_ND, // FRACTAL_NZ 转 ND ND_TO_FRACTAL_NZ // ND 转 FRACTAL_NZ }; TransdataType transdataType UNDEFINED; // 转换类型 SVectorint64_t outCrops {0, 0}; // 仅 NZ→ND 时使用 uint8_t rsv[8] {0}; // 预留参数 };transdataType取值必须是ND_TO_FRACTAL_NZ或FRACTAL_NZ_TO_ND之一UNDEFINED会在参数检查阶段被拒绝outCrops长度为 2仅在 NZ→ND 方向使用表示原 ND 数据的最后两维即m、n用于从 4 维 NZ 张量反推出 3 维 ND 输出的形状ND→NZ 方向不要求该字段。创建算子时通过模板化的CreateOperation入口完成注册见 transdata_operation.cpptemplate Status CreateOperation(const infer::TransdataParam opParam, Operation **operation) { if (operation nullptr) { return ERROR_INVALID_PARAM; } OP_PARAM_RSV_CHECK(opParam); // 校验 rsv 预留区全 0 *operation new (std::nothrow) TransdataOperation(opParam); ... }注意OP_PARAM_RSV_CHECKrsv[8]必须保持全 0否则初始化失败——这是跨版本 ABI 兼容的常见约束。2.2 ND 与 NZ 的维度映射约定参数头文件 中的注释给出了官方约定这是调用方必须遵守的对账规则NZ 张量的 dims 记为{b, n1, m1m0, n0}对应的 ND dims 为{b, m, n}b表示 batch为 1 时该维为 1不可省略m0/n0表示对齐位float16/bfloat16 时n0与m0均为 16int8 时n0为 32、m0为 16m1m0表示原始 ND 的m维按对齐位向上对齐后的值n1表示原始 ND 的n维向上对齐后除以n0的商。以 Demo 中使用的{8, 100, 30}batch8, m100, n30为例float16 下对应的 NZ dims 为{8, 2, 112, 16}m100向上对齐到 16 得 112 即m1m0n30对齐到 48 再除以 16 得 2 即n1。这一推导逻辑与 InferShapeImpl 的实现完全一致。2.3 outCrops 的合法取值区间文档注释对outCrops给出了闭区间形式的约束infer_op_params.h若m0*m1即m1m0落在区间(k1 × 16, (k1 1) × 16]内则该区间就是outCrops[0]的取值范围若n0*n1落在区间(k2 × 16, (k2 1) × 16]内则该区间就是outCrops[1]的取值范围。源码中 OutCropsCheck 正是该约束的实现int64_t outCrop0Lower OperationUtil::RoundUp(inTensorDesc.shape.dims[2], 16) - 16; int64_t outCrop0Upper OperationUtil::RoundUp(inTensorDesc.shape.dims[2], 16); // outCrops[1] 基于 dims[1] * dims[3]即 n1 * n0同理计算 if (param_.outCrops[0] outCrop0Upper || param_.outCrops[0] outCrop0Lower || ...) { return ERROR_INVALID_PARAM; }即outCrops[i]必须满足RoundUp(x, 16) - 16 outCrops[i] RoundUp(x, 16)其中x分别是 NZ dims 的第 2 维m1m0与dims[1] * dims[3]n1 * n0。物理含义是outCrops是原 ND 形状中未被对齐填充污染的有效尺寸必须严格小于向上对齐值、且大于上一对齐台阶——否则无法唯一定位有效数据区域。三、形状推导InferShapeImplInferShapeImpl 按转换方向分两支处理并内置了一张按数据类型区分的对齐表static std::mapaclDataType, uint32_t alignTable { {ACL_FLOAT16, 16}, // ALIGN_FLOAT16 16 {ACL_INT8, 32}, // ALIGN_INT8 32 {ACL_BF16, 16}, // ALIGN_BF16 16 };ND → NZ 分支输入允许 2 维或 3 维 ND 张量输出固定为 4 维const bool dim3Flag (inTensorDims DIM_3); auto outTensorDim0 dim3Flag ? inDims[0] : 1; // b2维输入补 batch1 int64_t outTensorDim1 RoundUp(inDims[dim3Flag ? 2 : 1], align) / align; // n1 auto outTensorDim2 RoundUp(inDims[dim3Flag ? 1 : 0], 16); // m1m0按 16 对齐 int64_t outTensorDim3 align; // n0两点值得注意2 维输入会被自动补上batch 1成为 3 维 ND 再参与推导这与 OpsRunner 中的视图函数见第四节配套m1m0恒按DEFAULT_ALIGN 16对齐n1则按数据类型相关的align对齐后除以align因此 float16/bfloat16 输入的第 4 维恒为 16int8 输入为 32。NZ → ND 分支输入必须是 4 维输出为 3 维 ND形状由outCrops直接决定outTensorDescs.at(0).format ACL_FORMAT_ND; outTensorDescs.at(0).shape.dims[0] inTensorDescs.at(0).shape.dims[0]; // b 不变 if (param_.outCrops[0] 0 param_.outCrops[1] 0) { outTensorDescs.at(0).shape.dims[1] param_.outCrops[0]; // m outTensorDescs.at(0).shape.dims[2] param_.outCrops[1]; // n } else { return ERROR_INVALID_PARAM; // outCrops can not 0! }输出 dtype 与输入保持一致format 字段相应置为ACL_FORMAT_ND或ACL_FORMAT_FRACTAL_NZ。四、合法性校验链Transdata 的校验分布在三个钩子中构成参数级 → 描述级 → 张量级的递进防线InferShapeCheckImpl源码ND_TO_FRACTAL_NZ输入 dimNum 必须为 2 或 3FRACTAL_NZ_TO_ND输入 dimNum 必须为 4且outCrops.size()必须为 2随后调用OutCropsCheck其他类型直接报transdataType is not support, only support ND_TO_FRACTAL_NZ and FRACTAL_NZ_TO_ND。SetupCheckImpl源码在 Setup 阶段对实际Tensor的 desc 再次确认——ND→NZ 要求输入 2/3 维、输出 4 维NZ→ND 要求输入 4 维、输出 3 维并复用OutCropsCheck。这意味着调用方必须预先按推导规则创建好输出 Tensor形状不符会在 Setup 阶段被拦截。参数构造期OP_PARAM_RSV_CHECK校验rsv全零见第二节。OutCropsCheck的区间约束与文档注释严格一致见 2.3 节越界会记录outCrops not in the valid range!日志并返回ERROR_INVALID_PARAM。五、Runner从 CreateRunner 到 Kernel Graph5.1 平台感知的 OpIR 选择构造函数中根据芯片平台选择 OpIR keytransdata_operation.cppif (GetSingletonConfig().Is310B()) { opIrKey param_.transdataType ND_TO_FRACTAL_NZ ? TransdataOperationNdToNzAtlas200I500A2 : TransdataOperationNzToNdAtlas200I500A2; } else { opIrKey param_.transdataType ND_TO_FRACTAL_NZ ? TransdataOperationNdToNz : TransdataOperationNzToNd; } operationIr_ GetSingletonAtbOperationIrCfg().GetOperationIr(opIrKey);可见 310BAtlas 200I A2平台与通用平台使用不同的 OpIR 配置项转换方向各占一个 key具体映射关系由 atb_operation_ir_cfg.cpp 维护。5.2 CreateRunner 的决策逻辑与路由文件提示一致CreateRunner的实现非常直接源码std::shared_ptrRunner TransdataOperation::CreateRunner(Context context) const { (void)context; return std::make_sharedTransdataOpsRunner(param_); }当前实现固定返回原生TransdataOpsRunnertransdata_aclnn_runner.cpp/h提供的 ACLNN Runner 路径含 Workspace 计算与 ACLNN API 调用作为 ACLNN 形态下的执行实现存在对应路由文件标注的 Runner 类型: OpsRunner, ACLNNRunner, Operation 与 ACLNN: yes可按需接入。5.3 TransdataOpsRunnerMKI 节点与平台适配TransdataOpsRunner 构造函数 构建了一个1 输入 Tensor 1 输出 Tensor 1 节点的最小 Kernel GraphkernelGraph_.nodes.resize(1); auto transdataNode kernelGraph_.nodes.at(0); switch (param_.transdataType) { case atb::infer::TransdataParam::FRACTAL_NZ_TO_ND: transdataNode.opDesc { 0, TransdataOperation, AsdOps::OpParam::Transdata({AsdOps::OpParam::Transdata::FRACTAL_NZ_TO_ND, outCrops})}; break; case atb::infer::TransdataParam::ND_TO_FRACTAL_NZ: transdataNode.opDesc { 0, TransdataOperation, AsdOps::OpParam::Transdata({AsdOps::OpParam::Transdata::ND_TO_FRACTAL_NZ, outCrops})}; break; default: ATB_LOG(WARN) Unsupported transdata type!; break; }要点算子名统一为TransdataOperation参数经AsdOps::OpParam::Transdata封装依赖 asdops/params/params.houtCrops通过TensorUtil::AtbSVector2OpsSVector从 ATB 的SVector转换为 Ops 侧类型文件尾部的REG_RUNNER_TYPE(TransdataOpsRunner)宏完成 Runner 类型注册使上层能按类型实例化输入节点挂了一个View 函数InTensorViewFunc当 ND→NZ 且输入为 2 维时将{m, n}视图改写为{1, m, n}与 InferShape 侧2 维输入补 batch的规则严格对应保证 Tiling 推导看到的维度始终是 3 维。Kernel 侧的实际执行落在src/kernels/kernels/transdatatransdata_kernel.cpp 与tiling/由上述 Kernel Graph 驱动。六、实战 Demo一次完整的 ND→NZ 调用仓库提供了可运行的示例 transdata_demo.cpp其调用序列即标准用法关键步骤如下// 1. 准备输入{BATCH8, SEQ100, HIDDEN30}float16ND 格式 atb::Tensor inTensor; CreateTensorFromVector(contextPtr, stream, inTensorData, ACL_FLOAT16, aclFormat::ACL_FORMAT_ND, {BATCH_SIZE, SEQ_LEN, HIDDEN_SIZE}, inTensor); // 2. 创建 Operation atb::infer::TransdataParam opParam; opParam.transdataType atb::infer::TransdataParam::TransdataType::ND_TO_FRACTAL_NZ; atb::CreateOperation(opParam, transdataOp); // 3. 按第 2.2 节约定手工推导 NZ 输出形状{8, (3015)/16, (10015)/16*16, 16} // 即 {8, 2, 112, 16} atb::Tensor outTensor; CreateTensor(ACL_FLOAT16, aclFormat::ACL_FORMAT_FRACTAL_NZ, {BATCH_SIZE, (HIDDEN_SIZE 15) / 16, (SEQ_LEN 15) / 16 * 16, 16}, outTensor); // 4. Setup 分配 workspaceworkspaceSize 由 Setup 返回 CHECK_STATUS(transdataOp-Setup(variantPack, workspaceSize, context)); if (workspaceSize 0) { aclrtMalloc((void **)(workspacePtr), workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } // 5. 执行并同步 CHECK_STATUS(transdataOp-Execute(variantPack, workspacePtr, workspaceSize, context)); CHECK_STATUS(aclrtSynchronizeStream(stream));示例演示了 ND→NZ 方向做 NZ→ND 时只需将transdataType置为FRACTAL_NZ_TO_ND并按 2.3 节区间规则为outCrops填入原 ND 的最后两维如{100, 30}输出则按 3 维 ND 形状{8, 100, 30}创建。更完整的运行方式可参考 op_demo 目录说明参数推导正确性亦有自动化测试覆盖见 TransdataOperation 测试用例。七、小结与延伸阅读参数核心transdataType决定方向outCrops长度 2仅在 NZ→ND 时必填且须落在(RoundUp(x,16)-16, RoundUp(x,16)]区间内形状核心ND{b, m, n}→ NZ{b, n1, m1m0, n0}对齐位 float16/bfloat16 为 16、int8 为 32m0 恒 162 维 ND 输入自动补 batch1执行核心TransdataOpsRunner用单节点 Kernel Graph AsdOps::OpParam::Transdata下发310B 平台走独立的 OpIR 配置项进一步阅读知识条目 ops/other/transdata/index.md、主索引 .agent/knowledge/README.md、Kernel 目录 src/kernels/kernels/transdata。【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库基于华为Ascend AI处理器提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boost创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表