返回资讯中心
外部精选
软件工程
#开发者实时流

qullama 将量子电路转为 GGUF 模型,借 llama.cpp 运行

来源标题:Running quantum circuits inside llama.cpp

qullama 把量子电路封装成 qgate GGUF 模型,用 llama-embedding 将电路作用于 |0...0> 并输出态矢量,每层对应一个量子门。实现基于 llama.cpp 的少量补丁,支持量化运行以降低内存占用,并包含 CUDA(未测试)和 Vulkan kernel。作者称这仍是概念验证,需进一步调整和测试才能实用。

Hacker News 最新dakkk2026/11/4 · 2 天前16 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

qullama 会把一个量子电路变成一个 qgate GGUF “模型”,它的每一层就是电路中的一个门;用 llama-embedding 运行这个模型,就相当于把电路作用到 |0...0> 上,并返回输出的状态向量。这里使用的 llama.cpp 打了一个小补丁,在现有的 ggml_map_custom3 算子之上构建了一个自定义架构。

量子电路可以在量化版本上运行,从而降低内存占用。这个实现还包含 CUDA(未测试)和 Vulkan 内核。这只是一个概念验证,还需要进一步调整、测试和开发,才能变得可用、有用。欢迎提交 PR。

量子态就是 prompt token 的 embedding 行:sqrt(2d) * [Re psi; Im psi],其中 d = 2^n,因此 n_embd = 2^(n+1),最后的 RMSNorm(eps=0,weights=1)是一个空操作。prompt 是单个字符,所以它会被 tokenize 成恰好一个 token(没有 BOS)。

每个门变成一个模型层。补丁的图构建器为每一层发出一个 ggml_map_custom3 节点;内核把门的 2^k x 2^k 矩阵(以其实块形式 [[Ur,-Ui],[Ui,Ur]] 存储在 blk.i.qgate.weight 中)作用到状态的目标量子比特块上。blk.i.qgate_meta(I32: [k, n_controls, targets..., controls...])选择目标和控制位;控制关闭的块保持不变。门矩阵和控制元数据直接来自 qiskit(op.to_matrix()、num_ctrl_qubits)。

用 llama-embedding -m model.gguf -p q --embd-normalize -1 --embd-output-format raw 读回:打印出的向量是 M x x,输出状态为 psi_out = (emb[:d] + 1j*emb[d:]) / sqrt(2d)。

pip install . ./build_patched_llama.sh # -> llama.cpp/build/bin/llama-embedding

VULKAN=1 ./build_patched_llama.sh # 启用 Vulkan

CUDA=1 ./build_patched_llama.sh # 启用 CUDA

qullama eval examples/bell.qasm --llama-embedding llama.cpp/build/bin/llama-embedding qullama eval examples/ghz4.qasm qullama eval examples/qft3.qasm

只写出 GGUF

qullama to-gguf examples/bell.qasm -o bell.gguf

测试

python3 tests/test_qgate.py

qullama eval 会打印概率最高的几个测量结果,以及相对于 qiskit Statevector 的最大振幅误差和 L2 振幅误差。

直接在 Python / Qiskit 中构建电路,并把 qullama 当作模拟器后端使用(见 examples/library_demo.py):

from qiskit import QuantumCircuit from qullama import simulate, QullamaBackend qc = QuantumCircuit(2) qc.h(0) qc.cx(0, 1) psi = simulate(qc) # 复数状态向量,长度为 2**n backend = QullamaBackend() # qiskit-backend 风格 sv = backend.run(qc).result().get_statevector()

simulate(qc) 会在临时目录中构建 qgate GGUF,用 llama.cpp/build/bin/llama-embedding 运行它,再把 embedding 解码回状态向量。QullamaBackend(llama_embedding=...) 也接受一个电路列表。

Python 侧的计算是 float64,但 GGUF 和内核按所选 dtype 运行——默认是 F32。门权重的量化在库和 CLI 中都可以选择(--dtype),状态 embedding 始终保持 F32:

qullama eval examples/qft3.qasm --dtype Q8_0 simulate(qc, dtype="Q8_0") # F32 | F16 | BF16 | Q8_0 | Q4_0

通过 python3 examples/bench_quant.py 测量(随机电路,行 = n_qubits x 深度,列 = dtype;状态 embedding 始终为 F32,只量化门权重;当 n >= 16 时只扫描 F32/Q8_0 以控制运行时间;总门数 <= 512):

