Python API 参考
Python 模块
import lacinfer
本章中的类和函数均由 lacinfer 模块导出。Python API 将底层 C++ 对象封装为 Python 对象,并自动管理相关资源,用户通常不需要手动释放。从 program 获取的 module、从 module 获取的 instruction_ref 等对象引用所属计算图中的内容,不应在所属计算图失效后继续使用。
张量形状(lacinfer.shape)
描述张量的数据类型、维度和内存布局。
构造函数
lacinfer.shape(
*,
type="float",
lens=[1],
strides=None,
permutation=None,
dyn_dims=None,
) -> lacinfer.shape
签名中的 *1表示其后的所有参数均须通过关键字传入。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type |
str |
"float" |
元素类型名称 |
lens |
list[int] |
[1] |
静态形状的各维长度 |
strides |
list[int] 或 None |
None |
显式步长;长度必须与 lens 相同 |
permutation |
list[int] 或 None |
None |
维度排列 |
dyn_dims |
list[shape.dynamic_dimension] 或 None |
None |
动态形状的各维范围 |
dyn_dims 存在时使用动态形状构造路径。静态形状中,strides 和 permutation 不应同时提供。
元素类型
type 接受类型枚举名称及实现支持的简写。建议使用下列明确名称:
| 名称 | 含义 |
|---|---|
bool_type |
布尔值 |
half_type |
IEEE FP16 [实验性] |
float_type |
IEEE FP32 |
double_type |
IEEE FP64 |
uint8_type |
无符号 8 位整数 |
int8_type |
有符号 8 位整数 |
uint16_type |
无符号 16 位整数 |
int16_type |
有符号 16 位整数 |
int32_type |
有符号 32 位整数 |
int64_type |
有符号 64 位整数 |
uint32_type |
无符号 32 位整数 |
uint64_type |
无符号 64 位整数 |
fp8e4m3fnuz_type |
FP8 E4M3 FNUZ [实验性] |
fp8e4m3fn_type |
FP8 E4M3 FN [实验性] |
fp8e5m2_type |
FP8 E5M2 [实验性] |
bf16_type |
BF16 [实验性] |
fp8e5m2fnuz_type |
FP8 E5M2 FNUZ [实验性] |
上述 FP8、FP16 和 BF16 类型在当前版本中属于 [实验性] 类型,其兼容性和行为可能在后续版本中调整。
对应枚举可通过 lacinfer.shape.type_t 访问。
查询方法
shape.type()
shape.type() -> lacinfer.shape.type_t
返回元素类型枚举。
shape.type_string()
shape.type_string() -> str
返回元素类型的字符串名称。
shape.lens()
shape.lens() -> list[int]
返回各维静态长度。
shape.strides()
shape.strides() -> list[int]
返回各维步长,以元素为单位。
shape.ndim()
shape.ndim() -> int
返回维数。
shape.elements()
shape.elements() -> int
返回逻辑元素总数。
shape.bytes()
shape.bytes() -> int
返回形状占用的字节数。
shape.type_size()
shape.type_size() -> int
返回单个元素占用的字节数。
shape.dyn_dims()
shape.dyn_dims() -> list[lacinfer.shape.dynamic_dimension]
返回动态维度描述。
shape.packed()
shape.packed() -> bool
当张量布局紧凑、元素之间没有间隙时返回 True。
shape.transposed()
shape.transposed() -> bool
当步长表示转置布局时返回 True。
shape.broadcasted()
shape.broadcasted() -> bool
当至少一个步长为零并表示广播维度时返回 True。
shape.standard()
shape.standard() -> bool
当形状为标准布局,即紧凑且未转置时返回 True。
shape.scalar()
shape.scalar() -> bool
当所有步长均为零时返回 True。
shape.dynamic()
shape.dynamic() -> bool
当形状包含动态维度时返回 True。
shape 支持使用 == 和 != 比较,并可通过 Python 内置函数 repr(shape) 获取其字符串表示。
动态维度(lacinfer.shape.dynamic_dimension) [实验性]
描述单个动态维度的范围和优选值。
构造函数
lacinfer.shape.dynamic_dimension() -> dynamic_dimension
lacinfer.shape.dynamic_dimension(min: int, max: int) -> dynamic_dimension
lacinfer.shape.dynamic_dimension(
min: int,
max: int,
optimals: set[int],
) -> dynamic_dimension
| 属性 | 类型 | 说明 |
|---|---|---|
min |
int |
运行时维度下界 |
max |
int |
运行时维度上界 |
optimals |
set[int] |
编译器重点优化的维度取值 |
dynamic_dimension.is_fixed()
dynamic_dimension.is_fixed() -> bool
当 min == max 时返回 True。
参数(lacinfer.argument)
将形状与数据缓冲区关联,并实现 Python 缓冲区协议。
构造函数
lacinfer.argument(data: Buffer) -> lacinfer.argument
data 必须实现缓冲区协议,例如 NumPy 数组。构造过程从缓冲区的数据类型、形状和步长推导张量形状,并引用其数据;调用方必须保证源缓冲区在使用期间有效。
lacinfer.create_argument()
lacinfer.create_argument(
s: lacinfer.shape,
values: list[float],
) -> lacinfer.argument
创建具有指定形状和值的参数。len(values) 必须等于 s.elements(),否则抛出异常。输入值按目标元素类型转换。
lacinfer.generate_argument()
lacinfer.generate_argument(
s: lacinfer.shape,
seed: int = 0,
) -> lacinfer.argument
使用指定种子生成测试数据。该函数不用于生成安全随机数。
lacinfer.fill_argument()
lacinfer.fill_argument(
s: lacinfer.shape,
value: int | float,
) -> lacinfer.argument
创建指定形状的参数,并用同一个值填充全部元素。
lacinfer.argument_from_pointer()
lacinfer.argument_from_pointer(
shape: lacinfer.shape,
address: int,
) -> lacinfer.argument
用现有地址构造零拷贝参数。函数不验证地址的可访问范围,也不取得内存所有权。地址必须指向至少 shape.bytes() 字节的有效内存,并满足目标对内存位置和对齐的要求。
属性获取函数
argument.get_shape()
argument.get_shape() -> lacinfer.shape
返回参数形状。
argument.data_ptr()
argument.data_ptr() -> int
返回底层数据的内存地址。返回值不持有数据缓冲区,也不会延长其生命周期;使用该地址期间,必须保证对应的 argument 及其底层缓冲区仍然有效。
argument.tolist()
argument.tolist() -> list
按逻辑形状把数据复制为 Python 列表。
argument.save()
lacinfer.argument.save(arg: lacinfer.argument, filename: str) -> None
静态方法。把参数的形状和数据编码到文件中。
argument.load()
lacinfer.argument.load(filename: str) -> lacinfer.argument
静态方法。从参数文件恢复对象。
argument 支持 ==、!=、repr() 和缓冲区访问。
编译目标(lacinfer.target)
表示程序编译目标。该类不直接公开构造函数,应使用 get_target() 创建。
lacinfer.get_target()
lacinfer.get_target(name: str) -> lacinfer.target
| 参数 | 说明 |
|---|---|
name="gpu" |
GPU 目标 |
name="ref" |
参考目标 |
当前发布版本只提供上述两个目标。其他名称会导致异常。
指令引用(lacinfer.instruction_ref)
表示模块中的一条指令。实例由 module 方法或模块迭代器返回,不能直接构造。
instruction_ref.shape()
instruction_ref.shape() -> lacinfer.shape
返回指令输出形状。
instruction_ref.op()
instruction_ref.op() -> lacinfer.op
返回指令关联的操作。
instruction_ref.inputs()
instruction_ref.inputs() -> list[lacinfer.instruction_ref]
返回输入指令。
instruction_ref.outputs()
instruction_ref.outputs() -> list[lacinfer.instruction_ref]
返回以当前指令为输入的指令。
instruction_ref.name()
instruction_ref.name() -> str
返回指令名称。
instruction_ref.get_literal()
instruction_ref.get_literal() -> lacinfer.argument
返回字面量指令保存的数据。只应对字面量指令调用。
该类型支持哈希、== 和 !=。
计算图模块(lacinfer.module)
表示程序中的一个计算图模块。实例通过 program 的 get_main_module() 或 create_module() 获取,不能直接构造。模块对象的有效期依赖所属程序。
module.print()
module.print() -> None
向标准输出打印模块指令。
module.add_instruction()
module.add_instruction(
op: lacinfer.op,
args: list[lacinfer.instruction_ref],
mod_args: list[lacinfer.module] = [],
) -> lacinfer.instruction_ref
向模块添加操作指令。args 是操作的数据输入,即产生各输入值的指令引用;mod_args 是控制流操作使用的子模块。
module.add_literal()
module.add_literal(
data: lacinfer.argument | Buffer,
) -> lacinfer.instruction_ref
向模块添加常量。缓冲区数据类型、维度和步长用于确定字面量形状。
module.add_parameter()
module.add_parameter(
name: str,
shape: lacinfer.shape,
) -> lacinfer.instruction_ref
添加命名输入参数。模块内参数名必须唯一。
module.add_return()
module.add_return(
args: list[lacinfer.instruction_ref],
) -> lacinfer.instruction_ref
添加返回指令。
module.replace_return()
module.replace_return(
args: list[lacinfer.instruction_ref],
) -> lacinfer.instruction_ref
用新的返回值替换模块现有返回指令。
模块支持 repr() 和迭代。迭代元素类型为 instruction_ref;迭代期间不得销毁或修改所属模块。
操作(lacinfer.op)
描述一个操作及其属性。
构造函数
lacinfer.op(name: str, **attributes) -> lacinfer.op
name 必须是当前构建已注册的操作名。attributes 用于设置操作属性;支持的属性名称、类型和取值由 name 指定的操作决定。例如,reshape 操作可通过 dims 指定目标维度。属性不受支持或取值无效时会产生异常。
op.name()
op.name() -> str
返回操作名称。
op.values()
op.values() -> dict[str, object]
返回操作属性。
op.pooling_mode
池化模式枚举:
| 枚举值 | 说明 |
|---|---|
lacinfer.op.pooling_mode.average |
平均池化 |
lacinfer.op.pooling_mode.max |
最大池化 |
lacinfer.op.pooling_mode.lpnorm |
Lp 范数池化 |
op.rnn_direction
循环神经网络方向枚举:
| 枚举值 | 说明 |
|---|---|
lacinfer.op.rnn_direction.forward |
正向 |
lacinfer.op.rnn_direction.reverse |
反向 |
lacinfer.op.rnn_direction.bidirectional |
双向 |
程序(lacinfer.program)
表示可构建、编译、执行和序列化的计算程序。
构造函数
lacinfer.program() -> lacinfer.program
创建具有空主模块的程序。
program.get_parameter_names()
program.get_parameter_names() -> list[str]
返回全部输入参数名称。
program.get_parameter_shapes()
program.get_parameter_shapes() -> dict[str, lacinfer.shape]
返回参数名到形状的映射。
program.get_output_shapes()
program.get_output_shapes() -> list[lacinfer.shape]
返回全部程序输出的形状。
program.is_compiled()
program.is_compiled() -> bool
返回程序是否已经编译。
program.compile()
program.compile(
t: lacinfer.target,
offload_copy: bool = True,
fast_math: bool = True,
exhaustive_tune: bool = False,
) -> None
| 参数 | 说明 |
|---|---|
t |
编译目标 |
offload_copy |
为 GPU 等使用独立设备内存的目标,在编译时加入必要的数据复制:将输入从主机内存复制到设备内存,并将结果复制回主机内存 |
fast_math |
启用速度更快的近似数学实现,可能产生轻微精度差异 |
exhaustive_tune |
扩大内核调优搜索,增加首次编译时间 |
该方法原地修改程序。图修改和量化应在编译前完成。
program.get_main_module()
program.get_main_module() -> lacinfer.module
返回主模块。
program.create_module()
program.create_module(name: str) -> lacinfer.module
创建命名子模块并加入程序。
program.run()
program.run(
params: dict[str, Buffer],
) -> list[lacinfer.argument]
同步执行已编译程序。
| 参数 | 说明 |
|---|---|
params |
参数名到缓冲区对象的映射;argument 也实现缓冲区协议 |
参数名称、元素类型、维度、布局与内存位置必须符合编译结果。返回值按程序返回指令的顺序排列。
program.run_async()
program.run_async(
params: dict[str, Buffer],
stream: int,
stream_name: str,
) -> list[lacinfer.argument]
在指定原生流上异步提交程序。
| 参数 | 说明 |
|---|---|
params |
输入缓冲区映射 |
stream |
原生流指针的地址 |
stream_name |
运行时用于识别流类型的名称 |
返回时计算可能尚未完成。调用方负责保持输入、输出和流有效,并在访问结果或复用内存前同步。
program.to_py()
program.to_py() -> str
返回以 Python 风格表示程序的文本。
program.sort()
program.sort() -> None
原地按拓扑关系整理模块中的指令。
program.print()
program.print() -> None
向标准输出打印程序。
program 支持 ==、!= 和 repr()。
ONNX 解析
lacinfer.parse_onnx()
lacinfer.parse_onnx(
filename: str,
default_dim_value: int = 0,
default_dyn_dim_value: lacinfer.shape.dynamic_dimension =
lacinfer.shape.dynamic_dimension(1, 1),
dim_params: dict[str, lacinfer.shape.dynamic_dimension] = {},
map_input_dims: dict[str, list[int]] = {},
map_dyn_input_dims:
dict[str, list[lacinfer.shape.dynamic_dimension]] = {},
skip_unknown_operators: bool = False,
print_program_on_error: bool = False,
max_loop_iterations: int = 10,
limit_max_iterations: int = 65535,
) -> lacinfer.program
| 参数 | 说明 |
|---|---|
filename |
ONNX 模型路径 |
default_dim_value |
未确定维度的固定默认值;当前绑定默认值为 0 |
default_dyn_dim_value |
未确定维度的默认动态范围 |
dim_params |
ONNX 符号维度名到动态范围的映射 |
map_input_dims |
指定输入名到静态维度的覆盖映射 |
map_dyn_input_dims |
指定输入名到动态维度列表的覆盖映射 |
skip_unknown_operators |
是否跳过未知操作并继续解析 |
print_program_on_error |
解析失败时是否打印已构建的程序 |
max_loop_iterations |
Loop 未提供 trip count 时的默认最大迭代数 |
limit_max_iterations |
Loop 允许的迭代数硬上限 |
返回未编译程序。输入覆盖名称必须与模型输入名精确一致。同一输入不要同时放入静态和动态覆盖映射。
lacinfer.parse_onnx_buffer()
lacinfer.parse_onnx_buffer(
filename: str,
default_dim_value: int = 0,
default_dyn_dim_value: lacinfer.shape.dynamic_dimension =
lacinfer.shape.dynamic_dimension(1, 1),
map_input_dims: dict[str, list[int]] = {},
map_dyn_input_dims:
dict[str, list[lacinfer.shape.dynamic_dimension]] = {},
skip_unknown_operators: bool = False,
print_program_on_error: bool = False,
external_data_path: str = "",
) -> lacinfer.program
尽管绑定参数名为 filename,该参数实际接收包含完整 ONNX 模型的字节序列。external_data_path 指定外部权重数据所在目录。其余参数与 parse_onnx() 含义相同。
lacinfer.get_onnx_operators()
lacinfer.get_onnx_operators() -> list[str]
返回当前构建支持的 ONNX 操作名称。
量化
量化函数原地修改 program,应在编译前调用。
lacinfer.quantize_int8()
lacinfer.quantize_int8(
prog: lacinfer.program,
t: lacinfer.target,
calibration: list[dict[str, lacinfer.argument]] = [],
ins_names: set[str] = {
"dot", "convolution", "convolution_backwards",
"pooling", "add", "sdpa"
},
force_i8_output: bool = False,
save_quantized_lir_path: str = "",
per_channel_ops: set[str] = set(),
asymmetric_activation_ops: set[str] = set(),
nodes_to_exclude: set[str] = set(),
) -> None
| 参数 | 说明 |
|---|---|
prog |
待量化程序 |
t |
执行校准数据的目标 |
calibration |
校准样本列表,每个元素是完整的程序输入映射 |
ins_names |
要量化的 LACInfer 操作名集合 |
force_i8_output |
为可量化的浮点模型输出插入对称 INT8 量化 [实验性] |
save_quantized_lir_path |
非空时将量化后的程序以 LIR 格式保存到指定路径 |
per_channel_ops |
启用逐通道量化的操作类型集合 |
asymmetric_activation_ops |
对非权重输入启用非对称量化的操作集合;权重仍采用对称量化 [实验性] |
nodes_to_exclude |
按源模型节点名排除量化,精确匹配;未知名称被忽略 [实验性] |
校准数据的参数名、类型和形状必须与程序输入匹配。sdpa 表示标准 ONNX 域的 Attention 路径。pooling 量化为 [实验性] 功能,当前仅支持平均池化(Average Pooling)。
per_channel_ops 当前支持以下节点类型:
| 节点类型 | 量化对象 | 通道轴 |
|---|---|---|
convolution |
第 2 个输入,即权重 | 0 |
convolution_backwards |
第 2 个输入,即权重 | 1 |
asymmetric_activation_ops 当前只支持 convolution,作用于第 1 个输入,即激活输入。该选项会导致性能下降,当前版本不推荐使用;仅在对 mAP 有极高要求,并经实际模型精度与性能测试确认收益后考虑启用。
nodes_to_exclude 只对具有源模型节点名、且进入 INT8 量化候选的节点生效。名称必须精确匹配;未命名、名称未知或在量化前已被优化掉的节点不会被排除。
lacinfer.quantize_fp16() [实验性]
lacinfer.quantize_fp16(
prog: lacinfer.program,
ins_names: list[str] = ["all"],
) -> None
把指定操作转换为 FP16。["all"] 表示使用全部适用操作。
lacinfer.quantize_bf16() [实验性]
lacinfer.quantize_bf16(
prog: lacinfer.program,
ins_names: list[str] = ["all"],
) -> None
把指定操作转换为 BF16。
lacinfer.quantize_fp8() [实验性]
lacinfer.quantize_fp8(
prog: lacinfer.program,
t: lacinfer.target,
calibration: list[dict[str, lacinfer.argument]] = [],
) -> None
使用校准数据将 prog 原地量化为 FP8。每个校准样本都应是完整的程序输入映射,其参数名、类型和形状必须与程序输入匹配;目标 t 用于执行校准过程。
lacinfer.autocast_fp8() [实验性]
lacinfer.autocast_fp8(prog: lacinfer.program) -> None
原地把程序的 FP8 参数和返回值自动转换为 FP32,以便作为 LACInfer 程序的输入和输出使用。
程序持久化
lacinfer.load()
lacinfer.load(
filename: str,
format: str = "msgpack",
) -> lacinfer.program
从文件加载程序。format 支持 "msgpack" 和 "json"。
lacinfer.save()
lacinfer.save(
p: lacinfer.program,
filename: str,
format: str = "msgpack",
) -> None
把程序保存到文件。
lacinfer.save_buffer()
lacinfer.save_buffer(p: lacinfer.program) -> bytes
把程序序列化为字节序列。
lacinfer.load_buffer()
lacinfer.load_buffer(b: bytes) -> lacinfer.program
从字节序列恢复程序。
已编译程序的可移植性受目标设备和软件版本影响。跨环境部署时应在目标环境验证加载与执行。
GPU 内存辅助函数
以下函数仅在启用 GPU 支持的构建中存在。
lacinfer.allocate_gpu()
lacinfer.allocate_gpu(
s: lacinfer.shape,
host: bool = False,
) -> lacinfer.argument
按指定形状分配内存。host=False 时分配 GPU 设备内存;host=True 时分配页锁定主机内存(Pinned Host Memory)2。
lacinfer.to_gpu()
lacinfer.to_gpu(
arg: lacinfer.argument,
host: bool = False,
) -> lacinfer.argument
把参数复制到 GPU 可用内存。
lacinfer.from_gpu()
lacinfer.from_gpu(arg: lacinfer.argument) -> lacinfer.argument
把 GPU 参数复制到主机可访问参数。
lacinfer.gpu_sync()
lacinfer.gpu_sync() -> None
等待 GPU 工作完成。
版本信息
lacinfer.__version__
lacinfer.__version__: str
扩展模块的版本字符串。
1. 这是 Python 通用的“仅限关键字参数”(keyword-only parameters)语法。参数列表中单独出现的*不是参数;其后的参数必须以名称=值的形式传入。 ↩
2. 页锁定主机内存位于系统内存中,其物理页不会被操作系统换出,适合 CPU 与 GPU 之间的高效数据传输;它不是 GPU 设备内存。 ↩