I am trying to bulid a quantum convolutional neural network for image classification with Pennylane and Keras but the model isn't training and I keep getting the warning:

WARNING:tensorflow:Gradients do not exist for variables ['params:0', 'params:0'] when minimizing the loss. If you're using model.compile(), did you forget to provide a loss argument?

How do I fix this issue?

I have used code from Quantum Convolutional Neural Network using Keras and Quanvolutional Neural Network.

Here are the relavent snippents of my code:

import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
from tensorflow import keras

This code creates the quantum circuit to act as a filter:

q = 4


dev = qml.device("lightning.qubit", wires=q)

#params has dimension 2
def unit2(params, wires=[0, 1]):
    for j in range(2):
        qml.RY(params[j], wires=wires[j])


#ZX pooling, params has dimensions 2
def pool1(params, wires=[0, 1]):
    qml.CRZ(params[0], wires=wires)
    qml.CRX(params[1], wires=wires)

@qml.qnode(dev, diff_method='parameter-shift')
def circuit(inputs, params):
    height = int(q/2)
    site = range(int(q))
    ##### ENCODING
    for i in range(q):
        qml.RX(inputs[i]*2*np.pi, wires=i)
    count = 0
    pdim = 2 #param dimension of unit
    for t in range(1, layers + 1):
        l = int(len(site)/2)
        ### CONVOLUTION
        for i in range(l):
            ## Change unit here
            unit2(params[count:count + pdim], wires=[site[2*i], site[2*i + 1]])
            count += pdim
        for i in range(l-1):
            ## Change unit here
            unit2(params[count:count + pdim], wires=[site[2*i + 1], site[2*i + 2]])
            count += pdim
        ### POOLING
        for i in range(l):
            ## Change unit here
            pool1(params[count:count + 2], wires=[site[2*i], site[2*i + 1]])
            count += 2
        trial = []
        for u in range(int(len(site)/2)):
            trial = trial + [site[2*u+1]]
        site = trial
    return [qml.expval(qml.PauliZ(q-1))] #### Only measures off final qubit

which looks like this where I only read off the final qubit (numbers on gates are placeholders for the filters weights): graph of quantum circuit defined above

I create the model here:

class QuantumClassifier(tf.keras.Model):

    def __init__(self, filter_channels, kernal_params):
        self.filters = filter_channels
        self.qfilters = []
        weight_shapes = {"params": (kernal_params)}
        for i in range(filter_channels):
            self.qfilters.append(qml.qnn.KerasLayer(circuit, weight_shapes,output_dim=1, name='quantum_filter')) 
        self.hidden = tf.keras.layers.Dense(128, activation = 'relu')
        self.flatten = tf.keras.layers.Flatten()
        self.dense = tf.keras.layers.Dense(10, activation='softmax')

    def call(self, inputs):
        width, length = inputs.shape[1], inputs.shape[2]
        batch_size = inputs.shape[0]

        total_out = tf.TensorArray(tf.float32, size=batch_size)
        count = 0
        #perform convolution with no padding and stride of 2
        for a in range(batch_size):
            out = np.zeros((width//2, length//2, self.filters))
            print(f"Image: {a}")
            for i in range(0, width, 2):
                for j in range(0, length, 2):
                    for f in range(self.filters):
                        # convolution windows, now only applying to one channel image
                        sub_input =  inputs[a,i:i+q, j:j+q, :]
                        # flatten into 1-D
                        sub_input = tf.reshape(sub_input, [-1])
                        quantum_filter = self.qfilters[f]
                        out[i//2][j//2][f] = quantum_filter(sub_input)

            total_out = total_out.write(count, out)
            count += 1
        total_out = total_out.stack()
        print("All input data for one batch have been convolved!")

        x = self.flatten(total_out)

        x = self.hidden(x)

        x = self.dense(x)
        return x

I created the model for 2 quantum filters where each one has 14 parameters:

model = QuantumClassifier(2, 14)
r = model.fit(x_train_small, y_train, epochs=10, batch_size=16, validation_data=(x_test_small, y_test))

Here is the dataset I am using:

mnist_dataset = keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist_dataset.load_data()
# Reduce dataset size
x_train = x_train[:n_train]
y_train = y_train[:n_train]
x_test = x_test[:n_test]
y_test = y_test[:n_test]
# Normalize pixel values within 0 and 1
x_train = x_train / 255
x_test = x_test / 255
# # Add extra dimension for "color" channels
x_train = np.array(x_train[..., tf.newaxis])
x_test = np.array(x_test[..., tf.newaxis])
print(f"train_images_shape: {x_train.shape}")
# use Bilinear Interpolation for downscaling
x_train_small = tf.image.resize(x_train, (10,10)).numpy()
x_test_small = tf.image.resize(x_test, (10,10)).numpy()
print(f"x_train_reshape: {x_train_small.shape}")

This is all in: python==3.11.5 tensorflow==2.15.0 PennyLane==0.34.0

Any solutions (or ways to speed up my code) greatly appreciated!



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.