Abnormal Operation of a Specific Circuit Possibly Caused by TF Batch

Hello! I encountered a somewhat peculiar issue while using Keras to write code. Specifically, when attempting to create a simple circuit similar to a QCNN, I am trying to control the output of two circuit qubits using a Toffoli gate onto four additional qubits. Here is an example of my code:

import pennylane as qml
from pennylane import numpy as np
import logging
import tensorflow as tf
from pennylane.templates.embeddings import AmplitudeEmbedding

logging.getLogger('tensorflow').disabled = True


dev = qml.device("default.qubit", wires=8)

def kernel(params, wires):  # 4 params
    qml.RY(params[0], wires=wires[0])
    qml.RY(params[1], wires=wires[1])
    qml.CNOT(wires=[wires[1], wires[0]])
    qml.RY(params[2], wires=wires[0])
    qml.RY(params[3], wires=wires[1])
    qml.CNOT(wires=[wires[0], wires[1]])

def pooling(params, wires): #2 params
    qml.CRZ(params[0], wires=[wires[0], wires[1]])
    qml.PauliX(wires=wires[0])
    qml.CRX(params[1], wires=[wires[0], wires[1]])   

@qml.qnode(dev, interface="tf")
def ancillary_qcnn_circuit(inputs, weights):
    kernel_size, pooling_size = 4, 2
    AmplitudeEmbedding(features=inputs, wires=range(4), normalize=True)
    kernel(weights[:kernel_size], wires=[0, 1])
    kernel(weights[:kernel_size], wires=[2, 3])
    kernel(weights[:kernel_size], wires=[3, 0])
    kernel(weights[:kernel_size], wires=[1, 2])
    pooling(weights[kernel_size:kernel_size +
                                    pooling_size], wires=[1, 0])
    pooling(weights[kernel_size:kernel_size +
                                    pooling_size], wires=[3, 2])
    kernel(weights[kernel_size+pooling_size:kernel_size*2+pooling_size], wires=[0, 2])
    # comment out any one of the four Toffoli gates
    qml.Toffoli(wires=[0, 2, 4])
    qml.Toffoli(wires=[0, 2, 5])
    qml.Toffoli(wires=[0, 2, 6])
    qml.Toffoli(wires=[0, 2, 7])
    return [qml.expval(qml.PauliZ(i)) for i in range(4, 8)]

x_train = np.random.rand(100, 16)
y_train = np.random.rand(100, 4)

qcnnlayer = qml.qnn.KerasLayer(ancillary_qcnn_circuit, {
                               "weights": 10}, output_dim=4)
model = tf.keras.Sequential([qcnnlayer])
opt = tf.keras.optimizers.Adam(learning_rate=0.002)
model.compile(opt, loss=tf.keras.losses.MeanSquaredError())
model.fit(x_train, y_train, epochs=50, batch_size=50)

I have encountered the following errors:

tensorflow.python.framework.errors_impl.InvalidArgumentError: Exception encountered when calling layer 'keras_layer' (type KerasLayer).

{{function_node __wrapped__MatMul_device_/job:localhost/replica:0/task:0/device:CPU:0}} Matrix size-incompatible: In[0]: [4,4], In[1]: [100,128] [Op:MatMul]

Call arguments received by layer 'keras_layer' (type KerasLayer):
  • inputs=tf.Tensor(shape=(50, 16), dtype=float32)

I’m not sure what errors are occurring in the code mentioned above. I have noticed that it seems to run fine if the input does not include a batch dimension, like:

input = np.random.rand(16)
# input = np.random.rand(20,16) would get an error
weights = np.random.rand(10)
ancillary_qcnn_circuit(input, weights)

Additionally, what further confuses me is that when I comment out any of the four Toffoli gates (or more) in the code, it runs.
My version is 0.34.0.dev0. (for I wanna use batch mode AmplitudeEmbedding in TensorFlow)

Hey @jracle! Glad to see you’re using the new feature :slight_smile:

I removed AmplitudeEmbedding from your code, ran that, and it gave the same error message. :thinking: Can you verify this too? If so, can you reduce your code down as much as possible while still maintaining the error message? That would help us try to figure out what’s going on :smile:

I have tested my code, and the simplest form seems to be like this:

import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
from pennylane.templates.embeddings import AmplitudeEmbedding

dev = qml.device("default.qubit", wires=8)
@qml.qnode(dev, interface="tf")
def ancillary_qcnn_circuit(inputs):
    AmplitudeEmbedding(features=inputs, wires=range(4), normalize=True)    
    qml.CNOT(wires=[0,1])
    qml.Toffoli(wires=[0, 2, 4])
    qml.Toffoli(wires=[0, 2, 5])
    qml.Toffoli(wires=[0, 2, 6])
    qml.Toffoli(wires=[0, 2, 7])
    return [qml.expval(qml.PauliZ(i)) for i in range(4, 8)]
input = np.random.rand(16,16)
ancillary_qcnn_circuit(input)

If any line in the ancillary_qcnn_circuit is commented out, the code will run without any issues. Similarly, removing the batch dimension from the input or removing the interface="tf" part will also allow the code to run successfully.

Hi @jracle ,

If I run your code with “lightning.qubit” it works. Do you need to use default.qubit?

Hello @CatalinaAlbornoz ,
could you please show me an example of a complete runnable code? I replaced default.qubit with lightning.qubit in the code mentioned above, but it still cannot run. However, the error message has changed. Regarding the code that includes the keras training part, I encountered the following

tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute Mul as input #1(zero-based) was expected to be a float tensor but is a double tensor [Op:Mul]

and regarding the second code:

ValueError: Broadcasting with MottonenStatePreparation is not supported. Please use the qml.transforms.broadcast_expand transform to use broadcasting with MottonenStatePreparation.

I have made no changes except for modifying default.qubit to lightning.qubit :confused:

Hi @jracle,

It seems like you have uncovered a bug! Thank you very much for opening this issue. One of my colleagues has fixed the bug in the latest development version of PennyLane, you can see the Pull Request here.

To install the PennyLane development version you can run:
pip install git+https://github.com/PennyLaneAI/pennylane.git#egg=pennylane

Let me know if you still encounter problems after using the development version.

Thank you very much. The code is able to run properly now. (I realized that I forgot to process the input using tf.Variable in the code snippet I provided in the second)

I’m glad to see that it now works for you @jracle! Thank you for helping us uncover the bug.