PyPTO 高级样例实战指南:Attention、多函数组合、Cost Model 与 ACLGraph 图捕获
2026/9/19 14:57:26 网站建设 项目流程

PyPTO 高级样例实战指南:Attention、多函数组合、Cost Model 与 ACLGraph 图捕获

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

本篇指南面向已经掌握 PyPTO 基础开发(如examples/00_hello_worldexamples/01_beginnerexamples/02_intermediate)的开发者,系统讲解examples/03_advanced目录下四个高级开发方向:复杂神经网络架构(缩放点积注意力)、多函数设计模式(多 JIT 组合构建 Transformer Block)、系统级性能调优(成本模型仿真)、以及图捕获模式(ACLGraph 优化 Host 侧开销)。读完本文,你将掌握如何在真实算子开发中组织大型多函数项目、如何用成本模型在无硬件环境下做性能预分析,以及如何将 PyPTO 算子嵌入torch.compile图捕获流程。

一、高级样例总览

examples/03_advanced/README.md将高级样例定位为“展示复杂架构实现、高级设计模式以及系统级性能调优”,目录结构如下:

子目录核心主题关键文件
advanced_nn/attention缩放点积注意力 / 多头注意力attention.py
patterns/function多 JIT 函数组合、残差连接、Transformer Blockfunction.py、multi_jit.py
cost_model成本模型评估算子执行效率cost_model.py
aclgraph图捕获模式优化 Host 侧开销aclgraph.py

高级样例的核心特性可以概括为三点:

  • 复杂张量变换:频繁的transposereshape在注意力机制中的应用;
  • 多函数协作:通过组合多个小函数保持大规模模型代码的可读性与可维护性;
  • 极致性能优化:通过对 Tiling、循环展开和硬件单元的深度适配来压榨硬件性能。

二、运行环境准备

在运行任何样例之前,需要先配置 CANN 环境并设置设备 ID:

# 配置 CANN 环境变量 # 安装完成后请配置环境变量,请用户根据 set_env.sh 的实际路径执行如下命令。 # 上述环境变量配置只在当前窗口生效,用户可以按需将以上命令写入环境变量配置文件(如.bashrc文件)。 # 默认路径安装,以root用户为例(非root用户,将/usr/local替换为${HOME}) source /usr/local/Ascend/ascend-toolkit/set_env.sh # 设置设备 ID export TILE_FWK_DEVICE_ID=0

所有高级样例(以及examples/00_hello_worldexamples/01_beginnerexamples/02_intermediate中的脚本)都会通过统一的get_device_id()工具函数读取TILE_FWK_DEVICE_ID:未设置时打印提示并退出;设置的值不是整数时报告ERROR: TILE_FWK_DEVICE_ID must be an integer。例如 attention.py 与 function.py 均实现了这一校验逻辑。

配置好环境后,进入对应子目录运行脚本,例如:

cd examples/03_advanced/advanced_nn/attention python3 attention.py # 运行全部示例 python3 attention.py --list # 列出可用示例

2.1 双运行模式:NPU 与 SIM

高级样例普遍支持--run_mode参数,取值为npu(默认,需要昇腾硬件)或sim(仿真模式,无需真实硬件)。以 attention.py 为例,脚本通过_peek_run_mode_from_argv()在模块加载早期解析命令行参数,从而让模块级装饰器@pypto.frontend.jit(runtime_options={"run_mode": global_run_mode})在编译阶段就能决定运行模式。

pypto.RunMode是一个整型枚举,定义在 python/pypto/runtime.py:

class RunMode(IntEnum): NPU = 0 SIM = 1

SIM模式在无 NPU 环境中也能完成编译、仿真执行与数值校验,非常适合 CI 和开发调试。仓库提供了批量验证执行器 examples/validate_examples.py,由build_ci.py --example调用,支持两种典型用法:

# 在真实 NPU 上验证全部样例 python3 examples/validate_examples.py -t examples/ -d 0 # 以仿真模式并行验证,使用 4 个 worker python3 examples/validate_examples.py -t examples/ --run_mode sim -w 4

该执行器会递归收集examples/下所有.py脚本(跳过validate_examples.py__init__.py),自动为支持--run_mode的脚本注入运行模式参数,并设置TILE_FWK_DEVICE_ID环境变量。

三、样例一:缩放点积注意力(advanced_nn/attention)

advanced_nn/attention 是高级样例中最核心的部分——注意力机制是现代所有 LLM 的基础。主文件 attention.py 实现了完整的缩放点积注意力(Scaled Dot-Product Attention)并支持多头注意力(Multi-head Attention),同时展示了静态与动态 Batch/序列长度两种用法。

3.1 注意力核心计算

纯 PyTorch 的参考实现(golden)按“Q @ K^T → 缩放 → softmax → 加权 V”的顺序组织:

