QNGOptimizer with Variational Classifiers

I am trying to implement the example in https://pennylane.ai/qml/demos/tutorial_data_reuploading_classifier.html with QNGOptimizer because I learned that QNGOptimizer is faster. Then I got the error, The QNG optimizer supports single QNodes or ExpvalCost objects as objective functions. Alternatively, the metric tensor can directly be provided to the step() method of the optimizer, using the metric_tensor_fn argument.

By searching the doc and forum, I also learn that QNGOptimizer cannot work with hybrid cost function.

The cost function in the tutorial is

def cost(params, x, y, state_labels=None):
    """Cost function to be minimized.

    Args:
        params (array[float]): array of parameters
        x (array[float]): 2-d array of input vectors
        y (array[float]): 1-d array of targets
        state_labels (array[float]): array of state representations for labels

    Returns:
        float: loss value to be minimized
    """
    # Compute prediction for each input in data batch
    loss = 0.0
    dm_labels = [density_matrix(s) for s in state_labels]
    for i in range(len(x)):
        f = qcircuit(params, x[i], dm_labels[y[i]])
        loss = loss + (1 - f) ** 2
    return loss / len(x)

In terms of this cost function, does it mean there are 2 Qnodes considering the two types of observable?

Also, could you shed light on combing data_reuploading_classifier with QNGOptimizer?

Thank you in advance.
Ban

One idea is that I should change the circuit from

@qml.qnode(dev, diff_method='adjoint')
def qcircuit(params, x, y):
    """A variational quantum circuit representing the Universal classifier.

    Args:
        params (array[float]): array of parameters
        x (array[float]): single input vector
        y (array[float]): single output state density matrix

    Returns:
        float: fidelity between output state and input
    """
    for p in params:
        qml.Rot(*x, wires=0)
        qml.Rot(*p, wires=0)
    return qml.expval(qml.Hermitian(y, wires=[0]))

to

@qml.qnode(dev, diff_method='adjoint')
def qcircuit(params, x, y):
    """A variational quantum circuit representing the Universal classifier.

    Args:
        params (array[float]): array of parameters
        x (array[float]): single input vector
        y (array[float]): single output state density matrix

    Returns:
        float: fidelity between output state and input
    """
    for p in params:
        qml.Rot(*x, wires=0)
        qml.Rot(*p, wires=0)
    return qml.expval(qml.PauliZ(wires=[0]))

And then redefine the cost function.
Do you think it is feasible?

Hi @Ban_Wong, welcome to the Forum!

It’s a strong claim to say that the QNG Optimizer will always be faster. This is probably not the case. However it’s interesting exploring whether or not it’s faster for this particular application.

In the case of the data reuploading classifier demo there’s a single qnode so this is not the source of the problem.

If you change the return to use a PauliZ instead of using the Hermitian of the density matrix y, you will notice that your code won’t train.

The real issue is that the return function of your qnode changes with each iteration because it’s tied to y. This is why the error message is that you have multiple qnodes.

If you go to the documentation for the QNG Optimizer you will find that the suggestion is to use qml.metric_tensor (note that ExpvalCost is deprecated). However you may need to do a lot of workarounds to get this to work.

It probably won’t be an easy fix so maybe instead of using the QNG Optimizer you can keep using the Adam Optimizer.

I hope this will be helpful for you.