Hi! I want to make the hybrid model as one without saving the classical NN first and then loading it again and add it in my quantum layer.
This is the code for my classical model:
def make_residual_lstm_layers(input, rnn_width, rnn_depth, rnn_dropout):
"""
The intermediate LSTM layers return sequences, while the last returns a single element.
The input is also a sequence. In order to match the shape of input and output of the LSTM
to sum them we can do it only for all layers but the last.
"""
x = input
for i in range(rnn_depth):
return_sequences = i < rnn_depth - 1
x_rnn = LSTM(rnn_width, recurrent_dropout=rnn_dropout, dropout=rnn_dropout, return_sequences=return_sequences)(x)
if return_sequences:
# Intermediate layers return sequences, input is also a sequence.
if i > 0 or input.shape[-1] == rnn_width:
x = add([x, x_rnn])
else:
# Note that the input size and RNN output has to match, due to the sum operation.
# If we want different rnn_width, we'd have to perform the sum from layer 2 on.
x = x_rnn
else:
# Last layer does not return sequences, just the last element
# so we select only the last element of the previous output.
def slice_last(x):
return x[..., -1, :]
x = add([Lambda(slice_last)(x), x_rnn])
return x
if __name__ == '__main__':
# Example usage
from keras.layers import Input
from keras.models import Model
from keras.layers.merge import add
from keras.layers import Lambda
input = Input(shape=(X_train.shape[1], X_train.shape[2]))
output = make_residual_lstm_layers(input, rnn_width=24, rnn_depth=3, rnn_dropout=0)
model = Model(inputs=input, outputs=output)
model.summary()
And this is my QNN:
n_qubits =16
dev = qml.device("lightning.qubit", wires=n_qubits)
tf.keras.backend.set_floatx('float64')
@qml.qnode(dev, diff_method="adjoint")
def qnode(inputs, weights):
QAOAEmbedding(features=inputs, weights=weights, local_field='Z', wires=range(n_qubits))
return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_qubits)]
n_layers = 1
weight_shapes = {"weights": (n_layers, 20)}
print(weight_shapes)
weights = np.random.random(QAOAEmbedding.shape(n_layers, n_wires=10))
features = np.array([1., 2.])
qlayer = qml.qnn.KerasLayer(qnode, weight_shapes, output_dim=n_qubits)
tf.keras.backend.set_floatx('float64')
from keras.models import load_model
prev_model = load_model(r"C:\Users\user\residual.h5") # loading the previously saved model.
model_gru = Sequential()
model_gru.add(prev_model)
model_gru.add(Dense(units=10, activation= 'relu'))
model_gru.add(qlayer)
model_gru.add(Dense(units=24, activation= 'linear'))
model_gru.add(Dense(units=24, activation= 'linear'))
model_gru(X_test[:2])
model_gru.summary()
To make a hybrid model with Keras, you don’t have to save the model, load it back, and then create your hybrid model. Our demo on turning quantum circuits into Keras layers contains an example where everything is defined on the fly (i.e., no classical elements of the network are loaded in).
~\anaconda3\lib\site-packages\keras\utils\traceback_utils.py in error_handler(*args, **kwargs)
65 except Exception as e: # pylint: disable=broad-except
66 filtered_tb = _process_traceback_frames(e.traceback)
—> 67 raise e.with_traceback(filtered_tb) from None
68 finally:
69 del filtered_tb
~\anaconda3\lib\site-packages\keras\engine\input_spec.py in assert_input_compatibility(input_spec, inputs, layer_name)
194 # have a shape attribute.
195 if not hasattr(x, ‘shape’):
→ 196 raise TypeError(f’Inputs to a layer should be tensors. Got: {x}')
197
198 if len(inputs) != len(input_spec):
TypeError: Inputs to a layer should be tensors. Got:
This is the updated code:
if name == ‘main’:
from keras.layers import Input
from keras.models import Model
from keras.layers.merge import add
from keras.layers import Lambda
input = Input(shape=(X_train.shape[1], X_train.shape[2]))
output = make_residual_lstm_layers(input, rnn_width=24, rnn_depth=3, rnn_dropout=0)
model = Sequential(Model(inputs=input, outputs=output))
model.add=Dense(units=10, activation= ‘relu’)
model.add(qlayer)
model.add(Dense(units=24, activation= ‘linear’))
model.add(Dense(units=24, activation= ‘linear’))
model(X_test[:2])
model.summary()
opt = tf.keras.optimizers.Adam(learning_rate=0.01)
model.compile(opt, loss=“mse”, metrics=[“accuracy”])
history = model.fit(X_train, y_train, epochs=100,validation_data=(X_test, y_test), batch_size=5000, shuffle= True)
It looks like part of your error message got cut off when you copy pasted! Can you resend that? Also, it would be awesome if you could gather a minimal example with inputs and outputs provided just to make sure that I’m able to reproduce your error without fail!
Oh, sorry. Here is the error:
TypeError Traceback (most recent call last)
in
11 model.add=Dense(units=10, activation= ‘relu’)
12 model(X_test[:2])
—> 13 model.add(qlayer)
14 model.add(Dense(units=24, activation= ‘linear’))
15 model.add(Dense(units=24, activation= ‘linear’))
~\anaconda3\lib\site-packages\keras\utils\traceback_utils.py in error_handler(*args, **kwargs)
65 except Exception as e: # pylint: disable=broad-except
66 filtered_tb = _process_traceback_frames(e.__traceback__)
---> 67 raise e.with_traceback(filtered_tb) from None
68 finally:
69 del filtered_tb
~\anaconda3\lib\site-packages\keras\engine\input_spec.py in assert_input_compatibility(input_spec, inputs, layer_name)
194 # have a `shape` attribute.
195 if not hasattr(x, 'shape'):
--> 196 raise TypeError(f'Inputs to a layer should be tensors. Got: {x}')
197
198 if len(inputs) != len(input_spec):
TypeError: Inputs to a layer should be tensors. Got: <Quantum Keras Layer: func=qnode>
And for the input, you can use the Iris Dataset and this is how I split it:
Hey @aouie! What version of all of your packages are you running? I’m running keras==2.9.0 and pennylane==0.24.0, but I can’t import keras.layers.merge (ModuleNotFoundError).
Make sure you’re using the right package versions that pennylane requires! I recommend that you make a virtual environment for your project (e.g., with conda: conda create -n my_environment_name python=3.8), then reinstall your packages
Hey @aouie! I can’t reproduce your error. I’m able to define dev = qml.device("lightning.qubit", wires=n_qubits) no problem. Can you tell me which version of PennyLane you’re using? You simply need to print qml.__version__.
import pennylane as qml
import tensorflow as tf
qml.about()
n_qubits =5
dev = qml.device("lightning.qubit", wires=n_qubits)
If you get no errors then your problem should be fixed. You should see some version and platform info printed out. If you see an error please post the printed info here, as well as the error. Hopefully this should fix your problem!
Hi @aouie. It looks like this is a bug with PennyLane-Lightning under Windows. We are trying to identify the cause now. Thank you for sharing these details!
If you do the following, does the problem get fixed?
B: Shift to Linux by using WSL on your Windows and using Visual Studio Code.
Follow the guide here
and use the Linux environment, they can pip install pennylane and it should work, getting around the Windows issue for now.
Thank you for this! I am using Linux now and it is working with pennylane v0.23. I will get back to you regarding my problem with my hybrid QNN. I really appreciate your help!!
Hi @aouie, I’m glad you can use lightning now!
If you’re on Linux you should be able to use v0.25 if you want.
Your new error looks like a problem with your inputs.
Are you able to run this tutorial?
If the tutorial runs but not your code then I would suggest making a minimum working example. This involves making a super simple version of your code that runs (or doesn’t run) and that is stripped of anything non essential.
In many cases this will lead you to finding the error yourself, and otherwise it can allow us to concentrate on a simpler version of your program. Be sure to share the data you’re using as test and train data so that we can run your example too.