# 量子神经网络 ## 1. 经典神经网络核心概念复习 在我们构建量子版本之前,先快速回顾一下经典神经网络的运作方式。 ### 1.1 组件:参数、算符与损失函数 一个最简单的经典神经元可以被看作一个数学函数 $y = f(wx + b)$。它由以下组件构成: - **输入 (input) $x$**:喂给网络的数据。 - **参数 (parameter) $w, b$**:网络的"知识",即权重 (weight) $w$ 和偏置 (bias) $b$。它们是**可学习的**。 - **线性算符 $wx + b$**:对输入进行线性变换。 - **非线性算符(激活函数 activation function)$f$**:如 Sigmoid、ReLU。这是网络能学习复杂模式的关键。**没有非线性,多层网络也只相当于一个单层网络**,因为线性变换的复合仍是线性变换。 - **输出 (output) $y$**:网络的预测值。 - **损失函数 (loss function)**:如均方误差 $L = (y_{\mathrm{true}} - y_{\mathrm{pred}})^2$,它衡量预测的好坏。我们的目标就是**最小化损失函数**。 ### 1.2 前馈与反向传播 - **前馈网络 (Feedforward)**:数据从输入层开始,逐层向前传递,经过一系列线性和非线性变换,最终在输出层得到结果。这个过程就是一系列函数的复合调用。 - **反向传播 (Backpropagation)**:为了最小化损失,我们需要知道应该如何调整参数 $w$ 和 $b$。反向传播本质上是利用**链式法则 (chain rule)** 高效计算损失函数 $L$ 对每一个参数的**梯度 (gradient)**,即 $\partial L/\partial w$ 和 $\partial L/\partial b$。随后,我们使用梯度下降 (gradient descent) 等优化算法,沿梯度的反方向微调参数,从而降低损失。 ------------------------------------------------------------------------ ## 2. 量子神经网络 (Quantum Neural Network, QNN) 现在,让我们用量子力学的语言来"翻译"经典神经网络的每一个组件。 > **核心类比** > > - 经典比特 → **量子比特 (Qubit)** > - 经典逻辑门 → **量子逻辑门 (Quantum Gate)** > - 可学习的参数 $w, b$ → **可学习的旋转门角度 $\theta$** > - 线性+非线性函数 $f(wx+b)$ → **含参数的量子电路 $U(\theta)$** > - 网络的输出 $y_{\mathrm{pred}}$ → **可观测量 $M$ 的期望值** ### 2.1 含参数量子逻辑门 我们之前学过的 $X$、$Z$、$H$ 门都是固定的。现在,我们引入**可以旋转任意角度**的门,这些角度就是我们要学习的参数 $\theta$。三个最基本的旋转门 (rotation gate) 的定义为 $$ R_x(\theta) = e^{-i\theta X/2} = \begin{pmatrix} \cos(\theta/2) & -i\sin(\theta/2) \\ -i\sin(\theta/2) & \cos(\theta/2) \end{pmatrix}, $$ $$ R_y(\theta) = e^{-i\theta Y/2} = \begin{pmatrix} \cos(\theta/2) & -\sin(\theta/2) \\ \sin(\theta/2) & \cos(\theta/2) \end{pmatrix}, $$ $$ R_z(\theta) = e^{-i\theta Z/2} = \begin{pmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{pmatrix}, $$ 它们分别绕布洛赫球的 X、Y、Z 轴旋转 $\theta$ 角(这些矩阵形式的完整推导见附录1《含参量子门与矩阵欧拉公式》)。这些门的旋转角度 $\theta$ 就是我们的"旋钮",是 QNN 中可以被优化的参数。 ### 2.2 构建含参数量子电路 (PQC) 一个量子神经网络,在结构上就是一个由三部分组成的量子电路: 1. **数据编码 (Data Encoding)**:将经典数据 $x$ 编码到量子态中。例如,可以用一个旋转门将数据作为角度编码进去:$|\psi_{in}\rangle = R_y(x)|0\rangle$。 2. **模型电路 (Model Circuit / Ansatz)**:这就是网络的主体,由一系列固定的门(如 CNOT)和**含参数的旋转门** $R(\theta)$ 组成。这部分电路的结构被称为**拟设 (Ansatz)**。 3. **测量 (Measurement)**:在电路的最后,我们选择一个或多个可观测量(如 $Z_0$、$Z_1$、$Z_0Z_1$),并计算其**期望值 (expectation value)**。这个期望值就是 QNN 的输出。 一个典型的"硬件高效型"(Hardware-efficient) Ansatz 结构如下: [![](https://pennylane.ai/qml/_images/hardware_efficient_layers.png "量子神经网络")](https://pennylane.ai/qml/_images/hardware_efficient_layers.png "点击放大图片") 它由重复的"旋转层"和"纠缠层"构成。 - **旋转层**:对每个量子比特应用可学习的旋转门 $R_x(\theta_1), R_y(\theta_2), R_z(\theta_3)$。 - **纠缠层**:用一系列 CNOT 门将量子比特纠缠起来。 ### 2.3 量子神经网络的前馈过程 QNN 完成一次前馈(即一次函数求值)的流程如下: 1. **准备初态**:通常是 $|00\dots0\rangle$。 2. **编码输入 $x$**:通过 $R(x)$ 等门将数据加载到量子态中。 3. **执行模型电路 $U(\theta)$**:将当前的一组参数 $\theta$ 应用到电路的旋转门上,让量子态进行演化。 4. **计算期望值**:测量某个可观测量 $M$,得到输出 $y_{\mathrm{pred}} = \langle\psi_{out}| M |\psi_{out}\rangle = \langle0| U^\dagger(x, \theta) M U(x, \theta) |0\rangle$。 5. **计算损失**:使用经典计算机,根据预测值 $y_{\mathrm{pred}}$ 和真实值 $y_{\mathrm{true}}$ 计算损失 $L$。 ### 2.4 量子神经网络的梯度计算:参数平移法则 接下来是最关键的问题:我们如何计算梯度 $\partial L/\partial\theta$ 来更新参数?难道要像经典反向传播那样复杂吗? 答案是:**不需要**。量子力学为我们提供了一个优雅得多的方法——**参数平移法则 (Parameter-Shift Rule, PSR)**。 对于一个由旋转门 $U = e^{-i\theta G/2}$(其中 $G$ 是泡利矩阵 $X$、$Y$ 或 $Z$)产生的参数 $\theta$,其最终期望值 $\langle M \rangle$ 对该参数的梯度可以被**精确地**计算: $$ \frac{\partial \langle M \rangle}{\partial \theta_k} = \frac{1}{2} \left( \langle M \rangle_{\theta_k + \pi/2} - \langle M \rangle_{\theta_k - \pi/2} \right) $$ 这个公式的含义是:要计算第 $k$ 个参数 $\theta_k$ 的梯度,我们只需要运行**完全相同**的量子电路两次: 1. 第一次,将参数 $\theta_k$ 增加 $\pi/2$(即 90 度),得到期望值 $\langle M \rangle_{\theta_k + \pi/2}$。 2. 第二次,将参数 $\theta_k$ 减少 $\pi/2$,得到期望值 $\langle M \rangle_{\theta_k - \pi/2}$。 将两个结果相减再除以 2,就得到了**解析梯度 (analytical gradient)**,而不是数值近似。得到 $\partial\langle M\rangle/\partial\theta_k$ 之后,再对输出的映射使用一次链式法则,就能得到损失函数的梯度 $\partial L/\partial\theta_k$。 这个强大的法则是变分量子算法(包括 QNN)能够有效训练的核心:它意味着我们可以直接利用量子计算机本身来计算梯度。该法则的完整证明、它的数值验证,以及它对哪些参数化门成立,都在附录2《参数平移法则》中详细讨论。 ------------------------------------------------------------------------ ## 3. PennyLane 实战:搭建你的第一个 QNN **PennyLane** 是一个专为量子机器学习设计的 Python 库。它将量子电路的搭建、自动微分(内部使用参数平移法则)与经典机器学习框架(如 PyTorch、TensorFlow)无缝集成。 我们的任务是构建一个简单的 QNN,学习一个一维函数 $y = \sin(x)$。步骤如下: 1. **定义量子设备**:我们使用模拟器。 2. **构建 QNN 电路 (QNode)**:编码层用 `RY(x)` 门编码输入;模型层添加若干带参数 `params` 的旋转门和 CNOT 门;测量层返回第一个量子比特的 `PauliZ` 期望值。 3. **定义损失函数**:使用均方误差。 4. **选择优化器**:使用 `AdamOptimizer`。 5. **训练循环**:多次迭代,计算梯度并更新参数。 ### 3.1 训练一个独立的 QNN:拟合 $\sin(x)$ 将上述步骤翻译成代码,我们得到下面的完整程序(可直接运行): ```python import pennylane as qml from pennylane import numpy as np # 使用 PennyLane 自带的 numpy,以支持自动微分 # 1. 定义量子设备:使用 2 个量子比特的默认模拟器 dev = qml.device("default.qubit", wires=2) # 2. 构建 QNN 电路 (QNode) # @qml.qnode(...) 是一个装饰器,它将一个 Python 函数转换成可在设备上运行的量子电路 @qml.qnode(dev) def quantum_neural_net(params, x): """一个简单的量子神经网络""" # --- 编码层:将经典数据 x 编码到第 0 个量子比特上 --- qml.RY(x, wires=0) # --- 模型层 (Ansatz):由可学习的参数 params 控制 --- qml.RX(params[0], wires=0) qml.RY(params[1], wires=0) qml.CNOT(wires=[0, 1]) qml.RX(params[2], wires=1) qml.RY(params[3], wires=1) # --- 测量层:返回第 0 个量子比特上 Z 算符的期望值作为输出 --- return qml.expval(qml.PauliZ(0)) # 3. 定义损失函数 def square_loss(labels, predictions): """计算均方误差""" return np.mean((labels - predictions) ** 2) # --- 准备数据和参数 --- # 生成一些 sin(x) 的数据 X_train = np.linspace(0, 2 * np.pi, 20) Y_train = np.sin(X_train) # 随机初始化 QNN 的参数 num_params = 4 params = np.random.uniform(0, 2 * np.pi, num_params, requires_grad=True) # 4. 选择优化器 opt = qml.AdamOptimizer(stepsize=0.1) # 5. 训练循环 epochs = 50 for i in range(epochs): # 定义一个只接受参数并返回损失的函数,这是优化器需要的格式 def cost_fn(p): predictions = np.array([quantum_neural_net(p, x) for x in X_train]) return square_loss(Y_train, predictions) # 优化器会自动计算梯度(使用参数平移法则)并更新参数 params, cost = opt.step_and_cost(cost_fn, params) if (i + 1) % 10 == 0: print(f"Epoch {i+1:2d}: Cost = {cost:.6f}") print("\n训练完成! 最终参数:", params) # --- 测试和可视化 --- import matplotlib.pyplot as plt X_test = np.linspace(0, 2 * np.pi, 100) predictions_test = [quantum_neural_net(params, x) for x in X_test] plt.plot(X_train, Y_train, 'bo', label="Training data") plt.plot(X_test, predictions_test, 'r-', label="QNN predictions") plt.legend() plt.show() ``` 运行这段代码时,你会看到损失值随迭代逐渐减小,并且在多数随机初始化下,QNN 的预测曲线能够很好地拟合 $\sin(x)$。这并非偶然:示例文档《量子神经网络:示例》中给出了该电路输出的解析表达式 $f(x) = -\sin(\theta_1)\sin x + \cos(\theta_0)\cos(\theta_1)\cos x$,取 $\theta_1 = 3\pi/2$ 时它与 $\sin(x)$ 严格相等,因此损失为零的全局最优解确实存在。 ### 3.2 增强QNN:作为"即插即用"模块的混合模型 我们刚刚学会了如何使用参数平移法则(PSR)来获取量子电路的梯度。这个发现的意义远不止于训练一个独立的 QNN:它意味着,一个含参数的量子电路(PQC)现在可以被看作是一个**完全可微的黑盒**。 既然它是可微的,我们是否可以将它像乐高积木一样,插入到已经非常成熟的经典深度学习模型中呢? 答案是肯定的!这就是**量子-经典混合模型 (Quantum-Classical Hybrid Model)** 的核心思想,也是一种强大的"即插即用" (Plug-and-Play) 策略。 #### 混合模型的架构 一个典型的混合模型(例如用于图像分类)的流程如下: 1. **经典预处理层 (Classical Pre-processing)**: - 一个大的输入(如一张 28x28 的图片)首先通过几层经典的 CNN。 - CNN 的作用是将图片降维,提取出关键的特征,输出一个小的特征向量(例如,一个长度为 4 或 8 的向量)。 2. **量子层 (Quantum Layer)**: - 从经典层输出的特征向量被用作**量子电路的输入**。通常,这些特征值会作为旋转门的角度,将信息编码到量子态中。 - 这个量子电路(PQC)本身也包含**可学习的参数 $\theta$**。 - 电路演化后,测量一个或多个可观测量,其**期望值**作为该量子层的输出。 3. **经典后处理层 (Classical Post-processing)**: - 从量子层输出的期望值(现在是普通的经典数值)可以被送入一个或多个经典的神经元(全连接层),进行最终的分类或回归。 #### 端到端的训练:无缝的梯度流 混合模型最美妙的地方在于,整个系统是**端到端可训练的**。当计算损失函数关于所有参数的梯度时: - 对于**经典层**的参数,梯度通过**反向传播**计算。 - 当梯度流"到达"量子层时,框架(如 PennyLane)会自动切换到**参数平移法则**来计算损失关于量子参数 $\theta$ 的梯度。 - 更进一步,框架还能计算出损失关于**输入到量子层的数据**的梯度,并将这个梯度继续向前传播给更早的经典层。 这意味着,我们可以像训练一个纯经典网络一样,调用 `loss.backward()` 和 `optimizer.step()`,整个混合模型的参数(包括经典的权重和量子的旋转角)都会被自动、协同地优化。 #### 以 PennyLane 和 PyTorch 为例 PennyLane 与 PyTorch、TensorFlow 等主流框架的集成让这种"即插即用"变得异常简单:我们可以将一个 `QNode` 包装成一个标准的 PyTorch 层。 让我们修改一下之前的代码,构建一个简单的混合模型。我们的任务是:用一个经典线性层对数据进行预处理,然后送入 QNN。 ```python import torch import pennylane as qml from pennylane import numpy as np # --- 1. 定义量子设备和 QNode(结构相同) --- dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def quantum_circuit(params, x): # 编码层:x 是长度为 4 的特征向量;按批输入时形状为 (batch, 4), # 因此用 x[:, 0]、x[:, 1] 取出特征,PennyLane 会自动按批广播 qml.RY(x[:, 0], wires=0) qml.RY(x[:, 1], wires=1) # 模型层:可学习的参数 params qml.CNOT(wires=[0, 1]) qml.RX(params[0], wires=0) qml.RY(params[1], wires=1) # 测量层:测量一个关联算符 return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) # --- 2. 构建混合模型 --- # a. 定义经典部分:一个从 1 维输入到 4 维输出的线性层 classical_layer = torch.nn.Linear(1, 4) # b. 将 QNode 包装成一个 PyTorch 层 # weight_shapes 定义了 QNode 中可学习参数的形状 weight_shapes = {"params": (2,)} quantum_layer = qml.qnn.TorchLayer(quantum_circuit, weight_shapes) # c. 使用 torch.nn.Sequential 将它们"即插即用"地连接起来 hybrid_model = torch.nn.Sequential( classical_layer, quantum_layer ) # --- 3. 训练循环(标准的 PyTorch 流程) --- # 准备数据 X_train = torch.linspace(0, 2 * np.pi, 20).reshape(-1, 1) Y_train = torch.sin(X_train) # 定义优化器,它会同时看到经典和量子的参数! opt = torch.optim.Adam(hybrid_model.parameters(), lr=0.1) loss_fn = torch.nn.MSELoss() epochs = 50 for i in range(epochs): opt.zero_grad() # 清空梯度 predictions = hybrid_model(X_train).reshape(-1) # 前向传播 loss = loss_fn(predictions, Y_train.reshape(-1)) # 计算损失 loss.backward() # 反向传播(PyTorch 和 PennyLane 在此协同工作) opt.step() # 更新所有参数 if (i + 1) % 10 == 0: print(f"Epoch {i+1:2d}: Loss = {loss.item():.6f}") # --- 4. 可视化结果 --- import matplotlib.pyplot as plt X_test = torch.linspace(0, 2 * np.pi, 100).reshape(-1, 1) predictions_test = hybrid_model(X_test).detach().numpy() # 使用 detach() 来切断梯度追踪 plt.plot(X_train.numpy(), Y_train.numpy(), 'bo', label="Training data") plt.plot(X_test.numpy(), predictions_test, 'r-', label="Hybrid QNN predictions") plt.legend() plt.show() ``` 在这个例子中,`qml.qnn.TorchLayer` 就是那个"适配器",它让量子电路完美地融入了 PyTorch 的生态系统:训练流程与纯经典模型的训练流程几乎完全一样,充分体现了"即插即用"的便利性。 ### 总结:混合模型的潜力 - **发挥各自优势**:结合了经典网络强大的特征提取能力和量子电路潜在的更强表达能力。 - **适应 NISQ 硬件**:使得在小规模、含噪声的量子设备上解决有意义的现实问题成为可能。 - **灵活性**:可以方便地将量子层插入到任何经典深度学习架构的任何位置,为模型设计提供了巨大的灵活性。 - **活跃的研究方向**:探索何种问题、何种架构最能从这种混合模式中获益,是当前量子机器学习领域最前沿的研究方向之一。 ## 本课总结 1. QNN 的核心思想是**用含参数的量子电路来替代经典神经网络的层**。 2. 旋转门的角度 $\theta$ 是 QNN 的**可学习参数**。 3. QNN 的输出是某个**可观测量 $M$ 的期望值**,它是一个关于 $\theta$ 的连续、可微函数。 4. 我们可以使用高效的**参数平移法则**来精确计算梯度,从而利用经典优化算法(如梯度下降)来训练 QNN。 5. **PennyLane** 等框架极大地简化了 QNN 的构建和训练过程,让我们能专注于模型设计本身。 在下一节课,我们将探讨更复杂的 QNN 结构、不同的数据编码方法,以及 QNN 在分类、强化学习等领域的潜在应用。