max |amp| 误差 vs qiskit GGUF 大小 (MB) 子进程峰值 RSS (MB) n x 深度 | F32 F16 BF16 Q8_0 Q4_0 | F32 ... (Q8_0) 4 x 8 | 1.5e-7 1.3e-4 1.7e-3 4.2e-3 6.1e-2 | 0.009 ... 0.029 | ~88 8 x 32 | 7.9e-8 1.4e-4 1.2e-3 4.3e-3 1.1e-1 | 0.065 ... 0.210 | ~88 12 x 32 | 4.5e-8 6.0e-5 8.0e-4 2.1e-3 6.8e-2 | 0.184 ... 0.396 | ~89 16 x 16 | 1.8e-8 ... 7.0e-4 | 1.630 ... 1.908 | ~92 20 x 6 | 1.1e-8 ... 5.7e-4 | 25.19 ... 25.32 | ~144 24 x 4 | 3.5e-9 ... 8.4e-5 | 402.7 ... 402.8 | ~1065

实际耗时 (s) | qullama F32 | qullama Q8_0 | qiskit Statevector 12 x 32 | 0.07 | 0.09 | 0.01 16 x 16 | 0.22 | 0.23 | 0.14 20 x 6 | 2.33 | 2.35 | 1.22 24 x 4 | 33.45 | 33.13 | 13.15

Shor 算法(examples/shor.py)

在 qullama 上运行完整的 Shor 分解。布局:t 个计数量子比特 + n 个工作量子比特;t 根据 a mod N 的乘法阶 r 自动确定大小(t = min(2n, 2bit_length(r)+2),因为连分数只需要 2^(t+1) > 2r^2)。模乘器 |x> -> |cx mod N> 是 Z_N 的一个置换(扩展为工作寄存器上的双射),作为单个 n 量子比特酉门发出,并在每个计数量子比特上受控。

./venv/bin/python examples/shor.py # N=15, a=2 -> 3 * 5(12 量子比特) ./venv/bin/python examples/shor.py 1023 2 --max-qubits=24

N=1023, a=2 -> 31 * 33(20 量子比特)

./venv/bin/python examples/shor.py 4095 4 --dtype=Q4_0 --max-qubits=24 --no-crosscheck

N=4095, a=4 -> 63 * 65(20 量子比特)

在 CPU 上测量(在 RAM 允许时用 qiskit Statevector 交叉验证): N=15(12 量子比特):误差 4.7e-9 -> 3 * 5 N=123(21 量子比特):5.0 s,误差 1.5e-8 -> 3 * 41 N=255(18 量子比特):误差 2.2e-9 -> 15 * 17 N=511(19 量子比特):误差 1.6e-8 -> 7 * 73 N=1023(20 量子比特):误差 1.8e-8 -> 31 * 33 N=4095(20 量子比特,Q4_0):54 s,峰值 RSS 约 4.5 GB -> 63 * 65

llama.cpp 补丁

qullama-b12075.patch(针对 tag b12075,即最新发布 tag;已验证可在干净的 checkout 上干净地应用)增加了一个真正的 ggml 算子 GGML_OP_QGATE:

GPU 结果(examples/bench_gpu.py,AMD Radeon 780M iGPU / RADV,对比 qiskit Statevector;在 16–22 量子比特下测量): n x 深度 | 门数 | cpu s | vk s | cpu 误差 | vk 误差 16 x 8 | 134 | 0.17 | 0.26 | 1.5e-8 | 2.0e-8 20 x 4 | 84 | 1.58 | 1.90 | 1.5e-8 | 1.7e-8 22 x 2 | 46 | 5.76 | 6.56 | 5.9e-9 | 1.3e-8

测量结果(打补丁的 b12075 构建,CPU) 电路 相对于 qiskit Statevector 的误差 bell.qasm, ghz4.qasm 精确(0.0) qft3.qasm 1.6e-8 随机 8 / 10 量子比特 4.8e-8 / 2.8e-8

扩展性(随机电路,每量子比特 4 个门):12 量子比特 -> 311 KB GGUF;16 量子比特 -> 1.6 MB / 0.27 s;20 量子比特 -> 25 MB GGUF / 3.9 s,且 sum(p) = 1 精确到 1e-7。实际上限是 RAM 中的状态向量(CPU 上约 25–28 量子比特,GPU 上更多)。

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →