简介量子LSTMqlstm示例工程是一份面向量子机器学习初学者的可运行代码包聚焦量子循环神经网络与经典LSTM的对比实验适合已有PyTorch基础、希望切入量子计算与深度学习交叉领域的读者。资源以Python脚本和Jupyter Notebook为核心提供了基于PennyLane的量子LSTM实现、词性标注示例以及经典LSTM对照训练流程通过训练历史曲线图可以直观比较量子模型与经典模型在相同任务上的收敛情况帮助理解量子神经网络的特性。压缩包共10个文件主要包含3个Python源码、1个Notebook、3张训练结果图、2个依赖/说明文本和1份说明文档整体仅84KB结构精简清晰方便快速下载与阅读。已有423人浏览学习。使用这套资源可以对环境配置、模型调用、训练参数调整形成完整认知并可作为后续扩展量子LSTM到其他序列任务的起点。1. 量子 LSTM 示例一个能跑的混合量子循环网络值不值得下qlstm 这份示例本质是一个放在 Jupyter Notebook 里的量子 LSTM 最小实现它把经典 LSTM 的记忆单元计算替换成变分量子电路其余门控仍然用经典网络完成。我实际拆过的感受是它不是要你立刻上量子硬件而是把「量子循环网络」这个黑匣子拆开给你看适合想入量子机器学习、又不想从论文公式读起的人。你如果有 PyTorch 和 PennyLane 的基础照着 notebook 顺序跑一遍能看到一条真实的训练曲线和一组可比较的预测输出。这份资源能解决的是「量子 LSTM 到底长什么样、参数怎么流动、梯度怎么回来」这组问题而不是提供一个可以直接上生产的高精度模型。2. qlstm 的结构拆解把经典单元换成量子电路的三个关键改动2.1 先想清楚量子 LSTM 是混合模型不是全量子模型真正的全量子 LSTM 在现有硬件上没法训练因为循环展开之后线路深度会爆炸。这份示例采用的做法是混合量子经典hybrid quantum-classical用变分量子线路替代 LSTM 内部状态更新的核心计算门控权重仍然是经典参数。你仍然用反向传播训练整个网络只不过梯度有一部分要穿过量子线路。这里有一个容易误会的点量子线路本身不是「模型」它更像一个可微分的非线性函数。在 qlstm 中输入x_t和上一个隐状态h_{t-1}拼接后先经过经典线性变换再映射到量子比特的旋转角度上测量得到的期望值作为候选记忆内容。这样做的好处是参数规模小坏处是边界要处理得仔细后文避坑章节会展开。我见过不少人一上来就问「量子 LSTM 是不是能在量子计算机上跑得比 GPU 快」这是个误区。这份示例跑在default.qubit模拟器上本质是模拟量子线路的张量运算速度远慢于经典 LSTM它的价值在于让你理解量子线路作为可微组件如何嵌入经典计算图以及未来真实量子设备上这类结构的梯度行为。2.2 数据编码方式角度编码和幅值编码怎么选量子线路能处理的是量子态所以进入线路之前必须把经典数据编码进去。qlstm 的示例里最常见的编码是角度编码angle encoding把每个特征直接映射为 RX/RY 旋转角度。这个方案的优点是实现简单、梯度能回传缺点是表达范围受角度周期限制输入不做归一化会翻车。另一种是幅值编码把多个特征编码到量子态的概率幅上理论上信息密度高但制备线路复杂而且对噪声更敏感。qlstm 这种教学示例用角度编码就够了不要为了炫技换成幅值编码。就这个资源而言保持角度编码即可动手改编码方式属于第 6 章的进阶内容。编码方式实现难度梯度回传适用场景注意点角度编码低直接少量特征、教学示例输入须归一化到适合旋转角的范围幅值编码高复杂大特征维度噪声下线路深度大训练慢基础编码低直接二值/低精度特征连续变量会丢失精度在跑这份 notebook 时你会发现示例代码里通常会对输入做一次tanh或归一化处理这正是因为角度编码对输入范围极其敏感。如果跳过这一步量子线路对不同输入产生的量子态区分度会急剧下降模型退化成几乎只依赖经典门控部分。2.3 变分量子电路 ansatz 设计纠缠层数决定表达能力qlstm 里量子线路的骨干是一个可训练参数化的 ansatz。以 4 量子比特为例线路可以拆成三层首先对输入做角度编码然后叠加带参数的 RY 旋转和 CNOT 纠缠最后测量前两个量子比特的泡利 Z 期望值。测量值多长候选记忆向量就多长。线路越深表达能力越强但参数越多、模拟越慢。对这份示例而言2 到 4 层纠缠层比较实际再深就退化成「用模拟器硬算高维线性代数」失去了体验意义。这里给一段 PennyLane 定义量子节点的示意代码实际项目中我一般把这段封装成独立模块方便切换设备import pennylane as qml n_qubits 4 n_layers 2 dev qml.device(default.qubit, wiresn_qubits) qml.qnode(dev, interfacetorch, diff_methodbackprop) def quantum_cell(inputs, weights): # inputs: shape (n_qubits,)已归一化到 [-pi/2, pi/2] for i in range(n_qubits): qml.RY(inputs[i], wiresi) for layer in range(n_layers): for i in range(n_qubits): qml.RY(weights[layer, i], wiresi) for i in range(n_qubits - 1): qml.CNOT(wires[i, i 1]) return [qml.expval(qml.PauliZ(i)) for i in range(2)]interfacetorch是关键它让 qnode 返回 torch 张量而不是 numpy 数组diff_methodbackprop只在模拟器上可用它直接走 PyTorch 的自动微分梯度最稳。如果未来要换真实量子硬件需要改成parameter-shift但那会带来采样噪声训练曲线的波动会明显变大。这段代码里的关键是权重的形状(n_layers, n_qubits)。每一层的 RY 参数是独立的层与层之间靠 CNOT 建立纠缠。如果你想让线路表达能力更强优先增加n_layers而不是增加量子比特数——量子比特多了模拟器的内存占用会指数增长4 比特和 8 比特之间的速度差距不是两倍而是几十倍。3. 在 Jupyter Notebook 里把 qlstm 复现出来环境准备与可抄代码3.1 环境版本建议PennyLane 与 PyTorch 的搭配运行 qlstm 需要 Jupyter Notebook、PennyLane、PyTorch 和 NumPy。我的经验是不要盲目装最新版。PennyLane 如果大版本跨代QNode 的接口行为会变尤其是qml.qnode的参数传递方式PyTorch 的torch.nn.Module和 PennyLane 接口之间偶尔会出现操作符不兼容的问题。我一般在 conda 里单开一个环境然后按下面的顺序装conda create -n qlstm python3.9 -y conda activate qlstm pip install jupyter notebook pip install pennylane pip install torch --index-url https://download.pytorch.org/whl/cpu这里torch我故意装 CPU 版因为 qlstm 这个规模的量子模拟器是 CPU 友好的GPU 版本在量子线路部分几乎用不上还容易引入 CUDA 环境问题。装完后在 notebook 第一格运行下面的代码做自检!python -c import pennylane as qml, torch; print(qml.__version__); print(torch.__version__)如果两个版本都能正常打印说明环境基本可用。常见翻车点是 conda 和 pip 混装导致包冲突这种问题优先检查pip check不要急着重装环境。另外要注意在 Jupyter 里通过!pip install安装的包和当前 kernel 使用的 Python 解释器可能不是同一个环境这也是新手常遇到「装了半天却 import 不到」的原因。3.2 实现一个可训练的 QuantumLSTMCell有了环境下一步是定义自己的量子 LSTM 单元。整体思路构建一个 PyTorch 的nn.Module内部持有量子节点所需的权重参数和经典门控参数。前向传播时把x_t和h_{t-1}拼接后线性映射成角度向量送进量子线路测量结果结合门控再更新记忆。import torch import torch.nn as nn import pennylane as qml class QuantumLSTMCell(nn.Module): def __init__(self, input_dim, hidden_dim, n_qubits4, n_layers2): super().__init__() self.input_dim input_dim self.hidden_dim hidden_dim self.n_qubits n_qubits # 经典部分输入投影 四个门向量 self.input_proj nn.Linear(input_dim hidden_dim, n_qubits) self.gate_proj nn.Linear(n_qubits, 4 * hidden_dim) # 量子部分可训练权重形状为 (n_layers, n_qubits) self.quantum_weights nn.Parameter( 0.1 * torch.randn(n_layers, n_qubits) ) self.dev qml.device(default.qubit, wiresn_qubits) self.qnode qml.qnode( self.dev, interfacetorch, diff_methodbackprop )(self._circuit) def _circuit(self, inputs, weights): for i in range(self.n_qubits): qml.RY(inputs[i], wiresi) for layer in range(weights.shape[0]): for i in range(self.n_qubits): qml.RY(weights[layer, i], wiresi) for i in range(self.n_qubits - 1): qml.CNOT(wires[i, i 1]) return [qml.expval(qml.PauliZ(i)) for i in range(self.n_qubits // 2)] def forward(self, x, h_prev, c_prev): combined torch.cat([x, h_prev], dim-1) angles torch.tanh(self.input_proj(combined)) * (torch.pi / 2) quantum_out torch.stack(self.qnode(angles, self.quantum_weights), dim-1) gates self.gate_proj(quantum_out) i_gate torch.sigmoid(gates[:, :self.hidden_dim]) f_gate torch.sigmoid(gates[:, self.hidden_dim:2*self.hidden_dim]) o_gate torch.sigmoid(gates[:, 2*self.hidden_dim:3*self.hidden_dim]) g_gate torch.tanh(gates[:, 3*self.hidden_dim:]) c_new f_gate * c_prev i_gate * g_gate h_new o_gate * torch.tanh(c_new) return h_new, c_new逻辑说明这个 cell 把量子线路当作「候选记忆生成器」。角度向量由经典线性层生成用 tanh 压缩到[-pi/2, pi/2]避免角度编码越过周期边界量子测量输出经过第二个线性层拆成输入门、遗忘门、输出门和候选值再用经典 LSTM 的更新公式更新记忆。参数说明hidden_dim不一定要等于n_qubits // 2可以靠gate_proj把量子输出映射到任意宽度如果发现 loss 不降优先把quantum_weights初始化的标准差从 0.1 调小到 0.01再检查门控有没有饱和。torch.stack那一步是把 qnode 返回的测量列表拼成向量如果不 stack 直接传给gate_projPyTorch 会把 list 当作序列操作报错。3.3 串成循环层并跑一次前向有了 cell就可以写一个简单的循环封装把时间步逐个展开。这里我一般不用 PyTorch 自带的nn.LSTM的接口约定因为量子 cell 里的梯度回传路径更敏感自己控制 BPTT 展开更安全。class QuantumLSTM(nn.Module): def __init__(self, input_dim, hidden_dim, n_qubits4, n_layers2): super().__init__() self.cell QuantumLSTMCell(input_dim, hidden_dim, n_qubits, n_layers) def forward(self, seq): batch_size, seq_len, _ seq.shape h torch.zeros(batch_size, self.cell.hidden_dim) c torch.zeros(batch_size, self.cell.hidden_dim) outputs [] for t in range(seq_len): h, c self.cell(seq[:, t, :], h, c) outputs.append(h.unsqueeze(1)) return torch.cat(outputs, dim1)这段代码的逻辑是把时间步循环展开每个时间步的h、c都保留返回所有时刻的隐状态。注意初始状态必须用零张量随机初始化会让早期 loss 波动很大。到此模型骨架已经能前向跑通下一步才是训练。跑一次前向时可以先构造一个(batch8, seq_len10, input_dim1)的随机张量确认输出 shape 是(8, 10, hidden_dim)。如果这一步报维度不匹配优先检查input_proj的输入维度是不是input_dim hidden_dim因为拼接后的维度是两者之和很多初稿会在这里少算一个维度。4. 训练与验证损失函数、优化器与结果判断4.1 造一份可以快速验证的数据叠加正弦信号qlstm 示例自带的训练数据往往是最简单的序列生成任务。我一般用叠加正弦来验证因为它有清晰的时序依赖又不会难到让人分不清是模型问题还是数据问题。import numpy as np import torch np.random.seed(42) t np.arange(0, 300, 0.1) signal np.sin(t) 0.3 * np.sin(3 * t) 0.05 * np.random.randn(len(t)) # 归一化到 0~1避免角度编码区间问题 signal (signal - signal.min()) / (signal.max() - signal.min()) seq_len 10 X, Y [], [] for i in range(len(signal) - seq_len): X.append(signal[i:iseq_len]) Y.append(signal[iseq_len]) X torch.tensor(np.array(X), dtypetorch.float32).unsqueeze(-1) Y torch.tensor(np.array(Y), dtypetorch.float32).unsqueeze(-1) train_x, train_y X[:240], Y[:240] val_x, val_y X[240:], Y[240:]逻辑说明这里用 10 步历史预测下一步是典型的单步预测任务。X的 shape 是(样本数, 10, 1)Y是(样本数, 1)。归一化这一步不是可选的而是角度编码的前提条件——如果不缩放信号幅值超过 π/2 之后角度的周期重复会让网络分不清两个相差一个周期的输入。4.2 训练循环与梯度检查训练量子模型最怕「loss 下降很快但其实是梯度走错了方向」。我的习惯是每 50 步打印一次 loss 和验证集 MAE同时检查量子权重梯度的范数是否是有限值。model QuantumLSTM(input_dim1, hidden_dim8, n_qubits4, n_layers2) opt torch.optim.Adam(model.parameters(), lr0.01) loss_fn torch.nn.MSELoss() for epoch in range(300): opt.zero_grad() pred model(train_x) loss loss_fn(pred[:, -1, :], train_y) loss.backward() grad_norm torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm5.0) opt.step() if epoch % 50 0: with torch.no_grad(): val_pred model(val_x) val_loss loss_fn(val_pred[:, -1, :], val_y) print(fepoch {epoch:3d} loss {loss.item():.4f} val {val_loss.item():.4f} grad {grad_norm:.4f})参数说明lr0.01对量子模型偏大如果看到 loss 横跳降到 0.003grad_norm打印出来小于 1e-6 说明梯度没回传到量子权重需要检查上一章的interfacetorch设置。clip_grad_norm_在这里不是必须的但对门控类模型能防止偶发梯度爆炸。pred[:, -1, :]取的是最后一个时间步的隐状态。在单步预测任务里中间时间步的预测也有损失但只取最后一步更干净而且和标签的 shape 对齐不容易写错。如果你发现 loss 在 0.1 附近徘徊很久通常不是因为模型能力不够而是量子部分贡献的梯度在训练后期变得很小经典门控层在自我更新——这时去调学习率已经没有太大作用应该去看量子线路的表达力问题。4.3 训练结果怎么判断先看三条曲线模型是否真正学到了时序规律不能只看 loss。我的判断顺序是训练 loss 下降、验证 loss 同步下降、最后用肉眼对比预测序列和真实序列的相位。这一步很重要因为量子模拟器的输出本身是确定性的如果预测曲线和真实曲线只在幅值上接近说明模型学会了均值预测这在时序任务里是典型的「聪明但没学到动态」。现象判断下一步训练 loss 下降验证 loss 不降过拟合增加数据、减小 hidden_dim训练 loss 降到 0.01预测仍是直线模型输出饱和检查门控初始化调整 gate_proj bias梯度范数偶发巨大BPTT 展开过长缩短 seq_len 或截断梯度两条 loss 都不降量子节点梯度没回来检查 diff_method 与 interface有了这一套判断标准任何网络结构改动换 ansatz、改量子比特数都能在一个下午内对比出来。量子 LSTM 的调参和经典 LSTM 没有本质区别唯一多出来的「量子玄学」就是梯度容易悄悄消失。你会在训练过程中发现经典 LSTM 里的那些经验在量子版本里依然有效只是触发条件更敏感。5. qlstm 常见问题与避坑我实际踩过的六个点5.1 loss 完全不下降输出趋近常数现象训练 loss 从一开始就基本不动预测输出永远是同一个值。原因最常见是角度编码输入范围过大导致量子线路对不同输入几乎无区分度另一常见原因是量子权重初始值太大使线路输出的期望值饱和在 ±1 附近。解决先把输入缩放到[-pi/2, pi/2]再把quantum_weights初始化标准差降到 0.01。如果还不行就把n_layers去掉一层看线路是否太深导致梯度消失。这个坑之所以隐蔽是因为 loss 不降的时候你往往会先去调学习率但问题根本不在优化器。5.2 diff_method 使用不当导致梯度断裂现象报TypeError: unsupported operand type(s)或者loss.backward()提示 numpy 不支持。原因没有在qml.qnode中指定interfacetorch。PennyLane 默认走 autograd返回的是 numpy 类型普通 PyTorch 张量运算能隐式转换但一旦进入loss.backward()就会翻车。解决定义 qnode 时同时写interfacetorch, diff_methodbackprop不要只写其中一个。还有一个细节diff_methodparameter-shift虽然也能在模拟器上跑但每次评估要执行多次线路速度慢一个数量级不建议训练时用。我在第一次跑通这份 notebook 时就是只写了diff_method忘了interface结果前向正常、反向全是坑。5.3 Jupyter 里重复执行 cell内存不断增长现象同一个 notebook 跑十几遍训练 cell 后内存占用越来越大最后 kernel 被杀。原因每执行一次 cellqml.device和 qnode 对象会被重新创建并保留在 Python 变量中PennyLane 的 simulator 会缓存中间态旧对象不释放。这是 Jupyter 交互式执行和量子模拟器叠加出的特殊问题普通 PyTorch 项目不会这么明显。解决把设备定义和 qnode 定义放在一个 cell 并通过「重启内核 全量运行」来做实验如果只是调超参用函数把 model 构造包装起来运行完主动del model。我后来习惯用这个写法def build_model(): return QuantumLSTM(input_dim1, hidden_dim8, n_qubits4, n_layers2)这样每次重置模型对象时旧对象的引用会被覆盖Python 的引用计数能及时回收。不要在一个 cell 里同时创建多个 model 实例做对比实验除非你确定用完就删。5.4 量子线路里用了 sample 测量导致梯度消失现象loss 能算出来但反向传播时梯度全是 nan 或 0。原因qml.sample返回的是采样值不是期望值对参数不可导。在混合训练中一旦采样测量进入计算图整个量子部分的梯度路径就断了。解决训练阶段只用qml.expval如果确实要看分布推理阶段再额外构造一个带qml.sample的线路。这是初学者最容易踩的坑也是「为什么 qlstm 示例里的测量一律是 expval」的原因。你如果从网上下到过其他变体实现大概率能看到有人在这里翻车后留下的注释。5.5 序列长度一变长训练速度急剧下降现象seq_len 从 10 改到 50每 epoch 时间从 1 秒涨到 30 秒。原因普通 LSTM 的反向传播是常数级而量子 LSTM 每个时间步都要调用一次量子线路模拟器BPTT 展开时长直接扩大 5 倍模拟代价近似线性放大。解决缩短 seq_len或者用截断 BPTT只对最近几个时间步反传梯度。真要处理长序列把量子单元放在整个模型的一小段上而不是逐时间步嵌入所有位置。这是个设计决策不是所有时间步都需要量子非线性混合结构完全可以只在关键位置插入量子层。5.6 loss 快速下降到固定值后冻结现象训练 loss 降到 0.2 左右就永远不再下降验证 loss 也卡住。原因门控的 sigmoid 饱和导致记忆单元不再更新。量子部分输出范围有限门控偏置在初始化时如果太大细胞会直接进入「只读」模式。解决给gate_proj的遗忘门加一个正 bias例如bias[1.0, 0.0, 0.0, 0.0]让初始遗忘门接近打开。经典 LSTM 也有这个技巧量子 LSTM 因为候选值方差更小这个技巧几乎是必须的。我实测过不加这个 bias 时loss 卡在 0.2 附近加了之后很快突破到 0.05 以下。6. 进阶用法把 qlstm 用到你的时序任务前先做这三步验证如果你看完示例想把它迁移到自己的数据上我建议不要直接替换经典 LSTM先做三个验证再决定。第一步固定随机种子跑同一个任务三次看 loss 方差。量子线路有参数化线路的初始值敏感性方差大说明结构不稳定先调初始化。第二步做一次「量子部分剃除」实验把量子输出替换成一个等维度的可训练线性层如果经典替代品明显更好说明线路结构没有给模型带来有效非线性。第三步把输入替成你的真实特征但保持角度编码的归一化范围不变。这步最容易出问题你的特征分布如果极不均匀min-max 缩放可能让角度编码集中在很窄的区间此时改成按百分位数裁剪到 5% 到 95% 再缩放。这三个验证做完你基本能确定手里的 qlstm 是该调线路、调门控还是干脆用回经典 LSTM。以我自己的习惯从那以后每次迁移量子模型我都强制先跑一遍「固定种子 经典替代 数据归一化检查」这三步再谈调参。它能挡住八成以上的伪失败——很多模型不是不 work是结构和数据根本没对齐。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
STM32入门详解:从内核架构到外设实战与避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:50:21
ROS 2与Navigation 2实战:自动巡检机器人定位导航调优与避坑指南 简介:本资源面向ROS 2与Navigation 2的初学者及机器人开发进阶者,提供一套完整的自动巡检机器人仿真项目,帮助解决多目标点循环导航、语音播报与图像采集保存等典型任务。压缩包共60个文件,约68KB,以20个Python脚本、1… · 2026/9/25 4:50:21
计算机体系结构课后习题解析:指令系统、流水线与多核设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:50:14
Horizon 科技新闻画像(tech-news)评分体系全解:从评估目标到 AI 分析管线的落地实现 人工智能AI 应用MCP 服务网页爬虫 【免费下载链接】Horizon 📡 Your own AI-powered news radar. Generates daily briefings in English & Chinese. | 用 AI 构建你专属的新闻雷达 项目地址: https://gitcode.com/gh_mirrors/horizon39/Horizon 点击… · 2026/9/25 5:20:31
Ariakit Form 组件实战指南:无障碍表单的提交、校验与状态管理 UI组件前端 【免费下载链接】ariakit Toolkit with accessible components, styles, and examples for your next web app 项目地址: https://gitcode.com/gh_mirrors/ar/ariakit 点击查看 免费下载 Ariakit 的 Form 组件基于 WAI-ARIA Form Role 设计,… · 2026/9/25 5:20:31
Windows免安装Oracle客户端:ODAC Xcopy部署实战指南 简介:面向64位系统的 Oracle 数据访问组件(ODAC)11.2.0.3.20 Xcopy 版,是为解决 SQL Server 与 Oracle 异构数据库集成而准备的开发包。组件中包含关键的 Oracle Provider for OLE DB 驱动,该驱动是在 SQL Server 环境… · 2026/9/25 5:20:25
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37