Training Parameters in QNode

Hi, I am writing the code given below:

# Quantum Generator
dev = qml.device("lightning.qubit", wires=num_qubits)

@qml.qnode(dev)
def quantum_generator (inputs, weights):
    qml.templates.AngleEmbedding(inputs, wires=range(latent_size))
    qml.templates.StronglyEntanglingLayers(weights, wires=range(num_qubits))
    return [qml.expval(qml.PauliZ(wire)) for wire in range(num_qubits)]

# Classical Discriminator
class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(image_size * image_size * 3, hidden_size),
            nn.LeakyReLU(0.2),
            nn.Linear(hidden_size, hidden_size),
            nn.LeakyReLU(0.2),
            nn.Linear(hidden_size, 1),
            nn.Sigmoid()
        )

def forward(self, x):
        x = x.view(x.size(0), -1)
        return self.model(x)

# Initialize generator and discriminator
generator = quantum_generator
discriminator = discriminator(). to(device)

# Loss function and optimizer
criterion = nn.BCELoss()
optimizer_generator = optim.Adam(generator.parameters, lr=learning_rate, betas=(beta1, 0.999))
optimizer_discriminator = optim.Adam(discriminator.parameters(), lr=learning_rate, betas=(beta1, 0.999))

The issue I am having is with generator.parameters when I define the losses and optimizer. I am getting the following error:

AttributeError: 'QNode' object has no attribute 'parameters'

Is there any way to get trainable parameters in PennyLane

Your quantum_generator should be invoked inside Discriminator(nn.Module) so that your parameters can be trained. Additionally, you did not declare any parameters in Discriminator(nn.Module) e.g something like:

self.q_params = nn.Parameter(torch.Tensor(self.n_qubits, self.n_qubits))

And then use this as a parameter to the quantum circuit so that it can learn the optimised angles.

Hey @mass_of_15!

Your code example isn’t complete — I’m missing some variables (e.g., latent_size and others). Without running your code, though, QNodes do not have a parameters attribute. However, if you make them Torch layers, they have a parameters method:

import pennylane as qml
import torch

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)
print(qlayer.parameters())

More info can be found here: qml.qnn.TorchLayer — PennyLane 0.30.0 documentation

I also encourage you to go through our tutorial on how to use the PennyLane-Torch interface: Turning quantum nodes into Torch Layers

Hope this helps!