날짜를 저장하십시오! Google I / O가 5 월 18 일부터 20 일까지 반환됩니다. 지금 등록
이 페이지는 Cloud Translation API를 통해 번역되었습니다.
Switch to English

안녕하세요, 많은 세계

TensorFlow.org에서보기 Google Colab에서 실행 GitHub에서 소스보기 노트북 다운로드

이 튜토리얼은 기존 신경망이 큐 비트 교정 오류를 수정하는 방법을 학습하는 방법을 보여줍니다. NISQ (Noisy Intermediate Scale Quantum) 회로를 생성, 편집 및 호출하는 Python 프레임 워크 인 Cirq를 소개하고 Cirq 가 TensorFlow Quantum과 인터페이스하는 방법을 보여줍니다.

설정

pip install -q tensorflow==2.3.1

TensorFlow Quantum 설치 :

pip install -q tensorflow-quantum

이제 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. 기본

1.1 Cirq 및 매개 변수화 된 양자 회로

TensorFlow Quantum (TFQ)을 살펴보기 전에 Cirq 기본 사항을 살펴 보겠습니다. Cirq는 Google의 양자 컴퓨팅을위한 Python 라이브러리입니다. 정적 및 매개 변수화 된 게이트를 포함한 회로를 정의하는 데 사용합니다.

Cirq는 SymPy 기호를 사용하여 자유 매개 변수를 나타냅니다.

a, b = sympy.symbols('a b')

다음 코드는 매개 변수를 사용하여 2- 큐 비트 회로를 생성합니다.

# Create two qubits
q0, q1 = cirq.GridQubit.rect(1, 2)

# Create a circuit on these qubits using the parameters you created above.
circuit = cirq.Circuit(
    cirq.rx(a).on(q0),
    cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1))

SVGCircuit(circuit)
findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.

svg

회로를 평가하기 위해 cirq.Simulator 인터페이스를 사용할 수 있습니다. cirq.ParamResolver 객체를 전달하여 회로의 자유 매개 변수를 특정 숫자로 cirq.ParamResolver . 다음 코드는 매개 변수화 된 회로의 원시 상태 벡터 출력을 계산합니다.

# Calculate a state vector with a=0.5 and b=-0.5.
resolver = cirq.ParamResolver({a: 0.5, b: -0.5})
output_state_vector = cirq.Simulator().simulate(circuit, resolver).final_state_vector
output_state_vector
array([ 0.9387913 +0.j        , -0.23971277+0.j        ,

        0.        +0.06120872j,  0.        -0.23971277j], dtype=complex64)

상태 벡터는 시뮬레이션 외부에서 직접 액세스 할 수 없습니다 (위의 출력에서 ​​복소수에 유의하십시오). 물리적으로 현실적이려면 상태 벡터를 기존 컴퓨터가 이해할 수있는 실수로 변환하는 측정을 지정해야합니다. Cirq는 Pauli 연산자 $ \ hat {X} $, $ \ hat {Y} $ 및 $ \ hat {Z} $의 조합을 사용하여 측정을 지정합니다. 예시로, 다음 코드는 방금 시뮬레이션 한 상태 벡터에서 $ \ hat {Z} _0 $ 및 $ \ frac {1} {2} \ hat {Z} _0 + \ hat {X} _1 $를 측정합니다.

z0 = cirq.Z(q0)

qubit_map={q0: 0, q1: 1}

z0.expectation_from_state_vector(output_state_vector, qubit_map).real
0.8775825500488281
z0x1 = 0.5 * z0 + cirq.X(q1)

z0x1.expectation_from_state_vector(output_state_vector, qubit_map).real
-0.04063427448272705

1.2 텐서로서의 양자 회로

TensorFlow Quantum (TFQ)은 Cirq 객체를 텐서로 변환하는 함수 인 tfq.convert_to_tensor 제공합니다. 이를 통해 Cirq 객체를 퀀텀 레이어퀀텀 오퍼레이션으로 보낼 수 있습니다. 이 함수는 Cirq Circuits 및 Cirq Paulis의 목록 또는 배열에서 호출 할 수 있습니다.

# Rank 1 tensor containing 1 circuit.
circuit_tensor = tfq.convert_to_tensor([circuit])

print(circuit_tensor.shape)
print(circuit_tensor.dtype)
(1,)
<dtype: 'string'>