def scaled_dot_product_attention_golden(q, k, v, scale, attn_mask=None): scores = torch.matmul(q, k.transpose(-2, -1)) # [batch, heads, seq_q, seq_kv] scores = scores * scale if attn_mask is not None: scores = scores + attn_mask attn_weights = torch.softmax(scores, dim=-1) output = torch.matmul(attn_weights, v) # [batch, heads, seq_q, head_dim] return output

对应的 PyPTO 核心逻辑(scaled_dot_product_attention_core)几乎可以逐行对应,区别在于使用了 PyPTO 的张量 API:

def scaled_dot_product_attention_core(q, k, v, scale, dtype): k_t = pypto.transpose(k, 2, 3) scores = pypto.matmul(q, k_t, out_dtype=dtype) scores_scaled = scores * scale attn_weights = pypto.softmax(scores_scaled, dim=-1) res = pypto.matmul(attn_weights, v, out_dtype=dtype) return res

3.2 JIT 内核与 Tiling 配置

真正在 NPU 上执行的 JIT 内核将注意力计算与 Tiling 配置结合在一起:

@pypto.frontend.jit(runtime_options={"run_mode": global_run_mode}) def scaled_dot_product_attention_kernel( q: pypto.Tensor((BATCH_SIZE, NUM_HEADS, SEQ_LEN_Q, HEAD_DIM), pypto.DT_BF16), k: pypto.Tensor((BATCH_SIZE, NUM_HEADS, SEQ_LEN_KV, HEAD_DIM), pypto.DT_BF16), v: pypto.Tensor((BATCH_SIZE, NUM_HEADS, SEQ_LEN_KV, HEAD_DIM), pypto.DT_BF16), output: pypto.Tensor((BATCH_SIZE, NUM_HEADS, SEQ_LEN_Q, HEAD_DIM), pypto.DT_BF16), ): scale = 1.0 / (HEAD_DIM**0.5) pypto.set_cube_tile_shapes([64, 64], [64, 64], [64, 64]) pypto.set_vec_tile_shapes(1, 8, 16, HEAD_DIM) scores = pypto.matmul(q, pypto.transpose(k, 2, 3), out_dtype=pypto.DT_BF16) scores_scaled = pypto.mul(scores, scale) attn_weights = pypto.softmax(scores_scaled, dim=-1) output.move(pypto.matmul(attn_weights, v, out_dtype=pypto.DT_BF16))

其中两行 Tiling 配置是关键的性能控制点:

  • pypto.set_cube_tile_shapes([64, 64], [64, 64], [64, 64]):设置 Cube(矩阵乘)单元在 M、K、N 三个维度上的 tile 形状,每个参数是长度为 2 的列表(L1/L0 缓存级配置),定义见 python/pypto/_controller.py;
  • pypto.set_vec_tile_shapes(1, 8, 16, HEAD_DIM):设置 Vector(向量)单元各维度的 tile 形状,实现同样位于 python/pypto/_controller.py。

该样例默认形状为BATCH_SIZE=2, SEQ_LEN_Q=16, SEQ_LEN_KV=16, SEQ_LEN=32, NUM_HEADS=8, HEAD_DIM=64, HIDDEN_SIZE=512,类型为DT_BF16。默认的scale = 1.0 / sqrt(HEAD_DIM)也可通过AttentionConfig.scale自定义。

3.3 带投影的完整注意力(Multi-head + 动态 Batch)

第二个示例attention_with_projection_kernel演示了从hidden_states出发的完整多头注意力流程:先通过三个线性投影得到 Q/K/V,reshape成多头形状后transpose[B, H, S, D],随后按 batch 切片做注意力计算,最后再次transpose/reshape并经out_weight输出投影回[B, S, HIDDEN]

这里体现了两种高级技巧:

  1. Batch 维循环 + view 切片:通过pypto.loop(0, b_loop, 1, name="LOOP_L0_bIdx", idx_name="idx")对 batch 逐块处理,用pypto.viewvalid_shape处理边界(b_offset_end - b_offset防止越界);
  2. 动态形状支持:注意力本身对动态 Batch 和动态序列长度天然友好,测试函数标注了@pypto.options(pass_options={"enable_slice": True}),允许编译器对算子图做切片优化。

验证时使用torch.allclose(out, golden, rtol=3e-3, atol=3e-3)与最大绝对误差max_diff双重检查,并打印Batch=2, SeqQ=16, SeqKV=16, Max diff: ...等关键信息。运行方式:

python3 attention.py # 运行全部 python3 attention.py attention_with_projection::test_attention_with_projection # 运行单个示例 python3 attention.py --list # 列出可用示例

四、样例二:多函数设计模式(patterns/function)

