Closed BoltzmannEntropy closed 1 year ago
Hi @BoltzmannEntropy!
First thing: you should not use Tensor in the expectation value. return qml.expval(Tensor(*[qml.PauliZ(i) for i in range(n_qubits)]))
but simply return qml.expval([qml.PauliZ(i) for i in range(n_qubits)])
, then you need to use hstack
on the QNode results.
Could you come up with a minimal non working example (few lines)? Remove all unnecessary steps and highlight a specific issue. It is possible that your model not training, is not related directly to PennyLane.
Thanks!
Hi there, I appreciate your greeting and gratitude.
The code snippet I shared is labeled as "minimal non-working." However, it is actually functional, although it may have a conceptual bug. The issue is that both ACC and LOSS remain unchanged throughout the code's execution. This behavior could be connected to PennyLane, although it's uncertain whether the problem is specific to that library.
Previously, I had transferred the code from Paddle-Quantum, where this particular issue did not occur and ACC reached almost 78%, but i can not really compare the two experiments since these are totally different issues.
Hi @BoltzmannEntropy!
First thing: you should not use Tensor in the expectation value.
return qml.expval(Tensor(*[qml.PauliZ(i) for i in range(n_qubits)]))
but simplyreturn qml.expval([qml.PauliZ(i) for i in range(n_qubits)])
, then you need to usehstack
on the QNode results.Regarding the expectation value issue, here is a minimal code to reproduce the issue:
# Install necessary packages
# !pip install torch==1.12.1 torchvision==0.13.1 pennylane==0.29.0 efficientnet_pytorch
# Import required libraries
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import pennylane as qml
from pennylane import numpy as np
import os
from tqdm import tqdm
import sys
from pennylane.operation import Tensor
import psutil
import matplotlib.pyplot as plt
import random
# Set device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Set parameters
patch_size = 2
img_size_single = 128
img_size_flat = img_size_single ** 2
RGB_C = 3 # Number of channels in the image (RGB)
batch_size = 32
num_epochs = 60
n_qubits = patch_size ** 2 * RGB_C
n_layers = 1
num_classes = 2
# Note if you forget to wrap your circuit with dev: AttributeError: 'tuple' object has no attribute 'float'
dev_train = qml.device('default.qubit', wires=n_qubits)
def Q_encoding_block(q_input_features, n_qubits):
for qub in range(n_qubits):
qml.Hadamard(wires=qub)
qml.RY(q_input_features[qub], wires=qub)
def Q_quanvol_block_A(q_weights, n_qubits, q_depth):
for layer in range(q_depth):
for i in range(n_qubits):
if (n_qubits - i - 1) != i:
if i % 2 != 0:
qml.CNOT(wires=[n_qubits - i - 1, i])
else:
qml.CNOT(wires=[i,n_qubits - i - 1,])
if (i < n_qubits - 1) and ((n_qubits - i - 1) != i):
qml.CRZ(q_weights[layer], wires=[i, (i + 1) % n_qubits])
# Prevent WireError: Wires must be unique; got [0, 0].
if i % 2 == 0:
qml.CNOT(wires=[n_qubits - i - 1, i])
else:
qml.CNOT(wires=[i,n_qubits - i - 1,])
qml.Hadamard(n_qubits - i - 1)
qml.RY(q_weights[layer], wires=i)
def Q_encoding_circuit_A(q_input_features, q_weights, n_qubits, q_depth):
# q_input_features = q_input_features.astype(np.float64)
# print('inputs / weights {}/{}'.format(inputs.shape, weights.shape))
Q_encoding_block(q_input_features, n_qubits)
Q_quanvol_block_A(q_weights, n_qubits, q_depth)
# exp_vals = [qml.expval(qml.PauliZ(position)) for position in range(n_qubits)]
# exp_vals=qml.expval(Tensor(*[qml.PauliZ(i) for i in range(n_qubits)]))
return qml.expval([qml.PauliZ(i) for i in range(n_qubits)])
# return exp_vals
def Q_Plot(cirq_0, q_b,q_d):
print("Plot Q/D:{}/{}".format (q_b,q_d))
# shapes:torch.Size([16129, 12]),torch.Size([12, 12]),12,2
fig, ax = qml.draw_mpl(cirq_0,expansion_strategy='device')(torch.zeros(q_b), torch.zeros(q_d),q_b,q_d)
# print (qml.draw(cirq_0,expansion_strategy='device')(torch.zeros(q_b), torch.zeros(q_d)))
# plt.figure(figsize=(5,3))
# from pylab import rcParams
# rcParams['figure.figsize'] = 3, 6
# fig.set_size_inches(12,6)
plt.show()
fig.show()
# Define the Quanvolutional Neural Network
class QuanvolutionalNeuralNetwork(nn.Module):
def __init__(self, n_qubits, n_layers, circuit, dev_train, gpu_device, patch_size, img_size_single, num_classes):
super().__init__()
self.n_qubits=n_qubits
self.patch_size=patch_size
self.img_size_single=img_size_single
self.n_layers=n_layers
self.device=gpu_device
self.circuit=circuit
self.num_classes=num_classes
self.dev_train=dev_train
weight_shapes = {"weights": (n_layers, 2 * n_qubits)}
self.fc1 = nn.Linear(self.n_qubits, self.num_classes)
self.q_params = nn.Parameter(torch.Tensor(self.n_qubits, self.n_qubits))
self.lr1 = nn.LeakyReLU(0.1)
nn.init.xavier_uniform_(self.q_params)
# qnode = qml.QNode(circuit, self.dev_train, interface = 'torch')
self.pqc = qml.QNode(circuit, self.dev_train, interface='torch')
# self.ql1 = qml.qnn.TorchLayer(qnode, weight_shapes)
Q_Plot(self.pqc,self.n_qubits,self.n_layers)
def extract_patches(self, x):
patches = []
bs, c, w, h = x.size()
for i in range(w - self.patch_size + 1):
for j in range(h - self.patch_size + 1):
patch = x[:, :, i:i+self.patch_size, j:j+self.patch_size]
patches.append(patch)
patches = torch.stack(patches, dim=1).view(bs, -1, c * self.patch_size * self.patch_size)
return patches
def forward(self, x):
assert len(x.shape) == 4 # (bs, c, w, h)
bs = x.shape[0] # batch_size = x.size(0)
c = x.shape[1] # RGB or mono
x = x.view(bs, c, self.img_size_single, self.img_size_single)
q_in = self.extract_patches(x)
q_in = q_in.to(self.device)
# print (q_in.shape)
# q_out = torch.Tensor(0, n_qubits)
q_out = torch.Tensor(0, self.n_qubits)
XL=[]
q_out = q_out.to(self.device)
for elem in q_in:
# print ('shapes:{},{},{},{}'.format(elem.shape, self.q_params.shape,self.n_qubits, self.n_layers))
# output = torch.stack([torch.hstack(circuit(x, params)) for x in input])
q_out_elem = self.pqc(elem, self.q_params,self.n_qubits, self.n_layers).float().unsqueeze(0)
# q_out=torch.hstack(q_out_elem)
XL.append(q_out_elem)
# q_out = torch.cat((q_out, q_out_elem))
X = torch.stack(XL, dim=0)
# Reshape X to match the subsequent layer's input requirements
x = self.lr1(X.view(-1, self.n_qubits))
x = self.fc1(x)
return x
if __name__ == '__main__':
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print (device)
# Initialize the Quanvolutional Neural Network
qnn= QuanvolutionalNeuralNetwork(n_qubits, n_layers, Q_encoding_circuit_A, dev_train, device, patch_size, img_size_single, num_classes)
qnn = qnn.to(device)
The resulting error:
Plot Q/D:12/1
Traceback (most recent call last):
File "qc-cnn.py", line 153, in <module>
qnn = QuanvolutionalNeuralNetwork(n_qubits, n_layers, Q_encoding_circuit_A, dev_train, device, patch_size, img_size_single, num_classes)
File "qc-cnn.py", line 108, in __init__
Q_Plot(self.pqc, self.n_qubits, self.n_layers)
File "qc-cnn.py", line 77, in Q_Plot
fig, ax = qml.draw_mpl(cirq_0, expansion_strategy='device')(torch.zeros(q_b), torch.zeros(q_d), q_b, q_d)
File "pennylane/drawer/draw.py", line 536, in wrapper
qnode.construct(args, kwargs_qnode)
File "pennylane/qnode.py", line 751, in construct
self._tape = make_qscript(self.func)(*args, **kwargs)
File "pennylane/tape/qscript.py", line 1371, in wrapper
result = fn(*args, **kwargs)
File "qc-cnn.py", line 70, in Q_encoding_circuit_A
return qml.expval([qml.PauliZ(i) for i in range(n_qubits)])
File "pennylane/measurements/expval.py", line 55, in expval
if not op.is_hermitian:
AttributeError: 'list' object has no attribute 'is_hermitian'
Hi @BoltzmannEntropy,
Sorry for the misunderstanding, you can use either return [qml.expval(qml.PauliZ(i)) for i in range(n_qubits)]
with hstack
as post processing or if you want the product of it qml.expval(qml.prod(*[qml.PauliZ(wires=i) for _ in range(n_qubits)]))
.
Let me know if that works
Hi @BoltzmannEntropy, I just wanted to leave this video here: 5 Tips for Making Great Forum Posts. These tips are also very helpful for reporting bugs on GitHub. I hope this helps.
Feature details
Dear team, This is a follow up from here: https://discuss.pennylane.ai/t/expectation-values-and-tensors-in-qnn/3024/7
I was unable to find an example that specifically addresses my requirements of processing RGB images, encoding, and training the parameters of a PQC using a quantum circuit alone. Most existing examples tend to involve a classical feature extractor combined with training of only a quantum FC layer, which is not what I am looking for.
I have written a self-contained example for binary classification using the bees/ants dataset, but facing an issue where the validation and training accuracy do not change. I believe this issue is not related to overfitting, but rather a problem in my code that I am unable to identify.
I would appreciate it if you could take a look at my code and provide guidance on this.
Implementation
Here is the code to reproduce the problem:
How important would you say this feature is?
2: Somewhat important. Needed this quarter.
Additional information
Here is the log: