尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

PyPTO 非对齐数据搬入指南:vf.load_unalign 接口原理、参数与实战示例

发布时间:2026/9/20 22:50:35

资讯中心
01
ARTICLE

PyPTO 非对齐数据搬入指南:vf.load_unalign 接口原理、参数与实战示例

PyPTO 非对齐数据搬入指南:vf.load_unalign 接口原理、参数与实战示例
人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载本文聚焦 CANN PyPTO 向量编程Vector Functionvf中的非对齐数据搬入接口vf.load_unalign系统讲解其在 reg_tensor 数据搬运场景下对非 32 字节对齐地址的支持原理、三类接口的触发条件与参数细节并基于仓库源码与可运行示例帮助读者掌握非对齐搬入的初始化、迭代与后处理完整流程以及连续非对齐搬入搬出的性能优化写法。vf.load_unalign属于 PyPTO 的 SIMD-APIreg_computation 数据搬移类接口用于将 TileUB 地址中起始地址非 32 字节对齐的数据连续搬运至 reg_tensor是处理不规则内存布局、跨对齐边界数据的关键能力。产品支持情况vf.load_unalign依赖底层非对齐加载硬件指令vldus/vldas其产品支持范围以当前仓库文档标注为准产品形态支持情况Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品不支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品不支持在使用前需先确认目标设备属于 Ascend 950 系列否则该接口不可用。功能定位突破 32 字节对齐限制在常规向量搬移中Tile 地址通常要求对齐访问而对不规则内存地址起始地址非 32 字节对齐的处理往往伴随额外开销。vf.load_unalign的出现正是为了提升对不规则内存地址的处理能力它支持在数据搬运过程中访问非 32 字节对齐的地址从而降低非对齐访问带来的性能开销。其核心机制是将数据从非对齐的 Tile 地址连续搬运至 reg_tensor并利用非对齐寄存器UnalignRegForLoad作为临时缓存区暂存跨对齐边界的数据从而实现高效的连续非对齐数据传输。三类搬入接口与触发条件非对齐搬入根据地址更新方式的不同分为三类接口接口类型触发条件说明普通搬运接口不传 stridepost_updateFalse默认完成一次搬运后Tile 地址不会自动更新每次迭代需要手动更新地址。PostUpdate 扩展搬运接口post_updateTrue或传入 stride完成一次搬运后Tile 地址会自动更新每次迭代不需要手动更新地址。AddrReg 存储偏移量接口offset 为vf.create_addr_reg创建的 AddrReg在每次迭代中需要先调用vf.create_addr_reg手动设定地址偏移量再调用搬运指令。无论使用哪类接口在读非对齐地址前都应该先通过vf.load_unalign_pre进行初始化保存非 32 字节对齐的数据然后再调用vf.load_unalign进行数据搬入。非对齐搬入原理以一个具体场景说明从 Tile 地址srcAddr ~ 304读取数据并搬运至目标 reg_tensor256B处理流程如下初始化load_unalign_pre调用load_unalign_pre进行非对齐搬入初始化。非对齐寄存器 ureg 缓存 Tile 地址 32 ~ 64 的有效数据作为后续非对齐访问的前置数据缓存。搬入load_unalign调用load_unalign硬件指令将 Tile 地址 64 ~ 320 的对齐数据搬入临时 reg_tensor并将 ureg 中srcAddr ~ 64对应的数据与临时 reg_tensor 中地址 64 ~ 304 对应的数据拼接在一起将结果写入目标 reg_tensor。此外Tile 地址 288 ~ 320 的数据会被写入 ureg作为下一次迭代的缓存。该流程的关键在于 ureg 承担了“跨对齐边界数据暂存”的职责搬入前先由load_unalign_pre把起始偏移之前的数据缓存好搬入时硬件将缓存数据与本次对齐搬入的数据拼接得到完整的、从非对齐起点开始的连续数据并把尾部越界部分再次缓存进 ureg供下一次迭代使用。连续非对齐搬入搬出原理对于循环多次迭代的场景vf.load_unalign会与搬出接口vf.store_unalign配合实现连续非对齐搬入搬出的性能优化连续非对齐搬入vf.load_unalign会将后续未对齐的数据缓存至vf.load_unalign_init创建的 ureg所以下一次搬入不需要再次调用vf.load_unalign_pre只需在迭代开始前调用一次vf.load_unalign_pre。连续非对齐搬出下次迭代的vf.store_unalign会将本次迭代vf.store_unalign缓存至 ureg 中的数据写入 Tile所以本次迭代不需要调用vf.store_unalign_post将 ureg 数据写入 Tile只需在迭代结束后调用一次vf.store_unalign_post。以图中示例为例将 Tile 地址 48 ~ 560 的 DT_UINT32 数据[1, 2, 3, ..., 128]搬入至 dstReg再搬回 Tile。需要两次搬入搬出操作即 for 循环执行两次初始化和后处理移至 for 循环外。其中stride 256B / sizeof(T)即每次地址偏移 256BrepeatTimes dataSize / 256B即迭代次数 总数据量 / VL。具体搬运步骤如下非对齐搬入初始化更新ureg [1, 2, 3, 4]非对齐搬入tmpReg [5, 6, 7, ..., 68]tmpReg 部分数据和 ureg 数据写入dstReg [1, 2, 3, ..., 64]更新ureg [61, 62, 63, ..., 68]非对齐搬出dstReg 部分数据[1, 2, 3, ..., 60]写入 Tile 地址 48 ~ 288更新align_reg [61, 62, 63, 64]非对齐搬入tmpReg [69, 70, 71, ..., 128]tmpReg 数据和 ureg 部分数据写dstReg [65, 66, 67, ..., 128]非对齐搬出align_reg 数据[61, 62, 63, 64]和 dstReg 部分数据[65, 66, 67, ..., 124]写入 Tile 地址 288 ~ 544更新align_reg [125, 126, 127, 128]非对齐搬出后处理将 align_reg 中缓存的数据[125, 126, 127, 128]写入 Tile 地址 544 ~ 560。可见通过把load_unalign_pre初始化与store_unalign_post后处理移出循环循环体内仅保留搬入、搬出与地址自动累进从而避免每轮迭代的重复初始化开销。函数原型load_unalign(align_reg, tile, strideNone, post_update: bool False) - dst参数说明参数输入/输出说明align_reg输入/输出非对齐寄存器UnalignRegForLoad类型用于存储非 32 字节的数据寄存器大小为 32 字节由vf.load_unalign_init()创建。tile输入源操作数Tile 地址起始地址需要 32 字节对齐。目的操作数与源操作数的数据类型需要保持一致。支持的数据类型为DT_INT8、DT_UINT8、DT_INT16、DT_UINT16、DT_FP16、DT_BF16、DT_INT32、DT_UINT32、DT_FP32、DT_INT64、DT_UINT64、DT_FP8E4M3FN、DT_FP8E5M2、DT_FP8E8M0、DT_HF8、DT_FP4E2M1、DT_FP4E1M2。stride输入可选地址更新步长单位元素个数。仅在post_updateTrue时有效。post_update输入可选True 时搬运后地址自动累进默认 False。注意align_reg与stride均以“元素个数/元素宽度”为语义单位。从源码实现看stride最终会换算为字节数参与地址累进详见下文“源码级实现”一节。约束说明vf.load_unalign_pre与vf.load_unalign接口需要组合使用缺一不可必须先初始化 ureg 缓存再执行搬入。返回值说明返回dst目的操作数类型为 reg_tensor支持的数据类型和 tile 中的说明一致。调用示例基本非对齐加载以下示例展示非对齐搬入的最小闭环初始化 ureg、执行load_unalign_pre、带post_updateTrue搬入随后使用store_unalign与store_unalign_post将数据搬回 Tileimport os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf(src_tile, dst_tile): ureg vf.load_unalign_init() vf.load_unalign_pre(ureg, src_tile) src_reg vf.load_unalign(ureg, src_tile, post_updateTrue) store_ureg vf.unalign_reg_for_store() vf.store_unalign(dst_tile, src_reg, store_ureg, 64, post_updateTrue) vf.store_unalign_post(dst_tile, store_ureg, 0, post_updateTrue) pl.jit() def example_kernel( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], ): tf pl.TileType(shape[1, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0x0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs0x100, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randn([1, 64], devicedevice, dtypetorch.float32) out torch.empty([1, 64], devicedevice, dtypetorch.float32) example_kernelNone, core_nums torch.npu.synchronize() torch.testing.assert_close(out, a, rtol1e-5, atol1e-5) if __name__ __main__: test_example() print(PASSED)该示例的验证逻辑为在 Vector 内存空间中创建 shape[1, 64]的 FP32 Tile经pl.load将全局 Tensor 数据载入 in_a调用example_vf完成非对齐搬入再搬回最后pl.store写回并断言out与a逐元素一致。mutex_ids用于标记 Tile 组的互斥资源确保搬入搬出之间的数据依赖正确。带步长的连续非对齐加载示例当需要按固定步长连续搬运多个数据块时为load_unalign传入 stride如 64 个元素让地址在每次搬运后自动累进配合循环即可实现高效连续搬移import os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_FP32) ureg vf.load_unalign_init() vf.load_unalign_pre(ureg, src_tile) store_ureg vf.unalign_reg_for_store() src_reg vf.load_unalign(ureg, src_tile, 64, post_updateTrue) vf.store_unalign(dst_tile, src_reg, store_ureg, 64, post_updateTrue) vf.store_unalign_post(dst_tile, store_ureg, 64, post_updateTrue) pl.jit() def example_kernel( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], ): tf pl.TileType(shape[1, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0x0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs0x100, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example_2(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randn([1, 64], devicedevice, dtypetorch.float32) out torch.empty([1, 64], devicedevice, dtypetorch.float32) example_kernelNone, core_nums torch.npu.synchronize() torch.testing.assert_close(out, a, rtol1e-5, atol1e-5) if __name__ __main__: test_example_2() print(PASSED)与基本示例相比本例中load_unalign与store_unalign均传入 stride64 并开启post_updateTrue地址在每次搬运后自动前进 64 个元素preg vf.create_mask(patternpl.MaskPattern.ALL, ...)创建全有效掩码为需要掩码参与的场景预留了完整写法。INT64 数据类型示例对于 8 字节元素宽度的数据类型非对齐搬入同样适用验证时使用整数精确相等断言rtol0, atol0import os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf_int64(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_INT64) reg_a vf.load_align(src_tile, 0) ureg vf.load_unalign_init() vf.load_unalign_pre(ureg, src_tile) reg_out vf.load_unalign(ureg, src_tile) vf.store_align(dst_tile, reg_out, preg) pl.jit() def example_kernel_int64( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_INT64], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_INT64], ): tf pl.TileType(shape[1, 32], dtypepl.DT_INT64, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs256, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf_int64(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example_int64(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randint(-100, 100, [1, 32], devicedevice, dtypetorch.int64) out torch.empty([1, 32], devicedevice, dtypetorch.int64) example_kernel_int64None, core_nums torch.npu.synchronize() torch.testing.assert_close(out, a, rtol0, atol0) if __name__ __main__: test_example_int64() print(PASSED)本例展示了非对齐搬入与普通对齐搬入load_align/store_align混用的写法非对齐搬入reg_out后直接使用对齐搬出接口配合掩码写入目标 Tile说明非对齐搬入的产物reg_tensor可以与常规对齐接口自由组合。源码级实现从 Python API 到 vldus 指令Python 侧 API 声明vf.load_unalign系列接口在 python/pypto_pro/language/_vf_api.py 中以_api_decl声明三个接口职责清晰vf.load_unalign_init()声明非对齐寄存器UnalignRegForLoad必须在load_unalign_pre/load_unalign之前调用以分配对齐状态寄存器vf.load_unalign_pre(align_reg, tile)初始化非对齐加载对应vldas指令为后续非对齐加载建立对齐状态vf.load_unalign(tile, align_reg, strideNone, post_update: bool False)从非对齐 UB 地址加载数据到寄存器对应vldus指令可选 stride 用于 POST_UPDATE 模式返回承载数据的RegTensor。在解析侧python/pypto_pro/language/parser/_call_parser.py 将load_unalign归入“1 个 dst”的操作集合即src_reg vf.load_unalign(...)的赋值形式而load_unalign_pre、store_unalign、store_unalign_post等属于“0 dst无赋值形式”的操作调用时直接作为语句执行不产生寄存器变量。IR 注册与类型推导在 framework/src/interface/ir/op/vf_ops.cpp 中三个接口以REGISTER_OP注册为VFOp类别的算子vf.load_unalign_init无参数描述为 “Declare unaligned register for load”vf.load_unalign_pre两个参数(ureg, src_ptr)描述为 “Setup unaligned load (vldas)”vf.load_unalign参数为(dst, ureg, src_ptr [, stride])描述为 “Load unaligned data from UB to register (vldus, optional stride for POST_UPDATE)”且f_deduce_type(DeduceVFFromDstArg)表示其数据类型由 dst 参数推导。CCE 后端指令发射framework/src/interface/pypto_pro/backend/backend_cce_vf_ops.cpp 实现了最终的指令生成逻辑EmitVFLoadUnalignPre强校验必须恰好 2 个参数且第一个参数必须是vf.load_unalign_init创建的 UnalignReg 变量元素宽度仅支持 b8/b16/b32/b64对应 1/2/4/8 字节根据元素宽度选择 UB 指针类型uint8_t/uint16_t/half/int32_t/uint32_t后发射vldas(ureg, src_ptr)。EmitVFLoadUnalign强校验参数个数为 3~4 个、ureg 类型合法且 dst 类型属于 b8/b16/b32/b64当传入 stride 时按 POST_UPDATE 模式发射vldus(dst, ureg, src_ptr, stride, POST_UPDATE)其中b648 字节元素会以uint32_t指针模拟并令有效 stride 翻倍stride * 2这一细节与 AscendCDataCopyUnAlignImpl的 cast 规则保持一致未传 stride 时发射普通vldus(dst, ureg, src_ptr)。代码生成阶段的特殊处理在 framework/src/interface/pypto_pro/codegen/cce/cce_codegen.cpp 中vf.load_unalign_init与vf.load_unalign_pre被列入无需自动声明 dst 变量的操作集合因为前者不产生寄存器、后者为无返回值的语句型操作均不需要走常规的寄存器变量声明路径。这一处理与_call_parser.py中“0 dst”的归类相互印证。小结vf.load_unalign是 PyPTO 向量编程中处理非 32 字节对齐数据搬入的核心接口其价值体现在三方面打破对齐限制通过UnalignRegForLoadureg暂存跨对齐边界数据实现从非对齐 Tile 地址到 reg_tensor 的连续高效搬入迭代友好load_unalign_pre只需在循环前初始化一次配合post_updateTrue/stride 自动累进地址可将重复开销移出循环与搬出侧对称配合搬出侧store_unalign/store_unalign_post采用同样的缓存机制循环内搬出、循环末统一后处理构成完整的连续非对齐搬入搬出性能优化方案。在实际编码中请牢记三点使用前必须用vf.load_unalign_init创建 ureg 并用vf.load_unalign_pre初始化Tile 源地址本身仍需 32 字节对齐非对齐的是数据起始偏移当前仅 Ascend 950 系列产品支持该能力。赞分享人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载相关推荐CANN PyPTO 非对齐数据搬入指南vf.load_unalign_pre 初始化接口详解与实战CANN PyPTO 非对齐数据搬入指南vf.load_unalign_pre 初始化接口详解与实战 导读 vf.load_unalign_pre 是 CAN人工智能编译器模型编译高性能计算深度学习CANNCANN pyasc 数据搬运接口 asc.data_copy_pad 详解非对齐搬运与填充实战CANN pyasc 数据搬运接口 asc.data_copy_pad 详解非对齐搬运与填充实战 导读 asc.data_copy_pad 是 CANN py编译器编程语言人工智能CANNCANN pypto 的 vf.subc 带借位减法接口原理、参数与实战示例CANN pypto 的 vf.subc 带借位减法接口原理、参数与实战示例 vf.subc 是 CANN pyptoParallel Tensor/Til人工智能编译器模型编译高性能计算深度学习CANN上一篇Material Design Extensions快速入门10分钟打造现代化WPF界面下一篇8GB显卡也能玩转AI视频生成ComfyUI-WanVideoWrapper让你的创意不再受限创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。