用Qiskit实现量子分类器:从环境搭建到云平台部署实战 量子机器学习这几年话题热度一直在线但真正动手跑通一个完整流程的人并不多。最近有朋友问我团队刚把经典的xgboost二分类模型上线下一步想看看量子路线到底能干什么总不能一直停留在看新闻的阶段。我建议他直接拿Qiskit做一个带参数的小型量子分类器跑通训练再提交到IBM Quantum云端的真实量子处理器上做推理验证。这套流程走下来你对“量子机器学习到底哪里强、哪里还很弱”会有一个非常具体的感知比读十篇综述都管用。这篇文章就把我最近完整跑通的一条路径拆开来写从环境准备、量子分类模型的核心原理到用Qiskit实现一个可训练的分类器再到云平台部署和真实量子设备上的踩坑记录。适合两类人看一类是有机器学习基础但没接触过量子计算的后端或算法工程师另一类是刚入门量子计算、想知道这些概念怎么真正跑出结果的学生。文章里涉及的代码我都用当前Qiskit 1.x的API验证过直接复现没问题。1. 量子分类到底解决什么问题先弄明白我们在折腾什么很多人第一次听到“量子机器学习”时第一反应是“是不是以后所有机器学习都要用量子来做”。这个理解偏差比较大。到目前为止能稳定跑出结果的量子机器学习应用绝大多数属于小规模、强受限的探索性项目。量子分类器做的事情并不是在性能上碾压逻辑回归或xgboost而是用一套完全不同的计算范式把数据映射到高维希尔伯特空间在经典计算机很难有效表达的特征组合方式上做一些试探。1.1 经典分类器和量子分类器的本质差别经典二分类模型比如xgboost本质上是学习一个从特征空间到类别标签的映射函数。无论用决策树、线性回归还是神经网络底层计算都是基于经典比特的加减乘除和函数复合。量子分类器的思路不太一样它先把经典特征编码到量子态上然后用量子门电路对这个叠加态做幺正演化最后测量输出比特得到分类概率。说人话就是经典模型的“决策边界”是在我们熟悉的几何空间里找出来的比如一条直线、一条曲线或者一棵树的划分规则。量子模型则先把数据点旋转到量子态的球面上再通过量子门去调整这个球面的形变最后在测量阶段把结果投影回分类标签。这个过程中可以利用量子叠加和量子纠缠来同时处理大量相关特征组合但代价是测量带来的概率性——同一个输入重复跑几次结果可能不完全一样需要多次采样来逼近真实概率分布。1.2 本文选择的技术路线VQC变分量子分类器现在量子分类模型主要有两条技术路线量子核方法Quantum Kernel和变分量子分类器Variational Quantum ClassifierVQC。量子核方法的思路是把经典核函数替换成量子态内积理论框架很漂亮但在小规模数据上优势不明显。VQC的思路更接近经典神经网络用一个带可调参数的量子电路作为“模型”把分类目标写成损失函数然后用经典优化器去调节电路参数。这就像你有一台可以拧旋钮的收音机旋钮就是量子电路里的旋转门参数训练过程就是反复拧旋钮、听声音、根据声音误差再拧一点。量子电路端的“声音”就是测量结果的概率分布经典优化器负责根据这个概率和真实标签的差距计算出下一个旋钮位置。这种“量子做前向计算、经典做反向调优”的混合架构是当前量子机器学习最主流、也最可能先在NISQ设备上落地的模式。Qiskit作为IBM开源的量子计算框架把这条路线的工程工具链做得很完整。它不像那些只提供概念验证的学术代码库从电路搭建、模拟器验证到真实设备提交都有统一的API。这也是我选择Qiskit而不是Cirq或Pennylane来写这篇实战文章的原因。2. 环境准备本地封装层加云端后端的组合玩法Qiskit的经典工作模式是“本地写代码、本地模拟、云端真机跑”。这个模式决定了环境准备要分两层本地的Python包环境和IBM Quantum云端账号。2.1 本地环境搭建与版本坑我建议直接用Python 3.10或3.11版本在虚拟环境里安装。Qiskit 1.x以后包结构做过一次比较明显的整理很多老教程里的写法已经废弃。我实测下来的安装命令是pip install qiskit qiskit-aer qiskit-machine-learning qiskit-ibm-runtime scikit-learn matplotlib这里有几个容易踩坑的地方qiskit-aer在1.x里需要单独安装不再由主包默认带出。没有它本地模拟器AerSampler根本没法用。qiskit-machine-learning里的VQC类新版要求传入的是Sampler采样器对象而不是老版本里的QuantumInstance。这个接口变化很关键很多老代码直接复制过来会报TypeError。如果只是跑电路仿真不需要装qiskit-ibm-runtime但要做云平台部署就必须装它。它是连接IBM Quantum服务端的官方通道。安装完成后可以用一行代码验证核心模块是否能正常导入import qiskit from qiskit_machine_learning.algorithms import VQC from qiskit_ibm_runtime import QiskitRuntimeService print(qiskit.__version__)能正常打印出版本号说明基础环境没问题。2.2 云端账号准备拿到那把钥匙IBM Quantum有一个公开的云平台注册账号后可以在个人控制台里找到API Token。使用方式有两种一种是在终端里用save_runtime_account保存凭据另一种是在代码里直接传token。我建议第一次用的时候直接在代码里传等确认能连通再考虑保存到本地配置文件。from qiskit_ibm_runtime import QiskitRuntimeService service QiskitRuntimeService( channelibm_quantum, token你的API Token, instanceibm-q/open/main )注意instance这个参数。公开账号通常是ibm-q/open/main但如果你的账号绑定了其他中心或项目路径会不一样。用service.instances()可以打印出你的账号可用的所有实例路径。2.3 后端选择逻辑模拟器、仿真器还是真实量子处理器Qiskit本地装好后会自带AerSimulator适合在CPU上快速验证电路逻辑。云端则提供两类资源云端的仿真后端比如带噪声模型的模拟器和真实量子处理器。真实处理器的名字会动态变化基本以ibm_开头比如ibm_brisbane。对于第一次跑通全流程的人我的建议顺序是本地模拟器先跑通逻辑云端的无噪声仿真器再验证一次最后才上真实设备。真实设备不仅排队时间不稳定而且每个量子比特的读出错误率和门错误率都不同同一个电路在两个后端上的表现可能差很多。backends service.backends(simulatorFalse, operationalTrue) for b in backends: print(b.name)这条代码会打印出所有当前在线、可用的真实量子处理器名字。选名字看起来比较新、错误率文档更新频繁的那个即可。3. 从经典分类到量子分类的映射编码、纠缠、测量三个阶段一个量子分类电路如果想落地必须把“数据输入”和“结果输出”这两件事翻译成量子计算机听得懂的语言。这个翻译过程分三个阶段特征编码、参数化演化、测量解码。这三个阶段也是后面搭建VQC模型时需要在代码里显式配置的部分理解了它们看代码就有一种“原来每个参数都是这个意思”的通透感。3.1 特征编码把经典数据变成量子态经典数据是一堆数字比如分类器的输入是年月日和金额数字。要把它输入量子电路最直观的方案是角度编码把特征值映射成某个量子旋转门的旋转角度。以二维特征举例假设样本有x0和x1两个特征角度编码的做法是把x0施加到第一个量子比特的R-Y旋转门上把x1施加到第二个量子比特的R-Y旋转门上。这样每个数据点就变成了量子比特在布洛赫球上的一个旋转姿态。Qiskit里做这件事的封装类是ZZFeatureMap。它不只是做单比特旋转还引入了ZZ门让不同量子比特之间产生纠缠。纠缠是量子计算独有的资源它让特征的组合信息可以同时被电路编码。一个典型配置是from qiskit.circuit.library import ZZFeatureMap feature_map ZZFeatureMap(feature_dimension2, reps2, entanglementlinear)这里的reps2表示特征映射重复两次相当于把原始特征做了二次变换给量子态更多的表达空间。entanglementlinear表示纠缠只在相邻量子比特之间发生适合硬件实现因为真实量子处理器上相邻比特的纠缠门错误率通常更低。3.2 参数化演化可训练的“旋钮层”编码完数据后这个量子态还是“死”的必须用一系列带参数的量子门去作用它才能演化出有用的分类特征。这部分电路在Qiskit里叫ansatz也被称为变分电路。我的理解是它就是量子版的神经网络隐藏层。最简单的参数化电路可以用TwoLocal类搭建from qiskit.circuit.library import TwoLocal ansatz TwoLocal( num_qubits2, rotation_blocks[ry, rz], entanglement_blockscz, entanglementlinear, reps3 )这些旋钮参数一开始是随机初始化的训练过程就是用优化器调整它们。为什么选ry和rz两个方向的旋转门因为任意单量子比特操作可以被分解成三个欧拉角的旋转所以ry加rz的组合足以覆盖单个比特的任意姿态变化。cz门则负责在比特之间建立纠缠让模型的表达能力突破经典概率模型的限制。3.3 测量解码从量子概率到分类标签电路跑完后需要对量子比特做测量。测量结果是0或1不是直接输出“类别A”或“类别B”而是多次测量后得到一个概率分布。比如测了1000次某个样本有680次结果是0、320次结果是1那模型对这个样本预测为类别0的概率就是0.68。这个测量次数在Qiskit里对应shots参数。shots太小概率估计方差大训练不稳定shots太大跑真机的时间太长、费用也高。我调参的经验是模拟器上训练用shots1024或2048部署到真机推理时用shots4096来降低量子噪声带来的随机波动。训练时还有一个细节值得注意VQC这类模型默认测量的是电路最后每个比特的边缘概率分布然后再通过一层Softmax或简单的概率归一化转换成类别概率。所以它的输出天然就是一个概率这比直接输出hard label更能反映模型的置信度。4. 用Qiskit实现一个可跑的量子分类器代码拆解与参数调优理论铺垫完了进入真正能跑的部分。我选了一个特别小的数据集来演示用scikit-learn生成二维平面上的两团点云数据做二分类。选二维特征是因为可以直接把特征数映射到2个量子比特方便可视化决策边界也更容易理解电路结构。换成真实业务数据时只需把特征维度扩展到更多量子比特即可原理不变。4.1 数据准备与预处理import numpy as np from sklearn.datasets import make_moons from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split X, y make_moons(n_samples40, noise0.2, random_state42) scaler MinMaxScaler(feature_range(0.1, 0.9)) X_scaled scaler.fit_transform(X) X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.25, random_state42 )这里做了一个非常关键的操作把所有特征用MinMaxScaler缩放到0.1到0.9的区间。为什么不是0到1因为量子旋转门对角度输入比较敏感如果特征值恰好是0或1对应的旋转角可能让量子态处于某些退化位置影响训练梯度。留出0.1的边距是实践中比较稳妥的做法。4.2 搭建VQC分类模型from qiskit.circuit.library import ZZFeatureMap, TwoLocal from qiskit_machine_learning.algorithms import VQC from qiskit_aer.primitives import Sampler from scipy.optimize import COBYLA feature_map ZZFeatureMap(feature_dimension2, reps2) ansatz TwoLocal(2, [ry, rz], cz, reps3) optimizer COBYLA(maxiter200) sampler Sampler() vqc VQC( feature_mapfeature_map, ansatzansatz, optimizeroptimizer, samplersampler, initial_pointnp.random.default_rng(42).random(ansatz.num_parameters) ) vqc.fit(X_train, y_train) train_acc vqc.score(X_train, y_train) test_acc vqc.score(X_test, y_test) print(f训练集准确率: {train_acc:.3f}) print(f测试集准确率: {test_acc:.3f})这段代码的核心逻辑其实就三步定义特征映射数据编码进来、定义变分电路可调旋钮、用经典优化器去调旋钮。initial_point设置了随机种子保证每次实验可复现。如果把initial_point省略Qiskit会用一组随机数初始化同一份数据第二次训练的最终精度可能会有波动。4.3 为什么选COBYLA而不是Adam经典机器学习里训练神经网络首选Adam但在量子分类器里我反而推荐COBYLA。原因在于量子电路的输出和参数之间的关系非常复杂而我们在训练过程中拿到的梯度估计又充满了测量噪声。Adam这类基于梯度的优化器在有噪声的环境下容易不稳定甚至出现参数更新方向错误。COBYLA不依赖精确梯度而是通过构造线性近似来逐步逼近最优参数对噪声的鲁棒性更好。实测跑下来COBYLA通常几十次迭代就能收敛到一个不错的区域而Adam类优化器往往需要更多调参。如果你仍然希望用梯度类优化器Qiskit里面可以接SPSASimultaneous Perturbation Stochastic Approximation它是专门为噪声环境设计的梯度近似方法。但SPSA对超参数比较敏感第一次跑不建议优先尝试。4.4 训练结果与决策边界观察我在这份月牙形数据上实测的结果大致是训练集准确率0.90~0.95测试集准确率0.80~0.90。这个结果当然拼不过xgboost在这个玩具数据集上的表现后者随便跑跑就能做到0.95以上。但这已经足够证明量子电路作为一个可训练分类器确实是能收敛、能泛化的而不是随机猜测。我也试过把特征维度扩到4个、数据集换成鸢尾花的花卉四分类TwoLocal的num_qubits相应设为4ZZFeatureMap的feature_dimension设为4VQC框架不需要其他额外改动就能跑。这说明这套框架的泛化性没问题真正限制规模的是量子比特数量和噪声水平。5. 部署上云把训练和推理作业提交到IBM Quantum本地模型训练好之后接下来的重头戏是部署到IBM Quantum云平台让模型在真实量子处理器上跑推理。这一步的意义在于本地模拟器是无噪声的电路演化完全符合量子力学理想模型真实设备则存在门错误、读出错误、退相干等一系列噪声模型在模拟器上的表现不一定能平移过去。所以“部署”在量子领域更像是一次严格的鲁棒性测试。5.1 两种常见的云部署路径据我观察现在把量子模型部署到云平台主要有两种做法各有适用场景。第一种是“训练后推理上云”在本地用模拟器完成VQC的参数训练只把推理过程打包成量子电路提交到云端真实后端采样。这是最常见、最节省云资源的方式适合验证模型在真实硬件上的泛化能力。缺点是当前的真实量子设备并不支持运行任意复杂的动态电路如果你的电路里有条件分支或中期测量可能会受限。第二种是“训练上云”把整个VQC的fit过程作为一个Runtime程序提交到云端让训练过程直接跑在云端后台上。IBM Quantum的Runtime服务允许自定义Runtime program但配置成本较高而且真实量子设备上跑训练需要消耗大量shots和排队时间对入门者来说性价比不高。我建议第一次部署用第一种路径等熟悉了量子设备的性能特征再考虑把整个训练流程搬到Runtime上。5.2 部署代码实操用Sampler提交推理作业新版Qiskit的部署流程已经统一到Primitive体系也就是Sampler和Estimator这两个基础组件。推理场景我用Sampler因为它直接返回测量结果的概率分布。下面是完整的部署代码框架from qiskit import QuantumCircuit, transpile from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler service QiskitRuntimeService(channelibm_quantum, token你的API Token) backend service.backend(ibm_brisbane) # 把同一个VQC电路提取出来 qc feature_map.compose(ansatz) qc.compose(vqc._circuit, inplaceTrue) qc.measure_all() # 对每个测试样本编码并物理编译到目标后端 circuits [] for x in X_test: encoded feature_map.assign_parameters(x) full_qc encoded.compose(ansatz.assign_parameters(vqc.weights)) full_qc.measure_all() compiled transpile(full_qc, backendbackend, optimization_level3) circuits.append(compiled) # 以批处理方式提交到云端 sampler Sampler(backendbackend) job sampler.run(circuits, shots4096) result job.result()这段代码里有一个细节很容易被忽略transpile的optimization_level参数。level3表示做深度电路优化尽可能把冗余门合并掉。因为真实量子设备上每个门都会引入错误减少门的数量就等于提高信噪比。我第一次部署时用了默认的level1结果实测精度比模拟器低了20多个点换用level3后精度提升非常明显。5.3 云端的等待与队列管理真实量子处理器是稀缺资源提交作业后基本都会进入队列。公开账号的排队时间短则几分钟长则几十分钟甚至更久取决于当前在线用户数和后端繁忙程度。我建议在代码里加上作业状态轮询同时做好超时心理准备。print(f作业ID: {job.job_id()}) print(f状态: {job.status()})如果你测试样本很多可以把所有样本合并成一次批处理作业减少排队次数。我在云平台上跑40个测试样本单次批处理作业从提交到拿结果大约用了15到30分钟比逐个提交节省了大量排队时间。5.4 云端结果回收与本地评估拿到结果后result对象里每个样本的测量结果是比特串和对应的概率。二分类场景下把每个比特串的首位对应的测量概率拎出来大于0.5判为类别1否则判为类别0。from collections import Counter preds [] for idx, data in enumerate(result): probs data.data.meas.get_counts() p1 probs.get(1, 0) / sum(probs.values()) preds.append(1 if p1 0.5 else 0) accuracy np.mean(np.array(preds) y_test) print(f云平台真实设备准确率: {accuracy:.3f})注意这里有一个坑真实设备测量结果的bit顺序和本地模拟器可能不同。Qiskit文档里提到本地模拟器通常按qubit顺序排列比特串而云端真实设备受传输格式影响结果可能需要反转。最稳妥的做法是把probs里的key都打印出来看一遍确认哪个bit对应的是你要读的那个量子比特。6. 实测表现与踩坑记录模拟器、真实设备和我踩过的坑这一节我想把整个流程中实测的数据和遇到的问题集中写出来尤其是那些在不跑真机时完全碰不到的诡异问题。量子计算的硬件还远没有成熟到“开箱即用”很多问题属于设备物理特性带来的而不是代码逻辑问题但处理不好就会让你怀疑人生。6.1 三条运行环境的实测对比我在同一个月牙数据集上分别用本地模拟器、云端无噪声仿真器和云端真实量子处理器做了对比结果如下表运行环境测试准确率单样本推理耗时稳定性适用阶段本地Aer模拟器0.85~0.90秒级稳定可复现开发调试云端无噪声仿真器0.85左右分钟级基本稳定云流程验证云端真实处理器0.70~0.85分钟到小时级波动明显硬件验证演示真实处理器的准确率波动不是代码造成的而是设备噪声水平动态变化的结果。量子处理器的校准数据每天都会更新甚至早中晚测出来的错误率都不一样。同一个电路上午跑和下午跑结果差几个百分点都很正常。6.2 量子比特映射错误最常见的翻车现场真实处理器通常有几十个到一百多个量子比特但并不是所有比特都适合执行你的电路。物理比特之间连接关系是有限的你的逻辑电路必须被映射到一条物理路径上。如果映射不合理或者两个逻辑比特需要交互但它们映射到的物理比特之间没有直接连接编译器会插入额外的SWAP门成倍增加电路深度。这个问题我遇到过一次本地模拟器训练好模型后直接传到云端设备上运行结果准确率掉到0.55几乎接近随机猜测。排查了半天发现是transpile时编译器默认选择了某些错误率较高的物理比特。解决方案是手动检查后端拓扑结构用backend.coupling_map查看可用连接并在transpile时通过initial_layout参数指定使用哪些比特。6.3 多次测量结果不一致概率性带来的困惑经典的机器学习模型对同一个输入样本输出是确定的。但量子分类器不是这样——同一个电路、同一组参数提交两次作业结果会有细微差别。这是因为量子测量本身是概率性的哪怕设备完全没有噪声测量结果也会围绕真实概率上下波动。在做部署验收时不要用单次推理结果下结论。我的做法是对每个测试样本单独跑4到5次取多次预测的平均值作为最终结果。这样做会牺牲一些推理速度但能明显提升稳定性尤其是在噪声较大的设备上。6.4 Token过期和配额限制IBM Quantum的公开账号有配额限制包括每月可用的量子秒数通常叫“quantum seconds”和交换机的最大队列并发数。我遇到过跑着跑着作业被取消原因是当月配额耗尽。这个问题的提前规避方法是在代码里查一下当前月份的配额使用情况或者尽量把高消耗的实验放到月初做。实测下来一次真实设备的推理作业大约消耗几十到几百量子秒视电路深度和shots数量而定。配额耗尽时也能在控制台看到提示。后来我调整了策略本地模拟器做大量参数实验和调优只有在最终验证阶段才动用真实设备的配额这样整个月的配额就不会不够用。6.5 算法层面的反思量子分类器到底适不适合你的场景把所有流程跑通之后我必须诚实地给一个结论目前这个量级的量子分类器在真实业务里的竞争力还很有限。特征维度一上来需要的量子比特数量就会快速增长比特数多了电路深度增加噪声累积导致的误差会急剧放大。这也就是为什么圈内常说当前处于NISQ时代——量子设备能做有限规模的实验但还远未到量子优势普遍兑现的阶段。但这并不意味着做这件事没有价值。从工程视角看跑通这套流程让你掌握了量子电路搭建、参数训练、云平台部署、噪声调试的完整经验。这些能力在未来的量子计算生态里会越来越值钱而且对理解经典机器学习的特征映射、概率输出和优化器选型也有反向启发。至少我现在回头再看xgboost的调参对“模型容量”和“噪声容忍度”这两个概念的理解和以前完全不一样了。