news 2026/5/22 4:02:43

CANN/pypto常见问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN/pypto常见问题

常见问题

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

kernel函数出参未写回导致计算不生效

问题现象描述

当前PyPTO框架用pypto.frontend.jit装饰的kernel函数,不支持有返回值,输出需要通过参数的形式传入并使用[:]等进行写回操作,如果直接使用等号赋值,无法将数据写入输出Tensor中。

示例代码:

@pypto.frontend.jit def add_kernel(x, y): pypto.set_vec_tile_shapes(4, 4) y = x + 1 # 此处会创建新的Tensor y torch.npu.set_device(0) x = torch.ones(4, 4, dtype=torch.float32) y = torch.empty(4, 4, dtype=torch.float32) add_kernel(pypto.from_torch(x), pypto.from_torch(y)) print(y) # 输出torch.empty创建的未经初始化的随机值

输出数据:

tensor([[2.0703e-19, 7.1833e+22, 1.8502e+28, 6.8608e+22], [4.8011e+30, 1.2123e+25, 4.7418e+30, 1.8465e+25], [1.2122e+25, 4.6114e+24, 1.7836e+31, 1.7591e+22], [1.1306e+24, 4.2245e-39, 6.8664e-44, 0.0000e+00]])

原因分析

在add_kernel函数内部执行y = x + 1时,这里的y是函数的局部变量(相当于创建了一个新的变量y),它会覆盖传入参数y的引用。也就是说,这行代码只是让函数内的y指向了x + 1的新Tensor,并不会修改外部传入的Tensor y的内容。

解决措施

通过全切片操作符[:],将计算结果写入函数参数y的原有内存空间

示例代码:

@pypto.frontend.jit def add_kernel(x, y): pypto.set_vec_tile_shapes(4, 4) y[:] = x + 1 # 将x+1的结果写入函数参数y的原有内存空间 torch.npu.set_device(0) x = torch.ones(4, 4, dtype=torch.float32) y = torch.empty(4, 4, dtype=torch.float32) add_kernel(pypto.from_torch(x), pypto.from_torch(y)) print(y) # 输出x + 1的结果

输出数据:

tensor([[2., 2., 2., 2.], [2., 2., 2., 2.], [2., 2., 2., 2.], [2., 2., 2., 2.]])

其中y[:] = x + 1也可以替换为y.move(x + 1)或者y.assemble(x + 1, [0, 0])

未设置执行算子的设备id

问题现象描述

在昇腾AI处理器上执行算子时,出现失败,报错信息如下。

2025-12-17 14:31:32.491 E | fail get device id, check if set device id 2025-12-17 14:31:32.492 E | RuntimeAgent::AllocDevAddr failed for size 20448 2025-12-17 14:31:32.493 E | RuntimeAgent::AllocDevAddr failed for size 20448 2025-12-17 14:31:32.493 E | aclmdlRICaptureGetInfo failed, return[100000]

可能原因

用户定义的算子未使用@jit进行装饰,且未使用torch_npu接口显式设置当前算子执行的Device ID。

处理步骤

在算子执行前设置Device ID,例如:

def test_onboard(): device_id = int(os.environ.get('TILE_FWK_DEVICE_ID', 0)) #从环境变量获取期望执行的device id torch.npu.set_device(device_id) #显式设置device id ....

CANN包不兼容

问题现象描述

算子上板执行时出现如下报错字样:

ErrorTracking callback in, task_id = 0, stream_id = 3. [ERROR] Exception Type: exception invalid error taskid: 0, streamid: 3, tid: 6495, deviceid: 0, retcode: 507018 kernelName = (null) ErrorTracking callback in, task_id = 1, stream_id = 3. [ERROR] Exception Type: exception invalid error taskid: 1, streamid: 3, tid: 6495, deviceid: 0, retcode: 507018 kernelName = (null)

且device日志中出现类似如下接口为空报错:

~/ascend/log/debug/device-0/device-6495_20251222194004973.log [ERROR] CCECPU(5670,aicpu_scheduler):2025-12-22-19:40:01.899.541 [ae_kernel_lib_aicpu_kfc.cpp:105][CallKernelApi][tid:5680][AICPU_PROCESSER] Get KFC DynTileFwkKernelServerInit api success, but func is nullptr: (null) [ERROR] CCECPU(5670,aicpu_scheduler):2025-12-22-19:40:01.902.745 [ae_kernel_lib_aicpu_kfc.cpp:105][CallKernelApi][tid:5681][AICPU_PROCESSER] Get KFC DynTileFwkKernelServer api success, but func is nullptr: (null)

原因分析

PyPTO驱动包支持25.2.0以上版本,CANN包支持8.5.0以上版本。

解决措施

可以查看驱动包安装目录下的version信息,如:

/usr/local/Ascend/driver/version.info Version=25.3.rc1 ascendhal_version=7.35.23 aicpu_version=1.0 tdt_version=1.0 log_version=1.0 prof_version=2.0 dvppkernels_version=1.1 tsfw_version=1.0 Innerversion=V100R001C23SPC002B212 compatible_version=[V100R001C19],[V100R001C20],[V100R001C21],[V100R001C22],[V100R001C23] compatible_version_fw=[7.0.0,8.9.9] package_version=25.3.rc1

同样可以查看CANN包安装目录下opp包内的version信息,如:

/usr/local/Ascend/ascend-toolkit/latest/opp/version.info Version=8.5.0.2.220 version_dir=8.5.0 timestamp=20251117_000024591 required_package_amct_acl_version="8.5"

按上述方法查看驱动包和CANN包是否满足版本要求,如不满足请升级对应版本。

TileShape与Tensor维度不匹配

问题现象描述

算子执行时出现如下报错:

2025-12-18 10:33:06.107 E | [ExpandFunction][Function][ERROR]: FUnction[TENSOR_b_loop_Unroll1_PATH0_hiddenfunc0] ExpandFunction failed: Tile shape size 1 is not matched the output shape size 2. 2025-12-18 10:33:06.107 E | Run pass [ExpandFunction] failed. 2025-12-18 10:33:06.107 E | Run pass <ExpandFunction> failed

可能原因

某个操作的TileShape设置的维度过小,小于该操作的输出Tensor的Shape维度,导致出现错误。

处理步骤

根据报错提示定位到相应的循环,如下所说,问题代码出现在b_loop循环中。

FUnction[TENSOR_b_loop_Unroll1_PATH0_hiddenfunc0]

找到对应的循环后,根据日志提示的错误维度以及代码逻辑,确定代码中TileShape的维度为1,而输出Shape的维度为2,将TileShape重新设置为2维即可。

view未传入valid_shape导致精度问题

问题现象描述

部分场景使用view时未传入valid_shape导致精度问题

问题原因

当view接口的输入tensor没有一个正确的validshape时,框架无法正确推导出输出的validshape。

处理步骤

当怀疑view部分的validshape推导有问题时,首先给view传入一个validshape,观察输出结果是否符合预期。

一个典型的需要传入validshape的场景:

当输入的validShape依赖别的tensor标识,必须传入dynValidShape。如下所示场景,q0的validshape curSeq来自于另外一个tensor,无法通过推导得到

# 输入 input [B, S, H] # 输入 act_seqs [B] # 输出 out [B, S, H] # 计算过程 AddS # 代码如下: for b_idx in pypto.loop(B, name="b_loop", idx_name="b"): cur_seq = act_seqs[b_idx] a0 = pypto.view(input, [1, S, H], [b_idx, 0, 0], valid_shape=[1, cur_seq, H]) a1 = a0 + 1.0 out[b_idx:, :, :] = a1

set_xxx_tile_shapes最后一维没有32字节对齐校验报错

问题现象描述

with pypto.function("TENSOR_SUM_FP32", [x], [res]): for _ in pypto.loop(1, name="LOOP_L0", idx_name="a_idx"): pypto.set_vec_tile_shapes(4, 8) res.move(x.sum())

通过pypto.set_xxx_tile_shapes设置TileShape大小最后一维需要32字节对齐,否则会校验报错。

C++ exception with description "ASSERTION FAILED: vecTile[lastDim] % alignNum == 0 Sum op: the tileShape of last axis need to 32Byte align!, func Sum, file reduction.cpp, line 374 libtile_fwk_interface.so(npu::tile_fwk::Sum(npu::tile_fwk::Tensor const&, int, bool)+0x620) [0xffff9ff2e090]

问题原因

硬件指令限制处理的数据需要32字节对齐。

处理步骤

通过pypto.set_xxx_tile_shapes设置TileShape大小需要将最后一维大小设置成32字节对齐的数,即TileShape[-1] * sizeof(dtype) % 32 == 0。

算子编译报堆栈溢出错误

问题现象描述

算子编译时出现类似如下报错字样:

error: stack frame size (*****) exceeds limit (32768) in function '*****'

在打屏日志中呈现样例如下:

error: stack frame size (47928) exceeds limit (32768) in function 'TENSOR_nLoop_Unroll1_PATH0_6_0_4503599627370496' error: stack frame size (47928) exceeds limit (32768) in function 'TENSOR_nLoop_Unroll1_PATH0_6_0_4503599627370496' 2 errors generated. terminate called after throwing an instance of 'npu::tile_fwk::Error' what(): ASSERTION FAILED: ret == 0 CompileCCE failed. errCode = 256, cce file: output/output_20251111_175724_806073/kernel_aicore/TENSOR_nLoop_Unroll1_PATH0_6_17699850674043372772_0_aic.cpp

原因分析

由于硬件限制,昇腾AI处理器核内的标量处理单元栈空间最大为32K。因此,在算子编译时,底层的毕昇编译器会对算子核内函数的栈使用情况进行分析和校验。如果函数实现较为复杂,例如变量较多或变量生命周期较长等因素,均可能影响分析结果。如果最终分析结果超出32K限制,毕昇编译器将拦截并报告该错误。

在PTO编程模型下,算子核内函数实现复杂的主要原因主要如下:

  • 子图规模较大,导致变量过多。
  • 子图计算逻辑复杂,导致变量的生命周期较长。

解决措施

针对上述可能的原因,可以采取以下措施进行处理:

  • 调整Tensor的Tiling切分策略,采用更大的Tile块进行切分。通过增加单个Tile块的计算数据量,在总数据量保持不变的情况下,可以减少子图所需的计算步骤,从而有效减小子图的规模。相关设置接口为:pypto.set_vec_tile_shapes和pypto.set_cube_tile_shapes。
  • 对于矩阵乘(MATMUL)计算场景,建议用户对K轴进行多核切分。
  • 修改控制子图大小的选项"cycle_upper_bound",将单个子图的最大规模限制在指定范围内。相关设置接口为:pypto.set_pass_options

循环中使用Python print函数打印

问题现象描述

@pypto.frontend.jit def add_kernel_0(a, b, c): for i in pypto.loop(20): print("i = ", i) c[:] = a + b >>> i = 0 @pypto.frontend.jit def add_kernel_1(a, b, c): for i in pypto.loop(20): print("i = ", i) if pypto.cond(i == 0): c[:] = a + b else: c[:] = a - b >>> i = 0 i = 1

可能原因

用户算子描述的是构图过程,而非实际的执行逻辑。在构图阶段,Loop执行仅用于遍历所有执行路径。示例代码add_kernel_0中仅有一条执行路径,因此Loop仅执行一次。add_kernel_1中存在if/else两条路径,因此Loop执行两次。

处理步骤

N/A

local Tensor 无 producer 时被读取触发device侧断言

问题现象描述

在算子编写过程中,如果 local Tensor 仅创建但未写入,就在 loop 内被读取,编译/执行到设备路径时可能触发设备侧断言或异常。典型报错如下:

ASSERTION FAILED: WORKSPACE_ITER_INVALID Root[...] incast ... slotIndex ... read from empty address.

该现象通常对应读取到的 slot 没有 producer,即 Tensor 对应 slot 未被任何 operation 写入。

最小示例(语义示意):

def kernel(x): t = pypto.tensor((1,), pypto.DT_FP32, "t") for i in range(n): _ = t[0]

可能原因

local Tensor(如t)仅被创建,但在被读取前没有任何写操作(如切片赋值、moveassemble或其他能建立 producer 的写入),导致读取路径访问到空地址并触发断言。

处理步骤

可采用以下任一方式规避:

  1. 在读取前先对 local Tensor 执行有效写入(例如切片赋值、moveassemble等),确保其存在 producer。
  2. 将该 local Tensor 写在 loop 内,作为 loop 内 Tensor 使用,使其在当前 loop 作用域内,pypto内存管理策略会为其申请内存地址

Loop 原理及其描述

在编译阶段会将loop编译为控制流,将loop body转换为计算流,分别对应kernel_aicpu/kernel_aicore. kernel_aicpu 负责控制流的执行,创建kernel_aicore任务,包括使用到的内存分配以及执行参数准备, 同时分析输入输出的依赖将kernel_aicore任务合并成一个更大的调度单元,然后提交给调度单元进行调度

原型介绍

def loop(start, end, step=1, name=None, idx_name=None, unroll_list = [1], submit_before_loop=False): def loop_roll(start, end, step=1, name=None, idx_name=None, unroll_list = [1], submit_before_loop=False):

