A couple of thoughts here:
- The definition of the quantum function would require an update so that the non-differentiable parameter (
X
) has a default parameter:def qnode(weights, X=None)
. This is required when defining theQNode
(included a bit more context in this answer). - The quantum function that you’ve defined currently returns an array with 4 (
n_qubits
) scalars. Therefore optimization will happen as described for Vector-valued QNodes:
for e in range(epochs):
for i in range(len(X)):
weights = opt.step(lambda weights: cost(weights, X=X[i]), weights, grad_fn=lambda weights: qml.jacobian(qnode, argnum=0)(weights, X=X[i]))
As convenience, defined a cost
function:
def cost(weights, X):
res = qnode(weights, X=X)
return res
Breaking this down a bit:
-
lambda weights: cost(weights, X=X[i])
: this helps to pass the current batch of features (X[i]
) to theQNode
-
lambda weights: qml.jacobian(qnode, argnum=0)(weights, X=X[i])
: this has to be defined so that Autograd can compute the gradient of the cost function.argnum=0
is specified as the first argument is differentiable, and we need to passX[i]
as keyword argument.
- A small adjustment would be required for looping through the extracted features (
for i in range(len(X))
loop definition):
for e in range(epochs):
for i in range(len(X)):
weights = opt.step(lambda weights: cost(weights, X=X[i]), weights, grad_fn=lambda weights: qml.jacobian(qnode, argnum=0)(weights, X=X[i]))
- A possible way of creating batches for each step is defining a
batch_size
and selecting a random batch for eachepoch
:
batch_size = 4
for e in range(epochs):
batch_index = np.random.randint(0, len(X), (batch_size))
X_batch = X[batch_index,0]
weights = opt.step(lambda weights: cost(weights, X=X_batch), weights, grad_fn=lambda weights: qml.jacobian(qnode, argnum=0)(weights, X=X_batch))
Hopefully, this gives a bit of direction!
(Note: edited this answer as on the first read didn’t consider the solution as a vector-valued QNode, but rather a QNode that has a tensor product observable as measurement and returns a single scalar. Let us know if specifying a tensor product observable would be desired here, and can provide further pointers!)