Skip to Content

量子机器学习

概述

unitarylab_algorithms.quantum_machine_learning 包提供适用于近期量子设备(NISQ 时代)的变分和生成量子算法。这些算法使用经典-量子混合优化循环来训练参数化量子线路。

算法任务
VQEVQEAlgorithm基态能量估计
VQCVQCAlgorithm量子分类器(鸢尾花数据集)
QAOAQAOAAlgorithm组合优化(最大割问题)
QCBMQCBMAlgorithm概率分布生成建模(Bars-and-Stripes)
CVQNNCVQNNAlgorithm连续变量量子神经网络分类
Fermi-Hubbard VQEFermiHubbardVQEAlgorithm一维开放费米-哈伯德模型基态求解

返回与输出

所有算法都返回 statuscircuit_pathplotcircuit,并附加各自的结果字段。plot 的内容因算法而异:VQE/VQC/CVQNN 各 1 项,QAOA 2 项,QCBM 3 项,Fermi-Hubbard VQE 包含收敛图和参数 .npy 文件。优化质量请结合能量、损失、精度和优化器状态等结果字段判断。


变分量子特征求解器(VQE)

背景

VQE 通过在参数化拟设态上最小化期望值 来估计厄米哈密顿量 的基态能量。该算法在量子化学和材料模拟中被广泛使用。

算法交替执行:

  1. 在量子线路上计算
  2. 使用 COBYLA(scipy.optimize.minimize)更新参数

拟设为 Ry-Rz 环形纠缠线路:每层先对每个量子比特施加 Ry+Rz 旋转,再用一圈 CNOT 纠缠相邻(含首尾回环)量子比特。

导入

from unitarylab_algorithms import VQEAlgorithm

.run() 参数

def run(self, n=2, layers=2, max_iter=150, seed=7, hamiltonian=None, normalize=True, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]
参数类型默认值说明
nint2量子比特数(仅在 hamiltonian=None 时生效)
layersint2拟设中的变分层数
max_iterint150COBYLA 最大迭代次数
seedint7随机哈密顿量生成与初始参数采样的随机种子
hamiltoniannp.ndarray | NoneNone自定义厄米哈密顿量;为 None 时内部生成随机厄米矩阵
normalizeboolTrue生成随机哈密顿量时是否按谱范数归一化(仅影响随机哈密顿量分支)

_validate_hamiltonian() 会校验矩阵是方阵、维数为 2 的幂、且满足 ,否则抛出 ValueError

返回值

{ "status": "ok", "circuit_path": "<VQE_Circuit.svg.svg 路径>", "plot": [{"format": "svg", "filename": "<VQE_Convergence.svg 路径>"}], "circuit": <Circuit 对象>, "Exact Energy": ..., "VQE Energy": ..., "Absolute Error": ..., "Optimizer Message": "...", "Quantum Comp Time": ..., }

示例

import numpy as np from unitarylab_algorithms import VQEAlgorithm # 使用自定义哈密顿量 H = np.array([[1, 0.5], [0.5, -1]]) algo = VQEAlgorithm() result = algo.run(n=2, layers=2, max_iter=150, hamiltonian=H) print(result['status'], result['VQE Energy'], result['Absolute Error'])

快速演示

from unitarylab_algorithms.quantum_machine_learning.vqe.algorithm import test test(n=2, layers=2, max_iter=150)

注意事项

  • 传入自定义哈密顿量时 n 会被静默覆盖:若 hamiltonianNone,代码会先校验并从矩阵维数推出真实量子比特数,然后执行 n = num_qubits,用户传入的 n 参数会被忽略而不会报错或警告——
  • normalize 参数只在 hamiltonian=None(内部随机生成分支)时才会被使用;若传入自定义哈密顿量,normalize 不产生任何效果。
  • parameters.json 中的 description 字段仍写着”寻找 2 量子比特 Ising 哈密顿量 H = Z0Z1 - 0.5X0 - 0.5X1 的基态能量”,但 run() 的默认行为其实是生成随机厄米矩阵(由 seed 决定),并非该固定 Ising 哈密顿量——parameters.json 描述已过期,不能作为默认行为的依据。
  • UI 默认值与 Python 默认值不一致parameters.jsonlayers 的默认值为 3,而 run() 签名的默认值为 layers=2;通过 Web UI 提交空表单与直接调用 VQEAlgorithm().run() 得到的层数并不相同。
  • status 恒为 'ok'(见包级提示),应改用 Optimizer Message 判断 COBYLA 是否真正收敛。

变分量子分类器(VQC)

背景

VQC 通过角度编码将经典特征映射到量子态中,然后用可训练拟设加 Pauli-Z 期望值观测量进行 3 分类。本实现固定应用于鸢尾花数据集(4 个特征、3 个类别),梯度通过手动实现的**参数漂移规则(Parameter Shift Rule)**逐参数计算(并非自动微分),使用 CrossEntropyLoss(对 10 倍缩放后的期望值 logits)训练。

导入

from unitarylab_algorithms import VQCAlgorithm

.run() 参数

def run(self, layers=3, epochs=20, lr=0.05, batch_size=16, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]
参数类型默认值说明
layersint3变分层数
epochsint20训练轮数(对完整训练集的遍历次数)
lrfloat0.05Adam 优化器学习率
batch_sizeint16小批量大小

量子比特数固定为 4(对应鸢尾花数据集的 4 个特征),不作为参数暴露。

返回值

{ "status": "ok", "circuit_path": "<vqc_algorithm_circuit.svg 路径>", "plot": [{"format": "svg", "filename": "<VQC_Metrics.svg 路径>"}], "circuit": <Circuit 对象>, "Final Loss": ..., "Final Accuracy": ..., "Quantal Computation Time (s)": ..., }

示例

from unitarylab_algorithms import VQCAlgorithm algo = VQCAlgorithm() result = algo.run(layers=3, epochs=20, lr=0.05, batch_size=16) print(result['status'], result['Final Accuracy'])

快速演示

from unitarylab_algorithms.quantum_machine_learning.vqc.algorithm import test test(layers=3, epochs=20, lr=0.05, batch_size=16)

注意事项

  • 返回字典中的输出键存在拼写问题:真实的输出键名为 "Quantal Computation Time (s)"(应为 “Quantum”),这是源码中的原样拼写,调用方按字段名取值时请使用这个确切(带拼写误差的)字符串,而非语义上”正确”的 "Quantum Computation Time (s)"
  • 量子比特数固定为 4(由鸢尾花数据集的特征数决定),无法通过参数调整为其他数据集。
  • _load_iris_data() 优先使用 sklearn.datasets.load_iris;若环境中未安装 scikit-learn,会退回到源码文件内嵌的鸢尾花数据固定副本(120 训练 / 30 测试样本),因此即使没有 scikit-learn 依赖算法也能运行,但退回路径下无法自定义数据集划分比例(内嵌数据固定 80/20 划分)。
  • 参数漂移梯度通过双重 for 循环对 theta 的每个分量分别做前向/后向偏移评估(共 次线路执行/参数更新),随层数和批大小增长计算开销线性上升。
  • __init__ 中固定调用 torch.manual_seed(42)np.random.seed(42),没有暴露 seed 参数。正常的“构造实例后立即调用 run()”路径中,初始参数与数据集划分均可复现——虽然 train_test_split 未显式传入 random_state,但它会使用刚被重置为 42 的 NumPy 全局随机状态;若在构造实例后、调用 run() 前有其他代码消耗该全局随机状态,数据集划分仍可能变化。因此当前实现依赖全局随机状态,可复现但不具备隔离性,且用户无法外部调整种子。
  • parameters.jsonlayers 默认值为 5,而 run() 签名默认值为 layers=3——同样存在 UI/Python 默认值不一致的情况。
  • status 恒为 'ok'(见包级提示)。

量子近似优化算法(QAOA)

背景

QAOA 是一种用于组合优化问题的变分算法。它交替应用编码目标函数的问题哈密顿量 (由图的每条边对应的 项构成)和由 旋转实现的混合层,共执行 layers 轮。本实现求解由边列表定义的图上的最大割问题,通过 COBYLA 优化

