news 2026/9/18 14:08:38

PyPTO 卷积反向输入 TileShape 配置指南:深入解析 pypto.set_convbp_input_tile_shapes

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyPTO 卷积反向输入 TileShape 配置指南:深入解析 pypto.set_convbp_input_tile_shapes

PyPTO 卷积反向输入 TileShape 配置指南:深入解析 pypto.set_convbp_input_tile_shapes

【免费下载链接】pyptoPyPTO(发音: pai p-t-o):Parallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto

pypto.set_convbp_input_tile_shapes是 CANN PyPTO(Parallel Tensor/Tile Operation 编程范式)中用于**手动指定卷积反向输入梯度(conv backward input,Dx)算子 L1/L0 两级缓存切分形状(TileShape)**的核心配置接口。本文基于 docs/zh/api/tensor_api/config/pypto-set_convbp_input_tile_shapes.md 展开,完整覆盖其函数原型、参数语义、对齐与缓存容量约束、调用示例,并结合仓库源码(Python 前端封装、pybind11 绑定、C++ TileShape 实现与单元测试)给出调用链与验证证据。读者掌握本文后,能够为任意 2D 卷积反向输入场景正确计算并填写合法的 M/N/K 三轴 TileShape,避免越界与 buffer 溢出问题。

功能说明:Dx 算子的 GEMM 化切分

卷积反向输入(Dx)算子的作用是:根据输出梯度grad_output与卷积核weight,反算输入特征图的梯度(conv_backward_input的完整参数约束见 pypto-conv_backward_input.md)。

PyPTO 将 Dx 算子等价视为一次矩阵乘法:

(HinWin, CoutKhKw) × (CoutKhKw, Cin)

其中 M/N/K 三轴分别对应:

  • M 轴HinWin(输入特征图高度 × 宽度,即空间位置的合轴)
  • N 轴Cin(输入通道)
  • K 轴Cout × Kh × Kw(输出通道与卷积核窗口的合轴)

pypto.set_convbp_input_tile_shapes的作用,就是为这个 GEMM 形式在L1 缓存层级L0 缓存层级分别指定 M/N/K 三个维度的 TileShape,从而控制数据在两级缓存中的分块搬运与计算粒度,其本质与常规 GEMM 的 L1/L0 两级 tiling 策略同源。

产品支持情况

产品形态支持情况
Ascend 950PR / Ascend 950DT不支持
Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持
Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持

函数原型与参数说明

set_convbp_input_tile_shapes(l1_info: pypto_impl.ConvBpTileL1Info, l0_info: pypto_impl.ConvBpTileL0Info) -> None
参数名输入/输出说明
l1_info输入L1 缓存层级下卷积反向计算的 TileShape 配置信息,包含tileML1tileNL1tileKL1三个参数,须按下文约束填写
l0_info输入L0 缓存层级下卷积反向计算的 TileShape 配置信息,包含tileML0tileNL0tileKL0三个参数,须按下文约束填写

返回值

void(Python 侧返回None)。配置通过 PyPTO 作用域机制写入当前编译上下文,供后续conv_backward_input算子编译时读取。

参数对应的底层结构

L1/L0 两类配置信息由底层 C++ 结构体承载,定义于 framework/include/tilefwk/tilefwk_op.h 的ConvBp命名空间中:

struct ConvBpTileL1Info { int64_t tileML1{0}; int64_t tileKL1{0}; int64_t tileNL1{0}; ConvBpTileL1Info(int64_t mL1, int64_t kL1, int64_t nL1) : tileML1(mL1), tileKL1(kL1), tileNL1(nL1) {} ConvBpTileL1Info() = default; }; struct ConvBpTileL0Info { int64_t tileML0{0}; int64_t tileKL0{0}; int64_t tileNL0{0}; ConvBpTileL0Info(int64_t mL0, int64_t kL0, int64_t nL0) : tileML0(mL0), tileKL0(kL0), tileNL0(nL0) {} ConvBpTileL0Info() = default; };

可见 C++ 侧构造顺序为(M, K, N),而 Python 关键字参数tileML1/tileKL1/tileNL1与之一一对应,从源码结构看,PyPTO 的 pybind11 绑定(见 python/src/bindings/controller.cpp)将两个结构体直接暴露为pypto_impl.ConvBpTileL1Infopypto_impl.ConvBpTileL0Info,并开放tileML1/tileKL1/tileNL1tileML0/tileKL0/tileNL0六个可读写属性。

约束说明

TileShape 必须同时满足对齐约束缓存 buffer 空间约束,否则算子编译或运行可能出错。

对齐约束

