ARTICLE DETAIL

资讯详情

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

量子K-means文本聚类实战:从swap test原理到代码实现

量子K-means文本聚类实战:从swap test原理到代码实现 简介面向量子机器学习与聚类分析研究者的代码与笔记合集围绕量子K-meansQK-means算法展开针对传统K-means在大规模高维数据上效率下降的问题给出基于量子线路加速聚类流程的改进实现。压缩包共20个文件、约1.06MB以14个Jupyter Notebook为核心从量子比特表示、距离计算与控制门线路到QK-means自动化输出和MTEB文本嵌入测试均有覆盖另含JSON/CSV数据、README、说明txt与附赠Word笔记便于对照实验与复现。资源还整理了经典S2S、PicturetoP等对比实验以及Hugging Face、NumPy保存数据等配套脚本结合自建数据集构建和V-measure评估可完整走通数据构造、特征表示、聚类训练到效果量化的流程并对量子比特退相干、误差控制等实现难点给出测试与排错思路。目前已有81人学习/下载。适合想理解量子聚类代码实现、开展文本嵌入实验的研究者也适合作为量子机器学习入门后的实战参考。1. QK-means 到底改了 K-means 的哪一步先分清混合计算和全量子很多人第一次看到“量子K-means”这个组合第一反应是“把 K-means 搬到量子计算机上跑”。真实落地时并不是这样。经典 K-means 每一轮迭代最大的开销是计算 n 个样本到 k 个质心的欧氏距离维度 d 越高这一步越贵。QK-means 的核心思路是用量子态之间的内积估计来替换逐维浮点运算用振幅编码把 d 维向量装进 log₂d 个量子比特里再用 swap test 一次读出相似度。于是原来复杂度 O(nkd) 的距离矩阵计算在原理上被压到了 O(nk log d) 的线路深度加常数次测量。这个标题里的“应用实现”就是把这条混合路线在文本聚类场景里跑通经典部分负责嵌入、质心更新和评估量子部分只干距离计算这一件事。这套方案不值得在模拟器上追求性能收益它的价值在于验证算法路径和评估口径。适合三类人研究量子算法落地的从业者做文本聚类但想探索下一代计算范式的工程师以及需要在自建数据集上给 QK-means 打分写结论的人。2. 从欧氏距离到量子态内积QK-means 的核心原理与选型理由2.1 经典 K-means 的瓶颈高维文本向量上的距离计算K-means 的迭代逻辑很简洁分配阶段把每个样本归到最近的质心更新阶段把每个簇的均值作为新质心。但如果把文本嵌入向量直接喂进去事情就不那么优雅了。用 sentence-transformers 这类模型产出的向量常见维度是 384、768 甚至 1024一次完整迭代要算 n×k 个 d 维欧氏距离每个距离做 d 次乘加。n 到万级、k 到几十时距离矩阵成了整个算法的绝对瓶颈。经典优化不是没有KD-Tree 和三角形不等式剪枝在低维数据上效果显著但在文本嵌入这种高维且分布稠密的场景里基本失效。这是维度灾难的典型表现——高维空间中距离趋于均匀树结构的剪枝收益被迅速稀释。Mini-Batch K-means 是工程上最常用的妥协方案但它改的是采样方式不是距离计算本身。QK-means 选择直接攻击最贵的那块用量子线路估计向量间的相似度再把相似度换算成距离。这不是替代 K-means 的全部而是精准替换其内层最热路径。2.2 振幅编码为什么只花 log₂d 个量子比特swap test 线路推导要把经典向量送进量子线路最常见的手段是振幅编码。一个 d 维单位向量 x被直接写进 2ⁿ 个基态的概率幅上其中 n ⌈log₂d⌉。也就是说384 维的文本嵌入只需要 9 个量子比特就能装下768 维只需要 10 个。对比经典内存里存 384 个浮点数这个压缩比是量子表示带来的第一层红利。代价是概率幅本身看不见摸不着只能通过测量间接读取而且读取的是概率而不是确定值。距离计算部分用的是 swap test。线路结构是一个辅助比特先过 Hadamard 门两份待比较的量子态分别放在两个寄存器里然后以辅助比特为控制位对两个寄存器逐比特做控制交换cswap最后再对辅助比特做 Hadamard 门并测量。测量结果为 |0⟩ 的概率满足 P(0) (1 |⟨ψ|φ⟩|²) / 2。这个式子很好用把它整理一下|⟨ψ|φ⟩|² 2P(0) − 1直接得到两个单位向量内积平方的估计值也就是量子保真度。对于单位向量欧氏距离和保真度之间存在一个非常干净的换算关系‖a − b‖² 2 − 2⟨a|b⟩。所以只要把 swap test 估计出的内积平方当作 cos²θ距离平方就等于 2(1 − cos²θ) 的补数关系吗这里要小心。swap test 给出的是内积绝对值平方而距离公式需要带符号的内积。如果直接用 |⟨a|b⟩|² 代进 2 − 2⟨a|b⟩需要先判断符号。文本嵌入向量经过大多数模型的激活函数输出后通常是非负的内积天然非负符号问题被绕开了。但换到其他领域必须先验证这个前提否则距离矩阵会错得悄无声息。这一点在第 5 章还会展开。2.3 为什么当前落地选 swap test 而非 Grover 优化量子 K-means 还有另一条常见路线用 Grover 算法加速“寻找最近质心”这一步把每轮分配的搜索开销从 O(k) 降到 O(√k)。听起来更诱人但工程落地有两个现实障碍。第一Grover 需要针对每个样本构造一个 oracle用来标记“哪些质心比当前候选更近”这个 oracle 的构造本身就是一次距离比较复杂度并不低第二Grover 对量子内存的要求更高当前 NISQ 阶段很难在真实硬件上稳定跑出有意义的加速。swap test 路线的优势在于浅和稳。线路深度只随 log₂d 增长辅助比特只需要一个测量结果直接换算成距离值不需要复杂的振幅放大流程。所以在“应用实现”这个标题的语境下swap test 几乎是唯一成熟、可复现、能在模拟器上跑完整个 K-means 迭代的选择。模拟器上它当然不会比经典 NumPy 更快但算法路径是完整的距离来自量子线路聚类质量可以量化评估。先把这条路走通等硬件成熟后才有参数和基线可以对照。3. 用 QK-means 跑通文本聚类嵌入、线路与迭代代码3.1 工具链选型与项目结构我一般会把这类项目拆成三个模块嵌入与数据准备、量子距离估计、聚类主循环与评估。量子部分用 Qiskit 的 AerSimulator 做状态向量模拟经典部分用 sentence-transformers 产出文本嵌入scikit-learn 提供 V-measure 等评估指标。三个模块各干各的事换库成本最低。模块职责关键依赖embedding.py文本转向量输出归一化嵌入sentence-transformers, numpyquantum_distance.py用 swap test 估计向量间保真度qiskit, qiskit-aerqkmeans.py聚类迭代、质心更新、评估numpy, scikit-learn选择这个组合的考虑是Qiskit 的 AerSimulator 对中小规模线路足够稳定initialize 方法可以直接把经典向量编码进量子态省去手动构造态制备线路的工作。sentence-transformers 负责把原始文本变成干净的数值输入这样量子部分专注做距离估计聚类逻辑完全透明。3.2 文本嵌入与自建数据集准备文本嵌入阶段最容易被忽视的是归一化。swap test 推导全程假设输入是单位向量没有归一化的向量直接送进 initialize内积估计的物理意义就会漂移。我通常在 encode 时直接打开 normalize_embeddings 参数一步到位。from sentence_transformers import SentenceTransformer import numpy as np # 自建小型聚类数据集结构上模仿 MTEB 聚类任务的“文本列表 标签列表”二元组 corpus [ 量子纠错码的阈值定理决定了容错计算的可行性, 表面码通过稳定子测量实现逻辑量子比特的冗余保护, K-means 的初始质心选择会显著影响最终聚类结果, DBSCAN 通过密度连接识别任意形状的数据簇, 梯度裁剪可以缓解深度 Transformer 训练中的梯度爆炸, 混合精度训练在保持训练精度的同时降低显存占用, ] labels [0, 0, 1, 1, 2, 2] model SentenceTransformer(paraphrase-multilingual-MiniLM-L12-v2) vecs model.encode(corpus, normalize_embeddingsTrue) print(vecs.shape) # (6, 384)这段代码的输出是 6 条文本对应的 384 维单位向量。normalize_embeddingsTrue 是关键参数它保证每条向量的 L2 范数为 1让 swap test 的距离换算公式成立。数据规模上自建数据集每类建议至少 20 条类别数控制在 3 到 5 个否则 V-measure 的区分度不够量子估计误差和聚类随机性会混在一起。3.3 量子距离估计核心代码swap test 的实现与换算量子距离估计是整个项目的核心模块。逻辑分三步把两个向量分别补零对齐到 2ⁿ 维用 initialize 编码进两个寄存器用 swap test 读出保真度。from qiskit import QuantumCircuit from qiskit_aer import AerSimulator import numpy as np def swap_test_fidelity(vec_a, vec_b, shots8192): 估计两个单位向量之间的保真度 |a|b|^2。 注意vec_a 和 vec_b 必须是单位向量。 dim vec_a.shape[0] n max(1, int(np.ceil(np.log2(dim)))) # 不足 2^n 的维度补零让两个向量拥有相同的量子比特表示 padded_a np.zeros(2 ** n) padded_b np.zeros(2 ** n) padded_a[:dim] vec_a padded_b[:dim] vec_b padded_a / np.linalg.norm(padded_a) padded_b / np.linalg.norm(padded_b) qc QuantumCircuit(2 * n 1, 1) qc.h(0) # 辅助比特进入叠加态 qc.initialize(padded_a, range(1, n 1)) # 第一个寄存器编码向量 a qc.initialize(padded_b, range(n 1, 2 * n 1)) # 第二个寄存器编码向量 b for i in range(n): qc.cswap(0, 1 i, 1 n i) # 控制交换两组寄存器 qc.h(0) # 辅助比特再次 Hadamard qc.measure(0, 0) counts AerSimulator().run(qc, shotsshots).result().get_counts() p0 counts.get(0, 0) / shots fidelity max(0.0, 2 * p0 - 1.0) # 由 P(0) 反解内积平方 return fidelity这里的 n 由输入维度动态推导。384 维向量补零到 512 维需要 9 个量子比特两个寄存器加一个辅助比特共 19 个量子比特AerSimulator 完全能承受。cswap 是控制交换门对应 swap test 线路中的核心操作。fidelity 换算公式 2p₀ − 1 直接来自 P(0) (1 |⟨ψ|φ⟩|²) / 2max 截断是为了处理有限采样造成的负值。如果想把距离直接用上单位向量下的欧氏距离平方就是 2(1 − fidelity)。3.4 跑起来的参数量子比特数、shots 与特征维度怎么定量子比特数和维度是直接挂钩的总量子比特数 2 × ⌈log₂d⌉ 1。下面是常见维度的资源配置参考表。嵌入维度 d振幅编码量子比特swap test 总量子比特shots 建议8PCA 降维后37204832511409612871581923849198192768102116384shot 数量直接决定保真度估计的方差。理论上 P(0) 的估计方差正比于 P(0)(1−P(0))/shots当真实保真度接近 0 或 1 时方差会自然变小中间区域需要更多采样。从 8192 起步如果发现同一对向量的重复估计波动超过 0.05就把 shots 翻倍。这个现象在代码里很好排查把同一个样本对放进 swap_test_fidelity 跑三遍看输出即可。维度选择有一个实践技巧先用 PCA 把 384 维降到 8 维或 32 维跑通整个流程确认聚类迭代和评估代码没有 bug再用原始维度做精度验证。降维会损失语义信息但流程验证阶段追求的是快和稳不是分数。我一般会保留两套配置一套给 CI 回归用一套给最终实验用。4. 借 MTEB 基准测试的口径在自建数据集上评估聚类质量4.1 为什么不自接跑完整 MTEB 基准测试MTEBMassive Text Embedding Benchmark是一个覆盖面很广的文本嵌入评测基准把嵌入模型丢进包括聚类、检索、分类、语义相似度在内的多个任务里统一打分。它的聚类任务基本协议是给一组带话题标签的句子或段落嵌入后跑聚类再用 V-measure 和 ARI 这类指标汇报聚类质量。这个协议本身非常清晰但完整复刻整套 MTEB 的成本很高数据集规模和任务数量都不是为单篇技术验证设计的。我们在这里真正要评估的不是嵌入模型而是 QK-means 这个聚类算法。评估目标不同就不该背上整个基准的包袱。我一般只沿用 MTEB 聚类任务的口径文本加真实标签嵌入后聚类聚类结果与真实标签计算 V-measure。这样既保证了评估方法有据可依又让实验可以在笔记本上几分钟内完成。4.2 自建数据集的三种构建方式自建数据集的构建方式决定了评估结论的适用范围我常用三种。第一种是公开语料采样找带类别标签的新闻、论文摘要或商品评论每个类别随机抽几十条。这种方式标签可靠、覆盖真实分布适合最终验证。第二种是从自己的业务文档里标注适合验证 QK-means 在特定领域文本上的表现代价是标注成本高。第三种是模板合成数据用少量种子文本加上同义改写或模板组合生成语料适合先跑通全流程。三种方式在评估价值上有明显差异。公开语料采样的结论可以外推到同类文本业务标注的结论只对本领域有效但最贴近生产合成数据只能用来验证代码正确性。我通常的做法是开发阶段用合成数据参数调优阶段用业务标注数据写结论前用公开语料做一次干净的对比实验。这个顺序能最大程度避免把 bug 当成实验结果。4.3 V-measure 评估与基线对比V-measure 是聚类结果与真实标签之间的一致性度量由同质性homogeneity和完整性completeness的调和平均得到。它不要求两边类别编号对齐只关注信息一致性适合评估这种自建数据集上的聚类算法。from sklearn.metrics import v_measure_score, homogeneity_score, completeness_score y_true np.array(labels) y_pred qkmeans(vecs, k3) # 见 3.3 节的主循环 v v_measure_score(y_true, y_pred) h homogeneity_score(y_true, y_pred) c completeness_score(y_true, y_pred) print(fV-measure{v:.3f} homogeneity{h:.3f} completeness{c:.3f})这段代码的唯一依赖是 scikit-learn评估指标本身不关心聚类是量子算出来的还是经典算出来的。跑对比实验时我会在同一份嵌入上并行跑经典 K-means、scikit-learn 的 K-Means 和 QK-means三者输出 V-measure 的平均值和标准差。量子版本如果和经典版本差距在 0.05 以内说明量子距离估计没有破坏聚类结构差距过大优先怀疑距离换算公式或归一化问题而不是量子硬件噪声。对比实验设计有一个细节经典 K-means 和 QK-means 必须使用相同的初始质心和相同的迭代上限否则差异会混杂初始化随机性。固定随机种子是最低要求更稳妥的做法是多次初始化取平均分。小数据集上单次运行的 V-measure 方差可能达到 0.1不看均值只看单次结果很容易得出错误结论。5. 量子K-means 落地避坑模拟器上的四个常见误判5.1 距离估计波动大聚类结果时好时坏现象同一份数据和固定种子QK-means 跑两次V-measure 一次 0.82 一次 0.61差距大到无法判断算法是否有效。原因swap test 本质是概率测量有限 shots 下保真度估计存在采样误差。当真实内积处在 0.5 附近时P(0) 的斜率最大换算成保真度后误差被放大。聚类迭代过程中一个小误差可能改变样本分配进而改变质心误差在迭代中累积放大。解决先把 shots 提到 16384 以上然后对每个样本对重复估计三次取中位数作为距离值。中位数比均值对离群噪声更鲁棒。如果波动仍然明显检查一下是否所有向量都做了归一化——未归一化向量的内积平方可能超过 1直接破坏整个距离矩阵。5.2 忘记归一化距离公式全盘错乱现象V-measure 分数和经典 K-means 差出 0.3 以上甚至不如随机标签。原因swap test 推导链路上每一步都要求单位向量。距离换算公式 d² 2(1−fidelity) 只对单位向量成立。如果嵌入向量模长不均匀内积平方丢失了模长信息欧氏距离的模长项完全没有进入计算。文本嵌入场景下不同文本的向量模长差异往往携带语义显著度信息丢掉它聚类结构必然受影响。解决在 sentence-transformers 的 encode 调用里直接打开 normalize_embeddingsTrue或者在送入 swap_test_fidelity 前手动除以 L2 范数。我还会顺手打印几个样本的范数做断言如果范数偏离 1 超过 1e-6立即中断并提示归一化错误。5.3 质心更新后偏离单位球面下一轮迭代距离漂移现象第一轮聚类正常第二轮开始距离矩阵数值分布明显变化最终收敛到一个解释不了的划分。原因K-means 的质心更新是算术平均两个单位向量的平均向量模长小于 1。而 QK-means 的距离计算把它当作单位向量处理等于强制把质心投影到单位球面上。这相当于算法在迭代过程中静默换了一个质心定义聚类目标不稳定结果自然不对。解决质心更新后立即重新归一化。这个做法的数学含义是QK-means 实际收敛到的是球面 K-means 的解——用余弦相似度而不是欧氏距离做聚类。如果业务场景需要保留模长信息需要在经典侧把质心模长作为额外标量传入距离公式即 d² ‖a‖² ‖b‖² − 2‖a‖‖b‖·fidelity。但工程上我推荐直接归一化实现简单且和 swap test 的物理语义一致。5.4 模拟器在 19 个量子比特以上变慢整个实验跑不完现象单个 swap test 线路跑得很快但放进 n×k×iterations 的嵌套循环后总时间指数上涨一个 200 条文本的小实验要跑几个小时。原因AerSimulator 的 statevector 模拟每次运行都会重新初始化完整的 2ⁿ 维状态向量19 个量子比特对应 2¹⁹ ≈ 52 万个复数状态分量虽然单次毫秒级但乘上上千次调用后累加效应非常明显。解决先做维度降维用 PCA 把嵌入压到 32 维甚至 8 维验证流程再逐步升维。量子线路的基本参数是 log₂d从 384 维降到 32 维量子比特数从 19 降到 11模拟开销接近减半。另一个常见做法是把同一个质心对多个样本的距离估计打包进一次批处理减少线路构造的开销。如果只是演示流程16 个量子比特以内的配置足够说明问题。6. 从模拟器到硬件的三步验证自适应 shots 与距离矩阵自检确定 QK-means 在模拟器上稳定之后还需要一套可以在真实硬件上迁移的验证方法。第一步是自适应 shots 校准。固定 shots 对距离矩阵中不同区域误差不均匀尤其是内积接近 0.5 的样本对误差显著大于接近 0 或 1 的区域。做法是设定一个目标方差对每个样本对做循环估计一次保真度算方差超过阈值就把 shots 翻倍重跑直到达标或达到上限。def adaptive_fidelity(vec_a, vec_b, base_shots2048, target_var1e-4, max_shots65536): shots base_shots while shots max_shots: f swap_test_fidelity(vec_a, vec_b, shotsshots) var 4 * (f 1) / 2 * (1 - (f 1) / 2) / shots # P(0) 方差近似换算 if var target_var or shots max_shots: return f, var shots * 2这段代码把 shots 从 2048 开始按需翻倍直到保真度估计的方差落在目标区间。核心逻辑是用概率估计的方差公式反推采样需求避免对所有样本对一刀切地使用大 shots 浪费模拟时间。真实硬件上跑的时候自适应校准能显著节约量子资源因为量子计算的时间成本比模拟器贵得多。第二步是距离矩阵自检。在进入聚类主循环前随机抽几十个样本对同时用经典 NumPy 算出真实距离和 swap test 的估计值画一张散点图点应该落在对角线上。这个检查能一次性暴露归一化错误、符号问题和 shots 不足。我跑这类项目时最看重这个检查因为它直接验证“量子部分说的距离和经典物理意义上的距离是同一个东西”。第三步是小规模硬件测试。先把量子比特数控制在 7 到 11 个之间用真实后端跑距离估计对比模拟器结果。真实硬件上的 swap test 输出会偏离理论值需要用 mitigated 测量或对已知内积的校准对做标定把偏差拟合成一条校正曲线。这个曲线不会完美但能为后续的更大规模实验提供误差上界。经验是保真度偏差超过 0.1 的硬件配置不要直接上 K-means 主循环先解决校准问题再继续。希望这个验证框架能在你把 QK-means 推向实际业务前帮你挡掉那些“模拟器上一切正常、换硬件就翻车”的深夜。本文还有配套的精品资源点击获取
返回列表