导入

from unitarylab_algorithms import QAOAAlgorithm

.run() 参数

def run(self, edges=None, n=6, layers=4, max_iter=100, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]
参数类型默认值说明
edgesList[Tuple[int,int]] | NoneNone图的边列表;为 None 时使用内置默认图 [(0,1),(1,2),(2,3),(3,0),(0,4),(1,5)]
nint6量子比特数(图的顶点数)
layersint4QAOA 演化层数
max_iterint100COBYLA 最大迭代次数

返回值

{ "status": "ok", "circuit_path": "<QAOA_Circuit.svg 路径>", "plot": [ {"format": "svg", "filename": "<QAOA_Convergence.svg 路径>"}, {"format": "svg", "filename": "<MaxCut_Solution.svg 路径>"}, ], "circuit": <Circuit 对象>, "Optimal bitstring": "...", "Max-Cut Value": ..., "Optimized Energy": ..., "Quantum Computation Time": ..., }

示例

from unitarylab_algorithms import QAOAAlgorithm edges = [(0, 1), (1, 2), (2, 3), (3, 0), (0, 4), (1, 5)] algo = QAOAAlgorithm() result = algo.run(edges=edges, n=6, layers=4, max_iter=100) print(result['status'], result['Optimal bitstring'], result['Max-Cut Value'])

快速演示

from unitarylab_algorithms.quantum_machine_learning.qaoa.algorithm import test test()

注意事项

  • QAOAAlgorithm.__init__ 中固定调用 np.random.seed(42)torch.manual_seed(42),未暴露 seed 参数;初始参数 initial_params = np.random.uniform(0, np.pi, 2*layers) 依赖该全局种子。
  • plot 字段包含 2 个条目(收敛曲线图 + 最大割结果图),调用方遍历 plot 时不应只取第一个元素。
  • 模块级 test() 函数自身默认 max_iter=60,与 .run() 方法签名的默认值 max_iter=100 不一致;而文件底部 if __name__ == "__main__": 块中又显式使用 max_iter=100。三处默认值并不统一,请以你实际调用的入口(.run() 还是 test())核对使用的默认值。
  • status 恒为 'ok'(见包级提示),应结合 Optimized Energy 与已知的图的精确最大割值比较来判断质量。

量子线路玻恩机(QCBM)

背景

QCBM 将参数化量子线路用作生成模型,训练 Born 概率分布 拟合目标分布。本实现的目标分布固定为 Bars-and-Stripes(BAS,条纹图案)分布,由 _get_bas_dist(n) 在内部计算生成(依据 自动推出最接近方形的 rows × cols 网格,枚举全行相同或全列相同的二进制模式作为”有效”状态,均匀赋予非零概率),不支持用户传入任意目标分布。损失函数为 KL 散度torch.sum(target * log((target+eps)/(curr+eps)))),通过参数漂移规则计算梯度。

导入

from unitarylab_algorithms import QCBMAlgorithm

.run() 参数

def run(self, n=4, layers=4, epochs=40, lr=0.1, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]
参数类型默认值说明
nint4量子比特数
layersint4变分线路深度
epochsint40训练迭代次数
lrfloat0.1Adam 优化器学习率

_validate_run_params() 会显式校验 n/layers/epochs 为正整数、lr 为正数,不满足时抛出 ValueError——这是本包中少数在 Python 层面做了真正入参校验的算法。

返回值

{ "status": "ok", "circuit_path": "<qcbm_algorithm_circuit.svg 路径>", "plot": [ {"format": "svg", "filename": "<QCBM_Loss.svg 路径>"}, {"format": "svg", "filename": "<QCBM_Distribution.svg 路径>"}, {"format": "svg", "filename": "<QCBM_Samples.svg 路径>"}, ], "circuit": <Circuit 对象>, "Final KL Loss": ..., "Quantum Computation Time": ..., }

示例