이 암호화하는 CIRQ는 다음과 같이 객체 tf.string 것을 텐서를 tfq 작업이 필요에 디코딩 할.

# Rank 1 tensor containing 2 Pauli operators.
pauli_tensor = tfq.convert_to_tensor([z0, z0x1])
pauli_tensor.shape
TensorShape([2])

1.3 배치 회로 시뮬레이션

TFQ는 기대 값, 샘플 및 상태 벡터를 계산하는 방법을 제공합니다. 지금은 기대 값에 중점을 두겠습니다 .

기대 값을 계산하는 최고 레벨 인터페이스이다 tfq.layers.Expectation A는 층 tf.keras.Layer . 가장 간단한 형태로이 계층은 많은 cirq.ParamResolvers 대해 매개 변수화 된 회로를 시뮬레이션하는 것과 동일합니다. 그러나 TFQ는 TensorFlow 의미 체계를 따르는 일괄 처리를 허용하며 회로는 효율적인 C ++ 코드를 사용하여 시뮬레이션됩니다.

ab 매개 변수를 대체 할 값 배치를 만듭니다.

batch_vals = np.array(np.random.uniform(0, 2 * np.pi, (5, 2)), dtype=np.float32)

Cirq의 매개 변수 값에 대한 일괄 회로 실행에는 루프가 필요합니다.

cirq_results = []
cirq_simulator = cirq.Simulator()

for vals in batch_vals:
    resolver = cirq.ParamResolver({a: vals[0], b: vals[1]})
    final_state_vector = cirq_simulator.simulate(circuit, resolver).final_state_vector
    cirq_results.append(
        [z0.expectation_from_state_vector(final_state_vector, {
            q0: 0,
            q1: 1
        }).real])

print('cirq batch results: \n {}'.format(np.array(cirq_results)))
cirq batch results: 
 [[-0.97633868]
 [ 0.68726736]
 [-0.67144978]
 [-0.92119527]
 [ 0.41925651]]

TFQ에서도 동일한 작업이 단순화됩니다.

tfq.layers.Expectation()(circuit,
                         symbol_names=[a, b],
                         symbol_values=batch_vals,
                         operators=z0)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[-0.9763384 ],
       [ 0.6872687 ],
       [-0.67144877],
       [-0.9211948 ],
       [ 0.41925824]], dtype=float32)>

2. 하이브리드 양자 고전적 최적화

이제 기본 사항을 확인 했으므로 TensorFlow Quantum을 사용하여 하이브리드 양자 클래식 신경망 을 구성 해 보겠습니다. 단일 큐 비트를 제어하기 위해 고전적인 신경망을 훈련합니다. 제어는 0 또는 1 상태에서 큐 비트를 올바르게 준비하도록 최적화되어 시뮬레이션 된 체계적 교정 오류를 극복합니다. 이 그림은 아키텍처를 보여줍니다.

신경망이 없어도 해결하기 쉬운 문제이지만, 주제는 TFQ를 사용하여 해결할 수있는 실제 양자 제어 문제와 유사합니다. 그것은 사용 양자 고전 연산 종단 예를 보여 tfq.layers.ControlledPQC (A)의 (매개 변수화 양자 회로) 층 내부 tf.keras.Model .

이 튜토리얼의 구현을 위해 이것은 아키텍처가 세 부분으로 나뉩니다.

  • 입력 회로 또는 데이터 포인트 회로 : 처음 세 개의 $ R $ 게이트.
  • 제어 회로 : 다른 3 개의 $ R $ 게이트.
  • 컨트롤러 : 제어 회로의 매개 변수를 설정하는 고전적인 신경망.

2.1 제어 회로 정의

위 그림에 표시된대로 학습 가능한 단일 비트 회전을 정의합니다. 이것은 우리의 제어 회로에 해당합니다.

# Parameters that the classical NN will feed values into.
control_params = sympy.symbols('theta_1 theta_2 theta_3')

# Create the parameterized circuit.
qubit = cirq.GridQubit(0, 0)
model_circuit = cirq.Circuit(
    cirq.rz(control_params[0])(qubit),
    cirq.ry(control_params[1])(qubit),
    cirq.rx(control_params[2])(qubit))

SVGCircuit(model_circuit)

svg

2.2 컨트롤러

이제 컨트롤러 네트워크를 정의하십시오.

