PyPTO 算子开发执行约束速查:从框架级约束到动态轴实现模式(PyPTO-Gym 实战指南) 人工智能大模型算子库AI 技能/插件【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址https://gitcode.com/cann/pypto-gym点击查看免费下载导读本文基于 CANN PyPTO-Gym 仓库中cannbot-skills/ops/pypto-op-develop/references/execution-constraints.md这一开发侧核心文档整理而成是 PyPTO 算子 impl 编码阶段必须对照的框架级约束清单。它覆盖 JIT 签名与类型注解、动态轴标注与pypto.loop合法性、Tile 配置、各 Operation API 的 dtype/维度限制以及loop 切 tile、API 只吃静态这一动态轴算子实现的核心范式。读完本文你将掌握一套可直接复用的 PyPTO kernel 编码规范从写一个合规的pypto.frontend.jit入口到用 2D reshape 嵌套 loop concrete tile 模式实现多动态轴算子再到通过 12 项预检清单避免最常见的编译失败与静默精度错误。适用前提本文约束以当前仓库PyPTO-Gym所对应的 PyPTO 前端与 CANN 环境为准具体 op 的 dtype/对齐要求以pypto-docs-search检索到的对应pypto-op_name.mdAPI 文档为最终依据。1. 框架级约束JIT 集成方式的边界PyPTO 与 PyTorch 的集成支持两种模式单算子模式eager与图捕获模式aclgraph。pypto.frontend.jit默认按单算子模式执行这也是本仓库算子开发的强制路径见 pypto-op-develop SKILL。1.1 无返回值、结果必须写回出参JIT kernel不支持返回值结果必须写回输出参数。可用的写回方式只有三种out[:] ...assemble 语义的整块写回out.move(...)搬移语义pypto.assemble(..., out)带 offsets 的散写回而out ...只会把局部变量重新绑定不会修改出参属于 OL02 门禁直接拦截的反模式。1.2 类型注解与参数顺序JIT 函数中的张量参数必须写成pypto.Tensor([...], dtype)形式的类型注解对应 OL05每个 tensor 参数必须有pypto.Tensor[...]注解且tensor 参数在前、非 tensor 参数在后OL26。kernel 内不允许returnOL03结果一律写回。1.3 动态轴必须显式标注动态轴必须在类型注解中标成pypto.DYNAMIC或pypto.DYN禁止使用pypto.Tensor()/pypto.Tensor([], dtype)等空注解——门禁 OL25 会直接判 FAIL。标成pypto.DYNAMIC的轴变化时无需重编译标成pypto.STATIC的轴变化会触发重编译。DESIGN.md 声明了动态轴时JIT 函数内必须包含遍历动态轴的pypto.loop(...)调用且 trip count 必须是tensor.shape[i]、函数参数或其符号表达式禁止用pypto.loop(1)/ 常量 trip count 的空循环冒充门禁 OL43。这一点在仓库 lint 规则中被专门正向校验。固定整数轴只接受该固定大小传入其他大小会报错runtime_debug_mode3开启校验时。...表示剩余轴按静态轴处理。在仓库真实实现中可以看到这种标注的落地形态例如 mla_prolog.pypypto.frontend.jit() def hybrid_stage2_kernel( compressed_kv_norm_2d: pypto.Tensor([pypto.DYNAMIC, pypto.STATIC], pypto.DT_FP16), k_pe_2d: pypto.Tensor([pypto.DYNAMIC, pypto.STATIC], pypto.DT_FP16), kv_b_weight: pypto.Tensor([pypto.STATIC, pypto.STATIC], pypto.DT_FP16), ... k_pe_embed_out: pypto.Tensor([pypto.DYNAMIC, pypto.STATIC], pypto.DT_FP16) ):batch/序列长度轴标pypto.DYNAMIC权重等固定形状标pypto.STATIC正是文档要求的标准写法。1.4 Tensor 未初始化语义pypto.tensor(...)创建的是未初始化随机值使用前必须初始化或保证先写后读。这一点也出现在 SKILL 的实现注意点第 1 条不要把pypto.tensor(...)当成已初始化张量使用。典型场景是循环携带累加器必须在is_loop_begin分支内做首迭代初始化而不是在循环外物化初始化后者还会引入 F00003 尾轴对齐问题详见本文 5.4 节与反模式表。1.5 尾轴对齐vector-sensitive 路径的通用约束必须遵守每个 op 在最后一维上的对齐要求典型为32B 对齐bf16/fp16 → 16 元素fp32 → 8 元素具体值见各 API 文档。如果逻辑张量窄到无法自然对齐只在回到语义的映射明确的前提下使用对齐友好的表示如把窄 tensor padding 到对齐宽度并记录原始有效宽度。需要查具体 op 的对齐规则时用 skillpypto-docs-search仓库见 pypto-docs-search搜索该 op 的 API 文档pypto-op_name.md。对齐约束在设计侧有对应条目tiling.md 的C-TILE-02明确要求尾轴 32B 对齐的操作满足tile_last × dtype_bytes % 32 0FP32 为 8 个元素FP16/BF16 为 16 个元素。2. 基础类型与前端基础设施2.1pypto.Element构造顺序固定为pypto.Element(dtype, value)。当标量参与计算且需要固定 dtype不能依赖隐式映射时显式使用Element。这对应 SKILL 实现注意点第 12 条用于消除对 Python 标量隐式 dtype 映射的依赖。2.2pypto.SymbolicScalar构造形式是pypto.SymbolicScalar(arg0None, arg1None)arg0int→ 创建常量符号标量arg0str→ 创建具名符号标量arg0SymbolicScalar→ 复制已有符号标量arg1只在arg0是字符串时作为初始值生效。用途动态 shape、运行时数值、算术/比较表达式。注意SymbolicScalar不能用作 Python list 索引会报TypeError: list indices must be integers or slices, not SymbolicScalar因为pypto.loop返回的是编译时符号值不是 Python runtime 对象见 SKILL 常见问题第 7 条。2.3pypto.from_torch算子开发中不使用签名from_torch(tensor, name, dynamic_axisNone, tensor_formatNone, dtypeNone)把torch.Tensor转成pypto.Tensor。输入必须是torch.Tensor或其子类输入在指定内存格式下必须是连续的。dynamic_axis用来把指定维度标记为动态轴。dtypeNone时按输入 tensor 的 dtype 推导需要固定 PyPTO dtype 时显式传dtype。显式标记format时传入的 torch tensor 必须与声明的format一致。但算子开发不使用from_torch。本仓库算子强制走 JIT 路径pypto.frontend.jit装饰的 kernel 直接接收原始torch.Tensor转换在 kernel 内部LaunchKernelTorch→TorchTensorConverter完成。host wrapper 调用 JIT 入口时直接传原始 torch tensor不要先from_torch# ❌ 反例先 from_torch 再传参 your_op_kernel_npu(pypto.from_torch(x), output) # → RuntimeError: Input tensor is not a valid torch tensor type # torch_tensor_converter.cpp 的 ParseTensorData 要求是 torch tensor # pypto.Tensor.data_ptr 是 int 而非 callable # ✅ 正例直接传原始 torch tensor your_op_kernel_npu(x, output) # x 是原始 torch tensor准备输入数据直接用torch.randn(...)等原始 torch 张量kernel 内部需要新建张量时用pypto.zeros / pypto.ones / pypto.full。这条约束在 impl_template.py.tmpl 的 Layer K 注释中被再次强调并补充了输出分配的配套规则OL58host wrapper 中 output 必须用torch.empty / torch.zeros / torch.ones / torch.full / torch.empty_like / torch.zeros_like且显式带dtype和device预分配禁止在 Layer K 内调用pypto.zeros等 JIT-context API会 runtime crash如F21003 INVALID_TYPE。2.4 Tile 配置pypto.set_vec_tile_shapes(...)的每个维度都必须大于 0参数个数最多 4 个。TileShape 维度数必须和相关输出维度匹配否则会在扩图阶段直接报错。pypto.set_cube_tile_shapes(...)是pypto.matmul的前置条件。具体 tile 值见 DESIGN.md「范式与设计决策」tile 推导规则见 tiling.md。tiling 约束文件中补充了几个关键细节tiling.mdC-TILE-01TileShape 的秩按具体 API 设置——例如 sum 对齐输入秩、exp 对齐输出秩不能一律按输出判断C-TILE-05矩阵乘的 m/k/n 各轴使用[L0, L1]配置满足0 L0 L1且L1 % L0 0Vector 配置不能替代 Cube 配置C-TILE-06TileShape 参数必须是编译期整数或可解析为整数的常量不能来自运行时 shape、kernel 参数或 SymbolicScalar对应门禁 OL48。实际代码中的正确用法mla_prolog.py# matmul 前必须设置 cube tile pypto.set_cube_tile_shapes([16, 16], [256, 256], [64, 64]) kv_total_tile pypto.matmul(compressed_kv_norm_tile, kv_b_weight, pypto.DT_FP16) # vec 操作前设置 vec tile pypto.set_vec_tile_shapes(128, num_heads, qk_nope_head_dim v_head_dim)3. 控制流3.1pypto.looppypto.loop返回的是符号索引不是普通 Python 整数循环。把它当作 Python 整数使用如 list 索引、int()转换会报错。在pypto.loop中用 Pythonprint打印看到的是构图阶段遍历到的路径不是运行时真实循环次数。pypto.loop默认会展开并分发到多核并行处理循环迭代之间存在数据依赖时必须设置submit_before_loopTrue。注意submit_before_loopTrue是有代价的。仓库实测记录chunked_gated_delta_rule_impl.py 的注释显示在 S 循环上错误地加submit_before_loopTrue会带来 183%~357% 的严重性能回退因此它只在确有跨迭代依赖时才使用——这正是本文 5.5 节两趟设计要规避的场景。3.2pypto.loop_unroll返回(idx, unroll_factor)。只对最内层循环做 unroll。循环体里包含pypto.cond时增大unroll_list会显著增加编译路径数和编译时间。实现阶段unroll_list只能含单一值默认[1]直接照搬 DESIGN.md「范式与设计决策」中选定的值不要自行扩成多值OL56 强制 FAILS0多值展开如[4, 2, 1]会触发编译路径爆炸、拖慢编译并使开发流程超时仅允许在性能优化阶段进行。3.3pypto.condpypto.cond必须和 Pythonif/elif/else一起使用。条件值应是SymInt或SymbolicScalar表达式。3.4pypto.is_loop_begin/pypto.is_loop_end这两个接口只接受pypto.loop(...)返回的循环索引。不是循环索引时会抛ValueError。必须直接写在pypto.frontend.jitbody 内包含pypto.is_loop_begin(idx)或pypto.is_loop_end(idx)的逻辑不能放进辅助函数再由 JIT body 调用否则 parser 会在编译期抛F00002, ValueError: Not concrete value且报错栈不指向具体行见 SKILL 实现注意点第 19 条。替代方案是给辅助函数加pypto.frontend.function仅支持 tensor 参数。4. Operation 级约束4.1 初始化 / 创建类zeros / ones调用前先设置set_vec_tile_shapes(...)文档覆盖的 dtype 是DT_FP32 / DT_INT32 / DT_INT16 / DT_FP16 / DT_BF16。fullfill_value与dtype必须一致动态图尾块无法自动推导有效范围时必须显式传valid_shape。arangestep ! 0、abs(step) 1e-8、(end-start)/step 0纯 int 输入受 int32 范围约束。4.2 Eltwise 算术add / sub / mul / div按2-4 维、单轴广播、输入 dtype 一致来写。add数字参数不做任意隐式转换other不支持nan/inf。sub标量路径文档化为float且不支持隐式转换。muldtype 为DT_FP16 / DT_BF16 / DT_INT16 / DT_INT32 / DT_FP32。div只支持DT_FP16 / DT_BF16 / DT_FP32other不支持nan/inf。neg支持DT_FP32 / DT_FP16 / DT_BF16 / DT_INT32 / DT_INT16和 2-4 维先配set_vec_tile_shapes(...)。abs支持DT_FP16 / DT_BF16 / DT_FP32和 2-4 维。多轴广播不在支持范围内时应改写成单轴广播或等价拆分写法对应 SKILL 检查点 5 与 API 约束C-API-06。4.3 数学 / 激活exp只支持DT_FP16 / DT_BF16 / DT_FP32和 2-4 维。log支持 1-4 维和DT_FP32 / DT_FP16 / DT_BF16自己做输入域保护负数/零输入。sqrt只支持DT_FP16 / DT_BF16 / DT_FP32。rsqrt负数输入返回NaN0 输入返回Inf先做数值保护。sin / cos支持DT_FP32。sigmoid支持DT_FP32。relu只支持DT_FP16 / DT_FP32 / DT_BF16和 2-4 维输入不支持nan/inf。lrelunegative_slope必须是非负实数且不能是nan/inf。preluweight必须是一维 Tensor长度等于input的第二维input/weight不支持nan/inf。4.4 比较 / 选择 / 裁剪eq / gt / maximum / minimum / where / clip按输入 dtype 一致和单轴广播来写。eq返回DT_BOOL两侧 dtype 必须一致只支持 2-4 维和一维广播。gt返回DT_BOOLdtype 只覆盖DT_FP16 / DT_BF16 / DT_FP32。maximum / minimum至少一侧必须是 Tensor若两侧都是 Tensor只支持单轴广播。wherecondition必须是DT_BOOLTensorinput/other只支持DT_FP32 / DT_FP16 / DT_BF16。clipmin/max类型必须一致浮点路径定义了NaN/INF/-INF语义。4.5min/max的正确用法高频易错点Tensor 逐元素最大最小值用pypto.maximum / pypto.minimum。SymbolicScalar 最大最小值用s.max(other)/s.min(other)。SymbolicScalar.max/min的other只支持SymbolicScalar | int两边都是具体值时返回具体常量否则返回符号表达式。宿主侧 Python 逻辑可以用原生min/maxkernel 内不要拿 Python 原生min/max代替maximum/minimum或SymbolicScalar.min/max对应门禁 OL06kernel 内禁用 Python builtinmin()/max()。4.6 归约 / 排序sum / amax / amin / topk除了dim/keepdim还要检查 TileShape、尾轴对齐和 UB 限制。sum只支持DT_FP32keepdimFalse后先重设 TileShape归约移除维度后沿用旧配置会导致秩不匹配即C-TILE-01的后果。amax / amin只支持DT_FP16 / DT_BF16 / DT_FP32和 2-4 维TileShape 受64KB、尾轴32B对齐、次尾轴255约束。topk只支持DT_FP32且只支持最后一个维度要求k TileShape[-1]尾轴满足32B对齐和22KB。4.7 矩阵 / 注意力相关matmul显式给out_dtype调用前必须设置set_cube_tile_shapes(...)3D/4D 场景还要设置set_vec_tile_shapes(...)。softmax仅支持DT_FP32。4.8 Shape / 视图 / 拼接通用警告不要假设 PyTorch 的 padding / concat / layout 语义可以直接 map 到 PyPTO。当 layout / pad 操作脆弱时优先用显式 reshape / concat / 对齐的形式重写保持 golden 与 kernel 在每个 layout 步骤上的映射清晰可对照。reshapeinplaceTrue时输入输出必须是当前 loop 的输入输出且输出不能作为整个 Function 的输出否则静默 NaN见 5.6 节。transpose4D 只支持部分轴交换组合5D 只支持(3,4)。viewoffsets和valid_shape必须落在原 Tensor 的 shape 范围内。view当有效 shape 依赖别的 Tensor 标识、框架无法自动推导时必须显式传valid_shape。unsqueeze返回共享数据的 viewdim必须满足[-input.dim-1, input.dim]。concat输入 tensor 数量要求2 len(tensors) 128除拼接轴外其余维度必须完全一致。clone复制出的 Tensor 与输入保持同 shape、同 dtype。4.9 索引 / 写回 / 填充gatherindex.dim必须等于input.dim被 gather 的dim轴不可切viewshape[dim] max(input.shape[dim], index.shape[dim])。index_selectindex只支持DT_INT32 / DT_INT64且 shape 只支持 1-2 维被选维不可切。scatter_update不支持 broadcastdim保持默认-2。assemble没有返回值会直接修改outoffsets必须小于out.shape。assemble同一个 Tensor 在同一图里既被view读取、又被assemble写回会形成图成环报错同图内避免这种回环读写。pad只支持constant模式多维场景只支持右侧和底部填充pad_left/pad_top必须为 0value只支持-inf/inf/0.0。4.10 类型转换cast显式暴露CastMode和SaturationMode不是简单的to(dtype)。浮点转整数时satmodeON/OFF会直接改变溢出后的结果值——需要饱和语义时务必显式指定。5. 动态轴算子的实现模式关键断点知识通用原则 —— loop 切 tileAPI 只吃静态当算子需要动态轴但所使用的 API 不支持接收含DYNAMIC维度的 tensor 时统一使用以下策略不限于 matmul同样适用于任何在编译期需要 concrete shape 的计算 API。如何识别 API 是否支持动态 shape运行时报dim[i] -1, must be 0、Cannot convert symbols to int、Not concrete value等错误或文档明确说明shape 必须在编译期确定均表明该 API 不支持动态 shape。处理步骤选合适的轴做动态轴优先选 batch / 序列长度等语义上天然变化的轴所选轴不能是 API 计算直接依赖的维度matmul 不选 K/N归约不选归约 dimview 的 shape 参数所对应的轴全不能选。将所选轴标为pypto.DYNAMIC其余轴标为pypto.STATIC或常量整数。若有多个动态轴对每个动态轴分别走pypto.loop嵌套处理。用pypto.loop沿动态轴迭代trip count 取自tensor.shape[i]或其符号表达式。循环体内pypto.view切出固定整数大小的 tileshape 参数必须全是 Python int。所有受限 API 只操作静态 tile永远不让它们看到含DYNAMIC维度的 tensor。pypto.assemble写回结果offset 可以是 SymbolicScalar尾块用valid_shape标记有效范围。多动态轴特例当算子有 2 个及以上动态轴如 Batch SeqLen时不能直接在高维 tensor 上调受限 API必须采用reshape 到 2D 嵌套 loop concrete tile模式。5.1 为什么 4D 多动态轴直接 matmul 会失败# ❌ 错误B 和 S 都是 DYNmatmul 编译期需要 concrete shape q: pypto.Tensor([pypto.DYN, N, pypto.DYN, D], pypto.DT_BF16) scores pypto.matmul(q, k, out_dtypepypto.DT_FP32, b_transTrue) # 报错: operand1 dim[0] -1, must be 0PyPTO 的 matmul 在编译期需要所有维度的 concrete shape 来生成 tiling 代码。DYN 维度在编译期表现为 -1硬件 matmul checker 直接拒绝。这是 SKILL 常见问题第 8 条反复强调的陷阱4D 多 DYN 轴直接 matmul 报错必须采用 2D reshape 嵌套 loop concrete tile 模式参考实现用pypto-docs-search搜索 attention 类算子范本如 glm_attention 之类。5.2 pypto.view 的 shape 参数不接受 SymbolicScalars q.shape[2] # SymbolicScalar # ❌ 错误shape 参数必须全部是 Python int q_s pypto.view(q, [1, N, s, D], [b_off, 0, 0, 0], valid_shape...) # 报错: View(): incompatible function arguments # ❌ 错误Python 切片内部也会对 SymbolicScalar 调 int() 转换 q_s q[b_off:b_off 1] # 报错: Cannot convert symbols to intpypto.view三个参数的类型要求shape必须全部是 Python int不接受 SymbolicScalaroffsets接受 SymbolicScalarvalid_shape接受 SymbolicScalar用于尾块有效数据标记。Python[]切片语法内部会对 index 做int()转换因此也不能用 SymbolicScalar 做切片索引。5.3 正确模式2D reshape 嵌套 loop concrete tile参考实现用pypto-docs-search搜索 attention 类算子范本仓库中见 experimental/attention 目录下的多个实现4D [B, N, S, D] ↓ 在 Python wrapper 层做 reshape 2D [B*N*S, D] ↓ 进入 kernel ↓ pypto.loop(b) → pypto.loop(N) → pypto.loop(s_tiles) ↓ pypto.view([S_TILE, D], [symbolic_offset, 0], valid_shape[actual_s, D]) 2D tile [S_TILE, D] ← shape 全是 concrete int编译通过 ↓ matmul / elementwise / sum都是 2D 操作 ↓ pypto.assemble(result, [symbolic_offset, 0], output_2d)关键点shape 全 concrete[S_TILE, D]都是固定整数常量动态性只进入 offset 和 loop boundoffset 和 loop 的边界可以是 SymbolicScalarvalid_shape 处理尾块actual_s (s - s_idx * S_TILE).min(S_TILE)kernel 内用SymbolicScalar.min见 4.5 节2D matmul[S_TILE, D] × [D, S_TILE]编译期 shape 完全确定。仓库范例mla_prolog.py 中pypto.loop_unroll(0, t, 1, ...)沿 token 维度切 tilepypto.view(..., [t_tile, kv_lora_rank], [tIdx, 0], valid_shape[t_tile, kv_lora_rank])用符号 offset 取块pypto.assemble(k_nope_tile, [tIdx, 0, 0], k_nope_out)写回——正是动态性只进入 offset / loop bound、shape 全 concrete、尾块 valid_shape的完整落地。5.4 循环内累加的标准模式acc pypto.tensor([TILE, D], pypto.DT_FP32, acc) for idx in pypto.loop(n, nameLOOP, idx_nameidx, unroll_list[1]): # 实现阶段单一值 (OL56) tile compute_something(...) if pypto.is_loop_begin(idx): acc[:] tile # 首次迭代初始化 else: acc[:] acc tile # 后续迭代累加 if pypto.is_loop_end(idx): result pypto.cast(acc, pypto.DT_BF16) pypto.assemble(result, [offset, 0], output) # 最后一次写回要点pypto.tensor()创建的是未初始化随机值必须在is_loop_begin中初始化unroll_list对内层循环使用让编译器为不同迭代次数生成优化代码实现阶段unroll_list只能含单一值默认[1]直接照搬 DESIGN.md「范式与设计决策」中选定的单一值不要自行扩成多值如[4, 2, 1]。多值会触发编译路径爆炸、拖慢编译并使开发流程超时多值展开调优仅允许在性能优化阶段进行OL56 强制 FAILS0。反模式表还专门指出了累加器初始化的两种错误写法见 pypto-op-develop SKILL 的实现阶段高频陷阱在循环前用pypto.full([X,1], ...)物化初始化 → F00003FP32 尾轴 4B 未满足 32B 对齐用acc[:] src期望[X,1]→[X,8]广播 →[:]是 assemble 语义只写首列其余列保持原值导致精度错。正确做法是 binary op 广播如pypto.mul(src, ones)后再 shape-matched 写回。5.5 梯度算子的两趟设计模式当算子有多个输出需要在不同维度上累加时如 FlashAttention backward 的 dQ/dK/dV使用两趟分离计算# 趟1: 计算 dQ外层循环 S1 tiles内层循环 S2 tiles 累加 dQ for s1_idx in pypto.loop(s_loop): dQ_acc pypto.tensor(...) for s2_idx in pypto.loop(s_loop): dQ_acc dS_ij K_j # dQ 沿 S2 维度累加 assemble(dQ_acc, ..., dq) # 趟2: 计算 dK, dV外层循环 S2 tiles内层循环 S1 tiles 累加 dK/dV for s2_idx in pypto.loop(s_loop): dK_acc pypto.tensor(...) dV_acc pypto.tensor(...) for s1_idx in pypto.loop(s_loop): dK_acc dS_ij^T Q_i # dK 沿 S1 维度累加 dV_acc P_ij^T dY_i # dV 沿 S1 维度累加 assemble(dK_acc, ..., dk) assemble(dV_acc, ..., dv)代价是中间结果P、dS重复计算一次但避免了跨 loop 的读写依赖不需要submit_before_loopTrue——与 3.1 节提到的该选项可能带来的 183%~357% 性能回退形成对照。仓库中 experimental/attention/BSA 的 FWD/BWD 分离实现即是这种前后向拆分的工程化样例。5.6 inplaceTrue 的限制# ❌ 错误dq 是函数输出参数不能用 inplaceTrue dq_2d pypto.reshape(dq, [bns, HEAD_DIM], inplaceTrue) # 结果静默错误输出 NaN约束inplaceTrue的输出不能是整个 Function 的输出参数。当输入 tensor 已经是目标形状时直接赋值引用即可# ✅ 正确在 wrapper 层提前 reshapekernel 直接使用 q_2d q # 已经是 2D不需要 reshape这与 SKILL 常见问题第 10 条一致在 wrapper 层提前 reshapekernel 内直接引用同时 impl_template 的 Layer K 注释也建议在 host 侧把 leading batch 维折叠成 2D让 kernel 的 matmul 保持 2D 操作。6. 写代码前先检查这 12 件事需要建图执行的代码直接写成pypto.frontend.jitkernel不要保留为普通 Python/Torch 逻辑。用[:]、move()或assemble()把结果明确写回出参不要用out ...代替写回。把所有动态轴显式标成pypto.DYNAMIC或pypto.DYN禁止用pypto.Tensor()空注解。声明了动态轴的 kernel 必须含真实pypto.looptrip count 为符号表达式不能是常量不允许pypto.loop(1)这类空循环。把依赖 Python 标量隐式 dtype 映射的写法改成显式Element或显式 dtype 转换。把多轴广播改写成文档支持的单轴广播或等价拆分写法。检查 TileShape 维度数、最后一维对齐和相关算子的 Tile 约束tile 值按 DESIGN.md「范式与设计决策」设置再执行编译。无法自动推导动态view的valid_shape时显式传入valid_shape。避免同一 Tensor 在同一图里既被读取又被assemble回写。多动态轴算子必须采用 2D reshape 嵌套 loop concrete tile 模式见第 5 节不要尝试在 4D DYN tensor 上直接 matmul。pypto.view的shape参数只接受 Python int用 SymbolicScalar 做 offset 和 valid_shape不要混入 shape。不要用inplaceTruereshape 在函数输出参数上在 wrapper 层提前 reshape。每次 matmul / mul / cast / sum 前都必须设置set_vec_tile_shapes或set_cube_tile_shapes维度数匹配操作数。漏设会报tile shape not set或得到错误结果。7. 与开发流程的衔接从约束清单到门禁合规7.1 约束清单在 per-Phase 流程中的位置在 pypto-op-develop SKILL 定义的开发流程中execution-constraints.md是进入实现阶段前的必读资料编码与自检时反复对照。每个 per-Phase 调度生成op_modulek_impl.py前需要基于本清单输出本模块适用约束项格式如【本模块适用约束项】 - M_k 有 B、S、N 三个动态轴 → 第5节必须采用 2D loop 模式 - M_k 使用 pypto.concat → 第4.8节仅支持 2-4D - M_k 需要 cast → 第4.10节显式指定 CastMode7.2 与 impl 模板的 Layer 划分对应impl_template.py.tmpl 将实现按 Layer G–K 组织执行约束在每一层都有落点Layer职责对应执行约束Layer Gcache / bridge纯 torch不调用任何 PyPTO APILayer Hpypto_*子内核单一职责本地设置 tile§11cdtype/维度遵守第 4 节各 op 约束Layer Ikernel 实现所有pypto.loop所在层动态轴 loop 合法性OL43、is_loop_begin/end写法第 5.4 节Layer Jpypto.frontend.jit入口类型注解OL05、tensor 参数在前OL26、无 returnOL03Layer Khost wrapper输出用torch.*预分配OL58、禁 Python loop 驱动 kernelOL45、不from_torch模板头部注释还给出了三个自动检测的致命反模式Layer K 用 Pythonfor循环逐 chunk 调 kernelOL45、用pypto.loop(1)包裹真实循环OL46、多 stage 共用一个全局set_*_tile_shapesOL47正确做法是每个pypto_*子内核内部局部设置。7.3 相关约束文档索引Tile 推导规则tiling.mdC-TILE-01 ~ C-TILE-08含秩匹配、32B 对齐、Cube/Vector 配置区分、编译期常量要求API 约束api.mdC-API-01 ~ C-API-06dtype 配对、广播规则、精度敏感归约优先 FP32错误码排查error-code-troubleshooting.mdLayer A–L 完整设计规范pypto-kernel-design-format.md含 §11 shape 标注、§11b loop(1) 用法、§11c tile 作用域性能约束多值 unroll、per-op keyed 流水参数等仅允许在优化阶段启用详见 SKILL 的Production 级配置用法一节7.4 仓库实测的反模式与教训SKILL 的实现阶段高频陷阱表格记录了本仓库实测反复触发编译/精度失败的 5 种反模式可作为执行约束的补充判据循环携带累加器在循环前pypto.full([X,1], ...)物化初始化 → F00003FP32 尾轴 4B 未满足 32B 对齐正确写法是pypto.tensor纯声明 is_loop_begin分支内 shape-matched 赋值。用acc[:] src期望[X,1]→[X,8]广播 → 只写首列导致列发散精度错正确用 binary op 广播。pypto.view([X,8]→[X,1])提取列 大 vec tile → 越界读OOB正确用pypto.amax(t, dim-1, keepdimTrue)归约提取。pypto.assemble源未按valid_shape裁剪尾块 → padding 行污染输出先pypto.view(..., valid_shape...)裁剪。遇 F40005 / F00003 未定位分配物即缩小 tile → 掩盖死代码物化问题先定位具体分配物再决定是否缩 tile。结语PyPTO 的执行约束看似条目繁多但可以归纳为三条主线写回显式结果必须通过[:]/move()/assemble()落到出参、静态与动态分离动态只进 offset 与 loop boundshape 永远 concrete、配置前置tile 在每次受限操作前按 DESIGN.md 设定。在 PyPTO-Gym 仓库中这套约束已被pypto-op-develop的 per-Phase 流程、impl_template.py.tmpl的 Layer G–K 骨架以及 OL 系列门禁固化为可执行的工程规范。写 kernel 前对照本文第 6 节的 12 项清单做一次自检可以把绝大多数编译失败和静默精度错误拦截在提交验证之前。赞分享人工智能大模型算子库AI 技能/插件【免费下载链接】pypto-gymPyPTO-Gym 是基于 PyPTO 编程框架构建的算子与模型样例仓库项目地址https://gitcode.com/cann/pypto-gym点击查看免费下载相关推荐PyPTO-Gym 约束知识库PyPTO-Pro 算子开发必须遵守的 9 类硬约束与实战规则PyPTO Gym 约束知识库PyPTO Pro 算子开发必须遵守的 9 类硬约束与实战规则 本篇指南系统梳理 CANN / pypto gym 仓库中 Py人工智能大模型算子库AI 技能/插件PyPTO API 探索实战指南从算子公式到 API 映射、约束检查与 Tiling 规划PyPTO API 探索实战指南从算子公式到 API 映射、约束检查与 Tiling 规划 导读 本文基于 CANN / pypto gym 仓库中的 pyp人工智能大模型算子库AI 技能/插件PyPTO-Gym 算子设计指南Tiling 约束C-TILE逐条解析与 Cube/Vector TileShape 实战PyPTO Gym 算子设计指南Tiling 约束C TILE逐条解析与 Cube/Vector TileShape 实战 导读 Tiling切分是人工智能大模型算子库AI 技能/插件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考