- 人工智能
- 深度学习
- 算子库
- CANN
- Ascend
【免费下载链接】asc-devkit
本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。
在算子 Tiling 函数(TilingParse)的本地调测中,往往没有真实的图引擎上下文可用。asc-devkit 提供的context_ascendc::ContextBuilder允许开发者在宿主机上手动构造TilingContext,而AddInputTd正是这条构造链中为算子逐一"补齐"输入 Tensor 元数据(dtype、格式、shape)乃至真实数据值的关键接口。读完本文,你将掌握AddInputTd的三个重载原型、参数约束、与NodeIoNum/IrInstanceNum的协作关系,以及它在源码层面的实现细节(包括 float 到 float16/bfloat16 的自动转换与 bin 文件加载),能够独立完成 Tiling 函数的离线调测。
在 Tiling 调测体系中的位置
asc-devkit 的 Utils-API 中专门设有 Tiling 调测模块,核心由两部分组成:
OpTilingRegistry:负责加载 Tiling 共享库并获取 Tiling 函数指针;- ContextBuilder:提供一系列 API 接口,支持手动构造
TilingContext来验证 Tiling 函数,以及构造KernelContext来验证 TilingParse 函数。
其典型用法分为两条路径:
// 构造 KernelContext(用于 TilingParse 函数验证) auto kernelContextHolder = context_ascendc::ContextBuilder() .Inputs(...) .Outputs(...) .BuildKernelRunContext(); gert::KernelContext* tilingParseContext = kernelContextHolder->GetContext<gert::KernelContext>(); // 构造 TilingContext(用于 Tiling 函数验证) auto tilingContextHolder = context_ascendc::ContextBuilder() .SetOpNameType(..., ...) .NodeIoNum(...) .IrInstanceNum(...) .AddInputTd(...) .AddOutputTd(...) .AddAttr(...) .BuildTilingContext(); gert::TilingContext* tilingContext = tilingContextHolder->GetContext<gert::TilingContext>();从源码结构看,ContextBuilder内部同时持有gert::OpKernelContextBuilder与gert::OpTilingContextBuilder两个底层构造器(见 context_builder_impl.h),前者服务BuildKernelRunContext(),后者服务BuildTilingContext()。AddInputTd只作用于后者的 Tiling 构造链路:它把用户声明的每个输入 Tensor 注册进内部的dependTensorsData_映射表,最终在BuildTilingContext()中统一交给tilingCtxBuilder_->InputTensors(tensorVec)(见 context_builder_impl.cpp)。
功能说明与函数原型
AddInputTd的功能是为算子增加输入 Tensor 的描述。在 context_builder.h 中声明了三个重载:
// 原型1:仅描述元数据(dtype/格式/shape),不带数据 ContextBuilder &AddInputTd(int32_t index, ge::DataType dtype, ge::Format originFormat, ge::Format storageFormat, gert::StorageShape storageShape); // 原型2:额外传入内存中的数据指针(值依赖场景) ContextBuilder &AddInputTd(int32_t index, ge::DataType dtype, ge::Format originFormat, ge::Format storageFormat, gert::StorageShape storageShape, void* constValues); // 原型3:额外传入 bin 格式数据文件路径(值依赖场景) ContextBuilder &AddInputTd(int32_t index, ge::DataType dtype, ge::Format originFormat, ge::Format storageFormat, gert::StorageShape storageShape, const std::string &filePath);三个重载的差异仅在于最后一项:是否提供该输入 Tensor 的"值"。若 Tiling 函数只依赖 shape/dtype 做切分,用原型 1 即可;若 Tiling 函数需要读取输入数据本身(即"值依赖"场景,如依据数据内容决定切分策略),则需使用原型 2 或原型 3 提供真实数据。
参数说明
| 参数 | 输入/输出 | 说明 |
|---|---|---|
| index | 输入 | 算子输入索引,从 0 开始计数 |
| dtype | 输入 | 算子输入 tensor 的数据类型(ge::DataType枚举,如ge::DT_FLOAT16、ge::DT_INT64) |
| originFormat | 输入 | 算子输入 tensor 原始格式(ge::Format枚举,如ge::FORMAT_ND) |
| storageFormat | 输入 | 算子输入 tensor 运行时格式(ge::Format枚举,如ge::FORMAT_ND) |
| storageShape | 输入 | 算子输入 tensor 的 shape(gert::StorageShape类型,分别携带原始 shape 与运行时存储 shape) |
| constValues | 输入 | 值依赖场景下该输入 tensor 需要设置的数据指针。bfloat16 与 float16 的数据依赖场景,请传入 float 格式的数据,接口内部自行转换成 bfloat16 或 float16 |
| filePath | 输入 | 值依赖场景下该输入 tensor 的 bin 格式数据文件路径 |
返回值说明
返回当前ContextBuilder的对象(引用类型),因此支持链式调用,这也是 intro 文档中调用示例采用级联写法的原因。
约束说明
- 输入的
index需要基于算子 IR 定义,按照IrInstanceNum声明顺序来排布; - 调用
AddInputTd前需要先调用 NodeIoNum 与 IrInstanceNum 接口。
其中NodeIoNum(inputNum, outputNum)声明算子 IR 原型定义中的输入/输出"种类"数;IrInstanceNum(instanceNum)则按输入 index 顺序声明实例化时每种输入的实际个数。这一点在源码中可以直接印证:ContextBuilderImpl::IrInstanceNum会把各输入的实例数累加后回写为inputNum_(即"展开后"的输入总数),而BuildTilingContext正是按该总数遍历dependTensorsData_(见 context_builder_impl.cpp 与 L111-L120)。也就是说,某个输入若在 IR 中是动态张量、被实例化为多个 Tensor(例如 MoE 算子的专家路由张量),就需要对该 index 的每个实例逐个调用AddInputTd。
源码级实现细节
元数据注册流程(原型 1)
无数据版本的核心逻辑(context_builder_impl.cpp):
- 通过
DataUtils::GetTensorSizeByStorageShape(storageShape, dtype)按运行时存储 shape与 dtype 计算 tensor 字节数。若 shape 乘积 ≤ 0 或按 dtype 换算后字节数 ≤ 0(含溢出场景),返回 -1 并置errFlag_,最终导致BuildTilingContext()返回空指针; - 调用
gert::Tensor::CreateFollowing(dtype, tensorSize, totalSize)创建带存储头部的 tensor 内存; - 依次写入
MutableOriginShape()、MutableStorageShape()、SetDataType、SetStorageFormat、SetOriginFormat; - 以 index 为键插入
dependTensorsData_供构建阶段取用。
值依赖数据填充(原型 2 与原型 3)
原型 2 会按 dtype 查表找到对应的数据填充函数(context_builder_impl.cpp 中的SET_CONST_DATA_FUNC_MAP):
- 整型/浮点通用类型(int8 至 double)走模板函数
SetConstData<T>,按字节直接拷贝; ge::DT_FLOAT16走SetConstDataWithFloat16:把传入的 float 数组逐个经FloatToUint16转为 float16(半精度位运算转换,含溢出处理);ge::DT_BF16走SetConstDataWithBF16:把 float 数组逐个经FloatToBF16转换(直接右移 fp32 低 16 位)。
这正是文档"参数说明"中强调的:bfloat16 与 float16 的值依赖场景必须传入 float 格式数据——接口内部以"float 元素数 = 目标字节数 × 2 / sizeof(float)"的方式解析输入指针并做转换(constexpr int64_t OFFSET = 2,见 context_builder_impl.cpp)。
原型 3 的实现(context_builder_impl.cpp):
- 同样先计算 tensor 字节数,
malloc一块与之一致的 buffer; - 调用
DataUtils::ReadBinFile读取文件:路径为空、长度 ≥PATH_MAX、realpath解析失败(文件不存在)或打开失败均返回 false,并置errFlag_; - 把文件内容
memcpy_s进 tensor 的数据区,随后释放临时 buffer。
因此 bin 文件必须与该 index 输入 tensor 的字节数精确匹配,且路径必须可被解析为真实存在的绝对路径。单元测试 test_tiling.cpp 专门覆盖了长文件名(5000 字符)、空字符串路径等异常分支,均断言BuildTilingContext()返回空指针。
构建阶段的失败语义
上述任何一个AddInputTd调用失败(shape 非法、内存分配失败、文件读取失败、dtype 无对应填充函数等)都不会立即抛错,而是累计到ContextBuilderImpl::errFlag_;BuildTilingContext()在检查到errFlag_为真时记录 "Build Context Error!" 并返回nullptr(见 context_builder_impl.cpp)。因此调测脚本中应在BuildTilingContext()返回值上做空指针判断。
完整调用示例
以下示例继承自官方文档的调用示例,构造一个 5 种输入、1 种输出的算子上下文;其中 index 2 是动态张量(声明 2 个实例),需要对该 index 连续调用两次AddInputTd。注意示例依赖了bias2_shape(原文档中未展示其声明,此处按上下文补全以保证代码可复制):
gert::StorageShape x_shape = {{1024, 5120}, {1024, 5120}}; gert::StorageShape expert_tokens_shape = {{16}, {16}}; gert::StorageShape weight1_shape = {{16, 5120, 0}, {16, 5120, 0}}; gert::StorageShape bias1_shape = {{16, 0}, {16, 0}}; gert::StorageShape bias2_shape = {{16, 5120}, {16, 5120}}; std::vector<float> x_const_value (1024 * 5120, 2.f); std::vector<float> bias_value (16 * 5120, 3.f); context_ascendc::ContextBuilder builder; (void)builder.NodeIoNum(5, 1) // 声明算子有5个输入,1个输出 .IrInstanceNum({1, 1, 2, 1, 1}) // 声明index 2的算子tensor有两个dynamic实例 .SetOpNameType("tmpName", "tmpType") .AddInputTd(0, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND, x_shape, reinterpret_cast<void *>(x_const_value.data())) // 内部会将该指针指向的数据转为float16类型 .AddInputTd(1, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND, weight1_shape) .AddInputTd(2, ge::DT_INT64, ge::FORMAT_ND, ge::FORMAT_ND, expert_tokens_shape, "./expert_tokens_data.bin") // index2 的第一个dynamic tensor,值依赖场景传入数据路径 .AddInputTd(3, ge::DT_INT64, ge::FORMAT_ND, ge::FORMAT_ND, expert_tokens_shape, "./expert_tokens_data.bin") // index2 的第二个dynamic tensor,值依赖场景传入数据路径 .AddInputTd(4, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND, bias1_shape) .AddInputTd(5, ge::DT_BF16, ge::FORMAT_ND, ge::FORMAT_ND, bias2_shape, reinterpret_cast<void*>(bias_value.data())) // 内部会将该指针指向的数据转为Bf16类型 .BuildTilingContext();几点实操提示:
- 每个 index 的
AddInputTd调用次数应等于IrInstanceNum中该位置声明的实例数,累计后与构建阶段展开的输入总数一致; gert::StorageShape的两组元素分别对应原始 shape 与运行时存储 shape,二者可以不同(如转置类算子);- 值依赖输入若为 float16/bfloat16 类型,
constValues指针必须指向 float 数组;若为 bin 文件,文件内容按目标 dtype 的原始字节排布,文件大小须等于storageShape换算出的字节数; - 构建成功后通过
holder->GetContext<gert::TilingContext>()取出上下文,可直接验证GetInputShape(i)、GetInputDesc(i)等读取结果是否与声明一致。
测试用例佐证
仓库中的单元测试 tests/api/utils/tiling/test_tiling.cpp 对AddInputTd做了较完整的验证,可作为调测参考:
TestTilingContextBuildWithConstValue(L381-L439):同时覆盖三种重载——constValues 指针(float → float16/bfloat16 转换)、纯元数据、bin 文件路径,并断言构建出的TilingContext中GetInputShape(1)、GetOutputShape(0)、GetInputDesc(0)->GetDataType()等值与声明一致;TestTilingContextBuildWithBinFile(L323-L379):验证不存在/超长/空路径时构建失败;TestAddInputTdMallocFailed(L40-L65):通过 mock 使 size 计算返回超大值,模拟分配失败后BuildTilingContext()返回空指针;TestTilingContextBuildFailed(L501-L519):shape 含负维度({-1, 5120})时GetTensorSizeByStorageShape判定非法,构建失败。
小结
AddInputTd是 asc-devkit Tiling 调测链路中"声明输入"的原子接口:三个重载分别对应"仅元数据、内存数据、bin 文件数据"三类诉求;调用前必须先完成NodeIoNum/IrInstanceNum声明,index 需严格对应 IR 声明顺序;float16/bfloat16 值依赖场景由接口内部完成 float 源数据转换。配合 AddOutputTd、AddAttr、TilingData、Workspace 等兄弟接口,即可在宿主机上完整离线构造TilingContext,实现对 Tiling 函数的本地验证与调测。
- 人工智能
- 深度学习
- 算子库
- CANN
- Ascend
【免费下载链接】asc-devkit
本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。
相关推荐
asc-devkit Tiling 调优指南:ContextBuilder::AddAttr 接口详解与 TilingContext 属性构造实战
asc devkit Tiling 调优指南:ContextBuilder::AddAttr 接口详解与 TilingContext 属性构造实战 在 asc
人工智能深度学习算子库CANNAscendMarkwon 有序列表缩进解析:从 `ol-2-spaces.md` 看 CommonMark 列表嵌套规则与测试验证
Markwon 有序列表缩进解析:从 ol 2 spaces.md 看 CommonMark 列表嵌套规则与测试验证 导读 本文以 Markwon 核心模块(
人工智能深度学习算子库CANNAscendtwilio-go 实战指南:用 Go 优雅调用 Twilio API 的短信、语音与号码管理
twilio go 实战指南:用 Go 优雅调用 Twilio API 的短信、语音与号码管理 twilio go 是 GitHub 上 kevinburke
人工智能深度学习算子库CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考