3. 经典神经网络与量子层的接口设计

在混合量子经典网络中,经典神经网络与量子电路并不是简单拼接,而是通过一个可微的数据接口耦合在一起。这个接口承担两件事:把经典张量编码成量子电路能接受的参数或态准备指令,以及把量子测量得到的统计量解码回经典张量,并保证梯度能从经典侧一路回传到量子门参数。接口设计得好不好,直接决定训练能否收敛、梯度是否稳定。

编码:经典输入如何进入量子电路

经典数据进入量子层有两条常见路径。第一条是数据编码:把经典特征映射为量子态的制备角度,例如用角度编码把特征 x_i 写成旋转门参数 RY(x_i),作用在初始态 |0…0⟩ 上。第二条是参数注入:经典网络输出的向量作为变分量子电路(VQA)的可训练门角度。两者在实现上都是“经典标量 → 量子门参数”,但语义不同:前者承载输入信息,后者承载可学习权重。

以 4 维输入、4 量子比特为例,一种直接的角度编码是:

for i in range(4):
    qc.ry(x[i], i)          # 数据编码层
for l in range(L):
    for i in range(4):
        qc.rx(theta[l][i], i)   # 变分层
    qc.cx(0,1); qc.cx(1,2); qc.cx(2,3)

这里 x 是经典侧的输出张量,theta 是可训练参数。编码方式的选择有实际影响:角度编码简单、梯度性质好,但表达力受限于单比特旋转;振幅编码能把 2^n 个特征压进 n 个量子比特,但态准备电路深、对噪声敏感。工程上通常优先角度编码,只有在特征维度远大于量子比特数时才考虑振幅编码或数据重上传(data re-uploading)结构。

一个容易被忽略的细节是输入归一化。旋转角是周期量,特征值超过 2π 会产生混叠,导致不同输入映射到相近的量子态。实践中的做法是把特征缩放到 [-π, π] 或 [0, π] 区间,并在经典侧固定这一预处理,使编码层成为整个可微链路中确定的一环。

解码:测量结果如何变回经典张量

量子电路不能直接输出连续向量,只能通过测量得到比特串的统计分布。解码就是把测量结果转成经典网络可用的张量。最常用的是期望值解码:对每个量子比特测量 Pauli-Z,得到 ⟨Z_i⟩ = P(0) − P(1),取值范围 [-1, 1]。若需要概率语义,则用 P(0) 或 softmax 化的测量频率。

期望值解码的估计依赖采样次数 shots。设 shots = 1024,某比特测得 0 的次数为 610,则 ⟨Z⟩ ≈ (610 − 414)/1024 ≈ 0.191。shots 越大估计越准,但每次前向的电路执行开销也越大。训练早期可用较小 shots(如 256)加快迭代,收敛阶段再提高,这是接口层可以暴露的一个可调参数。

解码后的向量通常还要经过一个经典线性层或激活函数,才能与下游任务对齐。例如分类任务中,把 n 个期望值送入一个 Linear(n, num_classes) 再接 softmax;回归任务则直接线性映射到目标维度。这个“测量 → 经典后处理”的部分必须保持可微,否则梯度会在接口处断裂。

可微分接口的关键约束

要让整条链路可训练,接口必须满足三点。第一,前向可计算:编码、电路执行、测量统计、经典后处理构成确定的数据流。第二,反向可传梯度:量子门参数处的梯度通常用参数移位规则(parameter-shift rule)估计,对形如 exp(−iθP/2) 的门,∂⟨O⟩/∂θ = [⟨O⟩(θ+π/2) − ⟨O⟩(θ−π/2)]/2,因此每个参数需要两次额外电路执行;数据编码处的梯度若也需要训练(如可学习编码),同样走这条路径。第三,接口张量形状一致:经典侧输出的维度必须等于编码层期望的输入维度,测量解码的输出维度必须等于下游经典层期望的输入维度,形状错配是这类流水线最常见的报错来源。

经典前端 特征归一化 x ∈ [-π, π] 数据编码层 RY(x_i) 角度编码 |0…0⟩ → |ψ(x)⟩ 变分量子电路 RX/RY(θ) + CNOT L 层,θ 可训练 测量与统计 Pauli-Z 期望值 shots = 1024 解码与后处理 ⟨Z_i⟩ → Linear → softmax / 回归头 经典输出 预测 / 损失 L(ŷ, y) 反向:参数移位规则估计 ∂L/∂θ,梯度回传至编码层与经典前端 编码参数(可固定或可学习) 变分参数 θ shots 影响估计方差

上图把接口拆成“经典前端 → 编码 → 变分电路 → 测量 → 解码后处理 → 经典输出”的前向链,以及沿虚线回传的反向梯度路径。可以看到,编码层和解码层是两个语义转换点,也是形状与可微性最容易出问题的地方。

一个可运行的接口骨架

下面用 PyTorch 与 PennyLane 风格的伪代码给出接口骨架,重点在形状对齐与梯度连通:

class HybridInterface(nn.Module):
    def __init__(self, in_dim, n_qubits, n_layers, n_out):
        super().__init__()
        self.enc = nn.Linear(in_dim, n_qubits)   # 经典→编码角度
        self.qnode = make_qnode(n_qubits, n_layers)  # 含 theta 参数
        self.head = nn.Linear(n_qubits, n_out)   # 解码后处理

    def forward(self, x):
        a = torch.tanh(self.enc(x)) * math.pi    # 缩放到 [-π, π]
        z = self.qnode(a, self.theta)            # 返回 ⟨Z⟩ 向量
        return self.head(z)

这里 tanh 乘 π 保证编码角落在安全区间,qnode 内部对每个参数使用 parameter-shift 求梯度,head 是普通线性层。训练时用常规优化器即可,但要注意量子部分的梯度是估计值,学习率通常比纯经典网络小一个量级,例如 0.01~0.05。

接口设计中的常见判断

实际调试时,有几个信号值得观察。若损失长期不降且梯度接近零,先检查编码角是否超出范围导致量子态饱和;若梯度方差很大、训练抖动,多半是 shots 太小,可提高到 2048 或 4096 再观察;若前向正常但反向报形状错误,检查 qnode 返回的是标量还是向量、head 的输入维度是否与量子比特数一致。把这三类现象与接口层的三个约束对应起来,排障就有明确方向。

接口层的设计原则可以概括为一句话:前向形状对齐、反向梯度连通、数值范围受控。三者任一缺失,混合流水线都无法稳定训练。