- 人工智能
- 编译器
- 模型编译
- 高性能计算
- 深度学习
- CANN
【免费下载链接】pypto
PyPTO(发音: pai p-t-o):Parallel Tensor/Tile Operation编程范式。
本篇文章以 PyPTO 编程范式中 Tile 逐元素除法算子pypto_pro.language.div为讲解对象,完整覆盖其产品支持范围、两种计算模式(Tile-Tile 与 Tile-Scalar)、函数原型、参数与数据类型约束,并结合仓库源码与 ST 测试用例深入剖析其底层调度逻辑与精度控制实现。读完本文,你将能够在 Ascend 950(A5)设备上正确编写、验证并优化基于 Tile 的逐元素除法内核。
产品支持情况
pypto_pro.language.div目前仅在 Ascend 950 系列产品上受支持,其余产品线暂不支持,使用时请先确认目标硬件:
| 产品 | 支持情况 |
|---|---|
| Ascend 950PR / Ascend 950DT | 支持 |
| Atlas A3 训练系列产品 / Atlas A3 推理系列产品 | 不支持 |
| Atlas A2 训练系列产品 / Atlas A2 推理系列产品 | 不支持 |
仓库中的 ST 测试同样通过@pytest.mark.soc("950")标记并显式检查设备名包含 "Ascend950",否则直接跳过(见 test_vector_operations.py),与文档的产品支持声明相互印证。
功能说明
div对两个操作数对应位置的元素执行逐元素除法,支持两种计算模式,并且都支持原地计算(即out与某个输入为同一个 Tile):
- Tile-Tile 模式:将
lhs对应位置的元素除以rhs中的元素,把结果写入out,即out[i] = lhs[i] / rhs[i]。 - Tile-Scalar 模式:将
lhs中的每个元素除以一个标量rhs,把结果写入out,即out[i] = lhs[i] / scalar。
从源码看,该算子归属于python/pypto_pro/language/_api.py中 "Section B1: Binary element-wise (out, lhs, rhs)" 这一二元逐元素计算组(与add、sub、mul并列),其语义被定义为out = lhs / rhs,API 声明见 _api.py。
函数原型
pypto_pro.language.div( out: Tile, lhs: Tile, rhs: Union[Tile, Scalar], ) -> None函数没有返回值,计算结果直接写入out。
参数说明
| 参数 | 输入/输出 | 说明 |
|---|---|---|
out | 输出 | 目的操作数,Tile 类型,存放逐元素除法的结果。数据类型与lhs一致,支持DT_INT16、DT_UINT16、DT_INT32、DT_UINT32、DT_INT64、DT_UINT64、DT_FP16或DT_FP32。可与lhs或 Tile 类型的rhs为同一 Tile,实现原地计算。 |
lhs | 输入 | 左操作数(被除数),Tile 类型。数据类型与out一致。 |
rhs | 输入 | 右操作数(除数),Tile 或 Scalar 类型。传入 Tile 时执行 Tile-Tile 计算,数据类型与out一致,且 shape 与out、lhs一致;传入 Scalar 时执行 Tile-Scalar 计算。 |
数据类型说明
与同组的add相比,div的整数支持范围更窄(不含DT_INT8/DT_UINT8),也不支持DT_BF16。这一差异在代码生成层面有所体现:除法、幂、取模等运算在向量二元指令生成时会被附加"精度类型"模板参数(见下节源码解析),因此对数据类型与算法选择有更严格的要求。实际使用中请以本文档表格列出的 8 种数据类型为准。
约束说明
官方文档声明无额外约束。从源码结构看,Section B1 组的公共约束同样适用于div,可作参考:
- 不支持广播:
out、lhs、rhs(当rhs为 Tile 时)的 shape 必须完全一致; - 无隐式类型提升:所有操作数的数据类型必须一致(见 _api.py 中的注释约束)。
返回值说明
无返回值,结果写入out指向的 Tile。
源码实现与底层原理
1. 模式分发的 IR 层实现
div在语言 API 层声明后,前端解析阶段通过tensor_ops.py中的div与div_scalar完成 IR 构造。核心逻辑在于根据rhs的类型自动选择 op:若rhs是ScalarType,则生成tensor.div_scalar调用;否则生成tensor.div调用,见 tensor_ops.py。
此外,标量操作数会被统一规范化为 FP32 表达式(_normalize_expr,int_dtype=DataType.FP32, float_dtype=DataType.FP32),保证标量在参与除法前的类型一致性。
2. 向量指令生成的精度控制
在代码生成阶段,div对应的OP_DIV/OP_DIVS指令会由AddBinaryPrecisionTypeParm注入一个额外的模板参数pto::DivAlgorithm。当算子的precisionType属性为 1 时使用HIGH_PRECISION,否则使用默认的DEFAULT算法,见 codegen_vector_binary.cpp。这意味着除法内核在高精度需求场景下存在算法切换的扩展通道,是理解其数值精度行为的关键实现细节。
调用示例
Tile-Tile 模式
下面是一个完整的 64×64 FP32 数据逐元素除法内核:先在pl.section_vector()向量切片内通过pl.load将全局 Tensor 加载到 Vector 内存的 Tile,再执行pl.div,最后pl.store写回:
import pypto_pro.language as pl @pl.jit(auto_mutex=True) def div_kernel(a: pl.Tensor[[64, 64], pl.DT_FP32], b: pl.Tensor[[64, 64], pl.DT_FP32], out: pl.Tensor[[64, 64], pl.DT_FP32]): tt = pl.TileType(shape=[64, 64], dtype=pl.DT_FP32, target_memory=pl.MemorySpace.Vec) tile_a = pl.make_tile_group(type=tt, addrs=0x0000, mutex_ids=[0]) tile_b = pl.make_tile_group(type=tt, addrs=0x4000, mutex_ids=[1]) tile_out = pl.make_tile_group(type=tt, addrs=0x8000, mutex_ids=[2]) with pl.section_vector(): cur_a = tile_a.current() cur_b = tile_b.current() cur_out = tile_out.current() pl.load(cur_a, a, [0, 0]) pl.load(cur_b, b, [0, 0]) pl.div(cur_out, cur_a, cur_b) pl.store(out, cur_out, [0, 0])要点说明:
pl.TileType通过shape、dtype、target_memory=pl.MemorySpace.Vec声明 Tile 的布局,div要求三个 Tile 的 shape 与 dtype 完全一致;pl.make_tile_group的addrs为 Tile 在对应内存空间中的偏移地址,mutex_ids用于向量算子的互斥与自动同步(配合auto_mutex=True使用);pl.section_vector()界定向量指令执行区间,保证load → div → store处于同一向量流水上下文。
实测结果示例如下。
输入数据a:[[1 1.25 1.5 1.75 2 2.25 2.5 2.75 ...], [17 17.25 17.5 17.75 18 18.25 18.5 18.75 ...], [33 33.25 33.5 33.75 34 34.25 34.5 34.75 ...], [49 49.25 49.5 49.75 50 50.25 50.5 50.75 ...], ...] 输入数据b:[[10 10.5 11 11.5 12 12.5 13 13.5 ...], [42 42.5 43 43.5 44 44.5 45 45.5 ...], [74 74.5 75 75.5 76 76.5 77 77.5 ...], [106 106.5 107 107.5 108 108.5 109 109.5 ...], ...] 输出数据out:[[0.1 0.119048 0.136364 0.152174 0.166667 0.18 0.192308 0.203704 ...], [0.404762 0.405882 0.406977 0.408046 0.409091 0.410112 0.411111 0.412088 ...], [0.445946 0.446309 0.446667 0.44702 0.447368 0.447712 0.448052 0.448387 ...], [0.462264 0.462441 0.462617 0.462791 0.462963 0.463134 0.463303 0.46347 ...], ...]可以看到,out每个元素严格等于a对应元素除以b对应元素,例如1 / 10 = 0.1、1.25 / 10.5 ≈ 0.119048。
Tile-Scalar 模式
Tile-Scalar 模式只需将第二个操作数替换为 Python 标量即可,适合归一化、缩放等"每个元素除以同一个常数"的场景:
# Tile每个元素除以Scalar值。 pl.div(out, lhs, 2.0)原地计算
由于div支持原地计算,out可以与lhs或 Tile 类型的rhs为同一个 Tile,例如:
# 将 tile_a 原地除以 tile_b,结果仍写回 tile_a。 pl.div(tile_a, tile_a, tile_b)测试验证
仓库的 ST 测试 test_vector_operations.py 中同时覆盖了div的两种模式:
- Tile-Tile:
pl.div(cur_out, cur_a, cur_b)后store到输出区域偏移[256, 0]; - Tile-Scalar:
pl.div(cur_out, cur_a, DIVISOR)(DIVISOR = 4.0)后store到偏移[576, 0]。
测试将内核输出与 torch 参考结果(a / b、a / DIVISOR)通过torch.testing.assert_close对比,容差为rtol=1e-2, atol=1e-2,见 test_vector_operations.py。该测试同时验证了div与add、sub、mul等算子共享同一套 64×64 Tile 模板的复用模式,是编写自定义逐元素算子的良好参考蓝本。
小结
pypto_pro.language.div是 PyPTO Tile 编程范式中的二元逐元素除法算子,支持 Tile-Tile、Tile-Scalar 两种模式及原地计算;- 仅支持 Ascend 950PR / Ascend 950DT,数据类型限定为
DT_INT16、DT_UINT16、DT_INT32、DT_UINT32、DT_INT64、DT_UINT64、DT_FP16、DT_FP32; - 底层由 tensor_ops.py 依据
rhs类型自动分发到tensor.div/tensor.div_scalar,并在代码生成阶段通过DivAlgorithm模板参数支持精度算法切换; - 实战中可参照 test_vector_operations.py 中的测试模式验证结果正确性。
- 人工智能
- 编译器
- 模型编译
- 高性能计算
- 深度学习
- CANN
【免费下载链接】pypto
PyPTO(发音: pai p-t-o):Parallel Tensor/Tile Operation编程范式。
相关推荐
PyPTO 逐元素乘法算子 pl.mul 详解:Tile-Tile 与 Tile-Scalar 双模式编程指南
PyPTO 逐元素乘法算子 pl.mul 详解:Tile Tile 与 Tile Scalar 双模式编程指南 PyPTO(Parallel Tensor/Ti
人工智能编译器模型编译高性能计算深度学习CANNCANN PTO-ISA 指令详解:TADD 双 Tile 逐元素加法
CANN PTO ISA 指令详解:TADD 双 Tile 逐元素加法 TADD(Tile ADD)是 CANN PTO ISA 向量指令集中的核心二元运算指令
人工智能指令集算子库CANNAscendCANN PTO 指令详解:TPOWS——逐元素标量指数幂(Tile Power Scalar)运算
CANN PTO 指令详解:TPOWS——逐元素标量指数幂(Tile Power Scalar)运算 TPOWS(Tile Power Scalar)是 CAN
人工智能指令集算子库CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考