使用 Python 构建量子神经网络分类器

运行前请准备 ArcQML 源码仓库及对应示例数据。下文命令和 examples/ 路径均以该仓库为基准;本文展示关键代码片段,完整程序位于文中标注的示例路径。

本教程使用 ArcQML Python API 对德国信用数据集进行二分类,对应 Rust QNN 教程benchmarks/qnn 的任务结构。完整程序位于 examples/python/qnn_german_credit.py

任务结构

教程默认 1 层、5 个 epoch;benchmark 会测试更深线路。

数据预处理

python
features, labels = load_data(path=DATA_PATH)
rng = np.random.default_rng(seed=4)
indices = rng.permutation(len(features))
train, validation, test = indices[:800], indices[800:900], indices[900:]

每列使用:

x=π2+xxminxmaxxminπ

原始 Creditability=0 被作为正类 1,表示信用不良。

特征编码

每个局部量子态为:

RZ(x)RX(x)|0=eix/2cos(x/2)|0ieix/2sin(x/2)|1

程序直接计算这些局部态的张量积,并生成 C 连续数组:

python
states = np.ones((len(features), 1), dtype=np.complex128)
for qubit in range(QUBITS - 1, -1, -1):
    angles = features[:, qubit]
    local_states = np.column_stack(
        (
            np.exp(-0.5j * angles) * np.cos(0.5 * angles),
            -1j * np.exp(0.5j * angles) * np.sin(0.5 * angles),
        )
    )
    states = np.einsum("bi,bj->bij", states, local_states).reshape(len(features), -1)

这样每个样本拥有不同初态,而整个 batch 共用同一组可训练 ansatz 参数。

构造线路和可观测量

python
circuit = arcqml.Circuit(num_qubits=QUBITS)
append_ansatz_layer(
    circuit=circuit,
    values=rng.standard_normal(PARAMETERS_PER_LAYER),
)

observable = arcqml.PauliSum.z(
    num_qubits=QUBITS,
    qubit=5,
    coefficient=1.0,
)

append_ansatz_layer 的完整 37 参数线路见示例源码。增加到 L 层后,线路具有 37L 个独立可训练参数。

Batch 训练

python
simulator = arcqml.BatchStateVectorSimulator.from_amplitudes(
    num_qubits=QUBITS,
    amplitudes=np.ascontiguousarray(states[batch_indices]),
)
logits = simulator.run(circuit=circuit, observable=observable)
targets = arcqml.tensor(np.ascontiguousarray(labels[batch_indices]))
loss = arcqml.binary_cross_entropy_with_logits(
    logits=logits,
    targets=targets,
)

loss.backward()
optimizer.step(circuit=circuit)
optimizer.zero_grad(circuit=circuit)

logits 的 shape 为 [batch_size]backward() 通过 BCE 节点把每个样本的梯度传给 batch 量子节点,再由伴随算法累计线路参数梯度。

验证和测试使用:

python
with arcqml.no_grad():
    scores = simulator.run(
        circuit=circuit,
        observable=observable,
    ).numpy()

分类时以 logit >= 0 为正类。ROC-AUC 与 PR-AUC 直接使用连续分数,不依赖分类阈值。

运行

bash
maturin develop --release
python examples/python/qnn_german_credit.py

输出形式:

text
samples: train=800, validation=100, test=100
qubits=10, layers=1, parameters=37
epoch 01/5: train_loss=..., validation_loss=..., validation_accuracy=...%
...
test ROC-AUC=..., PR-AUC=...