Optimize circuits returning counts

Hello there,

I want to optimize the parameters of a variational circuit that returns qml.counts() to minimize a post-processed classical cost function. From what I understand, this requieres a parameter-shift differentiation method, as the gradient is not analytically defined, however I keep getting the following error:

Can't differentiate w.r.t. type <class 'numpy.int64'>

Here is an example of my code:

import pennylane as qml
from pennylane import numpy as np

dev = qml.device('default.qubit', wires=2, shots = 100)

@qml.qnode(dev, diff_method="parameter-shift")
def circuit(params):
    qml.Rot(*params[0], wires=0)
    qml.Rot(*params[1], wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.counts(wires=[0, 1])

def cost(params):
    res = circuit(params)
    p0 = res['00']/(res['00'] + res['01'])
    p1 = res['10']/(res['10'] + res['11'])
    return np.abs(p0 - p1)

params = np.random.uniform(size=(2, 3))

opt = qml.AdamOptimizer(stepsize=0.1)

for i in range(100):
    params = opt.step(cost, params)
    if (i+1) % 10 == 0:
        print(f"Step {i+1}, Cost {cost(params)}")

I’m not sure if what I want to do makes sense, but I would appreciate any help!

Hi @psansebastian,

The issue with differentiating circuits which return qml.counts is that they return stochastic results. So regardless of the device that you use or the differentiation method, you cannot calculate gradients. This is the source for the error that you’re getting.

Notice that the parameter-shift method calculates analytic gradients, which is great! The magic with this method is that it can calculate these gradients over actual quantum hardware, but it cannot calculate gradients over samples or counts (or classical shadows), since they are stochastic. Instead I recommend that you use any of the other measurements listed in the Measurements page of the PennyLane docs. Measuring probs or expval for example should work.

Since you’re using a simulator, ‘default.qubit’, you can also change the differentiation method to other methods which are faster.

Please let me know if you have any further questions.

Hello,

Thank for your response! I understand qml.counts return stochastic result, but working with real quantum hardware, don’t probs and expval also return stochastic results? How are probs measured if is not by sampling? And how is expval measured?

Thank you in advance!

Hi @psansebastian,

Yes that’s right. But probs and expval return values that are continuous and differentiable so PennyLane allows you to differentiate over them. Instead if you return samples or counts the values will jump around too much so PennyLane doesn’t allow you to differentiate over them. There’s a hack, in case you really want to measure samples, and it’s to calculate probs or expval while specifying shots=1. This is basically tricking PennyLane because it does allow you to calculate gradients over these measurement types.

From your code however I feel that what you want is closer to the following

import pennylane as qml
from pennylane import numpy as np

dev = qml.device('default.qubit', wires=2, shots = 100)

@qml.qnode(dev)#, diff_method="parameter-shift")
def circuit(params):
    qml.Rot(*params[0], wires=0)
    qml.Rot(*params[1], wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.probs(wires=[0, 1])

def cost(params):
    probs = circuit(params)
    p0 = probs[0]/(probs[0] + probs[1])
    p1 = probs[2]/(probs[2] + probs[3])
    return np.abs(p0 - p1)

params = np.random.uniform(size=(2, 3))
circuit(params)

opt = qml.AdamOptimizer(stepsize=0.1)

for i in range(100):
    params = opt.step(cost, params)
    if (i+1) % 10 == 0:
        print(f"Step {i+1}, Cost {cost(params)}")

Is this what you wanted to do? If not let me know and I can try to help you.