ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

量子核SVM实战:基于Qiskit的手写体识别与经典RBF对比

量子核SVM实战:基于Qiskit的手写体识别与经典RBF对比 简介基于量子加速的SVM手写体识别项目完整整合Python源码、图文说明与PDF文档面向需要开展机器学习与量子计算交叉方向毕设、课设或初期演示的计算机、人工智能等相关专业学生。项目在传统支持向量机基础上引入量子核方法借助量子电路实现特征映射以手写数字分类为案例展示从量子线路设计、量子门操作到分类器训练的全流程。压缩包共21个文件主要涵盖py源程序、ipynb交互式笔记、tex量子电路绘图、PDF技术文档以及多张结果示意图整体仅3.4MB附带的量子算法教程与qSVM原理文档可帮助理解量子核函数构造与优化过程结构紧凑、宜按模块研读。目前已有136人学习下载代码经运行验证成功配套README与说明文档适合从零复现也可在示例基础上改造用于其他分类任务。1. 量子加速的SVM做手写体识别这个项目要解决的三个问题当标题同时出现“量子加速”“SVM”和“手写体识别”时很多人以为这就是把 RBF 核换成量子核、跑通一个数字分类就完事。实际做下来你会发现这个项目真正要回答的是三个问题量子电路算出来的核函数到底能不能接进 sklearn 的 SVC在同样的数据集上它比经典核强在哪、贵在哪以及一份以“源码文档说明图片介绍PDF”交付的课程设计要怎么把实验做扎实。它适合两类人——已经跑通了经典 SVM、想往量子机器学习延伸的 Python 开发者以及需要一份能讲清楚创新点和局限性的高分项目。如果只想要一个能跑的数字识别 demo这个方向反而复杂因为你要先处理特征映射、模拟器开销和核矩阵正定性三件额外的事。2. 量子核函数与经典 RBF 核的差异从量子态编码到“加速”的真实含义2.1 经典 SVM 在 64 维手写特征上的计算压力SVM 的核心是核矩阵一个 N 个样本的训练集要对每一对样本计算一次核函数值得到一个 N×N 的矩阵。以 UCI 的 optdigits 手写数字数据为例一份 1257 个样本的训练集核矩阵就有约 158 万个元素。如果换成 RBF 核每一个元素都要先算欧氏距离再做指数运算虽然 64 维上的单次计算不算贵但当样本量涨到几千甚至上万核矩阵的存储和计算量会把训练时间拖得很明显。手写体识别真正的难点不是维度而是同一数字在不同人笔下的非线性形变。数字“4”和“9”在 8×8 的网格上往往只差一个笔画的走向数字“7”和“9”在低分辨率下也经常互相混淆。经典 SVM 处理这类问题时RBF 核是最常用的选择因为它在局部做了平滑能把相邻像素的灰度变化转化为一个相对柔和的距离度量。但 RBF 核本质上是基于欧氏距离的相似度度量它对特征之间的高阶交叉关系不敏感。换句话说它知道你“长得像不像”但不太关心“哪个像素和哪个像素的组合决定了这个数字的语义”。这就是量子核切入的起点。量子特征映射会把每个样本编码成一组量子态的振幅核函数计算的是两个量子态之间的内积模方。这个内积发生在一个高维的希尔伯特空间里等价于把原始特征做了非常复杂的非线性组合。对于某些分布的数据量子核诱导出的几何结构能比欧氏距离更好地反映样本间真正的语义相似度。2.2 量子核的计算方式与“加速”在报告里怎么解释量子核的思想并不复杂。设特征映射电路为 U(x)它把经典特征向量 x 编码到 n 个量子比特的态上。两个样本 x 和 x′ 的量子核值定义为k(x, x′) |⟨0ⁿ|U†(x′)U(x)|0ⁿ⟩|²实际计算时先构造 U†(x′)·U(x) 这个整体电路在计算基下测量全零态出现的概率就得到了核值。这个值天然满足对称性并且因为来自量子态内积理论上是正定的。落到代码层面可以用量子计算框架里的模拟器完成这一步也可以提交到真实量子后端。把“量子加速”落到 SVM 上常见有两条路线一条是量子核方法把经典核替换成量子电路估算的核函数工程上最容易落地另一条是用量子线性代数加速 SVM 对偶问题的求解但那条路线在模拟器上不现实。课程设计级别的源码项目几乎都走第一条。需要特别说明的是标题里的“加速”不是指训练耗时更短——恰恰相反在模拟器上量子核往往会慢一个数量级。量子核的真实优势体现在样本复杂度上对特定分布的数据要达到同样的测试误差量子核可能只需要经典核一半的训练样本。这才是报告里应该重点论证的“加速”。很多初次接触这个方向的人会把量子核当成一个黑匣子只要换了核函数准确率就应该更高。实际不是这样。量子核的效果高度依赖特征映射的选择、数据的编码范围和核函数的测量方式。如果这些问题不处理好量子核的准确率甚至不如线性 SVM。2.3 特征映射的选择ZZFeatureMap 与角度编码在量子核 SVM 里特征映射决定了数据进入量子电路的方式。常见做法是使用角度编码把归一化后的特征值作为旋转角度施加到量子比特的 Ry 旋转门上。比如第 i 个特征 xᵢ 被编码为 Ry(2·xᵢ) 作用在第 i 个量子比特上。这样每个特征都映射到量子态的一个相位上样本之间的相似度就变成了量子态之间的重叠程度。比单比特旋转更进一步的是 ZZFeatureMap它在角度编码的基础上增加了 ZZ 相互作用项让不同特征之间产生纠缠。这个纠缠项是量子核相比经典核的重要区别——它显式建模了特征之间的高阶关联。ZZFeatureMap 有三个关键参数参数取值建议作用feature_dimension与降维后的特征数一致量子比特数量通常不超过 816reps从 2 开始调特征映射电路重复次数越大非线性越强entanglementlinear 或 full特征之间的纠缠方式这些参数直接决定了核函数的“形状”。reps 太小电路表达能力不足reps 太大在模拟器上计算量成倍增加而且容易过拟合。后面第 6 章会专门讲 reps 的对比实验怎么做这里先记住一个原则量子核不是一个固定的相似度度量而是一族可以由参数调节的度量调节方式与经典 SVM 调 gamma 的地位类似。3. 手写体数据准备与量子特征映射的输入要求维度、样本量与编码3.1 数据集选择optdigits 比 MNIST 更适合量子 SVM 入门手写体识别的经典数据集有 MNIST、USPS 和 UCI 的 optdigits。MNIST 是 28×28 的灰度图展开后是 784 维直接做量子特征映射需要 784 个量子比特这在模拟器上完全不可行。USPS 是 16×16 的灰度图展开后 256 维依然偏大。optdigits 是 8×8 的灰度图展开后 64 维恰好落在可以接受的范围内。optdigits 还有一个好处它已经被划分成了标准的训练集和测试集每类数字的样本量基本均衡做对比实验时不用自己处理类别不平衡。如果你用的是 sklearn 内置的 load_digits实际上拿到的就是 optdigits 数据的重排版本按像素范围 0~16 存储。读取和切分的代码如下import numpy as np from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split # 读取 8x8 手写数字数据集共 1797 个样本10 类 digits load_digits() X digits.data # 形状 (1797, 64)每个像素灰度范围 0~16 y digits.target # 形状 (1797,) # 先归一化到 [0, pi]这是角度编码的常用输入范围 X_scaled X / 16.0 * np.pi # 按类别比例切分保证训练集和测试集中各类数字占比一致 X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, stratifyy, random_state42 ) print(f训练集: {X_train.shape}, 测试集: {X_test.shape}) # 输出: 训练集: (1257, 64), 测试集: (540, 64)这里我做了两件事。第一把灰度值缩放到 [0, π]而不是 [0, 1]这是量子角度编码的常见做法。scikit-learn 的 RGB 数据通常归一化到 [0, 1]但量子旋转门的输入范围是 [0, 2π]如果特征值过小旋转角度接近 0不同样本的量子态几乎相同核矩阵会失去区分度。第二用 stratify 参数按类别比例切分避免某一类数字在训练集中占比过高导致模型偏向多数类。3.2 降维到 8 维PCA 是量子特征映射落地的前置步骤特征映射的量子比特数等于输入维度。64 维输入意味着 64 个量子比特在真实量子硬件上很多机器还达不到这么多比特位在模拟器上更是直接卡死。所以即便 optdigits 维度已经不高通常也要先做 PCA 降维到 8 或 16 维。降维会损失一部分像素级细节但量子核的纠缠结构在低维输入下更容易稳定计算。from sklearn.decomposition import PCA # 保留 8 个主成分累计方差通常在 80% 左右 pca PCA(n_components8, random_state42) X_train_pca pca.fit_transform(X_train) X_test_pca pca.transform(X_test) # 主成分方向上的值范围不确定重新缩放到 [-pi/2, pi/2] X_train_pca np.clip(X_train_pca, -3, 3) / 3.0 * (np.pi / 2) X_test_pca np.clip(X_test_pca, -3, 3) / 3.0 * (np.pi / 2) print(f降维后训练集: {X_train_pca.shape}) # 输出: 降维后训练集: (1257, 8)PCA 之后主成分的取值不是固定的有时是负值有时范围能到 10 以上直接作为旋转角会让量子电路的行为难以预测。我的习惯是先做一个 clip把极端值截断到 [-3, 3]再统一映射到 [-π/2, π/2]。这样既保留了主成分的相对关系又避免了过大的旋转角度导致核值在数值上不稳定。3.3 控制样本量量子核矩阵的大小与耗时预算量子核矩阵需要计算 N×N 个核值每个核值都要构造一次量子电路并采样。100 个样本就是 1 万个核值500 个样本就是 25 万个核值。在不做任何缓存优化的情况下模拟器上计算 500 个样本的量子核矩阵可能需要十几分钟到半小时。所以样本量控制是这个项目里最现实的问题。# 每类最多保留 25 个训练样本总共约 250 个样本 def stratified_sample(X, y, n_per_class): indices [] for cls in np.unique(y): cls_indices np.where(y cls)[0] selected np.random.choice(cls_indices, sizen_per_class, replaceFalse) indices.extend(selected) indices np.array(indices) return X[indices], y[indices] X_train_sub, y_train_sub stratified_sample(X_train_pca, y_train, n_per_class25) print(f子训练集: {X_train_sub.shape}) # 输出: 子训练集: (250, 8)这里用分层抽样每类取 25 个样本10 类共 250 个样本对应 6.25 万个核值在模拟器上是可接受的范围。样本量是你调节量子核参数时的第一控制变量——如果改一次 reps 就要等半小时你根本没法做参数对比实验。一个可行的策略是先用 100 个样本快速验证代码通路确认无误后再把样本量加到 250 或 300。4. 用 Python 搭建量子 SVM 训练流程FidelityQuantumKernel 与 SVC 完整代码4.1 安装量子计算框架与常用依赖量子核 SVM 的代码依赖两部分量子计算框架负责构造特征映射电路和估算核值scikit-learn 负责 SVM 的训练与评估。以下是我常用的安装方式pip install qiskit qiskit-machine-learning scikit-learn numpy matplotlibqiskit 提供了量子电路、模拟器和采样器的底层能力qiskit-machine-learning 则封装了量子核的高层接口。安装完成后可以先跑一段极小的验证代码确认 Sampler 能够正常工作再进入正式训练流程。4.2 构建量子核并接入 SVC 训练核心代码分三步定义特征映射电路用 FidelityQuantumKernel 封装成核函数然后作为 kernel 参数传入 SVC。以第 3 章准备好的 8 维数据为例import numpy as np from sklearn.svm import SVC from sklearn.metrics import accuracy_score from qiskit.circuit.library import ZZFeatureMap from qiskit.primitives import Sampler from qiskit_machine_learning.kernels import FidelityQuantumKernel # 1. 定义特征映射8 个量子比特深度为 2线性纠缠 feature_map ZZFeatureMap( feature_dimension8, reps2, entanglementlinear, ) # 2. 用 FidelityQuantumKernel 封装量子核 qkernel FidelityQuantumKernel( feature_mapfeature_map, samplerSampler(options{shots: 4096}), ) # 3. 把量子核接进 SVM svm_q SVC(kernelqkernel.evaluate, C1.0) svm_q.fit(X_train_sub, y_train_sub) # 4. 预测并评估 y_pred_q svm_q.predict(X_test_pca) acc_q accuracy_score(y_test, y_pred_q) print(f量子核 SVM 测试准确率: {acc_q:.4f})这段代码里最需要注意的是 SVC 接收的 kernel 参数形式。qkernel.evaluate 是一个可调用对象sklearn 会用它计算训练集的核矩阵也会在预测阶段计算测试样本与支持向量的核值。FidelityQuantumKernel 内部会把每一对样本构造为量子电路的两次内积估算所以这里传入的是“函数”而不是“预先算好的矩阵”。C1.0 是 SVM 的默认正则化系数在量子核场景下建议从 0.1 到 10 各试一遍因为量子核矩阵的数值尺度与经典核不同C 的敏感区间会有偏移。4.3 与经典 RBF 核做同一实验条件下的对比没有对比就没有说服力。量子 SVM 项目报告的骨干就是量子核与经典核在相同数据、相同划分下的对比。注意保持训练集完全一致不要为了量子核好看就偷偷加大训练样本。from sklearn.svm import SVC from sklearn.metrics import accuracy_score # 经典 RBF 核 SVM与量子核使用相同训练集和测试集 svm_rbf SVC(kernelrbf, C1.0, gammascale) svm_rbf.fit(X_train_sub, y_train_sub) y_pred_rbf svm_rbf.predict(X_test_pca) acc_rbf accuracy_score(y_test, y_pred_rbf) print(fRBF 核 SVM 测试准确率: {acc_rbf:.4f}) print(f量子核 SVM 测试准确率: {acc_q:.4f})在 250 个训练样本、8 维 PCA 特征下RBF 核的准确率通常能到 80% 左右量子核则可能在 75%85% 之间波动。如果你的量子核准确率比 RBF 低一截不要立刻怀疑代码写错了先检查三件事第一输入是否归一化到角度编码的可接受范围第二量子核矩阵的数值是否都在 [0, 1] 区间第三reps 是否太小导致表达能力不足。5. 量子 SVM 训练中的高频踩坑NaN、卡死、过拟合和“看不到加速”5.1 报错“kernel is not positive definite”或核值出现 NaN现象SVC 在 fit 阶段正常结束但在 predict 阶段报类似“Kernel is not positive definite”的错误或者在计算核矩阵时出现 NaN 值。原因量子核理论上是正定的但在模拟器上采样次数有限估算出的核矩阵会偏离理想值。当某两个样本的量子态重叠度极低时采样得到的概率可能为 0对数或归一化操作会产生 NaN。另一个常见原因是特征值超出旋转门可接受的相位范围比如直接把原始灰度值除以 16 就当作角度用。解决把灰度值先除以 16 再乘以 π确保输入落在 [0, π] 区间。同时把 Sampler 的采样次数从默认的 1024 提高到 4096减少估算方差。如果核矩阵仍然不稳定可以改用 precomputed 模式先手动计算好核矩阵再传入 SVC(kernelprecomputed)这样能绕过部分数值检查逻辑。5.2 几百个样本的核矩阵就卡到怀疑人生现象样本量加到 300 以后量子核矩阵的计算时间从几分钟暴涨到半小时以上像死机了一样。原因量子核矩阵的时间复杂度是 O(N²)每个核值都是一次电路构造加一次采样。300 个样本对应 9 万个核值4096 次采样意味着要把 9 万个电路各跑 4096 次这个开销在模拟器上是实打实的。解决把样本量降到 200 左右或者把 reps 从 2 降到 1。还有一种做法是减少采样次数到 1024虽然核值波动会变大但对最终准确率的影响在可控范围内。做参数对比实验时先用 100 个样本跑通确认参数方向有效后再用完整样本量做最终实验。5.3 量子核与 RBF 结果几乎一样甚至更差现象跑出来的准确率相差不到 1%从报表上看不出量子核有任何优势。原因这是最正常的现象。量子核的优势在理论上针对的是特定数据分布在 optdigits 这种经过 PCA 降维的小数据集上RBF 核本来就表现不俗。模拟器上的量子核还要承受采样误差精度反而可能被拖低。解决不要在报告里硬吹“量子加速让准确率提升”这是评审一眼就能看穿的问题。把标题里的“加速”重新解释为样本复杂度优势固定样本量为 100 时量子核与 RBF 的准确率差距通常比样本量为 250 时要大。所以实验应该设计成“固定训练集大小比较两种核的测试误差”而不是比训练时间。5.4 训练集准确率接近 100%测试集却只有七成现象fit 之后 svm_q.score 在训练集上超过 95%但测试集准确率明显下降典型的过拟合。原因量子核的非线性表达能力很强尤其在 reps 较大时几乎能记住每一个训练样本。样本量只有 250 时过拟合风险比经典 SVM 更高。C 值取得过大也会加剧这个现象。解决把维度和深度一起降下来。常见组合是 8 维输入、reps2、C1.0如果你的训练集准确率超过 95%先试试 C0.1。如果还是过拟合再试 reps1。过拟合的调参顺序和经典 SVM 相反——经典 SVM 是调 C 和 gamma量子核还要多调一个电路深度。5.5 混淆矩阵里“4”和“9”永远分不清现象分类报告里精确率最低的永远是类别 4 和类别 9混淆矩阵中这两个类互相误判最多。原因8×8 的图像分辨率太低4 和 9 的结构本来就很接近。PCA 降到 8 维后再丢掉一部分非线性细节二者在特征空间中的距离变得更近。量子核的纠缠结构可以建模像素间的高阶组合但如果你在 8 维输入上做信息损失已经不可逆。解决这个坑不一定要靠模型解决。可以增加这两个类的训练样本量或者在数据增强时对 4 和 9 做小角度的旋转扰动。更实用的办法是在报告里主动展示这个混淆分析为什么低分辨率下会混淆而不是试图掩盖。6. 量子 SVM 项目如何做实验验证reps 参数、学习曲线与混淆矩阵6.1 用学习曲线和训练耗时对比证明“加速在哪”学习曲线是这份项目报告里性价比最高的图表。横轴是训练样本量纵轴是测试准确率分别画量子核与 RBF 两条曲线。当样本量从 50 增加到 250 时如果量子核的曲线上升更快、更早达到平台期就说明它在少样本场景下确实有优势。这在理论上对应了量子核的样本复杂度优势。训练耗时对比同样值得记录但结论要诚实在模拟器上量子核训练耗时远高于 RBF。把这个耗时差距写进文档再补充一句“真实量子硬件可能在特定情况下改变这个结论”就是一份客观的对比数据。绘制学习曲线用 sklearn 的 learning_curve 函数即可注意测试集要保持固定否则曲线会抖动。6.2 报告里最加分的对比reps1/2/3 的核函数参数研究量子核没有 gamma 参数但 reps 承担了类似的角色。我每次做项目都会固定样本量为 200分别跑 reps1、reps2、reps3 三组实验记录准确率和核矩阵计算耗时reps训练准确率测试准确率核矩阵耗时200 样本190% 左右76% 左右约 2 分钟295% 左右82% 左右约 5 分钟398% 左右79% 左右约 12 分钟这张表能说明两个问题reps 越大非线性表达能力越强训练集拟合效果越好但过深的电路在测试集上不一定有正向收益反而会拖慢计算。这组对比能把“参数怎么调”讲得清清楚楚比单纯给一个准确率数字有说服力得多。我第一次做这类项目时一心想着让量子核准确率超过 RBF结果调了几十次参数都差两个百分点后来才发现训练集和测试集的归一化方式不一致PCA 变换没有在统一的 pipeline 里处理。养成的习惯是每次跑实验前先打印核矩阵的数值范围和训练集准确率确认数据通路正常后再谈调参。量子 SVM 的落地难度不在量子电路的物理概念而在工程链路长、变量多希望你从一开始就把数据预处理和实验对比的结构搭好少走这些弯路。本文还有配套的精品资源点击获取
返回列表