Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/zh-cn/quantum/tutorials/qcnn.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

量子卷积神经网络

本教程介绍如何实现一个简化的量子卷积神经网络 (QCNN),即对同样具有平移不变性的经典卷积神经网络的提议量子模拟。

本示例演示如何检测量子数据源的某些属性,例如设备的量子传感器或复杂模拟。量子数据源是可能有或可能没有激发的簇态,后者是 QCNN 将学习检测的对象(论文中使用的数据集是 SPT 阶段分类)。

设置

!pip install tensorflow==2.7.0

安装 TensorFlow Quantum:

!pip install tensorflow-quantum==0.7.2
# Update package resources to account for version changes. import importlib, pkg_resources importlib.reload(pkg_resources)

现在,导入 TensorFlow 和模块依赖项:

import tensorflow as tf import tensorflow_quantum as tfq import cirq import sympy import numpy as np # visualization tools %matplotlib inline import matplotlib.pyplot as plt from cirq.contrib.svg import SVGCircuit

1. 构建 QCNN

1.1 在 TensorFlow 计算图中组装电路

TensorFlow Quantum (TFQ) 提供了专为计算图中的电路构造而设计的层类。一个示例是从 tf.keras.Layer 继承的 tfq.layers.AddCircuit 层。此层可以追加或附加到电路的输入批次,如下图所示。

下面的代码段使用了此层:

qubit = cirq.GridQubit(0, 0) # Define some circuits. circuit1 = cirq.Circuit(cirq.X(qubit)) circuit2 = cirq.Circuit(cirq.H(qubit)) # Convert to a tensor. input_circuit_tensor = tfq.convert_to_tensor([circuit1, circuit2]) # Define a circuit that we want to append y_circuit = cirq.Circuit(cirq.Y(qubit)) # Instantiate our layer y_appender = tfq.layers.AddCircuit() # Run our circuit tensor through the layer and save the output. output_circuit_tensor = y_appender(input_circuit_tensor, append=y_circuit)

检查输入张量:

print(tfq.from_tensor(input_circuit_tensor))

检查输出张量:

print(tfq.from_tensor(output_circuit_tensor))

虽然不使用 tfq.layers.AddCircuit 也可以运行下面的示例,但这是一个理解如何将复杂的功能嵌入 TensorFlow 计算图的好机会。

1.2 问题概述

您将准备簇态,并训练一个量子分类器来检测它是否处于“激发”状态。簇态是高度纠缠的,不过,这对经典计算机而言并非难以解决的问题。为了让您更清楚地理解,我们使用的这一数据集比论文中使用的更简单。

对于此分类任务,您将实现一个类似深度 MERA 的 QCNN 架构,因为:

  1. 就像 QCNN 一样,环上的簇态具有平移不变性。

  2. 簇态是高度纠缠的。

这种架构在减少纠缠方面应该会很有效,通过读出一个量子位来获得分类。

根据定义,“激发”簇态是指将 cirq.rx 门应用到其任何量子位的簇态。Qconv 和 QPool 在本教程的后续部分讨论。

1.3 为 TensorFlow 构建块

使用 TensorFlow Quantum 解决此问题的一种方式是实现以下几点:

  1. 模型的输入是一个电路张量,空电路或表明激发的特定量子位上的 X 门。

  2. 使用 tfq.layers.AddCircuit 层构造模型的其他量子组件。

  3. 使用 tfq.layers.PQC 层进行推断。它会读取 Z^\langle \hat{Z} \rangle,并将其与激发态的标签 1 或非激发态的标签 -1 进行比较。

1.4 数据

在构建模型之前,您可以生成数据。在本例中,它将是簇态的激发(原论文使用的是一个更复杂的数据集)。激发通过 cirq.rx 门表示。我们将足够大的旋转视为激发,并使用 1 进行标记,不够大的旋转则使用 -1 标记,我们将其视为未激发。

def generate_data(qubits): """Generate training and testing data.""" n_rounds = 20 # Produces n_rounds * n_qubits datapoints. excitations = [] labels = [] for n in range(n_rounds): for bit in qubits: rng = np.random.uniform(-np.pi, np.pi) excitations.append(cirq.Circuit(cirq.rx(rng)(bit))) labels.append(1 if (-np.pi / 2) <= rng <= (np.pi / 2) else -1) split_ind = int(len(excitations) * 0.7) train_excitations = excitations[:split_ind] test_excitations = excitations[split_ind:] train_labels = labels[:split_ind] test_labels = labels[split_ind:] return tfq.convert_to_tensor(train_excitations), np.array(train_labels), \ tfq.convert_to_tensor(test_excitations), np.array(test_labels)