from unitarylab_algorithms import QCBMAlgorithm algo = QCBMAlgorithm() result = algo.run(n=4, layers=4, epochs=40, lr=0.1) print(result['status'], result['Final KL Loss'])

快速演示

from unitarylab_algorithms.quantum_machine_learning.qcbm.algorithm import test test(n=4, layers=4, epochs=40, lr=0.1)

注意事项

  • 目标分布固定为 BAS(Bars-and-Stripes)分布,由 n 通过 _get_bas_dist(n) 生成,不支持传入自定义目标分布。
  • 损失函数使用 KL 散度(见上方公式)。
  • plot 字段包含 3 个条目(损失曲线、分布对比图、采样网格图)。
  • QCBMAlgorithm.__init__ 固定调用 torch.manual_seed(42) / np.random.seed(42),未暴露 seed 参数。
  • status 恒为 'ok'(见包级提示),但本算法是本包中少数在入口处对参数做了真正校验(_validate_run_params)的算法,非法入参会直接抛出 ValueError 而不是静默产生错误结果。

连续变量量子神经网络(CVQNN)

背景

CVQNN 在**连续变量(CV)**量子计算范式下工作,使用光学模式而非量子比特,在截断 Fock 空间(维数为 cutoff)中通过位移(displacement)、压缩(squeezing)、分束器(beamsplitter)、旋转(rotation)和克尔非线性(Kerr)等算符(均以 torch.matrix_exp 实现)构造变分线路,训练用于二分类(MSELoss,标签映射到 )。

导入

from unitarylab_algorithms import CVQNNAlgorithm

.run() 参数

def run(self, x_train: np.ndarray, y_train: np.ndarray, n_layers: int = 2, cutoff: int = 6, epochs: int = 40, lr: float = 0.05) -> Dict[str, Any]
参数类型默认值说明
x_trainnp.ndarray— (必填)输入特征数组,形状 (N, 2)
y_trainnp.ndarray— (必填)标签数组(0/1)
n_layersint2变分 CV 层数
cutoffint6Fock 空间截断维数
epochsint40训练轮数
lrfloat0.05Adam 优化器学习率

注意:与本包其他算法不同,CVQNNAlgorithm.run() 没有 backend/device/dtype 参数——CV 模拟完全由自定义的 CVSimulator(基于 torch.matrix_exp 的稠密矩阵指数)实现,不经过 Circuit.execute() 后端调度。

返回值

{ "status": "ok", "circuit_path": "<cvqnn_algorithm_circuit.svg 路径>", "plot": [{"format": "svg", "filename": "<CVQNN_Metrics.svg 路径>"}], "circuit": <Circuit 对象>, "Final Loss": ..., "Final Accuracy": ..., "Total Computation Time (s)": ..., }

示例

import numpy as np from unitarylab_algorithms import CVQNNAlgorithm # 生成简单的二维数据集 x_train = np.random.randn(50, 2) y_train = (x_train[:, 0] + x_train[:, 1] > 0).astype(int) algo = CVQNNAlgorithm() result = algo.run(x_train=x_train, y_train=y_train, n_layers=2, cutoff=6, epochs=30) print(result['status'], result['Final Accuracy'])

快速演示

from unitarylab_algorithms.quantum_machine_learning.cvqnn.algorithm import test test(n_layers=2, cutoff=6, epochs=30, lr=0.05)

