Does Pennylane-SF Plugin simmulate Borealis


I am working on a Quanten Neuronal Network which includes on the pennylane template CVNeuralNetLayers. I have to try it on hardware in the coming month and hoped to be able to do so on Borealis (via AWS Braket Hybrid-Jobs).

However, I am currently a bit unsure how to best test the code before feeding it into Borealis.
Is the pennylane device ‘strawberryfields.fock’ sufficient, or do I need to use another one of the devices of the Strawberry Fields Plugin?
Or is there no Pennylane Simulator device at all and I would need to program something separate with Strawberry Fields?

Best wishes,

Hi @PhilippHS, great question.

Our Borealis device has a programmable but limited architecture so there are only some specific circuits that you can run there. You can learn more about the circuits that you can run here.

If you want to run on photonic hardware I suggest that you try out our X8_01 device, which is accessible for free on Xanadu Cloud. You can learn how to run programs on it here. The strawberryfields.fock device should work for simulations but take into account that the actual X8 device only supports gaussian gates.

You can get some inspiration in the work of others, which you can find here and here for example.

Please let me know if this answers your question!

Hi @CatalinaAlbornoz
yes, this answers my question. Thank you very much for the quick reply.

Just as a quick follow-up question:
Do I understand correctly that the strawberryfields.gaussian device would be better for simulating the X8_01 device, as it only includes gaussian gates?

Hi @PhilippHS,

You could use either device and only use the gates allowed by the hardware as specified in the Device details section of our X8 tutorial. You will still get differences due to loss and other problems as you can see in this thread. I would actually be curious to know the outputs that you get by running a program on the Gaussian backend vs the Fock backend, given that you have an X8-compatible circuit in both cases.

Hi @CatalinaAlbornoz,

thank you very much for your answer. I had to remove the Kerr operation from the original template in order to make it gaussian-only but it seems to work now.

Surprisingly, the Fock backend device requires significantly more run time for the Kerr operation removed (more then factor 100). It also does not seem to learn well. After the loss increased from the first to the second epoch I stopped it.

The Gaussian fackend also was quite slow too but at least it learned reasonably well.

The question is now if the X8_01 device would behave more like the gaussian- or the fock-backend.

Hey @PhilippHS! Were you able to try X8_01? It will be back online next week. :slight_smile:

Hi @isaacdevlugt
yes, I was able to access the device today. Due to the limitations of the X8_01 I needed to reduce the template further and I am the remaining two interferometer will not be able to learn much :confused:

Also I now receive the Warning UserWarning: The device strawberryfields.remote does not support the PolyXP observable. The analytic parameter-shift cannot be used for second-order observables; falling back to finite-differences.
I guess the X8_01 ist not really made to be used in a QNN, right? :sweat_smile:

Sorry to hear that! For your warning UserWarning: The device strawberryfields.remote does not support the PolyXP observable., this probably has to do with the face that X8 doesn’t support that particular observable. Check out the device details here!

Hi @isaacdevlugt
thank you for your answer. Unfortunately, looking into it I am actually more confused by error message then before: At the end of my circuit I am using the measurement qml.NumberOperator as I considered it to be most close to the sf.ops.MeasureFock observable on the X8_01.
The qml.PolyXP observable is not even part of the circuit. Therefore, I do not understand where the User Warning comes from.

Does the qml.NumberOperator somehow decompose into something involving qml.PolyXP ?
If so which measurement should I use instead for the X8_01.?

Would you be able to provide any code?

Hi @isaacdevlugt

I now created the following example code which can reproduce the user warning

from pennylane import numpy as np
import pennylane as qm
import tensorflow as tf

# 0) Initialise Device
dev = qml.device('strawberryfields.remote', backend='X8_01' )

# 1) Define Input
num_inputs = 2
num_data = 5
num_outputs = 1

inputs = np.asarray( [ [(1.2+x)*(d+1) for x in range(num_inputs)] for d in range(num_data)] )
outputs= np.asarray( [ [(3.5+y)*(d+1) for y in range(num_outputs)] for d in range(num_data)] )

# normalise and convert to tensors
inputs = inputs / np.max(inputs)
outputs= outputs / np.max(outputs)

inputs_tf = tf.convert_to_tensor(inputs, np.float32)
outputs_tf = tf.convert_to_tensor(outputs, np.float32)

