PennyLane 操作、测量与梯度
本页介绍 QNode 的常用操作、测量返回值,以及广播、测量分组和梯度如何展开成具体实验。示例使用本 SDK 的 QuantumSourceDevice 和 PennyLane 0.45。
建立共同连接后,选择需要的实验示例学习。每个示例先构造线路并展示报价;执行时,取消对应 confirm 行的注释。confirm 和开启自动批准后的 QNode 调用会使用量子计算资源。
共同前置:创建一个逻辑线路设备
import os
import pennylane as qml
from pennylane import numpy as pnp
from quantum_source_sdk import SchedulerClient
scheduler = SchedulerClient(
base_url=os.environ["QUANTUM_SOURCE_API_URL"],
currency="OPEN", # 如需 FULL,在准备任何任务前改为 FULL
)
backend_id = os.environ["QUANTUM_SOURCE_BACKEND"]
organization_id = os.environ["QUANTUM_SOURCE_ORGANIZATION_ID"]
dev = qml.device(
"quantum_source.device",
wires=2,
backend=backend_id,
organization_id=organization_id,
scheduler=scheduler,
auto_approve_quote=False,
)
平台认证由 QUANTUM_SOURCE_SDK_KEY 文件,或 QUANTUM_SOURCE_CLIENT_ID / QUANTUM_SOURCE_CLIENT_SECRET 提供。wires=2 声明两个逻辑 wire,插件和平台负责线路转换与映射。需要固定物理位置时,使用 Qiskit 布局流程。
查看可使用的 PennyLane 操作
plugin_caps = dev.capabilities
print("PennyLane 操作:", sorted(plugin_caps.operations))
print("可观察量:", sorted(plugin_caps.observables))
print("测量类型:", sorted(plugin_caps.measurement_processes))
| 当前插件操作 | 常用写法 | 解释 |
|---|---|---|
| Identity、PauliX/Y/Z、Hadamard、S、T、SX | qml.Hadamard(0) | 单 wire 的固定门。 |
| RX、RY、RZ、PhaseShift | qml.RY(theta, 0) | 带弧度参数的单 wire 门。 |
| CNOT、CY、CZ、CH、SWAP | qml.CNOT(wires=[0, 1]) | 双 wire 门;最终物理映射取决于所选设备的逻辑执行路径。 |
| CRX、CRY、CRZ、ControlledPhaseShift | qml.CRY(theta, wires=[0, 1]) | 参数化双 wire 门。 |
| Toffoli、CSWAP | 在三个 wire 上使用 | 将设备 wires 至少设为 3。 |
| Barrier、GlobalPhase | 线路结构 / 全局相位操作 | 按线路转换规则处理屏障和全局相位。 |
PennyLane 将可分解的高级操作转换为插件支持的操作,再生成 OpenQASM。当前工作流采用固定 wires 和末尾测量的静态线路;使用上表中的门及其可分解组合编程即可。查看目标硬件的原生门与连接图时,读取 dev.provider_capabilities。
| 可观察量 | 示例 | 处理方式 |
|---|---|---|
| Pauli、Identity、Hadamard | qml.expval(qml.Z(0)) | 按测量基取得 counts 并还原统计量。 |
| 张量积 / 标量乘 / 求和 | qml.expval(0.5 * qml.Z(0) + qml.X(1)) | PennyLane 根据测量关系分组和后处理;总项数不一定等于任务数。 |
| Hamiltonian / LinearCombination | qml.Hamiltonian([1.0, 0.5], [qml.X(0), qml.Z(0)]) | 不对易项可能拆为多个测量基。 |
| Hermitian | qml.Hermitian(matrix, wires=0) | 有限且厄米的矩阵;必要时添加基变换。互相重叠且不能共同处理的矩阵可观察量需要分组。 |
测量与返回值
| QNode 的 return | 有限 shots 返回 | 怎样读取 |
|---|---|---|
| qml.counts(wires=[0, 1]) | dict[str, int] | 键为测量位串,值为出现次数。 |
| qml.probs(wires=[0, 1]) | 形状 (4,) 的频率数组,顺序 00、01、10、11 | 读取由 counts 归一化得到的各位串频率。 |
| qml.expval(qml.Z(0)) | 标量期望值 | 读取可观察量的采样期望值估计。 |
| qml.var(qml.Z(0)) | 标量方差 | 读取可观察量测量值的方差。 |
| qml.sample(wires=[0, 1]) | 通常为 (shots, 2) 的位数组;单 wire 会压缩 wire 轴 | 按由 counts 重建的统计样本使用,样本顺序为重建顺序。 |
| 多个测量组成的 tuple | 按 return 顺序还原的 tuple | 逐项接收各测量结果,实际任务数见准备对象。 |
上表中的 counts 对应计算基 wires 测量;使用 counts(obs) 时,字典键为可观察量的本征值。数组结果按请求的接口返回 NumPy / PennyLane 包装,可根据形状和测量含义继续计算。有限 shots 工作流读取平台 counts;原生概率结果的用法见本页的概率扩展。
示例 A:同一个测量基返回三类统计量
下面构造带一个旋转门的线路,同时请求计数、概率和 Z 期望值。三种统计量共享同一计算基测量,通过 construct 和 prepare 查看本次报价。
@qml.set_shots(128)
@qml.qnode(dev, diff_method=None)
def experiment(theta):
qml.RY(theta, wires=0)
return (
qml.counts(wires=[0], all_outcomes=True),
qml.probs(wires=[0]),
qml.expval(qml.Z(0)),
)
tape = experiment.construct((0.42,), {})
prepared_statistics = dev.prepare(tape)
print(prepared_statistics.quote)
# 确认这个报价后,单独运行;这会执行本批次:
# counts, probabilities, expectation = prepared_statistics.confirm()
all_outcomes=True 使未出现的计算基结果也以 0 次显示。三个返回项依次对应 return 的三个请求。对于 N 次、一个 wire 的计数 C0/C1,插件计算 probs=[C0/N, C1/N]、Z 期望值=(C0−C1)/N。用 prepared_statistics.task_count 和 total_shots 查看实际任务量。
示例 B:为什么 128 shots 会变成 384 shots
shots 指每个展开后实验的采样次数。对同一 wire 同时测 X、Y、Z 时,插件会准备三个测量基不同的实验,每个 128 shots,总计 384 shots。
@qml.set_shots(128)
@qml.qnode(dev, diff_method=None)
def three_axes():
qml.RY(0.37, wires=0)
qml.RZ(0.28, wires=0)
return qml.expval(qml.X(0)), qml.expval(qml.Y(0)), qml.expval(qml.Z(0))
prepared_axes = dev.prepare(three_axes.construct((), {}))
print("展开任务数:", prepared_axes.task_count)
print("总 shots:", prepared_axes.total_shots)
print(prepared_axes.quote)
# 决定执行这三个实验后再运行;返回 X、Y、Z 三个期望值:
# x_value, y_value, z_value = prepared_axes.confirm()
本例的准备结果为 3 条任务、384 总 shots。不同线路按测量关系分组:可对易项可以共享实验,矩阵测量可能增加基变换。准备对象中的任务数和总 shots 会展示本次展开结果。
示例 C:一个参数数组代表多个实验
下面把三个角度广播到同一 RY 门,每个角度执行 32 shots。结果沿广播维度排列,依次对应这三个角度。
angles = pnp.array([0.0, 0.5, 1.0], requires_grad=False)
broadcast_tape = qml.tape.QuantumScript(
[qml.RY(angles, wires=0)],
[qml.expval(qml.Z(0))],
shots=32,
)
prepared_broadcast = dev.prepare(broadcast_tape)
print("任务 / 总 shots:", prepared_broadcast.task_count, prepared_broadcast.total_shots)
print(prepared_broadcast.quote)
# 决定执行后再运行;本例结果形状为 (3,):
# expectations = prepared_broadcast.confirm()
本例是 3 条任务、96 总 shots。广播和测量分组可以同时展开实验。需要为实验指定不同采样量时,分别创建带整数 shots 的 QuantumScript,再用 dev.prepare((tape_a, tape_b)) 一起准备。
示例 D:参数移位梯度与自动批准
PennyLane 的 parameter-shift 先生成参数移位线路,再由插件执行这些线路并返回统计量,最后组合成梯度。一次梯度计算可以包含前向实验和多条移位实验,每个具体批次都有对应报价。
# 独立的梯度分支:这台设备允许每个具体批次自动批准报价。
# qml.grad 调用会执行梯度所需的实验。
gradient_dev = qml.device(
"quantum_source.device",
wires=1,
backend=backend_id,
organization_id=organization_id,
scheduler=scheduler,
auto_approve_quote=True,
)
@qml.set_shots(32)
@qml.qnode(gradient_dev, interface="autograd", diff_method="parameter-shift")
def loss(theta):
qml.RY(theta[0], wires=0)
qml.RZ(theta[1], wires=0)
return qml.expval(qml.X(0))
theta = pnp.array([0.2, 0.3], requires_grad=True)
# 执行本次梯度实验时,取消以下代码的注释:
# gradient = qml.grad(loss)(theta)
# print(gradient)
# print(gradient_dev.job_ids)
# print(gradient_dev.total_credits_used)
结果是形状 (2,) 的梯度,分别对应 theta[0] 和 theta[1]。有限 shots 会带来采样噪声。项目离线测试中的同结构例子包含一次前向和四次移位,共 5 条任务、160 shots;实际调用的工作量可查看执行批次与报价。
自动求导流程使用 parameter-shift,并通过 auto_approve_quote=True 批准各个实验批次。需要逐批查看报价时,显式管理具体 tapes 和准备对象。auto_approve_quote=False 的直接执行入口以 QuoteApprovalRequired 返回当前准备信息;恢复已有实验时,继续操作该准备对象。
可选扩展:shots=None 的原生概率
目标设备提供原生 probabilities 时,可用 shots=None 请求单个 qml.probs,并通过 provider_probability_shots 指定平台执行与计费预算。该模式读取设备的概率结果;日常采样实验使用前面的有限整数 shots 流程。
# 为提供原生 probabilities 的设备构造概率测量分支。
probability_dev = qml.device(
"quantum_source.device",
wires=2,
backend=backend_id,
organization_id=organization_id,
scheduler=scheduler,
provider_probability_shots=128,
auto_approve_quote=False,
)
probability_tape = qml.tape.QuantumScript(
[qml.Hadamard(0), qml.CNOT(wires=[0, 1])],
[qml.probs(wires=[0, 1])],
shots=None,
)
# 先确认这台设备的 probabilities 契约,再准备:
# probability_quote = probability_dev.prepare(probability_tape)
返回的归一化概率数组按请求的 wire 顺序排列。插件会检查概率通道及其数据;counts、sample、expval、var 则使用有限整数 shots。
查看本次实验的任务量和费用
| 公开属性 | 范围 | 使用方式 |
|---|---|---|
| prepared.task_count / total_shots | 这次准备后的具体批次 | 确认前查看本批次任务数和总采样次数。 |
| prepared.job_ids | 该批次已取得的任务号 | 发送队列中的提交可先用 attempted_preparation_ids 查询。 |
| dev.last_execution_metadata | 最近一次执行 / 准备批次 | 读取最近一批次的任务数和 shots。 |
| dev.job_ids | 当前设备实例记录的任务号 | 保存任务号,供当前会话或稍后通过 Core 查询。 |
| dev.total_credits_used | 当前设备实例已读取的完成任务费用 | 汇总该实例读取到的已完成结果显式费用。 |
等待超时后,再次调用原 prepared.result(timeout=...) 即可继续读取同一实验。中断时,插件会尝试取消本批仍待发送的任务;已发送任务继续查询结果。恢复与取消的具体用法见 PennyLane 主教程和任务查询章节。
关闭本地连接
# 完成实验后关闭本次创建的设备与连接。
dev.close()
# gradient_dev.close()
# probability_dev.close()
scheduler.close()
API 参考与相关章节
设备构造、线路准备、执行、结果读取与恢复的参数和返回值,统一在 PennyLane API 参考中查阅。
- PennyLane 插件 API
- 接口实现与测试依据
- PennyLane:从构造到结果的主教程
- PennyLane:查询真实设备能力和参数
- 结果类型与计数来源
- OpenQuantum:支持操作(组织方式参考)
- OpenQuantum:基础示例(组织方式参考)
- OpenQuantum:VQE 示例(组织方式参考)
下载本页 Jupyter Notebook
收录本页 Python 示例与说明,便于在 Jupyter Notebook 中学习和运行;安装命令保留为说明。