# The classical neural network layers.
controller = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='elu'),
    tf.keras.layers.Dense(3)
])

명령 배치가 주어지면 컨트롤러는 제어 회로에 대한 제어 신호 배치를 출력합니다.

컨트롤러는 무작위로 초기화되므로 이러한 출력은 아직 유용하지 않습니다.

controller(tf.constant([[0.0],[1.0]])).numpy()
array([[0.        , 0.        , 0.        ],
       [0.08031327, 0.03002123, 0.0143298 ]], dtype=float32)

2.3 회로에 컨트롤러 연결

사용 tfq 하나로서, 제어 회로 제어기를 연결 keras.Model .

이 스타일의 모델 정의에 대한 자세한 내용은 Keras Functional API 가이드 를 참조하세요.

먼저 모델에 대한 입력을 정의하십시오.

# This input is the simulated miscalibration that the model will learn to correct.
circuits_input = tf.keras.Input(shape=(),
                                # The circuit-tensor has dtype `tf.string` 
                                dtype=tf.string,
                                name='circuits_input')

# Commands will be either `0` or `1`, specifying the state to set the qubit to.
commands_input = tf.keras.Input(shape=(1,),
                                dtype=tf.dtypes.float32,
                                name='commands_input')

다음으로 해당 입력에 연산을 적용하여 계산을 정의합니다.

dense_2 = controller(commands_input)

# TFQ layer for classically controlled circuits.
expectation_layer = tfq.layers.ControlledPQC(model_circuit,
                                             # Observe Z
                                             operators = cirq.Z(qubit))
expectation = expectation_layer([circuits_input, dense_2])

이제이 계산을 tf.keras.Model .

# The full Keras model is built from our layers.
model = tf.keras.Model(inputs=[circuits_input, commands_input],
                       outputs=expectation)

네트워크 아키텍처는 아래 모델의 플롯으로 표시됩니다. 이 모델 플롯을 아키텍처 다이어그램과 비교하여 정확성을 확인하십시오.

tf.keras.utils.plot_model(model, show_shapes=True, dpi=70)

png

이 모델은 두 가지 입력을받습니다. 컨트롤러에 대한 명령과 컨트롤러가 수정하려는 출력의 입력 회로입니다.

2.4 데이터 세트

모델은 각 명령에 대해 올바른 측정 값 $ \ hat {Z} $를 출력하려고합니다. 명령과 올바른 값은 아래에 정의되어 있습니다.

# The command input values to the classical NN.
commands = np.array([[0], [1]], dtype=np.float32)

# The desired Z expectation value at output of quantum circuit.
expected_outputs = np.array([[1], [-1]], dtype=np.float32)

이것은이 작업에 대한 전체 교육 데이터 세트가 아닙니다. 데이터 세트의 각 데이터 포인트에는 입력 회로도 필요합니다.

2.4 입력 회로 정의

아래의 입력 회로는 모델이 수정하는 방법을 배우는 임의의 오 보정을 정의합니다.

random_rotations = np.random.uniform(0, 2 * np.pi, 3)
noisy_preparation = cirq.Circuit(
  cirq.rx(random_rotations[0])(qubit),
  cirq.ry(random_rotations[1])(qubit),
  cirq.rz(random_rotations[2])(qubit)
)
datapoint_circuits = tfq.convert_to_tensor([
  noisy_preparation
] * 2)  # Make two copied of this circuit

각 데이터 포인트에 대해 하나씩 두 개의 회로 사본이 있습니다.

datapoint_circuits.shape
TensorShape([2])

2.5 훈련

정의 된 입력으로 tfq 모델을 테스트 실행할 수 있습니다.

model([datapoint_circuits, commands]).numpy()
array([[-0.14540803],
       [-0.16774747]], dtype=float32)

이제 표준 학습 프로세스를 실행하여 이러한 값을 expected_outputs 로 조정합니다.

optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
loss = tf.keras.losses.MeanSquaredError()
model.compile(optimizer=optimizer, loss=loss)
history = model.fit(x=[datapoint_circuits, commands],
                    y=expected_outputs,
                    epochs=30,
                    verbose=0)
plt.plot(history.history['loss'])
plt.title("Learning to Control a Qubit")
plt.xlabel("Iterations")
plt.ylabel("Error in Control")
plt.show()

png

이 플롯에서 신경망이 체계적인 오 보정을 극복하는 방법을 배웠 음을 알 수 있습니다.

2.6 출력 확인

이제 훈련 된 모델을 사용하여 큐 비트 교정 오류를 수정합니다. Cirq 사용 :

def check_error(command_values, desired_values):
  """Based on the value in `command_value` see how well you could prepare
  the full circuit to have `desired_value` when taking expectation w.r.t. Z."""
  params_to_prepare_output = controller(command_values).numpy()
  full_circuit = noisy_preparation + model_circuit

  # Test how well you can prepare a state to get expectation the expectation
  # value in `desired_values`
  for index in [0, 1]:
    state = cirq_simulator.simulate(
        full_circuit,
        {s:v for (s,v) in zip(control_params, params_to_prepare_output[index])}
    ).final_state_vector
    expt = cirq.Z(qubit).expectation_from_state_vector(state, {qubit: 0}).real
    print(f'For a desired output (expectation) of {desired_values[index]} with'
          f' noisy preparation, the controller\nnetwork found the following '
          f'values for theta: {params_to_prepare_output[index]}\nWhich gives an'
          f' actual expectation of: {expt}\n')


check_error(commands, expected_outputs)
For a desired output (expectation) of [1.] with noisy preparation, the controller
network found the following values for theta: [-1.8619336 -1.523817  -3.2972674]
Which gives an actual expectation of: 0.9911799430847168

For a desired output (expectation) of [-1.] with noisy preparation, the controller
network found the following values for theta: [1.0268601  1.7161715  0.44205332]
Which gives an actual expectation of: -0.9540284872055054

학습 중 손실 함수의 값은 모델이 얼마나 잘 학습하고 있는지 대략적인 아이디어를 제공합니다. 손실이 낮을수록 위 셀의 기대 값이 desired_values 에 가까워집니다. 매개 변수 값에 관심이 tfq 사용하여 항상 위의 출력을 확인할 수 있습니다.

model([datapoint_circuits, commands])
<tf.Tensor: shape=(2, 1), dtype=float32, numpy=
array([[ 0.9911797],
       [-0.9540284]], dtype=float32)>

3 다른 연산자의 고유 상태를 준비하는 방법 배우기

1과 0에 해당하는 $ \ pm \ hat {Z} $ 고유 상태의 선택은 임의적이었습니다. 1이 $ + \ hat {Z} $ 고유 상태에 해당하고 0이 $-\ hat {X} $ 고유 상태에 해당하는 것처럼 쉽게 원할 수 있습니다. 이를 수행하는 한 가지 방법은 아래 그림에 표시된대로 각 명령에 대해 다른 측정 연산자를 지정하는 것입니다.

이를 위해서는 tfq.layers.Expectationtfq.layers.Expectation 합니다. 이제 입력은 회로, 명령 및 운영자의 세 가지 개체를 포함하도록 증가했습니다. 출력은 여전히 ​​기대 값입니다.

3.1 새로운 모델 정의

이 작업을 수행하는 모델을 살펴 보겠습니다.

# Define inputs.
commands_input = tf.keras.layers.Input(shape=(1),
                                       dtype=tf.dtypes.float32,
                                       name='commands_input')
circuits_input = tf.keras.Input(shape=(),
                                # The circuit-tensor has dtype `tf.string` 
                                dtype=tf.dtypes.string,
                                name='circuits_input')
operators_input = tf.keras.Input(shape=(1,),
                                 dtype=tf.dtypes.string,
                                 name='operators_input')

다음은 컨트롤러 네트워크입니다.

# Define classical NN.
controller = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='elu'),
    tf.keras.layers.Dense(3)
])

회로 단일 제어기에 결합 keras.Model 사용 tfq :

dense_2 = controller(commands_input)

# Since you aren't using a PQC or ControlledPQC you must append
# your model circuit onto the datapoint circuit tensor manually.
full_circuit = tfq.layers.AddCircuit()(circuits_input, append=model_circuit)
expectation_output = tfq.layers.Expectation()(full_circuit,
                                              symbol_names=control_params,
                                              symbol_values=dense_2,
                                              operators=operators_input)

# Contruct your Keras model.
two_axis_control_model = tf.keras.Model(
    inputs=[circuits_input, commands_input, operators_input],
    outputs=[expectation_output])

3.2 데이터 세트