您可以看到,就像使用常规的机器学习一样,您创建了一个用于对模型进行基准测试的训练和测试集。利用以下代码段,您可以快速查看某些数据点:

sample_points, sample_labels, _, __ = generate_data(cirq.GridQubit.rect(1, 4)) print('Input:', tfq.from_tensor(sample_points)[0], 'Output:', sample_labels[0]) print('Input:', tfq.from_tensor(sample_points)[1], 'Output:', sample_labels[1])

1.5 定义层

现在,我们在 TensorFlow 中定义上图中显示的层。

1.5.1 簇态

第一步是使用 Cirq(Google 为量子电路编程提供的框架)定义簇态。由于这是模型的一个静态部分,因此使用 tfq.layers.AddCircuit 功能将其嵌入。

def cluster_state_circuit(bits): """Return a cluster state on the qubits in `bits`.""" circuit = cirq.Circuit() circuit.append(cirq.H.on_each(bits)) for this_bit, next_bit in zip(bits, bits[1:] + [bits[0]]): circuit.append(cirq.CZ(this_bit, next_bit)) return circuit

显示 cirq.GridQubit 的矩形的一个簇态电路:

SVGCircuit(cluster_state_circuit(cirq.GridQubit.rect(1, 4)))

1.5.2 QCNN 层

按照 Cong 和 Lukin QCNN 论文定义组成模型的层。这需要具备几个前提条件:

  • Tucci 论文中提出的单或双量子位参数化酉矩阵。

  • 一个通用的参数化双量子位池化运算。

def one_qubit_unitary(bit, symbols): """Make a Cirq circuit enacting a rotation of the bloch sphere about the X, Y and Z axis, that depends on the values in `symbols`. """ return cirq.Circuit( cirq.X(bit)**symbols[0], cirq.Y(bit)**symbols[1], cirq.Z(bit)**symbols[2]) def two_qubit_unitary(bits, symbols): """Make a Cirq circuit that creates an arbitrary two qubit unitary.""" circuit = cirq.Circuit() circuit += one_qubit_unitary(bits[0], symbols[0:3]) circuit += one_qubit_unitary(bits[1], symbols[3:6]) circuit += [cirq.ZZ(*bits)**symbols[6]] circuit += [cirq.YY(*bits)**symbols[7]] circuit += [cirq.XX(*bits)**symbols[8]] circuit += one_qubit_unitary(bits[0], symbols[9:12]) circuit += one_qubit_unitary(bits[1], symbols[12:]) return circuit def two_qubit_pool(source_qubit, sink_qubit, symbols): """Make a Cirq circuit to do a parameterized 'pooling' operation, which attempts to reduce entanglement down from two qubits to just one.""" pool_circuit = cirq.Circuit() sink_basis_selector = one_qubit_unitary(sink_qubit, symbols[0:3]) source_basis_selector = one_qubit_unitary(source_qubit, symbols[3:6]) pool_circuit.append(sink_basis_selector) pool_circuit.append(source_basis_selector) pool_circuit.append(cirq.CNOT(control=source_qubit, target=sink_qubit)) pool_circuit.append(sink_basis_selector**-1) return pool_circuit

要查看您创建的对象,请打印出单量子位酉电路:

SVGCircuit(one_qubit_unitary(cirq.GridQubit(0, 0), sympy.symbols('x0:3')))

以及双量子位酉电路:

SVGCircuit(two_qubit_unitary(cirq.GridQubit.rect(1, 2), sympy.symbols('x0:15')))

以及双量子位池化电路:

SVGCircuit(two_qubit_pool(*cirq.GridQubit.rect(1, 2), sympy.symbols('x0:6')))
1.5.2.1 量子卷积

按照 Cong 和 Lukin 的论文所述,将一维量子卷积定义为对每对步长为 1 的相邻量子位的双量子位参数化酉的应用。

def quantum_conv_circuit(bits, symbols): """Quantum Convolution Layer following the above diagram. Return a Cirq circuit with the cascade of `two_qubit_unitary` applied to all pairs of qubits in `bits` as in the diagram above. """ circuit = cirq.Circuit() for first, second in zip(bits[0::2], bits[1::2]): circuit += two_qubit_unitary([first, second], symbols) for first, second in zip(bits[1::2], bits[2::2] + [bits[0]]): circuit += two_qubit_unitary([first, second], symbols) return circuit

