QNode inside Keras layer

Hi,

I’ve recently started using pennylane. Thanks for the great tool!

I am trying (unsuccessfully) to build a custom Keras layer in TensorFlow 2 that includes a QNode. The goal is to use QNodes in a “standard” TensorFlow 2 workflow, i.e. define a Keras model, compile and fit. The Keras model should first process input data via a classical NN, then feed it into the parameters of a quantum circuit (all inside the model).

My first attempt failed due to AttributeError: 'Tensor' object has no attribute 'numpy', which seems to be related to pennylane assuming eager mode but Keras assuming that layers can be both executed as a graph and in eager.

Then I tried using dynamic=True in the layer init to tell Keras that the layer only works with eager, but this fails with NotImplementedError: in Keras.

My attempts are on Colab:
https://colab.research.google.com/drive/1OFxeEG2RSXyoX56lnhL7h7Pj4MzYFDCC

Would you mind having a look? I am not sure if I am doing something wrong or if my use case is just not supported.

Many thanks,
Matthias

Hi @Matthias_Rosenkranz! You’re right that PennyLane only currently works with TensorFlow eager (not autograph), so dynamic=True is currently required when using Keras.

I haven’t used PennyLane with Keras personally, however I can link you a few resources that have:

On our tutorials page, we have quite a few tutorials using PyTorch and TensorFlow directly, but none using Keras so far, this would be a great addition if you wanted to add a demonstration once your code is working!

Having a look at @Tom_Bromley’s code, I note that the error message in your colab notebook disappears if you add a compute_output_shape method:

class QuantumLayer(tf.keras.layers.Layer):
 def __init__(self, num_outputs, qnode, **kwargs):
   super(QuantumLayer, self).__init__(**kwargs)
   self.num_outputs = num_outputs
   self.qnode = qnode

 def call(self, inputs):
   outputs = []
   for input in inputs:
     outputs.append(self.qnode(input))
   return tf.reshape(outputs, shape=(inputs.shape[0], self.num_outputs))

 def compute_output_shape(self, input_shape):
   return input_shape

I’m not too familiar with Keras, but perhaps this needs to always be defined if dynamic=True.

1 Like

Thanks @josh! Defining compute_output_shape made it work.

1 Like

For reference, here is a working Colab including the Keras-style training via compile and fit. It’s not a very useful model in itself as it just fits a classical NN to output a parameter for R_y that flips the initial |0\rangle state.

https://colab.research.google.com/drive/1gKcSyiZ4pHuA1UEXhCz-C5YLhbn1Bho9

Btw, also works with the newly released pennylane 0.8 :).

2 Likes