이제 model_circuit 제공하는 각 데이터 포인트에 대해 측정하려는 연산자도 포함합니다.

# The operators to measure, for each command.
operator_data = tfq.convert_to_tensor([[cirq.X(qubit)], [cirq.Z(qubit)]])

# The command input values to the classical NN.
commands = np.array([[0], [1]], dtype=np.float32)

# The desired expectation value at output of quantum circuit.
expected_outputs = np.array([[1], [-1]], dtype=np.float32)

3.3 훈련

이제 새로운 입력 및 출력이 있으므로 keras를 사용하여 다시 한 번 훈련 할 수 있습니다.

optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
loss = tf.keras.losses.MeanSquaredError()

two_axis_control_model.compile(optimizer=optimizer, loss=loss)

history = two_axis_control_model.fit(
    x=[datapoint_circuits, commands, operator_data],
    y=expected_outputs,
    epochs=30,
    verbose=1)
Epoch 1/30
1/1 [==============================] - 0s 1ms/step - loss: 1.7510
Epoch 2/30
1/1 [==============================] - 0s 759us/step - loss: 0.8703
Epoch 3/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3938
Epoch 4/30
1/1 [==============================] - 0s 749us/step - loss: 0.1695
Epoch 5/30
1/1 [==============================] - 0s 722us/step - loss: 0.0820
Epoch 6/30
1/1 [==============================] - 0s 685us/step - loss: 0.0609
Epoch 7/30
1/1 [==============================] - 0s 676us/step - loss: 0.0704
Epoch 8/30
1/1 [==============================] - 0s 734us/step - loss: 0.0826
Epoch 9/30
1/1 [==============================] - 0s 732us/step - loss: 0.0723
Epoch 10/30
1/1 [==============================] - 0s 907us/step - loss: 0.0431
Epoch 11/30
1/1 [==============================] - 0s 731us/step - loss: 0.0178
Epoch 12/30
1/1 [==============================] - 0s 859us/step - loss: 0.0064
Epoch 13/30
1/1 [==============================] - 0s 763us/step - loss: 0.0035
Epoch 14/30
1/1 [==============================] - 0s 684us/step - loss: 0.0031
Epoch 15/30
1/1 [==============================] - 0s 710us/step - loss: 0.0030
Epoch 16/30
1/1 [==============================] - 0s 671us/step - loss: 0.0038
Epoch 17/30
1/1 [==============================] - 0s 716us/step - loss: 0.0062
Epoch 18/30
1/1 [==============================] - 0s 707us/step - loss: 0.0095
Epoch 19/30
1/1 [==============================] - 0s 700us/step - loss: 0.0120
Epoch 20/30
1/1 [==============================] - 0s 703us/step - loss: 0.0117
Epoch 21/30
1/1 [==============================] - 0s 697us/step - loss: 0.0089
Epoch 22/30
1/1 [==============================] - 0s 717us/step - loss: 0.0053
Epoch 23/30
1/1 [==============================] - 0s 739us/step - loss: 0.0025
Epoch 24/30
1/1 [==============================] - 0s 725us/step - loss: 9.8351e-04
Epoch 25/30
1/1 [==============================] - 0s 709us/step - loss: 3.7235e-04
Epoch 26/30
1/1 [==============================] - 0s 660us/step - loss: 3.4534e-04
Epoch 27/30
1/1 [==============================] - 0s 744us/step - loss: 6.7898e-04
Epoch 28/30
1/1 [==============================] - 0s 740us/step - loss: 0.0013
Epoch 29/30
1/1 [==============================] - 0s 770us/step - loss: 0.0020
Epoch 30/30
1/1 [==============================] - 0s 756us/step - loss: 0.0028
plt.plot(history.history['loss'])
plt.title("Learning to Control a Qubit")
plt.xlabel("Iterations")
plt.ylabel("Error in Control")
plt.show()

png

손실 함수가 0으로 떨어졌습니다.

controller 는 독립형 모델로 제공됩니다. 컨트롤러를 호출하고 각 명령 신호에 대한 응답을 확인하십시오. 이러한 출력을 random_rotations 의 내용과 올바르게 비교하려면 약간의 작업이 필요합니다.

controller.predict(np.array([0,1]))
array([[ 1.741399  , -0.22516271,  0.7868666 ],
       [-0.31710118,  1.6385193 ,  1.8622308 ]], dtype=float32)