显示(高度水平的)电路:

SVGCircuit( quantum_conv_circuit(cirq.GridQubit.rect(1, 8), sympy.symbols('x0:15')))
1.5.2.2 量子池化

量子池化层使用上面定义的双量子位池从 NN 个量子位池化为 N2\frac{N}{2} 个量子位。

def quantum_pool_circuit(source_bits, sink_bits, symbols): """A layer that specifies a quantum pooling operation. A Quantum pool tries to learn to pool the relevant information from two qubits onto 1. """ circuit = cirq.Circuit() for source, sink in zip(source_bits, sink_bits): circuit += two_qubit_pool(source, sink, symbols) return circuit

检查池化组件电路:

test_bits = cirq.GridQubit.rect(1, 8) SVGCircuit( quantum_pool_circuit(test_bits[:4], test_bits[4:], sympy.symbols('x0:6')))

1.6 模型定义

现在,使用定义的层构造纯量子 CNN。首先创建八个量子位,再将其池化为一个量子位,然后测量 Z^\langle \hat{Z} \rangle

def create_model_circuit(qubits): """Create sequence of alternating convolution and pooling operators which gradually shrink over time.""" model_circuit = cirq.Circuit() symbols = sympy.symbols('qconv0:63') # Cirq uses sympy.Symbols to map learnable variables. TensorFlow Quantum # scans incoming circuits and replaces these with TensorFlow variables. model_circuit += quantum_conv_circuit(qubits, symbols[0:15]) model_circuit += quantum_pool_circuit(qubits[:4], qubits[4:], symbols[15:21]) model_circuit += quantum_conv_circuit(qubits[4:], symbols[21:36]) model_circuit += quantum_pool_circuit(qubits[4:6], qubits[6:], symbols[36:42]) model_circuit += quantum_conv_circuit(qubits[6:], symbols[42:57]) model_circuit += quantum_pool_circuit([qubits[6]], [qubits[7]], symbols[57:63]) return model_circuit # Create our qubits and readout operators in Cirq. cluster_state_bits = cirq.GridQubit.rect(1, 8) readout_operators = cirq.Z(cluster_state_bits[-1]) # Build a sequential model enacting the logic in 1.3 of this notebook. # Here you are making the static cluster state prep as a part of the AddCircuit and the # "quantum datapoints" are coming in the form of excitation excitation_input = tf.keras.Input(shape=(), dtype=tf.dtypes.string) cluster_state = tfq.layers.AddCircuit()( excitation_input, prepend=cluster_state_circuit(cluster_state_bits)) quantum_model = tfq.layers.PQC(create_model_circuit(cluster_state_bits), readout_operators)(cluster_state) qcnn_model = tf.keras.Model(inputs=[excitation_input], outputs=[quantum_model]) # Show the keras plot of the model tf.keras.utils.plot_model(qcnn_model, show_shapes=True, show_layer_names=False, dpi=70)

1.7 训练模型

在整个批次上训练模型以简化此示例。

# Generate some training data. train_excitations, train_labels, test_excitations, test_labels = generate_data( cluster_state_bits) # Custom accuracy metric. @tf.function def custom_accuracy(y_true, y_pred): y_true = tf.squeeze(y_true) y_pred = tf.map_fn(lambda x: 1.0 if x >= 0 else -1.0, y_pred) return tf.keras.backend.mean(tf.keras.backend.equal(y_true, y_pred)) qcnn_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.02), loss=tf.losses.mse, metrics=[custom_accuracy]) history = qcnn_model.fit(x=train_excitations, y=train_labels, batch_size=16, epochs=25, verbose=1, validation_data=(test_excitations, test_labels))
plt.plot(history.history['loss'][1:], label='Training') plt.plot(history.history['val_loss'][1:], label='Validation') plt.title('Training a Quantum CNN to Detect Excited Cluster States') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.show()

2. 混合模型

您不必使用量子卷积将八个量子位池化为一个量子位,您可以执行一到两轮的量子卷积,然后将结果馈送到经典神经网络中。本部分探讨量子-经典混合模型。

2.1 使用单个量子滤波器的混合模型

