You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyTorch与PennyLane构建QNN时遭遇维度不匹配错误

PyTorch+PennyLane构建QNN时的维度不匹配错误解决

问题描述

使用PyTorch和PennyLane搭建量子神经网络(QNN),环境配置完成,但定义量子层时出现维度错误,怀疑输入数据与量子层预期形状不匹配。

原代码

# Get data 
train = datasets.MNIST(root="data", download=True, train=True, transform=ToTensor())
dataset = DataLoader(train, 32)
n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)

@qml.qnode(dev)
def qnode(inputs, weights_0, weight_1):
    print(inputs)
    qml.RX(inputs[0], wires=0)
    qml.RX(inputs[1], wires=1)
    qml.Rot(*weights_0, wires=0)
    qml.RY(weight_1, wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))
weight_shapes = {"weights_0": 3, "weight_1": 1}
qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)
print(qlayer)
class ImageClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(qlayer,
            nn.Conv2d(1, 32, (3, 3)),
            nn.ReLU(),
            nn.Conv2d(32, 64, (3, 3)),
            nn.ReLU(),
            nn.Conv2d(64, 64, (3, 3)),
            nn.ReLU(),
            nn.Flatten(),
            nn.Linear(64 * (28 - 6) * (28 - 6), 10)
        )

    def forward(self, x):
        result = self.model(x)
        return result
# Instance of the neural network, loss, optimizer
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Instance of the neural network, loss, optimizer
clf = ImageClassifier().to('cpu')
opt = Adam(clf.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

# Training flow 
if __name__ == "__main__":
    for epoch in range(1):  # train for 10 epochs
        for batch in dataset:
            X, y = batch
            X, y = X.to('cpu'), y.to(device)
            yhat = clf(X)
            loss = loss_fn(yhat, y)

            # Apply backprop 
            opt.zero_grad()
            loss.backward()
            opt.step()

        print(f"Epoch:{epoch} loss is {loss.item()}")

报错信息

RuntimeError                              Traceback (most recent call last)
<ipython-input-84-a98a57a9f607> in <cell line: 9>()
     12             X, y = batch
     13             X, y = X.to('cpu'), y.to(device)
---> 14             yhat = clf(X)
     15             loss = loss_fn(yhat, y)
     16 

10 frames
/usr/local/lib/python3.10/dist-packages/pennylane/qnn/torch.py in <listcomp>(.0)
    427 
    428         if len(x.shape) > 1:
---> 429             res = [torch.reshape(r, (x.shape[0], -1)) for r in res]
    430 
    431         return torch.hstack(res).type(x.dtype)

RuntimeError: shape '[896, -1]' is invalid for input of size 28

错误原因

  1. 输入维度不匹配:MNIST输入是(batch_size, 1, 28, 28)的4维张量,但量子层qnode仅接受2个输入特征(对应2个量子比特),直接传入高维图像会导致维度解析错误。
  2. 网络顺序错误:量子层被放在卷积层之前,而卷积层需要4维输入,量子层输出的是2维张量,两者形状不兼容。
  3. 设备不一致:数据和模型分别放在不同设备(CPU/GPU),可能引发隐性维度问题。

解决方案

调整网络结构,先用经典模块将图像特征压缩到量子层所需的维度,再接入量子层,最后完成分类任务。修改后的代码如下:

import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import pennylane as qml

# 数据加载
transform = transforms.ToTensor()
train = datasets.MNIST(root="data", download=True, train=True, transform=transform)
dataset = DataLoader(train, batch_size=32)

# 量子设备与量子节点定义
n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)

@qml.qnode(dev)
def qnode(inputs, weights_0, weight_1):
    qml.RX(inputs[0], wires=0)
    qml.RX(inputs[1], wires=1)
    qml.Rot(*weights_0, wires=0)
    qml.RY(weight_1, wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

weight_shapes = {"weights_0": 3, "weight_1": 1}
qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)

# 修改后的分类器结构:经典特征压缩 → 量子层 → 分类头
class ImageClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        # 经典编码器:将28×28图像压缩为2维特征,匹配量子层输入
        self.classical_encoder = nn.Sequential(
            nn.Conv2d(1, 16, 3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, 3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(32 * 7 * 7, 2)
        )
        # 量子层+分类输出层
        self.qnn_classifier = nn.Sequential(
            qlayer,
            nn.Linear(2, 10)
        )

    def forward(self, x):
        # 先提取并压缩图像特征
        features = self.classical_encoder(x)
        # 送入量子层完成分类
        return self.qnn_classifier(features)

# 训练配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
clf = ImageClassifier().to(device)
opt = torch.optim.Adam(clf.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

# 训练流程
if __name__ == "__main__":
    for epoch in range(1):
        total_loss = 0.0
        for batch in dataset:
            X, y = batch
            X, y = X.to(device), y.to(device)
            yhat = clf(X)
            loss = loss_fn(yhat, y)

            opt.zero_grad()
            loss.backward()
            opt.step()

            total_loss += loss.item()
        
        avg_loss = total_loss / len(dataset)
        print(f"Epoch:{epoch} average loss: {avg_loss:.4f}")

关键修改点

  • 新增classical_encoder模块:通过卷积、池化和全连接层,将高维图像压缩为量子层所需的2维特征。
  • 调整网络顺序:经典特征提取在前,量子层接在特征之后,最后用全连接层完成10分类,解决形状不兼容问题。
  • 统一设备:模型和数据都部署到同一设备(CPU/GPU),避免设备不一致引发的隐性错误。
  • 优化训练日志:计算每个epoch的平均损失,提升训练过程的可读性。

内容的提问来源于stack exchange,提问作者Hrridoy V2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:44:56