Thanks @eraraya-ricardo, that’s a good point regarding the variational classifier demo.
So it looks like autograd is indeed fine with params being a list of differently-shaped objects, for example the following works nicely:
import autograd
from autograd import numpy as np
def f(params):
angles = params[0]
bias = params[1]
return np.cos(angles[0]) + np.sin(angles[1]) + bias
params = [np.ones(2), 0.5]
df = autograd.grad(f)
df(params)
The issue arises when those parameters are within a QNode, e.g.,
import pennylane as qml
from pennylane import numpy as np
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev)
def f(params):
qml.Rot(*params[0], 0, wires=0)
qml.RX(params[1], wires=0)
return qml.expval(qml.PauliZ(0))
params = [np.ones(2), 0.5]
df = qml.grad(f)
df(params)
The way that the variational classifier demo gets around this (probably by accident) is by defining an intermediate classical function variational_classifier
which unpacks the parameters and feeds them to the QNode. For example, the above code can be adapted to:
import pennylane as qml
from pennylane import numpy as np
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev)
def f(a, b):
qml.Rot(*a, 0, wires=0)
qml.RX(b, wires=0)
return qml.expval(qml.PauliZ(0))
params = [np.ones(2), 0.5]
def cost(params):
return f(*params)
dcost = qml.grad(cost)
dcost(params)
This will now work, because cost()
unpacks the parameters.
For your code specifically, all you should need to do is update the signature of qcircuit()
to something like:
def qcircuit(params0, params1, params2, x=None, y=None):
as well as update the contents of qcircuit
correspondingly. Then, in DRC_Conv
you can do:
def DRC_Conv(params, x=None, y=None):
return qcircuit(*params, x=x, y=y) + params[-1]
This should hopefully work. However I agree that perhaps we should look at supporting this functionality for parameters processed within the QNode.