원클릭으로
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)。高频误区:
正确判定: