Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/ko/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은 변환적으로 불변인 고전적 컨볼루셔널 신경망의 양자화 버전으로 제시됩니다.

이 예는 양자 센서 또는 기기의 복잡한 시뮬레이션과 같은 양자 데이터 소스의 특정한 속성을 감지하는 방법을 보여줍니다. 양자 데이터 소스는 여기(excitation)가 있을 수도 있고 없을 수도 있는 클러스터 상태로, 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)는 그래프 내 회로 구성을 위해 설계된 레이어 클래스를 제공합니다. 한 가지 예는 tfq.layers.AddCircuit에서 상속되는 tf.keras.Layer 레이어입니다. 이 레이어는 다음 그림과 같이 회로의 입력 배치 앞이나 뒤에 놓일 수 있습니다.

다음은 이 레이어를 사용하는 코드 조각입니다.

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 클러스터 상태

첫 단계로 양자 회로 프로그래밍을 위해 Google에서 제공하는 프레임워크인 Cirq를 사용하여 클러스터 상태를 정의합니다. 이것은 모델의 정적인 부분이기 때문에 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 논문의 1-큐비트 및 2-큐비트 매개변수화된 단일 행렬

  • 일반적인 매개변수화된 2-큐비트 풀링 연산

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

생성 결과를 보기 위해 1-큐비트 단일 회로를 출력합니다.

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

그리고 2-큐비트 단일 회로입니다.

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

그리고 2-큐비트 풀링 회로입니다.

SVGCircuit(two_qubit_pool(*cirq.GridQubit.rect(1, 2), sympy.symbols('x0:6')))
1.5.2.1 양자 컨볼루션

Cong 및 Lukin의 논문에서와 같이 1D 양자 컨볼루션은 하나의 간격만큼 떨어진 인접한 큐비트의 각 쌍에 2-큐비트 매개변수화된 단일 행렬을 적용한 것으로 정의됩니다.

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 양자 풀링

양자 풀링 레이어는 위에서 정의한 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을 구성합니다. 8개 큐비트로 시작하여 1개 큐비트까지 풀링한 다음 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. 하이브리드 모델

양자 컨볼루션을 사용하여 8개 큐비트에서 1개 큐비트까지 모두 진행할 필요는 없습니다. 대신, 양자 컨볼루션을 1~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()