Multi dimensional Regression using CV-QNN

Can anyone tell me how to do multi dimensional regression (like we do with ANNs /Linear Regression). In my understanding we have to generalize the code in curve fitting tutorial . But i am having a hard time inputting multi dimensional inputs.

Hi @P.Kairon! Do you have a small code example you could share to illustrate your multi dimensional inputs?


This is the boston housing dataset. I want to predict output column using F1,F2,F3.

import pennylane as qml
from pennylane import numpy as np
from pennylane.optimize import AdamOptimizer
from numpy import *  # get the "numpy" library for linear algebra
from math import *
import pandas as pd
from sklearn.model_selection import train_test_split
from pennylane.templates.layers import CVNeuralNetLayers
from pennylane.init import cvqnn_layers_all
from pennylane.templates.embeddings import DisplacementEmbedding

data = np.loadtxt("sine.txt")

from sklearn import preprocessing

mm_scaler = preprocessing.MinMaxScaler()
data = mm_scaler.fit_transform(data)

print(data.shape)

X = data[:, 0:3]
Y = data[:, 3]

xtr, xt, ytr, yt = train_test_split(X, Y, test_size=0.3)
dev = qml.device("strawberryfields.fock", wires=3, cutoff_dim=50)


def circuit(*pars):
    CVNeuralNetLayers(*pars, wires=[0, 2])


@qml.qnode(dev)
def quantum_neural_net(*var, x1=None, x2=None, x3=None):
    # Encode input x into quantum state
    qml.Displacement(x1, 0.0, wires=0)
    qml.Displacement(x2, 0.0, wires=1)
    qml.Displacement(x3, 0.0, wires=2)

    for v in var:
        circuit(*v)

    return qml.expval(qml.X(0))


def square_loss(labels, predictions):
    loss = 0
    for l, p in zip(labels, predictions):
        loss = loss + (l - p) ** 2

    loss = loss / len(labels)
    return loss


def cost(var, features, labels):
    preds = [quantum_neural_net(var, x1=xlo[0], x2=xlo[1], x3=xlo[2]) for xlo in features]
    return square_loss(labels, preds)


init_pars = cvqnn_layers_all(n_layers=1, n_wires=3, seed=None)
print(init_pars)
opt = AdamOptimizer(0.01, beta1=0.9, beta2=0.999)

var = init_pars

for it in range(50):
    var = opt.step(lambda v: cost(v, xtr, ytr), var)
    print("Iter: {:5d} | Cost: {:0.7f} ".format(it + 1, cost(var, xtr, ytr)))

predics = [quantum_neural_net(var, x1=xlo[0], x2=xlo[1], x3=xlo[2]) for xlo in xt]

import matplotlib.pyplot as plt

plt.figure(figsize=(20, 10))
plt.plot(predics)
plt.plot(yt)

I keep getting worng input shape detected error when i run the code.
Also could you tell me how to do same code in data reuploading way

Hi @P.Kairon, I can’t seem to execute your code example, I get the error

Traceback (most recent call last):
  File "test2.py", line 50, in <module>
    Y = data[:, 3]
IndexError: index 3 is out of bounds for axis 1 with size 2

Since I can’t execute your code I can’t verify for sure the solution, but it looks like your QNode is calling circuit incorrectly; a for loop should not be required if we redefine the ansatz:

def circuit(pars):
    CVNeuralNetLayers(*pars, wires=[0, 2])

@qml.qnode(dev)
def quantum_neural_net(*var, x1=None, x2=None, x3=None):
    # Encode input x into quantum state
    qml.Displacement(x1, 0.0, wires=0)
    qml.Displacement(x2, 0.0, wires=1)
    qml.Displacement(x3, 0.0, wires=2)

    circuit(var)

    return qml.expval(qml.X(0))

Apologies @P.Kairon, looks like there was a typo in my previous reply. The QNode should look like this:

def circuit(pars):
   CVNeuralNetLayers(*pars, wires=[0, 2])

@qml.qnode(dev)
def quantum_neural_net(var, x1=None, x2=None, x3=None):
   # Encode input x into quantum state
   qml.Displacement(x1, 0.0, wires=0)
   qml.Displacement(x2, 0.0, wires=1)
   qml.Displacement(x3, 0.0, wires=2)

   circuit(var)

   return qml.expval(qml.X(0))