应用一层量子卷积,在后跟密集连接的神经网络的所有位上读出 Z^n\langle \hat{Z}_n \rangle

2.1.1 模型定义

# 1-local operators to read out readouts = [cirq.Z(bit) for bit in cluster_state_bits[4:]] def multi_readout_model_circuit(qubits): """Make a model circuit with less quantum pool and conv operations.""" model_circuit = cirq.Circuit() symbols = sympy.symbols('qconv0:21') model_circuit += quantum_conv_circuit(qubits, symbols[0:15]) model_circuit += quantum_pool_circuit(qubits[:4], qubits[4:], symbols[15:21]) return model_circuit # Build a model enacting the logic in 2.1 of this notebook. excitation_input_dual = tf.keras.Input(shape=(), dtype=tf.dtypes.string) cluster_state_dual = tfq.layers.AddCircuit()( excitation_input_dual, prepend=cluster_state_circuit(cluster_state_bits)) quantum_model_dual = tfq.layers.PQC( multi_readout_model_circuit(cluster_state_bits), readouts)(cluster_state_dual) d1_dual = tf.keras.layers.Dense(8)(quantum_model_dual) d2_dual = tf.keras.layers.Dense(1)(d1_dual) hybrid_model = tf.keras.Model(inputs=[excitation_input_dual], outputs=[d2_dual]) # Display the model architecture tf.keras.utils.plot_model(hybrid_model, show_shapes=True, show_layer_names=False, dpi=70)

2.1.2 训练模型

hybrid_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.02), loss=tf.losses.mse, metrics=[custom_accuracy]) hybrid_history = hybrid_model.fit(x=train_excitations, y=train_labels, batch_size=16, epochs=25, verbose=1, validation_data=(test_excitations, test_labels))
plt.plot(history.history['val_custom_accuracy'], label='QCNN') plt.plot(hybrid_history.history['val_custom_accuracy'], label='Hybrid CNN') plt.title('Quantum vs Hybrid CNN performance') plt.xlabel('Epochs') plt.legend() plt.ylabel('Validation Accuracy') plt.show()

如您所见,在适当的经典模型的帮助下,混合模型通常比纯量子版本收敛得更快。

2.2 使用多个量子滤波器的混合卷积

现在,我们来试试使用多个量子卷积和一个经典神经网络的架构,将其组合在一起。

2.2.1 模型定义

excitation_input_multi = tf.keras.Input(shape=(), dtype=tf.dtypes.string) cluster_state_multi = tfq.layers.AddCircuit()( excitation_input_multi, prepend=cluster_state_circuit(cluster_state_bits)) # apply 3 different filters and measure expectation values quantum_model_multi1 = tfq.layers.PQC( multi_readout_model_circuit(cluster_state_bits), readouts)(cluster_state_multi) quantum_model_multi2 = tfq.layers.PQC( multi_readout_model_circuit(cluster_state_bits), readouts)(cluster_state_multi) quantum_model_multi3 = tfq.layers.PQC( multi_readout_model_circuit(cluster_state_bits), readouts)(cluster_state_multi) # concatenate outputs and feed into a small classical NN concat_out = tf.keras.layers.concatenate( [quantum_model_multi1, quantum_model_multi2, quantum_model_multi3]) dense_1 = tf.keras.layers.Dense(8)(concat_out) dense_2 = tf.keras.layers.Dense(1)(dense_1) multi_qconv_model = tf.keras.Model(inputs=[excitation_input_multi], outputs=[dense_2]) # Display the model architecture tf.keras.utils.plot_model(multi_qconv_model, show_shapes=True, show_layer_names=True, dpi=70)

2.2.2 训练模型

multi_qconv_model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=0.02), loss=tf.losses.mse, metrics=[custom_accuracy]) multi_qconv_history = multi_qconv_model.fit(x=train_excitations, y=train_labels, batch_size=16, epochs=25, verbose=1, validation_data=(test_excitations, test_labels))
plt.plot(history.history['val_custom_accuracy'][:25], label='QCNN') plt.plot(hybrid_history.history['val_custom_accuracy'][:25], label='Hybrid CNN') plt.plot(multi_qconv_history.history['val_custom_accuracy'][:25], label='Hybrid CNN \n Multiple Quantum Filters') plt.title('Quantum vs Hybrid CNN performance') plt.xlabel('Epochs') plt.legend() plt.ylabel('Validation Accuracy') plt.show()