Weights tensor must have second dimension of length

Hi,
I applied Quantum Kernel SVM Classifier, and I got this error;

f"Weights tensor must have second dimension of length {len(wires)}; got {shape[1]}"

n_qubits = len(Xtrain[0])
n_qubits
5

Xtrain.shape

(580,5)

n_qubits = len(Xtrain[0])

n_qubits

dev_kernel = qml.device("default.qubit", wires=n_qubits)

projector = np.zeros((2**n_qubits, 2**n_qubits))

projector[0, 0] = 1

@qml.qnode(dev_kernel)

def kernel(x1, x2):

    """The quantum kernel."""

    AngleEmbedding(x1, wires=range(n_qubits))

    qml.StronglyEntanglingLayers(weights=x2, wires=range(n_qubits))

    qml.adjoint(AngleEmbedding)(x2, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""

    return np.array([[kernel(a, b) for b in B] for a in A])

#X_train[0:]

kernel(Xtrain[0,:], Xtrain[0,:])


---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-57-99a27e9473fc> in <module>()
     21 
     22 #X_train[0:]
---> 23 kernel(Xtrain[0,:], Xtrain[0,:])
     24 

3 frames
/usr/local/lib/python3.7/dist-packages/pennylane/templates/layers/strongly_entangling.py in __init__(self, weights, wires, ranges, imprimitive, do_queue, id)
    136         shape = qml.math.shape(weights)[-3:]
    137 
--> 138         if shape[1] != len(wires):
    139             raise ValueError(
    140                 ****f"Weights tensor must have second dimension of** length {len(wires)}; got {shape[1]}"**

IndexError: tuple index out of range

Hi @Kursat_KILIC!

You’re getting this issue because the weights that go into StronglyEntanglingLayers must have the shape (L, M, 3), where L = # of layers and M = # of qubits. In your case, if you have a single layer, it should be of size (1, 5, 3).

Also, AngleEmbedding receives weights of size (N,) where N is the number of features. The number of features needs to be equal or less than the number of qubits, which in your case is 5, so you can’t use the same weights for AngleEmbedding and for StronglyEntanglingLayers.

Finally, the adjoint needs to receive the same weight shape as AngleEmbedding.

The following code shouldn’t produce an error anymore although I’m unsure of why you had the first dimension of Xtrain being 580 (note that only the first 5 parameters are being used).

import pennylane as qml
from pennylane import numpy as np

X1train = np.random.rand(580,5)
#print(X1train[0,:].shape)

X2train = np.random.rand(580,1,5,3)
#print(X2train[0,:].shape)

n_qubits = len(Xtrain[0])

n_qubits = 5

dev_kernel = qml.device("default.qubit", wires=n_qubits)

projector = np.zeros((2**n_qubits, 2**n_qubits))

projector[0, 0] = 1

@qml.qnode(dev_kernel)

def kernel(x1, x2):

    """The quantum kernel."""

    qml.AngleEmbedding(x1, wires=range(n_qubits))

    qml.StronglyEntanglingLayers(weights=x2, wires=range(n_qubits))

    qml.adjoint(qml.AngleEmbedding)(x1, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""

    return np.array([[kernel(a, b) for b in B] for a in A])

kernel(X1train[0,:], X2train[0,:])

Please let me know if this is clear or if you have other questions.

1 Like

@CatalinaAlbornoz, thanks for your answer. My case is about tunnel geology classification. I have 18 features and 3 geological classes then I tried to apply classification. But I know 18 features is large for n_qubits because 2*n_qubits should be less than 25. Therefore, I have selected the first 5 columns (features) for classification. What I understood from your reply, I will need to reshape X values with (580,1,5,3) right?

Oh this is more clear now @Kursat_KILIC.

In this case you have 580 data points with 5 features each. Notice that the data points should be non-trainable.

You will need to create some weights that will go into your StronglyEntanglingLayers, and these are the parameters that will vary as you do your optimization. Below you will find an example of how you can construct your weights. Notice that I’ve changed the names x1 and x2 in order to avoid confusion.

import pennylane as qml
from pennylane import numpy as np

n_qubits = 5
n_layers = 2
n_features = 5 #Smaller or equal than the number of qubits
Xtrain = np.random.rand(580,n_features,requires_grad=False)
Labels = np.random.randint(1,4,580,requires_grad=False)
weights = np.array(np.random.rand(n_layers,n_qubits,3),requires_grad=True)

dev_kernel = qml.device("default.qubit", wires=n_qubits)

projector = np.zeros((2**n_qubits, 2**n_qubits))

projector[0, 0] = 1

@qml.qnode(dev_kernel)
def kernel(x, w):

    """The quantum kernel."""

    qml.AngleEmbedding(x, wires=range(n_qubits))

    qml.StronglyEntanglingLayers(weights=w, wires=range(n_qubits))

    qml.adjoint(qml.AngleEmbedding)(x, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

kernel(Xtrain[0,:],weights)

When you add your optimization be careful in how you define your cost function and your optimizer. Please let me know in case you have some questions about this part.

I hope this helps!

Thanks for your help. I got an error like TypeError: rand() got an unexpected keyword argument ‘requires_grad’

I deleted requires_grad in random function so it worked.

However, I got a different error.

    n_qubits = 5
    n_layers = 2
    n_features = 5 #Smaller or equal than the number of qubits
    Xtrain = np.random.rand(580,5)
    Labels = np.random.randint(1,4,580)
    weights = np.array(np.random.rand(n_layers,n_qubits,3))

dev_kernel = qml.device("default.qubit", wires=n_qubits)

projector = np.zeros((2**n_qubits, 2**n_qubits))

projector[0, 0] = 1

@qml.qnode(dev_kernel)

def kernel(x1, x2):

    """The quantum kernel."""

    qml.AngleEmbedding(x1, wires=range(n_qubits))

    qml.StronglyEntanglingLayers(weights=x2, wires=range(n_qubits))

    qml.adjoint(qml.AngleEmbedding)(x1, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

kernel(Xtrain[0,:],weights)

Output= tensor(0.07877843, requires_grad=True)

def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""

    return np.array([[kernel(a, b) for b in B] for a in A])


from sklearn.svm import SVC

svm = SVC(kernel=kernel_matrix).fit(Xtrain, ytrain)

predictions = svm.predict(Xtest)

print("Accuracy score:",accuracy_score(ytest,predictions))

print("F1 Score : ",f1_score(ytest,predictions,average="macro"))

print("recall score:",recall_score(ytest,predictions,average="macro"))

print("precision_score:", precision_score(ytest,predictions,average="macro"))

ERROR

ValueError                                Traceback (most recent call last)
<ipython-input-77-ff6e6d09c234> in <module>()
      1 from sklearn.svm import SVC
----> 2 svm = SVC(kernel=kernel_matrix).fit(Xtrain, ytrain)
      3 
      4 predictions = svm.predict(Xtest)
      5 print("Accuracy score:",accuracy_score(ytest,predictions))

2 frames
/usr/local/lib/python3.7/dist-packages/sklearn/utils/multiclass.py in check_classification_targets(y)
    195         "multilabel-sequences",
    196     ]:
--> 197         raise ValueError("Unknown label type: %r" % y_type)
    198 
    199 

ValueError: Unknown label type: 'continuous'

Hi @Kursat_KILIC, you need to import numpy from pennylane in order to be able to set parameters as trainable or not. You can do this by writing from pennylane import numpy as np.

Aside from this, your ValueError: Unknown label type: ‘continuous’ is coming from your ytrain data.

If you could post your entire code including how you generate your ylabel it can help me help you.

Note that if your data is continuous (for instance you generated random numbers from 0 to 1) then you might want to change it to random integer numbers. For instance you can do:

ytrain = np.random.rng.integers(low=0, high=3, size=580)

On the other hand, I noticed that your kernel_matrix is dependent on sets A and B but I’m not sure what you want to achieve from that. What are sets A and B? You’re likely to find errors there. I wonder what your goal is with that function and if there may be a better way of achieving it.

I hope this helps!

Thanks for your reply. Here is the full code;

import pandas as pd
#import numpy as np
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, f1_score, recall_score, precision_score
from pennylane import numpy as np

import pennylane as qml
from pennylane.templates import AngleEmbedding, StronglyEntanglingLayers
from pennylane.operation import Tensor

import matplotlib.pyplot as plt

np.random.seed(42)

import io
df2 = pd.read_excel(io.BytesIO(uploaded['classification_model.xlsx']))

(df2.columns.tolist())

df2.isnull().sum()

df = df2.fillna(0)

df.isnull().sum()

from sklearn.preprocessing import LabelEncoder

df["Layers"]=df["Layers"].astype("category")

df2.dtypes

df["Layers"]=df["Layers"].cat.codes

df

from sklearn.preprocessing import StandardScaler

    X = df.iloc[:,0:5]

    y = df.iloc[:,17]

    Xtrain, Xtest, ytrain, ytest=train_test_split(X, y, test_size=0.20)

from sklearn.preprocessing import StandardScaler

sc1=StandardScaler()

sc2=StandardScaler()

Xtrain= sc1.fit_transform(Xtrain)

Xtest=sc1.transform(Xtest)

Xtrain.shape
(580,5)

n_qubits = len(Xtrain[0])
n_qubits

5
n_qubits = 5

n_layers = 2
n_features = 5 #Smaller or equal than the number of qubits
Xtrain = np.random.rand(580,5, requires_grad=False)
ytrain = np.random.randint(1,4,580,requires_grad=False)
  
weights = np.array(np.random.rand(n_layers,n_qubits,3, requires_grad=True))

    dev_kernel = qml.device("default.qubit", wires=n_qubits)

    projector = np.zeros((2**n_qubits, 2**n_qubits))

    projector[0, 0] = 1

    @qml.qnode(dev_kernel)

    def kernel(x, w):

        """The quantum kernel."""

        AngleEmbedding(x, wires=range(n_qubits))

        qml.StronglyEntanglingLayers(weights=w, wires=range(n_qubits))

    qml.adjoint(AngleEmbedding)(x, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

kernel(Xtrain[0,:],weights)
def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""

    return np.array([[kernel(a, b) for b in B] for a in A])

from sklearn.svm import SVC

svm = SVC(kernel=kernel_matrix).fit(Xtrain, ytrain)

predictions = svm.predict(Xtest)

print("Accuracy score:",accuracy_score(ytest,predictions))

print("F1 Score : ",f1_score(ytest,predictions,average="macro"))

print("recall score:",recall_score(ytest,predictions,average="macro"))

print("precision_score:", precision_score(ytest,predictions,average="macro"))

Thanks for your help. I put the full code here. Inputs are continuous numbers and layers are 0,1 and 2 after encoding.

I followed this application

Hi @Kursat_KILIC,

I can’t run the first part of your code because I don’t have access to your data, but I did notice from the second part of your code that within your kernel_matrix function, your kernel function is getting the data in the wrong format. If you modify your code to see what’s going into “kernel” you will notice that both ‘a’ and ‘b’ are the same vector with length 5.

def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""
    for a in A:
        print('a',a)
        for b in B:
            print('b',b)
            k = kernel(a, b)

    #return np.array([[kernel(a, b) for b in B] for a in A])

However, as we had mentioned here, the weights that go into the StronglyEntanglingLayers must have shape (L, M, 3) , where L = # of layers and M = # of qubits.

I’m not you can change the inputs that go into your kernel_matrix from SVC but what you can do is change StronglyEntanglingLayers for something that can receive the kind of data that you have. You could also find hacky ways of changing the input that goes into the template. Here’s an example of how I did it with the BasicEntanglingLayers template.

import pennylane as qml
from pennylane import numpy as np

n_layers = 1
n_qubits = 5
n_datapoints = 3
n_features = 5 #Smaller or equal than the number of qubits
Xtrain = np.random.rand(n_datapoints,n_qubits, requires_grad=False)
ytrain = np.random.randint(1,4,n_datapoints,requires_grad=False)
Xtest = np.random.rand(n_datapoints+7,n_qubits, requires_grad=False)
  
#weights = np.array(np.random.rand(n_layers,n_qubits,3, requires_grad=True))
weights = np.random.random(n_qubits)
print(weights)

dev_kernel = qml.device("default.qubit", wires=n_qubits)

projector = np.zeros((2**n_qubits, 2**n_qubits))

projector[0, 0] = 1

@qml.qnode(dev_kernel)

def kernel(x, w):
    """The quantum kernel."""
    qml.AngleEmbedding(x, wires=range(n_qubits))
    #qml.StronglyEntanglingLayers(weights=w, wires=range(n_qubits))
    qml.BasicEntanglerLayers(weights=[w,w], wires=range(n_qubits))
    qml.adjoint(qml.AngleEmbedding)(x, wires=range(n_qubits))

    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

kernel(Xtrain[0,:],weights)

def kernel_matrix(A, B):

    """Compute the matrix whose entries are the kernel

       evaluated on pairwise data from sets A and B."""
    """for a in A:
        print('a',a)
        for b in B:
            print('b',b)
            k = kernel(a, b)"""

    return np.array([[kernel(a, b) for b in B] for a in A])

from sklearn.svm import SVC

svm = SVC(kernel=kernel_matrix).fit(Xtrain, ytrain)

predictions = svm.predict(Xtest)

Notice that I had to change the weights’ shape, the template, and the way the weights are passed into the template.

Please let me know if this is clear!