注意事项

  • 保存的电路图并不反映训练后的门参数save_circuit() 所绘制的 Circuit 来自 _build_circuit(),该方法仅用 qc.ry(0.0, ...)/qc.rx(0.0, ...)/qc.rz(0.0, ...)占位角度恒为 0 的门搭建拓扑用于展示结构,真正参与训练与推理的连续变量参数(sq_rdisp_rrot_thetakerr_kbs_theta)存在于独立的 CVClassifier/CVSimulator(基于原始 torch 张量运算)中,并不写回到导出的电路图上。因此 circuit_path 对应的 SVG 只能体现线路结构,不能体现训练得到的实际参数值。
  • 增大 cutoff 可以提升近似精度,但内存占用(cutoff × cutoff 稠密矩阵指数)随之增长,标准硬件上不建议超过 12parameters.json 中 UI 上限即为 12)。
  • CV 框架对光学量子系统建模,与基于量子比特的线路在本质上不同,x_opn_op 等算符定义在截断 Fock 基下,cutoff 过小会引入截断误差。
  • CVQNNAlgorithm.__init__ 固定调用 torch.manual_seed(42)np.random.seed(42) 并设置 torch.set_default_dtype(torch.float64),未暴露 seed 参数。
  • 模块级 test() 函数自身默认 epochs=30,与 .run() 方法签名默认值 epochs=40 不一致;test() 内部数据集优先用 sklearn.datasets.make_moons 生成,若不可用则退回到源码内嵌的固定副本(40 个样本)。
  • status 恒为 'ok'(见包级提示)。

费米-哈伯德模型 VQE(Fermi-Hubbard VQE)

FermiHubbardVQEAlgorithm 位于 fermi_hubbard_vqe/algorithm.py

背景

该算法针对一维开放边界费米-哈伯德模型L 个格点,最近邻跳跃系数 t、同格点相互作用强度 U、塞曼磁场系数 B):

  1. 通过 unitarylab.library.fermi_hubbard.fermi_hubbard_pauli 模块构建费米子哈密顿量及其经 Jordan-Wigner 变换后的 Pauli 字符串表达式;
  2. pauli_ground_state() 做稠密精确对角化,获得精确基态能量作为参照;
  3. 内部复用 VQEAlgorithm(见上文”变分量子特征求解器”一节)执行 VQE 优化,求得该 Pauli 哈密顿量的近似基态能量;
  4. 可选地对优化后线路测量总自旋磁矩。

端序(Endianness)适配

fermi_hubbard_pauli 生成的 Pauli 表达式采用的量子比特编号约定,与 UnitaryLab 线路模拟器的最低位比特(q0)为最低有效位约定相反。因此源码在把 Pauli 哈密顿量矩阵交给 VQEAlgorithm 之前,会调用内部的 _bit_reverse_hamiltonian() 对矩阵的行列做比特翻转置换,并做以下自检(任一项不满足即抛出异常,不会静默产生错误结果):

  • 往返一致性:翻转两次应还原原矩阵,误差需 < 1e-12(否则抛出 ValueError);
  • 谱一致性:翻转前后矩阵的特征值谱应一致,误差需 < 1e-10(否则抛出 ValueError);
  • 环境自检 _check_unitarylab_environment():进程内首次调用时执行 Circuit(2).x(0) 并检查末态峰值确实落在索引 1(即验证 q0 是最低有效位这一假设本身成立),若当前 UnitaryLab 版本的比特序约定发生变化则抛出 RuntimeError

导入

from unitarylab_algorithms import FermiHubbardVQEAlgorithm

.run() 参数

def run(self, params: Dict[str, Any] | str | None = None, *, L: int = 2, t: float = 1.0, U: float = 4.0, B: float = 1.5, layers: int = 5, max_iter: int = 1000, seed: int = 7, measure_shots: int = 10000, backend: str = "torch", device: str = "cpu", dtype = np.complex128) -> Dict[str, Any]
参数类型默认值说明
paramsdict | str | NoneNone可选:一次性以字典或 JSON 字符串传入下列关键字参数(详见下方说明),覆盖对应的关键字默认值
Lint2一维格点数(开放边界)
tfloat1.0最近邻跳跃系数
Ufloat4.0同格点相互作用强度
Bfloat1.5塞曼磁场系数
layersint5VQE 拟设变分层数
max_iterint1000COBYLA 最大迭代次数
seedint7VQE 初始参数随机种子
measure_shotsint10000优化后线路测量总自旋磁矩的采样数;设为 0 可跳过该测量阶段

params 外,其余参数均为仅限关键字参数(签名中 * 之后)。若提供 params,其中的键会覆盖对应关键字的默认值;layers/max_iter/measure_shots 还分别兼容别名键 vqe_layers/vqe_max_iter/measurement_shots

