qml.compiler¶
该模块提供混合量子-经典编译的支持。通过使用qjit()装饰器,整个工作流可以进行即时(JIT)编译——包括量子和经典处理——在首次函数执行时编译为机器二进制文件。对编译后的函数的后续调用将执行之前编译的二进制文件,从而显著提高性能。
目前,PennyLane 支持
Catalyst 混合编译器
和 CUDA 量子编译器
以及 qjit() 装饰器。Catalyst 的一个显著优点是能够在编译过程中保留与量子
操作相关的复杂控制流——例如 if 语句和 for 循环,以及包含测量
反馈——同时继续支持端到端的自动微分。
注意
Catalyst 目前仅支持 PennyLane 的 JAX 接口。
概述¶
PennyLane中混合编译的主要入口点是通过qjit()装饰器,该装饰器可以与其他编译器特定的装饰器和函数混合使用:
|
PennyLane中用于即时编译混合量子程序的装饰器。 |
|
A |
|
A |
|
PennyLane程序的 |
|
PennyLane程序的 |
此外,还有几个开发者函数可用于探测可用的混合编译器。
加载并返回已安装且与 |
|
|
检查给定编译器包的可用性。 |
检查在 |
|
|
检查调用者是否在 |
下面呈现的是与qjit()兼容的PennyLane原语的列表。
|
创建一个算子的伴随或一个应用所提供的函数伴随的函数。 |
|
量子兼容的if-else条件 --- 基于中途电路量子比特测量结果等参数对量子操作进行条件处理。 |
|
创建一个方法,该方法应用所提供操作的受控版本。 |
|
返回作为混合量子-经典函数的可调用函数的梯度。 |
|
返回雅可比矩阵,作为向量值(QNodes的函数)的可调用函数。 |
编译器¶
编译器模块提供了将外部混合量子-经典编译器与PennyLane集成的基础设施,但不提供内置编译器。
目前,仅支持与PennyLane一起使用的Catalyst混合编译器和CUDA Quantum编译器工具链,然而计划在不久的将来引入其他编译器。
基本用法¶
注意
Catalyst 支持的后端设备包括
lightning.qubit, lightning.kokkos, lightning.gpu, 和 braket.aws.qubit,
但 不支持 default.qubit。
有关支持的设备的完整列表,请参见 支持的设备。
使用即时编译(JIT)时,编译在量子函数第一次执行时的调用位置触发。例如,circuit 在第一次调用时被编译。
dev = qml.device("lightning.qubit", wires=2)
@qml.qjit
@qml.qnode(dev)
def circuit(theta):
qml.Hadamard(wires=0)
qml.RX(theta, wires=1)
qml.CNOT(wires=[0,1])
return qml.expval(qml.Z(1))
>>> circuit(0.5) # the first call, compilation occurs here
array(0.)
>>> circuit(0.5) # the precompiled quantum function is called
array(0.)
或者,如果提供了参数类型提示,编译可以在函数被修饰时“提前”发生。
from jax.core import ShapedArray
@qml.qjit # compilation happens at definition
@qml.qnode(dev)
def circuit(x: complex, z: ShapedArray(shape=(3,), dtype=jnp.float64)):
theta = jnp.abs(x)
qml.RY(theta, wires=0)
qml.Rot(z[0], z[1], z[2], wires=0)
return qml.state()
>>> circuit(0.2j, jnp.array([0.3, 0.6, 0.9])) # calls precompiled function
array([0.75634905-0.52801002j, 0. +0.j,
0.35962678+0.14074839j, 0. +0.j])
Catalyst编译器还支持在编译程序中捕获命令式Python控制流,这使得控制流在运行时而不是在编译时在Python中被解释。您可以通过autograph=True关键字参数启用此功能。
@qml.qjit(autograph=True)
@qml.qnode(dev)
def circuit(x: int):
if x < 5:
qml.Hadamard(wires=0)
else:
qml.T(wires=0)
return qml.expval(qml.Z(0))
>>> circuit(3)
array(0.)
>>> circuit(5)
array(1.)
请注意,AutoGraph 会导致额外的限制,特别是在涉及全局状态时。有关支持和不支持的使用案例的完整讨论,请参阅AutoGraph 指南。
有关使用 qjit() 装饰器和 Catalyst
与 PennyLane 的更多详细信息,请参阅 Catalyst
快速入门指南,
以及 调试技巧和要点
页面,以了解 Catalyst 和 PennyLane 之间的差异,以及
如何最佳地构建工作流以提高使用 Catalyst 时的性能。
添加编译器¶
警告
PennyLane 编译器 API 是实验性的,可能会有所变化。
要注册任何编译器软件包,可以使用一个实验性的接口。该接口在指定的组名 pennylane.compilers 下公开 entry_points 元数据,包括以下入口点:
compiler_name.context": 编译评估上下文管理器的路径。 这个上下文管理器应该有一个方法context.is_tracing(), 如果在被跟踪或捕获的程序中调用,返回True。compiler_name.ops: 编译器操作模块的路径。这个操作模块可能包含特定于编译器的PennyLane操作版本,例如cond()、measure()和adjoint()。在JIT上下文中,PennyLane操作可能会调度到这些函数。compiler_name.qjit:编译器提供的JIT装饰器的路径。 该装饰器应具有以下签名qjit(fn, *args, **kwargs), 其中fn是要被编译的函数。
其中 compiler_name 应替换为编译器的名称。
例如,对于 Catalyst,我们定义入口点 catalyst.context、
catalyst.ops 和 catalyst.qjit。这允许 catalyst 包定义多个编译器。
编译器的名称可以被用户用来指示应使用哪个编译器。例如:
@qml.qjit(compiler="catalyst")
def function(x, y):
...
@qml.qjit(compiler="compiler_name")
def function(x, y):
...
为了支持在有和没有参数的情况下应用 qjit 装饰器,
@qml.qjit
def function(x, y):
...
@qml.qjit(verbose=True, additional_args, ...)
def function(x, y):
...
您应该确保 qjit 装饰器本身返回一个装饰器,如果没有提供函数:
def qjit(fn=None, **kwargs):
if fn is not None:
return compile_fn(fn, **kwargs)
def wrapper_fn(fn):
return compile_fn(fn, **kwargs)
return wrapper_fn