ConvBpTileL1Info(L1 层级)各维度范围约束:

  • tileML1:需小于Win或者为Win的整数倍,即tileML1 <= WintileML1 % Win == 0。这是对HinWin合轴切分的约束,目的是保证 M 方向切分不跨 Win 行,即每个 tile 落在完整的行集合上;
  • tileNL1:需为Cin0的倍数,即tileNL1 % 16 == 0
  • tileKL1:需为Cout0 × Kh × Kw的倍数,即tileKL1 % (16 * Kh * Kw) == 0

ConvBpTileL0Info(L0 层级)各维度对齐约束:

  • tileML0:需为 16 的倍数(tileML0 % 16 == 0),且tileML0 <= CeilAlign(tileML1, 16)
  • tileNL0:需为 16 的倍数(tileNL0 % 16 == 0),且tileNL0 <= tileNL1
  • tileKL0:需为 16 的倍数(tileKL0 % 16 == 0),且tileKL0 <= tileKL1

其中常量定义:

  • Cin0 = 16
  • Cout0 = 16
  • CeilAlign(a, b)表示按b向上对齐,例如CeilAlign(tileML1, 16)tileML1向上取整到 16 的倍数。

buffer 空间约束

L0A / L0B / L0C 空间约束:

tileML0 * tileKL0 * sizeof(dtype) <= L0A_size tileKL0 * tileNL0 * sizeof(dtype) <= L0B_size tileML0 * tileNL0 * sizeof(FP32) <= L0C_size

其中:

  • L0A_size = 65536 bytes(64KB)
  • L0B_size = 65536 bytes(64KB)
  • L0C_size = 131072 bytes(128KB)
  • dtype为输入矩阵的数据类型(Dx 场景下支持 FP16/BF16,见下文测试说明)
  • 注意 L0C 的容量计算固定按FP32累加器精度估算,即sizeof(FP32) = 4,这是为卷积累加器预留的空间预算

L1 空间约束:

(L1Weight + houtL1 * woutL1 * coutL1) * sizeof(dtype) <= L1_size

其中:

  • L1Weight = tileKL1 * tileNL1(L1 中权重分块占用的元素数)
  • houtL1 = min(CeilDiv(tileML1, Win) + (Kh - 1) * dilationH, (Hout - 1) * strideH + 1)
  • woutL1 = min(min(tileML1, Win) + (Kw - 1) * dilationW, (Wout - 1) * strideW + 1)
  • coutL1 = tileKL1 / (Kh * Kw)
  • L1_size = 524288 bytes(512KB)
  • CeilDiv(a, b) = (a + b - 1) // b

houtL1/woutL1实际度量的是:在当前 M 方向 tile(tileML1)覆盖下,考虑到空洞卷积膨胀率dilation与步长stride后,输出侧(梯度图)在 H/W 两个方向需要参与计算的范围。这两项决定了 L1 中用于存放中间激活的空间,因此与L1Weight一起参与 512KB 的容量校验。

调用示例

以下示例完整取自原文档,并结合仓库单元测试 python/tests/ut/operation/test_convbp_op.py 中反复使用的合法取值(3×3 卷积核、Kh=Kw=3)进行注释:

# 构造L1 Tile配置(确保各值在合法范围) l1_tile_info = pypto.pypto_impl.ConvBpTileL1Info( tileML1=16, # HinWin切分,需满足 <= Win 或 % Win == 0 tileNL1=16, # Cin切分,需为16的倍数 tileKL1=144 # Cout*Kh*Kw切分,需为16*Kh*Kw的倍数(如Kh=3,Kw=3时16*9=144) ) # 构造L0 Tile配置(满足对齐约束) l0_tile_info = pypto.pypto_impl.ConvBpTileL0Info( tileML0=16, # 需为16的倍数,且不大于CeilAlign(tileML1, 16) tileNL0=16, # 需为16的倍数,且不大于tileNL1 tileKL0=16 # 需为16的倍数,且不大于tileKL1 ) # 设置卷积反向TileShape pypto.set_convbp_input_tile_shapes(l1_tile_info, l0_tile_info)

取值核对(以 3×3 卷积核为例):

  • tileKL1 = 144 = 16 × 9 = Cout0 × Kh × Kw,恰好满足tileKL1 % (16 * Kh * Kw) == 0
  • tileML1 = tileNL1 = 16均满足 16 对齐;
  • L0 侧三个维度均为 16,满足 16 对齐且分别不超过 L1 对应维度(CeilAlign(16, 16) = 16)。

集成到完整 Dx 计算流程

仓库单元测试展示了set_convbp_input_tile_shapes必须与pypto.function作用域及pypto.conv_backward_input配合使用的完整流程(FP16、3×3、stride=1、pad=1 场景):