I’ve attached a working Jupyter notebook example below if you want to explore it further!

Untitled.ipynb (11.6 KB)

1 Like

Hey @josh thanks for the help it runs fine . But it is very slow , since i can’t switch simulators (correct me if i’m wrong here) .
Is there any way to speed up computation ?
Can i interface it with TF ?
My thought is to run it on GPU but not sure how to do that .

Hi @P.Kairon, glad it’s now working! Unfortunately, the Strawberry Fields Fock backend is quite computationally intensive — the memory required for a simulation scales like D^N, for a cutoff of D and N wires.You can try decreasing the cutoff or the number of wires to see a speed improvement.

Strawberry Fields itself now comes with a simulator backend that supports TensorFlow 2.0, which works on GPUs. This is not yet supported via PennyLane, but we are working on integrating this backend!

Hi @josh , thanks for the info. I reached out to Aroosa previously regarding a similar problem. She suggested using data reuploading to encode all the 3 features into a single wire. Could you please suggest and if possible demonstrate , necessary changes in the code that i need to make to do that ?

Hi @P.Kairon,

It would be an interesting problem to try this with data reuploading technique :slight_smile: See our tutorial and this paper for more details.

You can simply change the code above as follows:

dev = qml.device('strawberryfields.fock', wires=1, cutoff_dim=1)


def circuit(pars):
    CVNeuralNetLayers(*pars, wires=0)

@qml.qnode(dev)
def quantum_neural_net(var, x1=None,x2=None,x3=None):

    qml.Displacement(x1, 0.0, wires=0)
    qml.Displacement(x2, 0.0, wires=0)
    qml.Displacement(x3, 0.0, wires=0)
    
    circuit(var)
    return qml.expval(qml.X(0))

The cost function can stay the same.

You can try and vary the number of layers in CVNeuralNetLayers to see if your model works better. Another trick is to re-upload data as follows:

dev = qml.device('strawberryfields.fock', wires=1, cutoff_dim=1)


def layer(pars):
    CVNeuralNetLayers(*pars, wires=0)

@qml.qnode(dev)
def quantum_neural_net(var1, var2, x1=None,x2=None,x3=None):

    qml.Displacement(x1, 0.0, wires=0)
    qml.Displacement(x2, 0.0, wires=0)
    qml.Displacement(x3, 0.0, wires=0)
    
    circuit(var1)

    qml.Displacement(x1, 0.0, wires=0)
    qml.Displacement(x2, 0.0, wires=0)
    qml.Displacement(x3, 0.0, wires=0)
    
    circuit(var2)
    return qml.expval(qml.X(0))

Hope this helps!

Thanks alot @AroosaIjaz . First method worked , however we have to increase the cutoff else cost function remains the same. Although second method is giving errors

Also model is performing really bad as cost function plateaus around 0.02 sometimes and even starts climbing up. Could you please take a look at the uploaded code(data uploaded as well),(sorry for the troubles , i have a deadline coming up :sweat:. @AroosaIjaz @josh.

https://drive.google.com/drive/folders/13cK5lmcmEWvY1JZ68lyRdAZ9-iHghCX8?usp=sharing

Hi @P.Kairon

We’re glad to hear that @AroosaIjaz’s proposed method worked. Indeed, you’ll need to set the cutoff dimension to a larger number to ensure numerical accuracy/stability, the value of 1 is just a placeholder.

You mentioned that the second method is giving errors. Would you be able to provide the traceback/error msg here so we can try to help?

Regarding how well your model is performing: we can see if we can spot anything obvious, and make suggestions, but we aren’t necessarily able to debug code that is error-free, but just achieves unsatisfactory outputs.

My first guess is that you will need to check whether the cutoff level is sufficiently high to ensure numerical accuracy (this is a tradeoff with the amount of time/memory you need to simulate). Too low a cutoff and you have the risk that some operations—like Displacements, Squeezing, Cubic Phase, etc—push the quantum state outside of the space given by the cutoff. One way to check this would be to see if your state has a trace much less than 1 (equivalently, the expectation value of the identity is much less than 1)