بنقرة واحدة
pypto-pitfalls
PyPTO 常见首次生成错误及正确写法
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
PyPTO 常见首次生成错误及正确写法
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
AscendC direct-invoke 崩溃/挂起修复索引:Kernel timeout、hang、Segmentation Fault、aic error、buffer 死锁、plog/memcheck 调试。
AscendC direct-invoke 精度失败修复索引:输出全 0/随机值、DataCopy 对齐、EnQue/DeQue 同步、FP16/FP32 精度、Cast RoundMode、DumpTensor 分段定位。
AscendC direct-invoke 工程契约:WA 使用 kernel.py + ascendc_op/,ModelNew 调用 torch.ops.npu.*,adapter 负责复制工程、CMake 构建和 npu-arch patch。适用于 dsl=ascendc 的 autoresearch 任务。
把注册式 AscendC 算子迁移为 direct-invoke 工程的保真原则:kernel 算法和 tiling 公式不乱改,只替换注册框架胶水、入口 ABI、host launch 与 PyTorch extension。
CATLASS TileShape 与 on-chip 缓存容量约束:L1/L0A/L0B/L0C 预算公式、fp16/fp32 Pingpong 双缓冲、512B 对齐与排布对 Tile 选型的影响。调参前必读。
CATLASS Gemm 性能调优:DispatchPolicy、Tile 与分核负载均衡、Swizzle、何时用 padding/Split-K/Preload。面向 AR 修改 catlass_kernel.asc 中的类型别名。
| name | pypto-pitfalls |
| description | PyPTO 常见首次生成错误及正确写法 |
| category | implementation |
| version | 1.0.0 |
| metadata | {"backend":"ascend","dsl":"pypto","operator_patterns":"all"} |
PyPTO kernel 不是普通 Python 函数:输出张量必须作为 kernel 形参传入,并在 kernel 内原地写出。禁止 -> ... 返回注解,禁止 return 输出,否则解析阶段直接报错:
NotImplementedError: Return annotation is not allowed —— 写了 def kernel(...) -> pypto.Tensor(...):ParserError: Return statements are not allowed —— kernel 里 return out正确写法:输出也是入参,三种写出方式任选其一。
@pypto.frontend.jit(...)
def kernel(
x: pypto.Tensor((flat_size,), pypto.DT_FP32),
out: pypto.Tensor((flat_size,), pypto.DT_FP32), # 输出张量也是形参,不要 return
):
pypto.set_vec_tile_shapes(8192)
out[:] = pypto.exp(x) # 1) 整块覆盖写
# 2) loop 分块按偏移写: pypto.assemble(chunk_result, [off], out)
# 3) 显式 in-place 提交: out.move(src)(loop+assemble 后常见收尾)
+ *:标量任意位置。- /:tensor 必须在左。函数调用:第一参数必须 Tensor。
1.0 + x # OK(__radd__)
1.0 - x # CRASH(__rsub__ 未实现)
1.0 / x # CRASH(__rtruediv__ 未实现)
pypto.add(1.0, x) # CRASH(函数调用标量在前)
# 1 - x 正确写法
x * (-1.0) + 1.0 # 推荐
# 标量之间用 Python 运算
neg_delta = -delta # OK(delta 是闭包 float)
pypto.clamp 不可用。min(x, d) 用双重取反:-max(-x, -d)。pypto.minimum(x, 0.0) 可用。
# min(abs_diff, delta) — delta 是闭包 float
neg_abs = pypto.mul(abs_diff, -1.0)
clipped = pypto.mul(pypto.maximum(neg_abs, -delta), -1.0) # = min(abs_diff, delta)
Huber Loss 完整模式(必须用 clamp,不能简化):
diff = predictions - targets
abs_diff = pypto.abs(diff)
neg_abs = pypto.mul(abs_diff, -1.0)
clipped = pypto.mul(pypto.maximum(neg_abs, -delta), -1.0) # min(|d|, delta)
half_sq = clipped * clipped * 0.5
loss = half_sq + abs_diff - clipped # 完整 Huber 公式
total = pypto.sum(loss, dim=0, keepdim=True)
output[:] = total / flat_size
标量参数(eps、slope、margin 等)必须作为工厂函数参数通过闭包传入 kernel。
3D+2D matmul 时,forward 展平后传展平维度 nm=N*M 给工厂,不要分别传 N、M。
用逐元素乘法 + pypto.sum(a * b_broadcast, dim=1) 替代。forward 中 B.reshape(1, -1) 使其可广播。
sum(diff*diff) 是平方距离,不是 L2 距离。TripletMarginLoss 等必须 pypto.sqrt(sum_sq + eps)。
set_vec_tile_shapes 参数个数必须等于被操作 tensor 的 rank。2D tensor 用 2D tile。
示例里的 16384/8192 是经验候选,不是固定答案。必须按当前 shape 和归约维重算。
(128, 4096) 却写 set_vec_tile_shapes(1, 16384)。set_vec_tile_shapes(4, 4096)(归约轴不浪费,且 batch 并行更高)。要点:
tile[i] > shape[i] 的“预算浪费”。“连续搬运达阈值后再调归约轴”是二级目标,但不是“归约轴 tile 越大越快”。
tile_hidden = hidden,追求归约轴一次覆盖。正确做法:
prod(tile_shape) <= 16384 与 auto_tiles <= 2048。16384 -> 8192 -> 4096。auto_tiles > 2048,优先改为 loop 分块,不要硬塞更激进 tile。1KB(经验阈值),再在达标候选里做归约轴甜点比较(常试 16/32/64)。连续搬运是先达标,不是无限放大。达到高效区后,继续把预算给非规约轴通常收益很小,反而会挤占规约轴 tile 预算。
正确做法:
contiguous_bytes(tile) >= 1KB。(1,16,256) 优于 (1,64,256) 的场景)。shape 当成连续搬运长度(高频误判)连续搬运阈值必须按 tile 的实际连续段 计算,不能按输入 shape 计算。
错误示例:
shape=(16,256,256), dim=1, tile=(1,256,64) 时,写成“连续维是 256,所以已达 1KB”。正确计算:
contiguous_tile_elems = tile[last_axis]。tile[2]=64 计算:64*4=256B(FP32),未达 1KB。高频误用:
set_cube_tile_shapes(...) 做 matmul,随后直接做 add/mul/expand_clone。典型报错:
ASSERTION FAILED: vecTile.valid()op [ADD] tile shape not set正确做法:
pypto.set_vec_tile_shapes(...)。y = x @ w + b 推荐:b 在 forward 先 reshape(1, -1),kernel 用 expand_clone 广播后再 add。pypto.sigmoid、pypto.softmax、pypto.abs、pypto.exp、pypto.log、pypto.sqrt 等有内建的直接用,禁止手动实现。
auto-tile 自动处理余数。只有 loop+view 模式需要确保整除性。
2D 输入的 per-sample loss:Phase 1 (4, 4096) 算 per-sample → Phase 2 (128, 1) 跨 batch 归约。
pypto.where 不可用。pypto.minimum 可用!
# ELU
output[:] = pypto.maximum(x, 0.0) + (pypto.exp(pypto.minimum(x, 0.0)) - 1.0) * alpha
# LeakyReLU
output[:] = pypto.maximum(x, 0.0) + pypto.minimum(x, 0.0) * slope
禁止 maximum(x, f(x)) 做条件选择(正半轴 f(x)>x 时结果错误)。
var = sq_sum * inv_count - mean * mean(E[x²]-E[x]²)。符号反了会 NaN。
必须与原始 Model 一致。shape 在 forward 中获取,不要加到 __init__ 参数里。
高频误用:
if dim == 0/1/2,试图一次覆盖所有归约维。keepdim=True 再在 forward squeeze 回去。为什么不推荐:
shape/dim 来自固定 get_inputs/get_init_inputs,本质是静态合同。Example, change to desired ... 这类注释是题库说明,不是当前运行要求;据此扩展多 dim 属于过拟合题面文字。正确做法:
dim=1)。keepdim 是否保留按 baseline 来),不做“先改再补”的绕行。dim 时,不要把 dim 作为 kernel 运行时参数透传;在 kernel 内直接使用固定常量 dim=<固定值>。pypto不是 pyto、pytorch、pto。所有调用以 pypto. 开头。
最危险的错误不是语法,而是“语义合同”读错:代码能编译、甚至能 PASS,但算的不是同一个东西。
高发误读源:
input/target/predictions)。防错流程(先语义、后实现):
forward 写出数学式。sum、batchmean、或 mean 语义=sum/count,并明确规约轴与输出形状。示例(KLDiv,仅示例):
F.kl_div(torch.log(pred), target, reduction='batchmean')pred * (log(pred) - log(target)),方向就反了。当规约目标本质是“连续多轴联合规约”时,直接链式 sum(dim=...) 常会产生中间张量与额外调度。
更优候选:
H,W -> HW,或 (B,H) -> (B*H))。batchmean 的除 B)。高频误区:
正确判定: