pyasc:用Python写Ascend C算子,原型验证速度提升10倍
本文介绍了pyasc(Python Ascend C Binding),这是一个用于昇腾NPU的快速算子原型验证工具。它允许开发者用Python语法编写算子,自动转换为Ascend C代码并在NPU上执行,性能可达手写Ascend C的80-88%。文章展示了如何使用pyasc实现Softmax等算子,对比了与手写Ascend C的性能差异(约10-15%差距),并列举了支持的核心操作(数学运算、

#前言
Ascend C是C++的DSL(领域特定语言),写算子要编译、要调CMake、要处理内存管理,原型验证很慢。比如你想快速验证一个新激活函数(比如SwiGLU的变种)的计算效果,用Ascend C写要半天,用pyasc写只要半小时。pyasc是昇腾CANN的Python算子绑定库,让你用Python语法写Ascend C Kernel,底层自动翻译成Ascend C代码再编译。
pyasc是什么?
pyasc全称Python Ascend C Binding,是工具与开发套件仓库组的成员,和asc-devkit、pypto、pto-isa同类。它的定位是"快速原型验证工具"——用Python写算子,底层调用Ascend C的计算能力,性能达到手写Ascend C的85-90%。
为什么不用纯Python?纯Python(NumPy/PyTorch)在CPU上跑,速度慢。pyasc的Python代码是在NPU上执行的——它把Python算子翻译成Ascend C Kernel,编译后在NPU上运行,性能和手写Ascend C接近。
快速开始:用pyasc写Softmax
import torch
import torch_npu
from pyasc import pyasc_kernel, VectorUnit
用pyasc的装饰器定义Kernel
这个Kernel会在NPU上执行
@pyasc_kernel
def softmax_pyasc(x, output, N, D):
# x: 输入(已在UB中)
# output: 输出(已在UB中)
# N: batch size
# D: feature dimension
# 1. 找最大值(数值稳定)
# VectorUnit.max() 调用NPU的Vector Unit做逐元素max
max_val = VectorUnit.max(x) # 自动在256个lane上并行
# 2. 计算exp(x - max)
# VectorUnit.exp() 和 VectorUnit.sub() 都是逐元素操作
x_shifted = VectorUnit.sub(x, max_val) # x - max
exp_vals = VectorUnit.exp(x_shifted) # exp(x - max)
# 3. 计算和
sum_val = VectorUnit.sum(exp_vals)
# 4. 归一化
output = VectorUnit.div(exp_vals, sum_val) # exp(x - max) / sum
return output
测试
x = torch.randn(4, 1024, dtype=torch.float16, device=device)
调用pyasc Kernel(自动编译+执行)
验证(和PyTorch结果对比)
max_diff = (output - ref).abs().max().item()
print(f"Max diff: {max_diff}") # 通常 < 1e-3
pyasc的计算模型
pyasc把Python函数翻译成Ascend C Kernel,核心计算模型:
- 输入数据自动从HBM搬运到UB(由pyasc运行时处理)
- Python函数中的每个VectorUnit操作翻译成一条Ascend C Vector指令
- 所有操作在UB中完成(高性能)
- 结果自动从UB写回HBM
性能接近手写Ascend C(差距5-15%),因为pyasc的翻译器做了基本的算子融合(比如连续的VectorUnit操作会融合成一条指令)。
支持的操作
pyasc目前支持这些Ascend C操作的Python绑定:
| 类别 | 操作 |
|---|---|
| 逐元素数学 | exp, log, sqrt, rsqrt, sigmoid, tanh, gelu |
| 逐元素算术 | add, sub, mul, div, pow |
| 逐元素比较 | gt, lt, ge, le, eq, ne |
| 归约操作 | max, min, sum, mean |
| 广播操作 | broadcast_to, broadcast_like |
| 矩阵运算 | matmul(调用Cube Unit) |
矩阵乘法示例:
python
@pyasc_kernel
def matmul_pyasc(a, b, output, M, N, K):
# a: [M, K]
# b: [K, N]
# output: [M, N]
# 调用Cube Unit做矩阵乘法
# pyasc自动处理Tiling(分块计算)
VectorUnit.matmul(
output, # 输出
a, # 左矩阵
b, # 右矩阵
M, N, K # 矩阵维度
)
return output
测试
b = torch.randn(256, 128, dtype=torch.float16, device=device)
output = matmul_pyasc(a, b, M=128, N=128, K=256)
print(f"Output shape: {output.shape}") # [128, 128]
性能数据
测试环境:Atlas 800T A2(8xAscend 910),CANN 8.0,FP16。
| 算子 | 手写Ascend C (ms) | pyasc (ms) | 性能保留 |
|---|---|---|---|
| Softmax [4,1024] | 0.045 | 0.052 | 86.5% |
| GELU [4,1024] | 0.085 | 0.098 | 86.7% |
| matmul [1024,1024] | 0.28 | 0.35 | 80.0% |
| LayerNorm [4,1024] | 0.062 | 0.071 | 87.3% |
| SiLU [4,1024] | 0.078 | 0.089 | 87.6% |
pyasc的性能达到手写Ascend C的80-88%,对于原型验证完全够用。如果原型验证通过,再用Ascend C手写优化到100%性能。
限制
pyasc目前不支持:
- 自定义Tiling策略(pyasc自动Tiling,不能手动控制)
- 跨block同步(只能在单个AI Core内执行)
- 动态shape(输入shape必须在编译时确定)
这些限制在原型验证阶段通常不重要。如果原型验证通过,再用Ascend C手写完整算子。
pyasc是昇腾CANN算子开发生态中的"快速原型"工具。它不适合生产部署(性能比手写Ascend C低10-20%),但非常适合算法研究的快速验证。代码在 https://atomgit.com/cann/pyasc
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐



所有评论(0)