# 2) Define Qnode
def qnode(inputs, theta_1, phi_1, varphi_1, theta_2, phi_2, varphi_2):

   # 2.1) Rotation embedding (as squeezing only possible with binary inputs)
    for i in range(num_inputs):
        qml.Rotation(inputs[i], wires=i)
        qml.Rotation(inputs[i], wires=i+4)

    # 2.2) Interferometer-Layers
        qml.Interferometer(theta=theta_1[:], phi=phi_1[:], varphi=varphi_1[:], mesh='rectangular', wires=[i for i in range(4)] )
        qml.Interferometer(theta=theta_1[:], phi=phi_1[:], varphi=varphi_1[:], mesh='rectangular', wires=[i + 4 for i in range(4)] )
        qml.Interferometer(theta=theta_2[:], phi=phi_2[:], varphi=varphi_2[:], mesh='triangular',  wires=[i for i in range(4)] )
        qml.Interferometer(theta=theta_2[:], phi=phi_2[:], varphi=varphi_2[:], mesh='triangular',  wires=[i + 4 for i in range(4)] )

    # 2.3) measure 
    ops =  [qml.expval(qml.NumberOperator(wires=i)) for i in range(num_outputs) ]

    return ops

# 3) get weight shapes
M = 4
K = int( M/2*(M-1) )

weight_shapes = {  'theta_1':(K), 'phi_1':(K), 'varphi_1':(M),
                   'theta_2':(K), 'phi_2':(K), 'varphi_2':(M) }  

# 4) Create and train a simple toy model

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense( num_inputs , activation=tf.nn.tanh),
    qml.qnn.KerasLayer(qnode, weight_shapes, output_dim=num_outputs) ])

model.compile(optimizer='adam' , loss='mse' ), y=outputs_tf, epochs=3)

Hey! Thank you for providing that. I just tested your code on Xanadu Cloud and reproduced the result you’re getting. I’ll list my thoughts out just to make it easier to read:

  1. The docs for qml.PolyXP state the following:

… Used for evaluating arbitrary order-2 CV expectation values of CVParamShiftTape .

Since qml.NumberOperator is an order-2 CV operator, this is why qml.PolyXP gets called under the hood.

  1. So what’s the deal with the warning UserWarning: The device strawberryfields.remote does not support the PolyXP observable. The analytic parameter-shift cannot be used for second-order observables; falling back to finite-differences.?

I’m in the midst of clarifying something with one of the members of the software team to double check what I think the problem is. Will get back to you soon!

On point number two:

X8 only supports PNR measurements, meaning that it can only measure the number operator \hat{n}.

When you train the model, the training is invoking the gradient, and X8 cannot differentiate, using the second-order PS rule, second-order observables like \hat{n}. But, it can differentiate using finite differences!

Hi @isaacdevlugt

thank you very much for coming back to me. Do I understand correctly my use of the qml.NumberOperator for measuring the circuit results is correct and the network could in fact learn?
So it just uses a less efficient method for calculating the gradient and therefore requires more circuit executions? (I noticed that it is executing far more jobs than expected.)

Definitely the network can learn! Just not by using the parameter-shift rule :slight_smile:. As you said, you’d have to resort to finite differences (which, unfortunately, of the hardware-compatible differentiation methods isn’t the best… but that’s your only option :sweat:).

I wouldn’t say that finite differences are less efficient. To calculate the gradient with finite differences requires 2p circuit evaluations (the parameter-shift rule in this case would need more than that), where p is the number of trainable parameters. This isn’t terribly inefficient for hardware-compatible methods!

Finite difference gradients aren’t ideal because

  1. They aren’t exact
  2. On noisy hardware, the gradient can get “lost in the noise” so to speak. Finite difference derivatives rely on evaluating the circuit at \theta_i + h and \theta_i - h, where \theta_i is the parameter of interest and h << 1. We typically need h ~ O(10^{-5}) to get “good” gradients (not exact still!). But, on noisy hardware, shifting a parameter by h and re-evaluating the circuit is risky business! The noise might overrule the value of h, leading to very inaccurate derivatives.

If you’re interested, we have a Youtube video on hardware-compatible differentiation methods :slight_smile:

Hi @isaacdevlugt

thank you very much for answers. The video is indeed very insightful.
Unfortunately it looks like my circuit is in fact not suited to determine a gradient suitable for training. Even with a simulator, it does not work, no chance that the real device would produce something useful.

Are you aware if anyone managed to use the X8_01 for a QML application?

I can’t think of anything off the top of my head. But it should be entirely possible!