PyPTO Element 标量类型详解:常量表达式的载体与 Tensor/Scalar 混合运算的类型规则
PyPTO Element 标量类型详解常量表达式的载体与 Tensor/Scalar 混合运算的类型规则【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto本文围绕 PyPTO 框架中的Element标量类型展开讲解它在计算类操作中作为常量表达式的角色、构造方式与int/float的默认类型映射规则并结合 Element Python 封装、C 绑定 与 底层 Element 类 的源码实现说明 Tensor 与 Scalar 混合运算时标量如何被转换为对应 Tensor 的数据类型帮助读者在编写 PyPTO kernel 时正确使用标量常量。Element 是什么计算操作中的常量表达式在 PyPTO 框架中Element类型用于存储标量常量服务于计算类操作中的常量表达式。可以把它理解为带数据类型标签的标量它既有一个明确的DataType如DT_FP32、DT_INT64又持有该类型下的一个具体数值从而可以被算子识别并参与代码生成。这一点与 PyTorch 中torch.Tensor与 Python 原生标量混合运算的体验类似在 PyPTO 里标量并不是裸的 Python 数字而是通过Element显式携带类型信息供后端生成 CCE/Tile 代码时使用。PyPTO 同时提供了pypto.Element与pypto.element两个入口二者指向同一个类——从 pypto 包导出文件 中可以看到from ._element import Element以及element Element的别名定义。Element的官方 API 文档包含以下三篇本文在此简介基础上结合源码进一步展开pypto.Element 构造函数pypto.Element.dtypepypto.Element.value构造 Element函数原型与默认类型映射构造函数原型按官方文档构造函数原型为__init__(self, dtype, value)参数说明参数名输入/输出说明dtype输入数据类型详见 DataTypevalue输入整数或者浮点数调用示例t pypto.Element(pypto.DT_FP32, 3)产品支持情况Ascend 950PR/Ascend 950DT、Atlas A3 训练/推理系列、Atlas A2 训练/推理系列产品均支持。int 与 float 的默认类型映射原始文档给出的关键规则是Python 内置的int类型通常会映射为DT_INT64类型float类型则映射为DT_FP32类型。这与框架中其他Python/PyTorch 类型 → DataType的映射约定保持一致例如 torch 类型转换表 中定义了torch.float32: DataType.DT_FP32与torch.int64: DataType.DT_INT64即 Python 的float对应 FP32、int对应 INT64。Python 层的类型校验从 Python 封装实现 可以看到构造Element时封装层会对value做严格的 Python 类型检查class Element: def __init__(self, dtype, data): if isinstance(data, int): self._base pypto_impl.Element(dtype, data) elif isinstance(data, float): self._base pypto_impl.Element(dtype, data) else: raise FeError(ValueError(fInvalid data type {type(data)} for Element))这意味着只接受 Python 的int或float作为数值来源其他类型如str、numpy标量会在构造阶段直接抛出FeError包装的ValueError问题可以尽早暴露实际的数值与类型存储委托给 C 扩展模块pypto_impl.Element即底层npu::tile_fwk::Element。dtype 与 value只读的类型与数值访问Element提供两个只读属性均由 Python 封装 转发到底层 C 方法dtype获取数据类型dtype(self) - pypto.DataTypet pypto.Element(pypto.DT_FP32, 3) t.dtype # DT_FP32源码实现上dtype属性返回self._base._get_data_type()对应 C 侧的Element::GetDataType()。该属性为只读数据构造后不可变更。value获取数据value(self) - int | floatt pypto.Element(pypto.DT_FP32, 3) t.value # 3.0value属性的实现体现了底层按类型选择读取方式的设计property def value: if self._base._is_float(): return self._base._get_float_data() else: return self._base._get_signed_data()即浮点类型走_get_float_data()返回float整型走_get_signed_data()返回有符号整数。此外封装层还提供base()方法直接返回底层pypto_impl.Element对象测试代码中常用于把显式构造的Element喂给具体算子例如 test_where_onboard.py 中的pypto.Element(dtype, scalar).base()。源码级实现从 pybind11 绑定到 C Element 类pybind11 绑定绑定文件 将 CElement暴露给 Python 侧注册了三种构造函数与一组访问器py::class_Element(m, Element) .def(py::initDataType, int64_t(), py::arg(type), py::arg(sData)) .def(py::initDataType, uint64_t(), py::arg(type), py::arg(uData)) .def(py::initDataType, double(), py::arg(type), py::arg(fData)) .def(_get_data_type, Element::GetDataType) .def(_get_signed_data, Element::GetSignedData) .def(_get_unsigned_data, Element::GetUnsignedData) .def(_is_float, Element::IsFloat) .def(_get_float_data, Element::GetFloatData);可以看到底层同时支持有符号整型int64_t、无符号整型uint64_t与浮点double三种存储通道。C Element 类联合体存储与类型分类framework/include/tilefwk/element.h 定义了核心存储结构union { int64_t sData; // 有符号整型 uint64_t uData; // 无符号整型 double fData; // 浮点 } data_; DataType type_;构造时的Init模板函数根据DataType把传入值统一转换到对应存储通道有符号类型转为int64_t、无符号类型转为uint64_t、浮点类型统一以double存储。类型判断逻辑如下IsSigned()DT_INT4/INT8/INT16/INT32/INT64及DT_BOOLIsUnsigned()DT_UINT8/UINT16/UINT32/UINT64IsFloat()DT_FP8/FP16/FP32/BF16/HF4/HF8/DT_DOUBLE。从源码结构看这一一个值 一个 DataType 标签的紧凑设计使得Element可以直接作为值类型嵌入算子的属性或 IR 节点中携带常量表达式参与调度与代码生成。同时该类在 C 层还重载了 - * / %算术运算符与 ! 比较运算符为常量折叠等场景提供了基础能力。Tensor 与 Scalar 混合场景标量自动转换为 Tensor 的数据类型原始文档的第三条规则值得特别注意在操作数类型同时存在 Tensor 和 Scalar 的场景中int 和 float 通常会被转换成对应 Tensor 的数据类型。这正是 PyPTO 算子处理Tensor Python 标量这类混合输入的机制。以 add 算子实现 为例op_wrapper def add(input_tensor: Tensor, other: Union[Tensor, float, int]) - Tensor: if isinstance(other, pypto_impl.Tensor): return pypto_impl.Add(input_tensor, other) else: _check_scalar_type(add, input_tensor.dtype, other) other _clip_scalar_to_dtype(input_tensor.dtype, other) return pypto_impl.Add(input_tensor, pypto_impl.Element(input_tensor.dtype, other))关键流程分三步分支判断若other是 Tensor 则走 Tensor-Tensor 路径否则视为 Python 标量类型检查_check_scalar_type当标量为float而 Tensor 是整型 dtype 时直接报错提示float scalar incompatible with integer tensor dtype防止隐式的浮点—整型混算标量转换用input_tensor.dtype而非 Python 默认类型构造pypto_impl.Element(input_tensor.dtype, other)即标量被染上Tensor 的数据类型。随后 _clip_scalar_to_dtype 还会按目标整型 dtype借助 numpy 对应类型对整数值做范围裁剪避免越界值进入无符号/小位宽整型。同样的转换逻辑贯穿sub、mul、div、fmod、remainder、ceil_div、floor_div等标量运算参见 python/pypto/op/math.py 中各算子对_check_scalar_type的调用。其他典型使用场景常量填充pypto.full(size, fill_value, dtype)的fill_value支持int、float、SymbolicScalar和Element四种形式见 creation.py。其中对Element形式的填充值源码还会检查无符号整型 dtype 不接受负数填充值full() does not support negative fill_value for unsigned integer dtype范围生成pypto.arange/range类接口在步长缺省时使用pypto_impl.Element(pypto_impl.DataType.DT_INT32, 1)作为默认 step见 creation.py体现了Element作为类型化常量在生成算子中的常规用法条件选择pypto.where(cond, x, y)的分支参数允许传入Element其取值合法性由测试用例守护。测试用例佐证unsigned 标量边界检查测试 覆盖了一系列有代表性的场景pypto.where(cond, x, pypto.Element(pypto.DT_FP32, 1.0)) pypto.where(cond, pypto.Element(pypto.DT_FP16, 1.0), y) pypto.full([2, 2], pypto.Element(pypto.DT_UINT8, -100), pypto.DT_UINT8) # 期望报错 pypto.where(cond, x, pypto.Element(pypto.DT_UINT8, -100)) # 期望报错这些用例印证了两点Element可以直接作为where/full等算子的操作数无符号整型场景下负值会被框架在构造/校验阶段拒绝符合标量值必须能由其 dtype 表示的语义。使用建议小结需要显式携带类型的标量常量如传给full、where、Range等算子时使用pypto.Element(dtype, value)或别名pypto.element(dtype, value)构造只做Tensor 与 Python 标量的混合运算时可直接写 Pythonint/float算子内部会自动按 Tensor dtype 转换为Element无需手动构造注意整型 Tensor 不接受float标量此类组合会抛出TypeError应改用整型标量或先将 Tensor 转为浮点类型无符号整型 dtype下不要使用负数标量填充值框架会明确报错dtype与value均为只读属性构造后不可修改。参考Element 构造函数 API、dtype API、value APIDataType 定义Element Python 封装、pybind11 绑定、C Element 类算子标量转换实现、full/range 实现无符号标量检查测试、where 算子用例【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址: https://gitcode.com/cann/pypto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考