patterns/function 演示如何将多个独立的@pypto.frontend.jit函数组合成复杂计算流水线。其子 README 明确指出设计动机:在开发大型算子(如完整 Transformer 层)时,把全部逻辑写进一个巨型函数不利于维护和优化。核心模式包括:

  • 顺序组合(Sequential Composition):多个 JIT 函数按顺序串联;
  • 残差连接(Residual Connection):在不同函数执行路径间建立跳连;
  • 函数复用(Function Reuse):同一 JIT 函数以不同输入多次调用;
  • 构建复杂模块:从 LayerNorm、Linear、Activation 等小函数逐步构建完整 Transformer Block。

4.1 五个可复用的 JIT 函数

function.py 定义了五个独立编译的 JIT 函数,每个都自带 Tiling 配置:

函数用途关键 Tiling 配置
layer_norm_kernelLayer Normalizationset_vec_tile_shapes(64, 128)
linear_projection_kernel线性投影(MatMul)set_cube_tile_shapes([64,64],[64,64],[64,64])
gelu_activation_kernelGELU 激活(x * sigmoid(1.702x)近似)set_vec_tile_shapes(32, 32)
residual_add_kernel残差相加set_vec_tile_shapes(64, 128)
attention_kernel简化版注意力set_cube_tile_shapes([64,64],[64,64],[64,64])

其中layer_norm_kernel使用动态形状标注pypto.Tensor()(不带具体 shape),展示了对动态形状输入的支持;linear_projection_kernel中保留的bias分支展示了pypto.add(pypto.matmul(...), bias)的写法。注意 GELU 内核使用的是 tanh-free 的 sigmoid 近似:out[:] = x * pypto.sigmoid(x * 1.702)

4.2 顺序组合与函数复用

test_sequential_functions展示了标准顺序流水线:先layer_norm_kernel归一化,再gelu_activation_kernel激活,最后与 PyTorch 参考实现(layer_norm_goldengelu_golden)逐项比对最大误差。

test_function_reuse则用同一layer_norm_kernel分别处理三组输入x1/x2/x3,并分别在 NPU 模式下调用torch.npu.synchronize()保证设备同步,验证“一次编译、多次复用”的 JIT 特性。

4.3 组合出完整 Transformer Block

test_transformer_block将上述函数组装成一个接近 SwiGLU 结构的 FFN + 残差模块,计算流程为:

  1. layer_norm_kernel(x, gamma, beta, normed)— 归一化;
  2. linear_projection_kernel(normed, gate_weight, gate)linear_projection_kernel(normed, up_weight, up)— Gate/Up 双路投影(128 → 256);
  3. gelu_activation_kernel(gate, activated)— 对 Gate 路做激活;
  4. activated = activated * up— 与 Up 路逐元素相乘(SwiGLU 风格);
  5. linear_projection_kernel(activated, down_weight, ffn_out)— Down 投影(256 → 128);
  6. residual_add_kernel(x, ffn_out, output)— 残差连接。

每一步在 NPU 模式下都紧跟torch.npu.synchronize(),保证 Host 侧观察到的中间结果确定性。运行方式:

python3 function.py # 运行全部 python3 function.py transformer_block::test_transformer_block # 单个示例 python3 function.py --list

4.4 多 JIT 组合创建(multi_jit.py)

multi_jit.py 进一步展示“多 JIT 函数组合创建”模式:把可选的标量加法逻辑封装在add_core中,由@pypto.frontend.jit内核根据布尔参数add1_flag在编译期分支出不同计算路径(是否追加+ VAL)。同一内核在单次运行中以False/True两个分支分别调用,分别与torch.add(input0, input1)torch.add(...) + val对比验证。这展示了 JIT 内核在参数层面进行运行时分支的灵活性。

五、样例三:成本模型仿真(cost_model)

cost_model/cost_model.py 演示如何使用 PyPTO 的成本模型(Cost Model)评估和优化算子执行效率。该样例最大的特点是不依赖真实 NPU 硬件:内核以pypto.RunMode.SIM模式编译运行,PyPTO 会生成仿真执行输出(如 swimlane JSON),供开发者在无硬件环境下做性能预分析。

5.1 内核与输出产物

样例内核是带动态 Batch 的 softmax:

@pypto.frontend.jit(runtime_options={"run_mode": pypto.RunMode.SIM}) def softmax(input_tensor: pypto.Tensor(), output_tensor: pypto.Tensor()): tensor_shape = input_tensor.shape b = tensor_shape[0] # 动态 batch n1, n2, dim = tensor_shape[1:] # 静态维度 tile_b = 1 b_loop = b // tile_b pypto.set_vec_tile_shapes(1, 4, 1, 64) for idx in pypto.loop(b_loop): b_offset = idx * tile_b b_offset_end = (idx + 1) * tile_b input_view = input_tensor[b_offset:b_offset_end, :n1, :n2, :dim] softmax_out = softmax_core(input_view) pypto.assemble(softmax_out, [b_offset, 0, 0, 0], output_tensor)