描述

  1. start, end, step 分别可以表示循环的起始值、结束值和步长,类型可以为 SymbolicScalar 或者 int, 和Python中的range语法基本保持一致

  2. name 表示循环的名称,默认值为loop_{id}, 对实际使用运行效果无影响,仅用于调试和生成代码中注释信息

  3. idx_name 表示循环索引的名称,默认值为loop_idx_{id}, 对于嵌套累的Loop使用相同的idx会产生覆盖行为, 目前会在前端进行检查报错

  4. unroll_list 主要用于循环展开,产生更大的loop body, 降低调度开销。对于unroll_list=2, loop大概会产生如下代码

    new_start = start for k in unroll_list: left = (stop - start) % k for idx in loop(new_start, stop - left, k): for i in range(k): body(idx) # 需要用户一次处理step=1的步长 new_start = stop - left

    loop_unroll 大概会产生如下代码

    new_start = start for k in unroll_list: left = (stop - start) % k for idx in loop(new_start, stop - left, k): body(idx, k) # 需要用户一次处理k的步长 new_start = stop - left

    原则上如果可以一次处理多个i, 使用loop_unroll会更高效; 如果一次只能处理1个i, 则需要使用loop

  5. submit_before_loop 表示是否在循环开始前提交任务,默认值为False。如果设置为True,则循环前的任务会先提交到调度队列中,等待后续任务完成后再开始执行,过多的设置submit_before_loop会增加调度开销, 建议仅在必要时设置为True

  6. unroll_list 对pypto.cond影响, 通常一个循环中有一个pypto.cond, 会产生两个分支,当unroll次数为4次时,会产生 2 ** 4 16个路径分支,通常上每个分支都需要单独编译, 因此会大量增加编译时间和编译出的代码量. 为了支持关键算子FA的编译优化,提供了两个特殊的函数pypto.is_loop_begin()pypto.is_loop_end()用于优化条件分支

  7. 考虑到对外层loop进行loop_unroll不能提升loop body的大小, 当前仅支持最内侧循环进行unroll

  8. 为了写代码方便,可能有时看到前端算子并没有直接表达loop,是如何产生loop和loop body的呢. 实际是在构图阶段前端会隐式的在function开始的位置插入一个loop, 循环次数为1. 循环直到下一个循环开始前结束,举例如下

    @pypto.frontend.jit def foo(a, b, c): c[:] = a + b # 等价于 @pypto.frontend.jit def foo(a, b, c): for i in pypto.loop(1): c[:] = a + b @pypto.frontend.jit def foo(a, b, c): t = a + 1 for i in pypto.loop(1): c[:] = t + b # 等价于 @pypto.frontend.jit def foo(a, b, c): for i in pypto.loop(1): t = a + 1 for i in pypto.loop(1): c[:] = t + b

    框架当前不会自动进行loop(1)合并,因此在实际使用中,建议用户手动合并loop(1),以提高效率

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 3:55:08

从零实现一个高性能 FTP 服务器(C++ / Linux)

目录一、搭建 TCP 服务器骨架服务器代码测试二、支持多客户端并发三、线程模型核心思路为什么使用 detach输出为什么会错乱四、函数重构重构后的结构五、FTP 协议基础控制连接数据连接六、命令解析行缓冲区命令解析为什么要转大写七、PASV 被动模式为什么需要数据连接&#xff…

作者头像 李华
网站建设 2026/5/22 3:55:07

达梦数据库-统计信息收集-记录

达梦数据库-统计信息收集-记录总结 1统计信息收集 统计信息主要是描述数据库中表和索引的大小及数据分布状况等信息。比如&#xff1a;表的行数、块数、平均每行的大小、索引的高度、叶子节点数以及索引字段的行数等。统计信息对于CBO&#xff08;基于代价的优化器&#xff0…

作者头像 李华
网站建设 2026/5/22 3:52:17

LangChain 是什么?从零开始学会 LangChain 的工程实践指南

LangChain 是什么&#xff1f;从零开始学会 LangChain 的工程实践指南 1. 文章背景&#xff1a;为什么这个主题重要 在大模型应用开发中&#xff0c;很多人第一次接触 LangChain&#xff0c;是因为想快速做一个“基于大模型的应用”&#xff1a;例如知识库问答、RAG 检索增强生…

作者头像 李华
网站建设 2026/5/22 3:48:59

VCG Mesh平滑整形

文章目录 一、简介 二、实现代码 三、实现效果 参考资料 一、简介 这里使用拉普拉斯算子来优化Mesh,之前我们写过一篇关于极小曲面的文章,它就是将拉普拉斯算子尽可能都靠近0,以这种目标实现对极小曲面的求解。这里的Mesh平滑整形也是同样的到了,只不过我们并不要求曲率处处…

作者头像 李华
网站建设 2026/5/22 3:48:01

学Simulink——多路输出反激式开关电源(SMPS)交叉调整率改善仿真

目录 手把手教你学Simulink——多路输出反激式开关电源(SMPS)交叉调整率改善仿真 摘要 Abstract 1. 引言 1.1 研究背景 1.2 交叉调整率定义 2. 交叉调整率产生机理 2.1 电路结构 2.2 主要原因 3. Simulink 主电路建模 3.1 参数设置 3.2 关键模块 4. 传统单反馈控…

作者头像 李华
网站建设 2026/5/22 3:42:00

AMDGPU SVM Set Attr 流程分析:XNACK ON vs OFF

AMD工程师的更新频率很快啊,看提交版本应该是先支持XNACK off,然后再支持XACK on, 最后两者合一。下面是lore的最新版本链接: RFC XNACK on/off 统一版 RFC migration v4 版 XNACK-on 本文基于上述版本,进行了设计上的分析,及时跟踪SVM的最新进展。 1. 概述 AMDGPU SVM(…

作者头像 李华