Hello everyone, I want to construct a quantum convolutional neural network with a quantum convolutional layer and two classical fully connection layers. When using keras librarys to convert quantum convolutional layers into classical layers, an error accurred. It means the qnode function must return a single measurement, or a nonempty sequence of measurements, but In the code , I must return the data. Can you help me think of a way?
# -- coding: utf-8 --
import pennylane as qml
from pennylane import numpy as np
from pennylane.templates import RandomLayers
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
n_epochs = 30 # Number of optimization epochs
n_layers = 1 # Number of random layers
n_train = 50 # Size of the train dataset
n_test = 30 # Size of the test dataset
SAVE_PATH = “quanvolution/” # Data saving folder
PREPROCESS = True # If False, skip quantum processing and load data from SAVE_PATH
np.random.seed(0) # Seed for NumPy random number generator
tf.random.set_seed(0) # Seed for TensorFlow random number generator
mnist_dataset = keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist_dataset.load_data()
Reduce dataset size
train_images = train_images[:n_train]
train_labels = train_labels[:n_train]
test_images = test_images[:n_test]
test_labels = test_labels[:n_test]
Normalize pixel values within 0 and 1
train_images = train_images / 255
test_images = test_images / 255
Add extra dimension for convolution channels
train_images = np.array(train_images[…, tf.newaxis], requires_grad=False)
test_images = np.array(test_images[…, tf.newaxis], requires_grad=False)
train_images = tf.reshape(train_images,[-1,784])
test_images = tf.reshape(test_images,[-1,784])
train_images = tf.constant(train_images)
test_images = tf.constant(test_images)
train_labels = tf.one_hot(train_labels, depth=10)
test_labels = tf.one_hot(test_labels, depth=10)
dev = qml.device(“default.qubit”, wires=4)
dev1= qml.device(“default.qubit”, wires=4)
Random circuit parameters
rand_params = np.random.uniform(high=2 * np.pi, size=(n_layers, 4))
@qml.qnode(dev)
def circuit(phi,params):
# Encoding of 4 classical input values
for j in range(4):
qml.RY(np.pi * phi[j], wires=j)
# Random quantum circuit
RandomLayers(params, wires=list(range(4)))
# Measurement producing 4 classical output values
return [qml.expval(qml.PauliZ(j)) for j in range(4)]
@qml.qnode(dev1)
def quanv(inputs,params): #必须返回一个测量
“”“Convolves the input image with many applications of the same quantum circuit.”“”
if(inputs.shape[0] == 784):
inputs = tf.reshape(inputs,[28,28,1])
out = np.zeros((14, 14, 4))
# Loop over the coordinates of the top-left pixel of 2X2 squares
for j in range(0, 28, 2):
for k in range(0, 28, 2):
# Process a squared 2x2 region of the image with a quantum circuit
q_results = circuit(
[
inputs[j, k, 0],
inputs[j, k + 1, 0],
inputs[j + 1, k, 0],
inputs[j + 1, k + 1, 0]
],params
)
# Assign expectation values to different channels of the output pixel (j/2, k/2)
for c in range(4):
out[j // 2, k // 2, c] = q_results[c]
out = tf.reshape(out,[784,])
return out
weight_shapes = {“params”: (1,4)} #参数名必须和qnode中的参数名一致
qlayer = qml.qnn.KerasLayer(quanv,weight_shapes,output_dim = 10) # output_dim = 49
clayer1 = tf.keras.layers.Dense(10)
clayer2 = tf.keras.layers.Dense(10, activation = “softmax”)
q_model = tf.keras.models.Sequential([qlayer, clayer1, clayer2])
opt = tf.keras.optimizers.SGD(learning_rate=0.5)
q_model.compile(
optimizer=‘adam’,
loss=“sparse_categorical_crossentropy”,
metrics=[“accuracy”],
) #model.compile()方法用于在配置训练方法时,告知训练时用的优化器、损失函数和准确率评测标准
q_history = q_model.fit( #数据集数据类型必须是张量,将训练数据在模型中训练一定次数,返回loss和测量指标
train_images,
train_labels,
validation_data=(test_images,test_labels),
batch_size=4,
epochs=2,
verbose=2,
)
plt.style.use(“seaborn”)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 9))
ax1.plot(q_history.history[“val_accuracy”], “-ob”, label=“With quantum layer”)
#ax1.plot(c_history.history[“val_accuracy”], “-og”, label=“Without quantum layer”)
ax1.set_ylabel(“Accuracy”)
ax1.set_ylim([0, 1])
ax1.set_xlabel(“Epoch”)
ax1.legend()