返回值

{ "status": "ok", "circuit_path": "<Fermi_Hubbard_VQE_Circuit.svg 路径>", "plot": [ {"format": "svg", "filename": "<Fermi_Hubbard_VQE_Convergence.svg 路径>"}, {"format": "npy", "filename": "<Fermi_Hubbard_VQE_Parameters.npy 路径>"}, ], "circuit": <Circuit 对象>, "Exact Energy": ..., "VQE Energy": ..., "Absolute Error": ..., "Circuit Energy": ..., "Number of Qubits": ..., "Optimizer Evaluations": ..., "Optimizer Converged": ..., "Optimizer Message": "...", "VQE Runtime": ..., "Total Runtime": ..., "Qubit Mapping": ..., "Fermionic Hamiltonian": "...", "Pauli Hamiltonian": "...", # 仅当 measure_shots > 0 时追加: "Measured Magnetic Moment": ..., "Magnetic Moment Standard Errors": ..., "Measurement Total Shots": ..., }

示例

from unitarylab_algorithms import FermiHubbardVQEAlgorithm algo = FermiHubbardVQEAlgorithm() result = algo.run(L=2, t=1.0, U=4.0, B=1.5, layers=5, max_iter=1000, measure_shots=10000) print(result['status'], result['VQE Energy'], result['Exact Energy'])

也可以用一个参数字典整体传入(与 params=None 时逐关键字传参等价):

algo = FermiHubbardVQEAlgorithm() result = algo.run(params={"L": 3, "U": 6.0, "vqe_layers": 6})

快速演示

from unitarylab_algorithms.quantum_machine_learning.fermi_hubbard_vqe.algorithm import test test(L=2, t=1.0, U=4.0, B=1.5, layers=5, max_iter=1000, seed=7, measurement_shots=10000)

注意事项

  • 最佳观测参数追踪:源码内部用 _TrackingVQEAlgorithmVQEAlgorithm 的子类)重写 _expectation(),在 COBYLA 每次目标函数求值时记录能量历史与迄今为止能量最低的参数组合(best_energy/best_parameters),因为 COBYLA 收敛时的最终迭代点未必是历史最优点——最终返回的 VQE Energy/Circuit Energy 来自这个”历史最优”,而非优化器返回的最后一次迭代。
  • 多重正确性自检、失败即抛异常:除端序自检外,run_pauli_vqe() 还会检查:VQE 内部调用是否报告 status == 'ok'(否则 RuntimeError)、是否发生过零次目标函数求值(否则 RuntimeError)、best_parameters 是否存在且能量有限(否则 RuntimeError)、VQE 报告的精确能量是否与 Pauli 哈密顿量谱一致(误差 < 1e-10,否则 ValueError)、重新在优化线路上计算的能量是否与记录的最优能量一致(误差 < 1e-8,否则 RuntimeError)、以及最优能量是否违反变分法下界(< 精确能量 - 1e-8ValueError,提示可能是端序问题)。因此该算法一旦正常返回(不抛异常),其数值一致性比包内其他算法更有保障;但这也意味着它比其他算法更容易在输入或环境异常时直接抛出异常终止,而非返回一个 status: 'failed' 的结果字典。
  • params 与逐关键字参数可以混用,但 params 中的键始终优先覆盖对应关键字的默认值(不会覆盖你显式传入的同名关键字实参之外的其他关键字)。
  • plot 字段的第二项是 .npy 文件(优化后 VQE 参数的 NumPy 数组),并非图片,前端渲染或下载逻辑需要按 format 字段区分处理,不能假设 plot 列表内全部是可直接显示的图像。
  • measure_shots=0 时会跳过磁矩测量阶段,返回字典中不会包含 Measured Magnetic Moment 等三个测量相关键——调用方应先判断这些键是否存在,而非假定其总是出现。

版本引用

from unitarylab_algorithms import ( VQEAlgorithm, VQCAlgorithm, QAOAAlgorithm, QCBMAlgorithm, CVQNNAlgorithm, FermiHubbardVQEAlgorithm, )
最后更新于