PyPTO Tensor.view 详解:切片视图、valid_shape 动态有效数据与数据语义

PyPTO Tensor.view 详解:切片视图、valid_shape 动态有效数据与数据语义 PyPTO Tensor.view 详解切片视图、valid_shape 动态有效数据与数据语义【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto导读pypto.Tensor.view是 PyPTOParallel Tensor/Tile Operation 编程范式中用于从输入 Tensor 中取出部分视图类似切片的核心接口。本文以 pypto-Tensor-view.md 为主干结合 pypto-view.md 的完整参数说明与仓库源码实现系统讲解view的调用方式、valid_shape动态有效数据语义、dtype重解释读取以及它与pypto.assemble的配合用法。读完本文你将掌握在 tiling 循环、PageAttention/kv_cache、填充pad等场景中正确使用view提取子张量并规避视图独立拷贝这一与 PyTorchview截然不同的语义陷阱。一、函数原型与产品支持情况pypto.Tensor.view以实例方法形式提供定义于 python/pypto/tensor.pyview(self, shape: List[int], offsets: List[Union[int, SymbolicScalar]], *, valid_shape: Optional[List[Union[int, SymbolicScalar]]] None) - Tensor其底层转发至模块级函数pypto.view函数原型见 python/pypto/operation.pyview(input: Tensor, shape: List[int] None, offsets: List[Union[int, SymbolicScalar]] None, *, valid_shape: Optional[List[Union[int, SymbolicScalar]]] None, dtype: DataType None) - Tensor两种调用形态完全等价区别仅在于实例方法版本未暴露dtype参数如需按其他数据类型重新解读输入请使用模块级pypto.view(x, dtype...)形式。产品支持情况根据文档声明view在以下产品上均受支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持注意文档中的产品支持矩阵npu950、npuA3、npu910b以注释形式标记表示对应架构的验证状态实际可用性请以当前安装的 CANN 版本与硬件环境为准。二、参数说明参数名输入/输出说明input输入源操作数。支持 PyPTO 支持的全部数据类型不支持空 TensorShape Size 不大于 2147483647即 INT32_MAX。shape输入取出视图的大小维度数量必须与 input 一致Shape Size 不大于 INT32_MAX仅支持 List[int] 类型不支持 SymbolicScalar 类型。offsets输入获取视图时每个维度相对于 input 的偏移需要保证 offsets 小于 input 的 Shape支持int与SymbolicScalar混合。valid_shape输入取出视图块的有效数据大小需要保证小于 input 的 Shape在类似 PageAttention 场景下当 kv_cache 等张量包含无效数据、编译器无法正确推导输出的 valid_shape 时需要手动传入。dtype输入返回值的数据类型允许将输入数据解读为不同数据类型按位重解释不改变底层位模式。关键语义解读shape 必须为静态整数列表shape描述视图的分配大小逻辑盒子仅接受List[int]这也是它与 offsets/valid_shape 的最大区别——后两者允许携带SymbolicScalar动态值。offsets 可动态在 tiling 循环中偏移量通常由循环下标计算而来如offset_x b_idx * view_shape[0]此时偏移是编译期未知的运行时标量因此offsets支持SymbolicScalar。valid_shape 是有效数据而非分配大小shape定义了视图的盒子大小valid_shape则声明盒子内真正有意义的元素个数二者缺一不可时输出 Tensor 的真实大小以valid_shape为准见下文返回值说明。三、返回值说明pypto.view返回输出 Tensor其语义如下Tensor 的数据类型与 input 相同Shape 为参数shape指定的大小若指定了valid_shape则真实有效大小为valid_shape若指定dtype则输入按dtype进行位级重解释读取输出元素的个数与位宽相应变化。四、调用示例完整实操以下示例均来自 pypto-view.md 并可在仓库源码 python/pypto/operation.py 的 docstring 中找到等价版本。4.1 基本用法按 shape offsets 提取子视图x pypto.tensor([4, 8], pypto.DT_FP32) shape [4, 4] offsets [0, 4] y pypto.view(x, shape, offsets)结果示例如下输入数据x: [[1 1 2 2 3 3 4 4], [1 1 2 2 3 3 4 4], [1 1 2 2 3 3 4 4], [1 1 2 2 3 3 4 4]] 输出数据y: [[3 3 4 4], [3 3 4 4], [3 3 4 4], [3 3 4 4]]即从[4, 8]的输入中以[0, 4]为偏移取出大小为[4, 4]的子块。实例方法与模块级函数等价y x.view(shape, offsets) # 实例方法 y pypto.view(x, shape, offsets) # 模块级函数4.2 增加 valid_shape声明有效数据大小x pypto.tensor([4, 8], pypto.DT_FP32) shape [4, 4] offsets [2, 4] valid_shape [2, 4] y pypto.view(x, shape, offsets, valid_shape)结果示例如下输入数据x: [[1 1 2 2 3 3 4 4], [1 1 2 2 3 3 4 4], [1 1 2 2 5 5 6 6], [1 1 2 2 5 5 6 6]] 输出数据y: [[5 5 6 6], [5 5 6 6], [0 0 0 0], [0 0 0 0]]可以看到视图的盒子大小仍为[4, 4]从[2, 4]偏移开始但只有前两行[5 5 6 6]是有效数据后两行被填充为 0。这正是 PageAttention / kv_cache 场景的典型形态——张量按最大长度分配但实际有效数据随 query 动态变化。4.3 指定 dtype按位重解释读取x pypto.tensor([2, 2], pypto.DT_FP32) y pypto.view(x, dtypepypto.DT_INT8)结果如下底层位模式不变仅解读方式改变输入数据x: [[0.9405094 0.20237109], [0.99819463 0.13246714]] 输出数据y: [[ 57 -59 112 63 94 58 79 62], [ -81 -119 127 63 119 -91 7 62]]每个 FP32 元素4 字节被重解释为 4 个 INT8 元素输出张量元素个数变为原来的 4 倍。源码中当dtype非空时直接构造pypto_impl.View(input, dtype)见 python/pypto/operation.py其 docstring 亦注明 dtype 场景支持DT_FP32, DT_FP16, DT_BF16, DT_INT8。五、约束与语义差异务必注意文档明确列出以下约束它们与 PyTorch 用户对view的直觉有显著差异需要 valid_shape 时必须用 pypto.view当需要指定valid_shape动态有效数据大小时不能使用[]切片语法必须使用显式的pypto.view接口。输入 Tensor 和输入 shape 的维度数量需要一致shape的维数必须与input相同。view 创建后与源 input 相互独立这是最关键的一条语义——view创建后即成为独立的数据拷贝对 view 的读写含view[:] ...只作用于 view 自身不会写回源 inputview 也不会感知源 input 的后续修改若需要将数据写回源 Tensor例如在循环中向 persistent buffer 分片累积写入的场景请使用pypto.assemble(value, offsets, dest)。仓库源码在 docstring 中同样以加粗警示强调WARNING: view has a very different behavior from torch.view, it is more like slice.见 python/pypto/operation.py即 PyPTO 的view语义更接近切片拷贝而非 PyTorch 的零拷贝重排视图。与 assemble 的配合在 tiling 分块处理中典型的读-改-写循环模式是for b_idx in pypto.loop(...): for s_idx in pypto.loop(...): offset_x b_idx * view_shape[0] offset_y s_idx * view_shape[1] valid_x pypto.min(pypto.symbolic_scalar(n_in) - offset_x, pypto.symbolic_scalar(view_shape[0])) valid_y pypto.min(pypto.symbolic_scalar(m_in) - offset_y, pypto.symbolic_scalar(view_shape[1])) tile_a pypto.view(a, view_shape, [offset_x, offset_y], valid_shape[valid_x, valid_y]) # 读出分块 tile_res tile_a.pad(padding, modeconstant, valuepad_val) # 计算 pypto.assemble(tile_res, [offset_x, offset_y], b) # 写回目标上述模式取自仓库实测用例 python/tests/st/operation/vector/test_pad.py清晰展示了view负责从源张量按偏移取块只读方向assemble负责把结果按偏移写回目标张量写方向两者配合即可实现分块 pad、分片累积等算法。Tensor.assemble的实例方法定义见 python/pypto/tensor.py。六、valid_shape 与 assume_divisible 的进阶用法文档特别指出valid_shape可以配合pypto.experimental.assume_divisible使用。6.1 解决什么问题当某个动态标量如 PageAttention 中的实际长度l已知可被 tile shape 整除时可通过assume_divisible声明该事实帮助编译器消除该轴逐 tile 动态 valid_shape的复杂计算使能 dualdst 等依赖静态 valid_shape的优化。6.2 实现原理assume_divisible(expr, divisor)定义于 python/pypto/experimental/operation.py其行为如下将expr归一化为SymbolicScalarint输入会被转换并把可整除假设注册到当前 Program 上func.base.RegisterDivisibleAssumption(expr, divisor)注册后编译器可将动态 valid-shape 表达式例如min(max(vm - off, 0), T)化简为T见 docstring 中的化简示例默认情况下该假设在运行时不做校验当开启runtime_debug_mode4时codegen 会把每个注册的归一化假设表达式在控制流入口处编译为取模断言用于运行时兜底检查若expr是编译期常量expr % divisor ! 0会直接抛出ValueError假设被证明为假expr % divisor 0则为无操作平凡成立divisor必须为正数否则抛出ValueError。6.3 典型使用形态在 matmul 分块场景中tile 大小vm往往取 128/256 等对齐值若运行时行数m已知为 tile 的整数倍可显式声明from pypto.experimental import assume_divisible m_aligned assume_divisible(m, vm) # 声明 m 可被 vm 整除 a_view pypto.view(a_tensor, [k, vm], [0, m_offset], valid_shape[k, min(vm, m - m_offset)])仓库实测用例 python/tests/st/operation/matmul/test_scaled_mm_mxfp8.py 展示了更完整的模式valid_shape中写入min(vm, m - m_offset)之类的动态表达式配合整除假设即可让编译器在满足条件时将其静态化简为vm从而启用 dualdst 等依赖静态 valid_shape 的优化路径。七、源码实现要点从 python/pypto/operation.py 可以看出view的底层分发逻辑if dtype is not None: return pypto_impl.View(input, dtype) elif valid_shape is None: result pypto_impl.View(input, shape, offsets) else: result pypto_impl.View(input, shape, to_syms(valid_shape), to_syms(offsets))要点如下三种分支纯 dtype 重解释、无 valid_shape静态切片、带 valid_shape动态有效数据分别构造不同的pypto_impl.View调用动态值归一化传入 valid_shape 时valid_shape与offsets会先经to_syms归一化为 SymbolicScalar 表示确保动态表达式在 IR 层可追踪视图登记簿创建结果后_view_original_shapes、_view_input_ids、_view_input_names会记录视图的原始 shape 与源 Tensor 的 Id/Name供编译与调试阶段回溯 view 的来源关系。相关测试佐证仓库中view被广泛用于各类算子的分块实现可作为最佳实践参考python/tests/st/operation/vector/test_pad.pypad 分块 view assemble 完整循环python/tests/st/operation/matmul/test_scaled_mm_mxfp8.pymatmul 分块中动态 valid_shape 的书写范式python/tests/st/operation/matmul/test_gather_in_l1.pyPageAttention 风格下用valid_shapesrc.shape构造动态视图python/tests/st/frontend/test_reshape_copy_out.pyvalid_shape[t_tile, l, d]携带动态长度l的典型用法。八、总结pypto.Tensor.view是 PyPTO 中按偏移取块 动态有效数据声明 按位重解释三合一的核心切片接口静态分块shape offsets即可完成基本子视图提取动态场景valid_shape精确表达 PageAttention/kv_cache 等场景中盒子大、有效数据小的语义并可与assume_divisible配合消除逐 tile 动态计算、使能 dualdst 优化位级重解释dtype参数支持将输入按不同数据类型读取无需拷贝即改变元素解读粒度语义陷阱牢记 PyPTOview是独立拷贝而非零拷贝别名写回请使用pypto.assemble。掌握这些要点即可在 tiling 循环、attention、pad 等实际算子开发中正确、高效地使用view。【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考