import pypto dtype = pypto.DT_FP16 # grad_output [N, Cout, Hout, Wout] = [1, 16, 16, 16] # weight [Cout, Cin, Kh, Kw] = [16, 16, 3, 3] grad_output = pypto.tensor((1, 16, 16, 16), dtype, "grad_output") weight = pypto.tensor((16, 16, 3, 3), dtype, "weight") input_size = [1, 16, 16, 16] with pypto.function("CONV_BP", grad_output, weight): pypto.set_convbp_input_tile_shapes( pypto.pypto_impl.ConvBpTileL1Info(tileML1=16, tileNL1=16, tileKL1=144), pypto.pypto_impl.ConvBpTileL0Info(tileML0=16, tileNL0=16, tileKL0=16), ) pypto.set_vec_tile_shapes(16, 16, 16, 16) # 输入shape各维度的TileShape切分 result = pypto.conv_backward_input( grad_output, input_size, weight, dtype, [1, 1], [1, 1, 1, 1], [1, 1], groups=1 ) assert isinstance(result, pypto.tensor) assert result.shape == [1, 16, 16, 16]

同一测试文件中还覆盖了BF16空洞卷积 dilation=2无 paddingbatch=2等变体(见 python/tests/ut/operation/test_convbp_op.py),这些场景下set_convbp_input_tile_shapes的取值方式完全一致,说明该配置对 dtype、dilation、padding、batch 均通用,仅需满足上述对齐与容量约束。

必须注意的调用前提

根据 pypto-conv_backward_input.md 的约束说明:

  • 调用conv_backward_input接口前,必须通过pypto.set_convbp_input_tile_shapes设置 L1/L0 层级的卷积反向 TileShape,且必须通过pypto.set_vec_tile_shapes设置输入 shape 每个维度的 TileShape 切分;
  • 当前不支持 bias、不支持动态 shape、仅支持groups = 1
  • grad_outputweight数据类型必须一致,且支持范围限定为 FP16/BF16(测试同时验证了 INT8 等非法 dtype 会抛出PyptoError)。

源码级实现原理:一次配置如何落入编译作用域

Python 前端:控制器封装

pypto.set_convbp_input_tile_shapes的实际 Python 实现在 python/pypto/_controller.py:

def set_convbp_input_tile_shapes(tile_l1_info: pypto_impl.ConvBpTileL1Info, tile_l0_info: pypto_impl.ConvBpTileL0Info): """ set the tile shapes in conv backward computation ... """ convbp_tile = ConvBpTile(tile_l1_info, tile_l0_info) pypto_impl.SetScope({"convbp_tile_shapes": convbp_tile.impl()})

可见该接口并非直接设置全局状态,而是:

  1. 将 L1/L0 两份配置包装为ConvBpTile对象(定义于 python/pypto/config.py 的ConvBpTile类,负责把tileL1Info/tileL0Info转发到底层pypto_impl.ConvBpTile);
  2. 通过pypto_impl.SetScope({"convbp_tile_shapes": ...})将配置写入当前作用域(scope)。这也解释了为什么配置需要在with pypto.function(...)块内调用——它与算子的编译上下文绑定,实现多函数场景下的隔离。

pybind11 绑定:Python 世界与 C++ 世界的桥

绑定层位于 python/src/bindings/controller.cpp:

py::class_<ConvBp::ConvBpTileL1Info>(m, "ConvBpTileL1Info") .def(py::init<>()) .def_readwrite("tileML1", &ConvBp::ConvBpTileL1Info::tileML1) .def_readwrite("tileKL1", &ConvBp::ConvBpTileL1Info::tileKL1) .def_readwrite("tileNL1", &ConvBp::ConvBpTileL1Info::tileNL1); py::class_<ConvBp::ConvBpTileL0Info>(m, "ConvBpTileL0Info") ... .def_readwrite("tileML0", &ConvBp::ConvBpTileL0Info::tileML0) .def_readwrite("tileKL0", &ConvBp::ConvBpTileL0Info::tileKL0) .def_readwrite("tileNL0", &ConvBp::ConvBpTileL0Info::tileNL0); m.def("SetConvBpTile", [](const ConvBp::ConvBpTileL1Info& tileL1Info, const ConvBp::ConvBpTileL0Info& tileL0Info) { TileShape::Current().SetConvBpTile(tileL1Info, tileL0Info); });

C++ 核心:TileShape 单例与作用域回写

最终落到 framework/include/tilefwk/tile_shape.h 中TileShapeconvBpTile成员(SetConvBpTile/GetConvBpTile接口),其实现位于 framework/src/interface/operation/tile_shape.cpp:

void TileShape::SetConvBpTile(const ConvBp::ConvBpTileL1Info& tileL1Info, const ConvBp::ConvBpTileL0Info& tileL0Info) { convBpTile = {tileL1Info, tileL0Info}; ConfigManagerNg::CurrentScope()->UpdateValue("convbp_tile_shapes", convBpTile); }

TileShape::Current()会依据ConfigManagerNg::CurrentScope()动态生成当前作用域的 TileShape 实例,SetConvBpTile在更新内存成员的同时,将convbp_tile_shapes回写进作用域配置管理器,供后续编译流水线(tile 图生成、codegen)读取。C++ 侧的用法可参考 framework/tests/ut/codegen/src/test_dynamic/test_codegen_dyn_mte/test_codegen_dyn_convbp.cpp:

ConvBp::ConvBpTileL1Info l1TileShape(16, 144, 16); ConvBp::ConvBpTileL0Info l0TileShape(16, 144, 16); TileShape::Current().SetConvBpTile(l1TileShape, l0TileShape);

配套接口:读取当前配置

若需要校验或回读当前作用域已设置的卷积反向 TileShape,可调用配套接口pypto.get_convbp_input_tile_shapes()(见 pypto-get_convbp_input_tile_shapes.md):

l1_tile = pypto_impl.ConvBpTileL1Info(tileML1=128, tileKL1=64, tileNL1=64) l0_tile = pypto_impl.ConvBpTileL0Info(tileML0=128, tileKL0=64, tileNL0=64) pypto.set_convbp_input_tile_shapes(l1_tile, l0_tile) convbp_tile = pypto.get_convbp_input_tile_shapes() # 返回 (ConvBpTileL1Info, ConvBpTileL0Info)

get_convbp_input_tile_shapes在 python/pypto/_controller.py 中的实现同样基于当前作用域:scope.get_convbp_input_tile_shapes(),返回(tileL1Info, tileL0Info)二元组。该接口可用于调试或动态生成配置时的自校验,与set_convbp_input_tile_shapes构成完整的写入/读取闭环,二者均登记在 PyPTO 公共接口列表中(见 config/index.md)。

常见配置错误排查

结合约束条件与测试用例,配置时最容易出现的问题集中在以下三点:

  1. K 轴对齐错误tileKL1必须为16 * Kh * Kw的整数倍。非 3×3 卷积核(如 5×5)时,最小合法值为16 * 25 = 400,直接沿用示例中的144会违反对齐约束;
  2. L0 超过 L1tileML0不得超过CeilAlign(tileML1, 16)tileNL0/tileKL0不得超过对应的 L1 维度值,这是两层缓存逐级放大的基本前提;
  3. L0C 空间超限:L0C 容量按 FP32 累加器计算(tileML0 * tileNL0 * 4 <= 131072),当tileML0tileNL0同时取较大值时容易触碰 128KB 上限,需要反推缩小 L0 切分。

此外还需注意 dtype 一致性:Dx 场景下grad_outputweightout_dtype三者必须一致且限定为 FP16/BF16(单元测试 python/tests/ut/operation/test_convbp_op.py 中对 dtype 非法组合的用例会抛出PyptoError)。

总结

pypto.set_convbp_input_tile_shapes是 PyPTO 将卷积反向输入算子显式 GEMM 化的关键 tiling 配置入口:它把 Dx 计算映射为(HinWin, CoutKhKw) × (CoutKhKw, Cin)的矩阵乘法,并为 L1/L0 两级缓存分别指定 M/N/K 三轴切分。使用时需同时满足 16 字节对齐约束(含tileKL1 % (16*Kh*Kw) == 0tileML1不跨 Win 行等特殊规则)与 L0A/L0B/L0C/L1 四级 buffer 容量约束(64KB/64KB/128KB/512KB),并在pypto.function作用域内、调用conv_backward_input之前完成设置。从源码调用链看,该接口经由_controller.pyConvBpTile包装、pybind11 绑定,最终落入 C++ 侧TileShape::SetConvBpTile并回写当前作用域配置,整个过程清晰、可追溯,为算子的高性能代码生成提供了确定性的切分依据。

【免费下载链接】pyptoPyPTO(发音: pai p-t-o):Parallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 14:07:28

快速UDP网络连接之QUIC协议介绍

文章目录 一、QUIC协议历史 1.1 问题:QUIC为什么在应用层实现 1.2 QUIC协议相关术语 1.3 QUIC和TCP对比 1.4 QUIC报文格式 1.4.1 QUIC报文格式-Stream帧1 1.4.2 QUIC报文格式-Stream帧2 二、QUIC的特点 2.1 连接建立低时延, 2.2 多路复用 流复用-HTTP1.1 流复用-HTTP2 流复用…

作者头像 李华