量子机器学习这几个字在我刚开始接触的时候最大的障碍并不是数学而是“想跑通一个实验却不知道从哪一行代码开始”。你搜到的资料要么是纯理论推导要么直接甩一个几十步的 notebook中间缺了太多“为什么这样做”的环节。这篇文章我想认真拆一个能直接跑起来的项目用 Qiskit 实现量子支持向量机QSVM在经典 Iris 鸢尾花数据集上完成二分类。从环境搭建到特征映射从量子核函数到最终的精度评估全部用代码说话并且把我在实际跑实验时踩过的坑一并写出来。适合的读者你已经写过 Python用过 sklearn了解 SVM 的基本概念但对量子计算只有模糊印象。读完之后你可以亲手把这条链路跑通再根据自己的数据替换特征映射和分类器。量子计算真正难的不是那些好看的公式而是文档里不会告诉你的版本差异和噪声带来的各种诡异现象——这部分我会讲得比官方示例更直白。1. 先对齐战场QSVM 到底在解决什么问题1.1 经典SVM的核函数困境做分类任务时SVM 是我用得很顺手的一个模型。它的核心思想很清晰如果数据在当前维度下线性不可分就通过一个核函数把它映射到更高维的空间在高维空间找一个能把两类样本分开的超平面。问题是核函数的选择依赖经验。RBF 核、多项式核、sigmoid 核各有各的适用场景同一个数据集换一个核函数精度可能从 0.8 跳到 0.95。你很难事先判断哪个核最合适很多时候只能靠交叉验证去试本质上是碰运气。更麻烦的是经典核函数的表达能力是有限的。RBF 核本质上衡量的是两个样本在欧氏空间里的距离相似度它对数据的内在结构感知比较单一。当数据存在周期性、对称性或者需要跨维度的特征交互时经典核往往需要精心设计特征工程才能救回来。量子机器学习提供了一个不同的思路不要让核函数为人脑服务而是让量子线路替我们生成特征空间。1.2 量子核用量子态做特征映射量子核方法的基本逻辑是这样的每个样本 x 不再直接喂给 SVM而是先通过一个量子特征映射线路feature map编码成一个量子态 |φ(x)然后计算两个量子态的内积平方 |φ(x_i)|φ(x_j)|^2 作为核函数值。这个值在物理上就是“态保真度”state fidelity量子计算机可以直接用线路测量算出来。从经典机器学习角度看我们其实是在做一个隐式的特征映射原始样本 x 被映射到了一个由量子比特张成的希尔伯特空间里。量子态空间的规模非常惊人。n 个量子比特构成的态空间维度是 2^n20 个 qubit 时就已经是百万维级别30 个 qubit 时超过十亿维。经典核函数大多是把数据映射到有限维或者可数的无限维空间而量子特征空间的理论容量完全不在一个量级上。更重要的一点是量子特征映射线路里可以加入纠缠门。纠缠意味着不同特征维度之间不再是简单的加权组合而是产生了经典相关性难以模拟的联合分布。这是量子核与经典核在结构上的本质差异。1.3 为什么QSVM是量子机器学习最合适的入门项目和量子神经网络相比QSVM 有一个非常大的优势它把量子部分和经典部分拆得很干净。量子线路只负责计算核矩阵训练分类器这件事还是交给 sklearn 的 SVC 来做。也就是说你想验证量子特征映射到底有没有用可以直接和经典核跑同一个 SVM 框架做对比变量控制得很清晰。我建议所有想入门量子机器学习的朋友第一个实战项目就选 QSVM。理由有三个第一代码链路短不需要自己去写梯度计算和参数更新第二核矩阵是中间产物可以拿出来检查、可视化、调试第三它天然适合小数据集而小数据集恰恰也是当前量子硬件能处理的规模。2. 环境准备与第一个量子线路2.1 安装与版本选型跑实验之前先把环境讲清楚因为在 Qiskit 1.0 之后API 有过一轮比较大的变动网上很多教程已经过时了。我用的环境是 Python 3.11Qiskit 1.1.xqiskit-machine-learning 0.7.xqiskit-aer 0.15.x。创建虚拟环境后一次性安装所有依赖pip install qiskit qiskit-machine-learning qiskit-aer scikit-learn numpy这里最需要提醒的是Qiskit 1.0 已经把BasicAer移除了。你如果在老教程里看到from qiskit import BasicAer或者from qiskit.providers.aer import AerSimulator这样的写法可以直接跳过。现在统一使用新的 Primitive 接口即Sampler和Estimator后端选择上用AerSimulator或者 IBM Quantum 的SamplerV2。版本不对的典型报错长这样ModuleNotFoundError: No module named qiskit.providers.basicaer ImportError: cannot import name QuantumInstance from qiskit.utils遇到这一类错误先别怀疑自己的代码先检查 qiskit 版本。2.2 第一个量子线路验证环境安装完成之后跑一个最简单的 Bell 态线路来验证环境。Bell 态的意思是两个量子比特先做 Hadamard 门使第一个 qubit 进入叠加态再用 CNOT 门把两个 qubit 纠缠起来测量结果应该是 00 和 11 各占一半。from qiskit import QuantumCircuit from qiskit.primitives import Sampler qc QuantumCircuit(2) qc.h(0) qc.cx(0, 1) qc.measure_all() sampler Sampler() result sampler.run([qc], shots1024).result() counts result[0].data.meas.get_counts() print(counts)运行结果大概是{00: 512, 11: 512}虽然每次跑出来的具体数字会有浮动但 00 和 11 各占约一半这个规律是稳定的。这一步跑通说明安装环境没问题后面就可以放心构建更复杂的线路了。2.3 特征映射从经典数据到量子态量子计算机没有办法直接读取浮点数所以要把每个样本编码到量子态上。最直观的编码方式是角度编码把特征缩放到一个合适的区间然后作为旋转门的旋转角参数。Qiskit 里最常用的就是ZZFeatureMap。它在角度编码的基础上加了对角纠缠门让不同特征维度之间产生相互作用。构造一个两维的特征映射非常简单from qiskit.circuit.library import ZZFeatureMap feature_map ZZFeatureMap(feature_dimension2, reps2, entanglementfull) print(feature_map.draw())你能看到这个线路包含 H 门、RZ 旋转门和 CNOT 纠缠门。其中的reps参数控制线路的重复次数值越大特征映射的表达能力越强但线路越深越容易受噪声影响。实际使用中2 是一个比较稳妥的起点。量子特征映射的思路可以这样理解经典数据是低维空间里的点量子特征映射把这些点投射到一个超高维的量子态空间而投影的方式取决于线路结构。换一个角度说QSVM 里的量子线路本质上是替代了经典机器学习里的“手工特征工程”。3. 完整示例QSVM 在 Iris 数据集上的二分类3.1 准备数据选特征和归一化我用的是经典的 Iris 鸢尾花数据集取 setosa 和 versicolor 两种花各 50 个样本。Iris 有四个特征全用的话特征维度有点高对入门示例来说没必要我选了前两个特征花萼长度和花瓣长度。这两个特征在这个二分类任务上区分度很好。注意原始特征值的量纲差异很大必须先做归一化。我习惯用MinMaxScaler把特征缩放到 0 到 π 之间。为什么不是 0 到 1因为角度编码的旋转门输入是弧度缩放范围选得不好会影响特征映射的表现。import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler iris load_iris() X iris.data[iris.target ! 2][:, [0, 2]] y iris.target[iris.target ! 2] X MinMaxScaler(feature_range(0, np.pi)).fit_transform(X) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 )这里有个我踩过的坑如果直接把原始数据丢进ZZFeatureMap不归一化特征的数值范围可能远超 π 或者远小于 0。旋转门的参数在这个范围之外时编码出的量子态差异不再直观核矩阵会变得很奇怪。所以数据缩放这步不能省。3.2 构建量子核并训练SVM核心代码其实不长分成三步构建特征映射、基于特征映射计算量子核矩阵、把核矩阵喂给 sklearn 的 SVC。from sklearn.svm import SVC from qiskit.circuit.library import ZZFeatureMap from qiskit.primitives import Sampler from qiskit.algorithms.state_fidelities import ComputeUncompute from qiskit_machine_learning.kernels import FidelityQuantumKernel feature_map ZZFeatureMap(feature_dimension2, reps2, entanglementfull) fidelity ComputeUncompute(samplerSampler(shots1024)) kernel FidelityQuantumKernel(fidelityfidelity, feature_mapfeature_map) kernel_matrix_train kernel.evaluate(x_trainX_train) svc SVC(kernelprecomputed) svc.fit(kernel_matrix_train, y_train) kernel_matrix_test kernel.evaluate(x_trainX_train, x_testX_test) y_pred svc.predict(kernel_matrix_test) accuracy np.mean(y_pred y_test) print(fQSVM Accuracy: {accuracy:.3f})在我本机用 Aer 模拟器跑输出大约是QSVM Accuracy: 0.967这个效果在 Iris 二分类上已经很不错了。作为对比直接用 RBF 核跑同一个训练集测试集精度大概在 0.95 上下。也就是说一个未经任何超参调优的量子核分类器已经和经典 RBF 核打平甚至略好。这还只是一个两比特的量子线路能够说明量子特征映射在这种情况下确实捕获到了数据里的有效结构。3.3 代码里每个参数到底在干什么Sampler(shots1024)中的 shots 是测量次数。量子线路每次运行得到的是一个概率分布shots 越多估计出的内积越准。我试过 shots100 的时候核矩阵的数值波动很大精度也忽高忽低。1024 是个性价比比较高的值。ZZFeatureMap里的entanglementfull表示两两比特之间都建立纠缠。在二特征的情况下full 和 linear 差别不大但如果特征维度超过 4full 会导致线路非常深噪声影响急剧放大此时我建议先用linear跑通再说。FidelityQuantumKernel是 qiskit-machine-learning 库里的封装它负责把两个量子态的内积转换成核矩阵。ComputeUncompute是计算保真度的算法实现采用“先正变换再逆变换”的线路设计把量子态的内积转化为测量概率。3.4 核矩阵长什么样代码跑完建议把核矩阵打印出来看一眼print(kernel_matrix_train[:5, :5])你会看到它的主对角线元素接近 1而不同类别样本之间的核函数值明显偏小。这其实就相当于在对角线上形成了“同类相聚、异类相斥”的结构SVM 拿它做分类自然会容易不少。如果你发现核矩阵对角线都不接近 1那多半是特征映射或者数据缩放出了问题。4. 量子核为什么可能比经典核更能打4.1 测量内积是量子硬件的天然优势量子核函数有一个很优雅的性质内积平方可以通过物理测量直接获得。具体来说把两个对应的量子态线路正接再反接然后测量全零态的概率这个概率值就等于内积模长的平方。也就是说量子计算机在“算核函数”这件事上不需要像经典那样进行繁重的浮点运算只需要跑线路、做统计。当然现在量子硬件的误差远大于经典浮点运算的误差所以这个优势目前在真机上还不能兑现。但从原理上说量子核函数的计算路径是自然的、直接的不是对某个经典函数的模拟。4.2 量子特征空间的表达能力不同在哪经典 RBF 核的特征映射是基于距离的它对应的特征空间里每个维度可以理解为某个中心点附近的“软指示”。这种表达方式对局部结构敏感但对全局的结构关系比较弱。量子特征映射则不同。以 ZZFeatureMap 为例它把数据编码成多个量子比特上的旋转角再通过纠缠门把这些角度进行非线性耦合。在量子态空间里不同特征维度之间的相关性不局限于加权组合而可以形成类似“特征A为高值时特征B必须为低值”的复杂约束。这类模式在一些特殊结构的数据里可能比经典核更容易被线性超平面分开。这个差异很像选房子经典核给你一个位置到市中心距离的评分量子核给你一个综合考虑了朝向、楼层、周边设施和采光的联合评分——后者更复杂但能不能用得好取决于有没有吃透数据本身的结构。4.3 一个简单的对比实验我把同一个数据集换回 RBF 核跑了一遍svc_rbf SVC(kernelrbf, C1.0, gammascale) svc_rbf.fit(X_train, y_train) y_pred_rbf svc_rbf.predict(X_test) print(np.mean(y_pred_rbf y_test))结果在 0.95 左右。这个对比不是为了证明谁更好因为 Iris 数据太简单两者的差异完全在噪声范围内。但这个对比的意义在于它验证了量子核在小型分类任务上不会明显输给经典核同时给你一个基线参考。4.4 清醒一点量子核不是万能的我得泼一盆冷水。在目前这个阶段QSVM 在大多数经典数据集上并不会真正超越 RBF 核。量子特征空间的维度虽然指数级增长但量子线路的容量、测量次数限制和真机噪声都会把优势抵消掉。量子核的研究更多是在探索“什么样的数据模式是经典核难以表达、而量子核天然匹配的”比如具备某种对称性的数据、周期性数据、和图结构相关的数据。所以我的建议是如果你想做量子机器学习研究QSVM 是理解原理的最佳支架如果你想拿它解决实际生产问题现阶段大概率还是经典模型更可靠。把量子核当成一个“核函数生成器”在数据规模小、特征维度低、你有耐心调线路结构的前提下可以认真试试。5. 模拟器到真机噪声会怎样毁掉实验5.1 模拟器上的好结果有欺骗性Aer 模拟器默认是理想无噪声的所以核矩阵计算得非常干净分类器精度高在预期之中。但我必须提醒你这套代码如果原封不动提交到 IBM 真机上结果会很难看。原因很直白真机上有测量误差、门操作误差、退相干线路执行 1024 次测量每一次的量子态都已经偏离了理想状态。一个很典型的现象是量子核矩阵会变得“糊”。理想情况下同类样本的核值应该明显大于异类样本引入噪声后所有核值都向 0.5 附近靠拢SVM 的决策边界就失去了有效信息。这不是代码逻辑的问题是物理层面的误差。5.2 在Aer里模拟噪声实验不一定要花真机的时间去体验这种差距你可以在 Aer 里手动加噪声模型。比如 1% 的退极化噪声已经足以让精度掉一截from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel, depolarizing_error noise_model NoiseModel() error depolarizing_error(0.01, 1) noise_model.add_all_qubit_quantum_error(error, [rz, ry, rx]) backend AerSimulator(noise_modelnoise_model) sampler_noisy SamplerV2(backendbackend) fidelity_noisy ComputeUncompute(samplersampler_noisy) kernel_noisy FidelityQuantumKernel( fidelityfidelity_noisy, feature_mapfeature_map ) kernel_matrix_train_noisy kernel_noisy.evaluate(x_trainX_train) svc_noisy SVC(kernelprecomputed) svc_noisy.fit(kernel_matrix_train_noisy, y_train) kernel_matrix_test_noisy kernel_noisy.evaluate(x_trainX_train, x_testX_test) y_pred_noisy svc_noisy.predict(kernel_matrix_test_noisy) print(fNoisy QSVM Accuracy: {np.mean(y_pred_noisy y_test):.3f})在我本机的模拟测试里无噪声精度 0.967加了 1% 退极化噪声之后掉到了 0.80 左右。噪声再大一点直接掉到 0.55和随机猜测差不多了。这种对幅度对做量子机器学习的人来说必须刻在脑子里线路越深噪声影响越大特征维度越高线路越深精度崩得越快。5.3 真机调试的三个可行对策第一个对策是增加 shots。噪声的本质是测量结果带有随机偏差通过增加 shots 让统计平均逼近真实概率分布可以一定程度上救回核矩阵质量。我把 shots 提高到 8192 之后噪声下的精度回升了不少但运行时间也成倍增加。第二个对策是缩短线路。减少reps把ZZFeatureMap的纠缠改成线性或者选择更浅的量子线路。线路短了噪声对结果的影响指数级下降。精度不一定变差但稳定性显著提高。第三个对策是用 IBM Quantum 的弹性运行时服务。Qiskit 1.x 里可以通过qiskit-ibm-runtime访问带错误缓解的SamplerV2它会在后端替你做一些测量误差纠正。真机上跑之前建议先在 Aer 里加噪声模拟器验证一下自己的算法对噪声的耐受度再上真机排队。5.4 我的实测感受说句实在话在真机上跑这种小实验的体验算不上愉快。排队时间几个小时甚至半天都是常态真正运行只花几秒钟但拿到手的精度往往还不如模拟器加 1% 噪声的结果。我个人现在的工作流是所有算法验证都在 Aer 上完成只有论文级的实验或者需要真实硬件数据做演示时才去申请真机额度。这个观念能帮你节省大量时间和精力。6. 进阶变分量子分类器VQC和我踩过的坑6.1 QSVM的局限性QSVM 虽然好上手但它有一个天然的短板核矩阵的大小是样本数的平方。训练样本 100 个核矩阵就是 100×100训练样本 5000 个就是 2500 万的矩阵算得又慢又费量子资源。所以 QSVM 只适合数据规模很小的实验场景。如果你想走得更远一点应该了解变分量子分类器VQC。它的思路是把量子线路当作一个可训练的模型输入特征经过特征映射后再进入一组带参数的旋转门和纠缠门最后测量输出并和标签计算损失用优化器调节参数。6.2 VQC代码示例一个最简的 VQC 在 Iris 二分类上的实现大概是这样的from qiskit.circuit.library import TwoLocal, ZZFeatureMap from qiskit.algorithms.optimizers import COBYLA from qiskit.primitives import Sampler from qiskit_machine_learning.algorithms import VQC feature_map ZZFeatureMap(feature_dimension2, reps1) ansatz TwoLocal(2, [ry, cz], reps1, entanglementfull) vqc VQC( feature_mapfeature_map, ansatzansatz, optimizerCOBYLA(maxiter200), samplerSampler(shots1024), ) vqc.fit(X_train, y_train) score vqc.score(X_test, y_test) print(fVQC Accuracy: {score:.3f})VQC 的训练过程明显比 QSVM 慢因为每一步参数更新都要重新跑多次线路。但它的优势是参数量可以控制并且在理想模拟器上往往能达到比 QSVM 更紧凑的模型表现。如果你想在量子机器学习上做更深入的实战VQC 是绕不开的下一步。6.3 我的三个踩坑实录第一个坑是 API 版本问题我开头提过。Qiskit 1.0 大量旧接口失效网上教程要么过时要么互相矛盾。我现在养成了习惯任何量子机器学习教程先看它是否基于 Qiskit 1.x 和 qiskit-machine-learning 0.7 及以上版本不满足的直接放弃。第二个坑是数据归一化区间。我最早直接用 MinMaxScaler 缩放到 0 到 1然后把原始值喂给 ZZFeatureMap。结果核矩阵对角线都不太好分类精度一直上不去。后来看文档才发现ZZFeatureMap对输入范围比较敏感一般推荐在 [-π, π] 或者 [0, π] 之间我改成 0 到 π 之后问题立刻消失。第三个坑是 shots 太少导致核矩阵不再是正定矩阵。有一次我把 shots 调到 100SVC 直接报错错误信息提示核矩阵含有非有限值。量子测量本身有随机性shots 太少时核函数估计的方差很大导致矩阵出现奇异值。类似问题在生产环境里更难排查因为报错来得莫名其妙。6.4 项目选型建议我把这次实验的几个关键对比整理成了表格方便你选择适合自己项目的路线方案量子部分训练方式优点适合场景QSVM 量子核只有特征映射经典SVC加载核矩阵链路封闭、容易调试小规模分类实验、对比研究VQC 变分分类器特征映射参数化线路量子线路端到端训练参数化可控、灵活小数据、探索性研究经典SVM/RBF无纯经典稳定、快、工具成熟大多数实际生产任务我的核心建议是如果你只是想理解量子机器学习QSVM 绝对是第一站如果你在调研量子模型的表达能力VQC 更值得深挖如果你有真实业务需求暂时还是以经典模型为主量子线路最多当作特征增强模块去测试。最后分享一个小技巧我在比较不同特征映射对核矩阵的影响时习惯先打印核矩阵的热力图而不是直接看精度。热力图能直观展示同类和异类的数值间隔如果间隔不明显调线路结构往往比调 SVM 参数更有效。这个习惯帮我少走了很多弯路。