Differentiation with AmplitudeEmbedding

Hi!

I am working on a Quantum Neural Network using PennyLane with PyTorch interface,
My training data is a simple MNIST classical data, which I scale it to 4x4, My idea was to use AmplitudeEmbedding and encode the 16 features into a 4-qubit system and implement the rest of the network.

However, AmplitudeEmbedding(Along with QubitStateVector) functions are non-differentiable and I am stuck here, what is causing this problem and how can I solve it?

The thing is, AngleEmbedding works fine, however that way I embed my features into 16-qubit system and it takes forever to optimize.

One quick note is, I do not actually want the AmplitudeEmbedding layer to be optimized, since it is only helping to create the quantum input. Therefore, I do not actually need this node within my autograd graph.

#Error message: 
Cannot differentiate with respect to argument(s) {'inputs[12]', 'inputs[0]', 'inputs[11]', 'inputs[2]', 'inputs[4]', 'inputs[5]', 'inputs[7]', 'inputs[3]', 'inputs[6]', 'inputs[9]', 'inputs[13]', 'inputs[10]', 'inputs[15]', 'inputs[14]', 'inputs[1]', 'inputs[8]'}

#Code 
class Net(nn.Module):
def __init__(self):
    super(Net, self).__init__()

    @qml.qnode(dev)
    def my_circuit(inputs,weights):
        self.embed(inputs)
        
        for i in range(n_qubits):
            # implementation of the circuit
        return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)),qml.expval(qml.PauliZ(2)), qml.expval(qml.PauliZ(3))

    @qml.template
    def embed(self,inputs):
        qml.QubitStateVector(inputs, wires = range(n_qubits))

Hey @Bmete7, welcome to the forum!

This should be a case of setting the inputs argument to be a keyword argument, i.e.,
def qcircuit(weights, inputs=False):
This syntax is designed to support the Autograd interface, where keyword arguments are treated as non-trainable.

Here is an example that works:

import pennylane as qml
import torch

qubits = 4
layers = 3
dev = qml.device("default.qubit", wires=qubits)

@qml.qnode(dev, interface="torch")
def qcircuit(weights, inputs=False):
    qml.templates.AmplitudeEmbedding(inputs, wires=range(qubits), normalize=True)
    qml.templates.StronglyEntanglingLayers(weights, wires=range(qubits))
    return [qml.expval(qml.PauliZ(i)) for i in range(qubits)]


weights = torch.tensor(qml.init.strong_ent_layers_uniform(layers, qubits), requires_grad=True)
images = torch.ones(16)

out = torch.sum(qcircuit(weights, inputs=images))
out.backward()

print(weights.grad)
print(images.grad)
1 Like

Thank you very much for a very quick response @Tom_Bromley !

And you were right, I completely missed the need for using a keyword argument with AmplitudeEmbeddings. Now the code is working alright.

I am quite new to the QML area, and I should say it is really exciting to be a part of such a great community!

1 Like