其中softmax_coreamax → sub → exp → sum → div五步实现数值稳定的 softmax,并通过pypto.assemble将逐 batch 的计算结果写回输出张量。测试形状为 NCHW 布局(32, 32, 1, 256),其中 N 是动态轴。

5.2 仿真输出与验证

test_softmax在仿真运行后,通过get_out_put_path()定位./output目录下与当前进程 PID 匹配的最新输出子目录,并断言关键产物存在:

merged_swimlane, error = safe_json_load( os.path.join(output_path, 'CostModelSimulationOutput/merged_swimlane.json') ) assert not error

即仿真会产出CostModelSimulationOutput/merged_swimlane.json泳道图数据,用于分析各硬件单元的占用与流水情况。该文件解析工具可参考仓库中的 tools/profiling/tilefwk_prof_data_parser.py 与 tools/profiling/draw_swim_lane.py。数值正确性则通过与torch.softmax(input_data, dim=3)的逐元素最大误差比对完成,且与ASCEND_HOME_PATH是否配置无关。

运行方式:

python3 cost_model.py # 运行示例 python3 cost_model.py --list

六、样例四:ACLGraph 图捕获(aclgraph)

aclgraph/aclgraph.py 演示如何使用图捕获(Graph Capture)模式优化 Host 侧开销。其核心思路是:将 PyPTO 内核封装成可被torch.compile与 NPU 图捕获 API 识别的算子,把多次内核启动合并为一次图重放(replay),显著降低 Host 侧的调度开销。

6.1 动态形状内核与返回值模式

内核沿用动态 batch 的 softmax 写法(B = pypto.DYNAMIC),但有两个与 aclgraph 兼容相关的关键点(源码注释指向 docs/zh/guide/programming_guide/tensor/pytorch_integration.md):

@pypto.frontend.jit() def softmax_kernel(input_tensor, output_tensor): ... output_tensor[b_offset:, ...] = softmax_out
  1. 使用返回值模式(在函数内通过切片写回输出)以兼容图捕获流程;
  2. 通过@torch._dynamo.allow_in_graph修饰 Python 封装函数,使torch.compile能够把 PyPTO 算子调用纳入被捕获的图中;对FakeTensor输入直接返回形状相同的占位张量,以支持动态 shape 的图编译。

6.2 图捕获与重放

测试流程展示了完整的“捕获 → 重放 → 校验”闭环:

model = torch.compile(MM(), backend="eager", dynamic=True) # graph capture(图捕获) g = torch.npu.NPUGraph() with torch.npu.graph(g): y = model(x, dynamic) # execute graph(图重放) g.replay() torch.npu.synchronize()

其中MM是一个简单torch.nn.Moduleforward内部调用被封装的softmax。捕获阶段把内核启动记录进NPUGraph,之后的每次g.replay()都以极低的 Host 开销重放整张图,这正是图捕获模式优化 Host 侧开销的原理。最后用assert_allclose(..., rtol=3e-3, atol=3e-3)torch.softmax参考结果比对。该示例需要 NPU 硬件,--list输出中会标注(Requires NPU)

七、学习路线与进阶建议

原文档给出的学习建议具有很强的路径依赖,结合仓库源码可以进一步细化:

  1. 首先深入学习 advanced_nn/attention:注意力机制是当前所有现代 LLM 的核心,重点理解transpose/reshape组合、set_cube_tile_shapesset_vec_tile_shapes对性能的影响,以及 golden 参考实现与 PyPTO 实现的对应关系;
  2. 通过 patterns/function 学习如何组织大型算子项目:从 5 个基础 JIT 函数出发,体会顺序组合、残差连接、函数复用三种模式,最终拼装出完整的 Transformer Block,这是大规模模型开发的工程化范式;
  3. 将高级特性应用到实际生产中:参考 cost_model 在无硬件环境预评估算子效率,参考 aclgraph 将算子无缝嵌入torch.compile图捕获流水线。原文档提到可参考models目录下的真实模型实现,但当前仓库中尚未包含该目录,请以examples/03_advanced内现成的四个样例为蓝本。

如果希望进一步深入底层原理,可以从以下仓库源码入手:运行模式与 JIT 编译入口见 python/pypto/frontend/parser/entry.py(RunMode定义于第 62 行,run_mode校验于第 995-1015 行);tile 形状的底层 scope 机制见 python/pypto/_controller.py;成本模型仿真与泳道图产出的分析工具见 tools/profiling。将--run_mode sim与 examples/validate_examples.py 配合使用,即可在 CI 中无硬件地持续验证全部样例。

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询