Google I / O, 18-20 Mayıs'ta geri dönüyor! Yer ayırın ve programınızı oluşturun Şimdi kaydolun

Merhaba birçok dünya

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Defteri indirin

Bu eğitim, klasik bir sinir ağının kübit kalibrasyon hatalarını düzeltmeyi nasıl öğrenebileceğini gösterir. O tanıtır Cirq oluşturmak, düzenlemek için bir Python çerçeve ve gürültülü Orta Ölçekli Quantum çağırmak (NISQ) devreler ve TensorFlow Quantum ile nasıl Cirq arayüzleri göstermektedir.

Kurulum

pip install -q tensorflow==2.3.1

TensorFlow Quantum'u yükleyin:

pip install -q tensorflow-quantum

Şimdi TensorFlow ve modül bağımlılıklarını içe aktarın:

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. Temel Bilgiler

1.1 Cirq ve parametreli kuantum devreleri

TensorFlow Quantum (TFQ) keşfetmeden önce, bazı Bakalım Cirq temelleri. Cirq, Google'ın kuantum hesaplaması için bir Python kitaplığıdır. Statik ve parametreli kapılar dahil olmak üzere devreleri tanımlamak için kullanırsınız.

Cirq, ücretsiz parametreleri temsil etmek için SymPy sembollerini kullanır.

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

Aşağıdaki kod, parametrelerinizi kullanarak iki kübitlik bir devre oluşturur:

# 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

Devreleri değerlendirmek için, cirq.Simulator arayüzünü kullanabilirsiniz. Bir cirq.ParamResolver nesnesine geçerek bir devredeki serbest parametreleri belirli sayılarla değiştirirsiniz. Aşağıdaki kod, parametreli devrenizin ham durum vektör çıktısını hesaplar:

# 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)

Durum vektörlerine simülasyon dışında doğrudan erişilemez (yukarıdaki çıktıdaki karmaşık sayılara dikkat edin). Fiziksel olarak gerçekçi olmak için, bir durum vektörünü klasik bilgisayarların anlayabileceği gerçek bir sayıya dönüştüren bir ölçüm belirlemelisiniz. Cirq, Pauli operatörleri $ \ hat {X} $, $ \ hat {Y} $ ve $ \ hat {Z} $ kombinasyonlarını kullanarak ölçümleri belirtir. Örnek olarak, aşağıdaki kod, simüle ettiğiniz durum vektöründe $ \ hat {Z} _0 $ ve $ \ frac {1} {2} \ hat {Z} _0 + \ hat {X} _1 $ değerlerini ölçer:

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 Tensörler olarak kuantum devreleri

TensorFlow Quantum (TFQ), Cirq nesnelerini tensörlere dönüştüren bir işlev olan tfq.convert_to_tensor işlevini sağlar. Bu, Cirq nesnelerini kuantum katmanlarımıza vekuantum operasyonlarımıza göndermenizi sağlar. İşlev, Cirq Circuits ve Cirq Paulis listelerinde veya dizilerinde çağrılabilir:

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

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

Bu, Cirq nesnelerini, gerektiğinde tfq işlemlerinin kodunu çözen tf.string tensörleri olarak kodlar.

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

1.3 Dozajlama devresi simülasyonu

TFQ, beklenti değerlerini, örnekleri ve durum vektörlerini hesaplamak için yöntemler sağlar. Şimdilik beklenti değerlerine odaklanalım.

Beklenti değerlerini hesaplamak için en üst düzey arayüz, tfq.layers.Expectation olan tf.keras.Layer . En basit haliyle, bu katman birçok cirq.ParamResolvers üzerinde parametreleştirilmiş bir devreyi simüle cirq.ParamResolvers ; ancak TFQ, TensorFlow semantiğini izleyen gruplamaya izin verir ve devreler, verimli C ++ kodu kullanılarak simüle edilir.

a ve b parametrelerimizin yerini alacak bir grup değer oluşturun:

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

Cirq'deki parametre değerleri üzerinden gruplama devresi yürütme bir döngü gerektirir:

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.4557516 ]
 [ 0.19779062]
 [-0.52832156]
 [ 0.888587  ]
 [-0.20134428]]

Aynı işlem TFQ'da basitleştirilmiştir:

tfq.layers.Expectation()(circuit,
                         symbol_names=[a, b],
                         symbol_values=batch_vals,
                         operators=z0)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[-0.45575225],
       [ 0.19779024],
       [-0.5283203 ],
       [ 0.8885881 ],
       [-0.2013425 ]], dtype=float32)>

2. Hibrit kuantum-klasik optimizasyon

Artık temelleri gördüğünüze göre, hibrit bir kuantum-klasik sinir ağı oluşturmak için TensorFlow Quantum'u kullanalım. Tek bir kübiti kontrol etmek için klasik bir sinir ağı eğiteceksiniz. Kontrol, simüle edilmiş bir sistematik kalibrasyon hatasının üstesinden gelerek 0 veya 1 durumunda kübiti doğru bir şekilde hazırlamak için optimize edilecektir. Bu şekil mimariyi göstermektedir:

Bir sinir ağı olmasa bile, bu çözülmesi kolay bir problemdir, ancak tema TFQ kullanarak çözebileceğiniz gerçek kuantum kontrol problemlerine benzer. Bir tfq.layers.ControlledPQC içindeki tfq.layers.ControlledPQC (Parametreli Kuantum Devresi) katmanını kullanarak kuantum klasik hesaplamanın uçtan uca bir örneğini tf.keras.Model .

Bu öğreticinin uygulanması için, bu mimari 3 bölüme ayrılmıştır:

  • Giriş devresi veya veri noktası devresi : İlk üç $ R $ geçidi.
  • Kontrollü devre : Diğer üç $ R $ geçidi.
  • Kontrolör : Kontrol edilen devrenin parametrelerini ayarlayan klasik sinir ağı.

2.1 Kontrollü devre tanımı

Yukarıdaki şekilde gösterildiği gibi öğrenilebilir bir tek bit dönüşü tanımlayın. Bu, kontrollü devremize karşılık gelecektir.

# 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 Kontrolör

Şimdi denetleyici ağını tanımlayın:

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

Bir grup komut verildiğinde, kontrolör, kontrol edilen devre için bir grup kontrol sinyali verir.

Denetleyici rastgele başlatılır, bu nedenle bu çıktılar henüz kullanışlı değildir.

controller(tf.constant([[0.0],[1.0]])).numpy()
array([[0.        , 0.        , 0.        ],
       [0.54904324, 0.12798752, 0.48068655]], dtype=float32)

2.3 Kontrolörü devreye bağlayın

Denetleyiciyi kontrol edilen devreye tek bir keras.Model olarak bağlamak için tfq kullanın.

Bu model tanımlama stili hakkında daha fazla bilgi için Keras Functional API kılavuzuna bakın.

Önce modelin girdilerini tanımlayın:

# 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')

Ardından, hesaplamayı tanımlamak için işlemleri bu girişlere uygulayın.

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])

Şimdi bu hesaplamayı tf.keras.Model olarak tf.keras.Model :

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

Ağ mimarisi, aşağıdaki modelin grafiği ile belirtilmiştir. Doğruluğu doğrulamak için bu model planını mimari diyagramla karşılaştırın.

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

png

Bu model iki giriş alır: Denetleyici için komutlar ve denetleyicinin çıkışını düzeltmeye çalıştığı giriş devresi.

2.4 Veri kümesi

Model, her komut için $ \ hat {Z} $ 'ın doğru ölçüm değerini vermeyi dener. Komutlar ve doğru değerler aşağıda tanımlanmıştır.

# 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)

Bu, bu görev için tüm eğitim veri kümesi değildir. Veri kümesindeki her veri noktası ayrıca bir giriş devresine ihtiyaç duyar.

2.4 Giriş devresi tanımı

Aşağıdaki giriş devresi, modelin düzeltmeyi öğreneceği rastgele yanlış kalibrasyonu tanımlar.

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

Her veri noktası için bir tane olmak üzere devrenin iki kopyası vardır.

datapoint_circuits.shape
TensorShape([2])

2.5 Eğitim

Tanımlanan girdiler ile tfq modelini test edebilirsiniz.

model([datapoint_circuits, commands]).numpy()
array([[-0.11818343],
       [ 0.06576699]], dtype=float32)

Şimdi bu değerleri expected_outputs çıktılara göre ayarlamak için standart bir eğitim süreci çalıştırın.

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

Bu arsadan, sinir ağının sistematik yanlış kalibrasyonun üstesinden gelmeyi öğrendiğini görebilirsiniz.

2.6 Çıkışları doğrulayın

Şimdi, kübit kalibrasyon hatalarını düzeltmek için eğitimli modeli kullanın. Cirq ile:

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.1870269  2.520571   1.9310579]
Which gives an actual expectation of: 0.9146309494972229

For a desired output (expectation) of [-1.] with noisy preparation, the controller
network found the following values for theta: [2.4382339  0.06558019 1.4365435 ]
Which gives an actual expectation of: -0.9835573434829712

Eğitim sırasında kayıp fonksiyonunun değeri, modelin ne kadar iyi öğrendiğine dair kabaca bir fikir verir. Kayıp ne kadar desired_values , yukarıdaki hücredeki beklenti değerleri istenen değerlere o kadar yakın desired_values . Parametre değerleriyle o kadar ilgilenmiyorsanız, her zaman yukarıdan çıktıları tfq kullanarak kontrol edebilirsiniz:

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

3 Farklı operatörlerin özdurumlarını hazırlamayı öğrenmek

1 ve 0'a karşılık gelen $ \ pm \ hat {Z} $ eigenstates seçimi keyfi idi. 1'in $ + \ hat {Z} $ eigenstate'e ve 0'ın $ - \ hat {X} $ eigenstate'e karşılık gelmesini kolaylıkla isteyebilirdiniz. Bunu gerçekleştirmenin bir yolu, aşağıdaki şekilde gösterildiği gibi, her komut için farklı bir ölçüm operatörü belirlemektir:

Bu, tfq.layers.Expectation kullanılmasını gerektirir. Şimdi girdiniz üç nesneyi içerecek şekilde büyüdü: devre, komut ve operatör. Çıktı yine de beklenti değeridir.

3.1 Yeni model tanımı

Bu görevi gerçekleştirmek için modele bir göz atalım:

# 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')

İşte denetleyici ağı:

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

Devre ve denetleyiciyi tek bir keras.Model birleştirin. keras.Model kullanarak 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 Veri kümesi

Şimdi model_circuit için model_circuit her veri noktası için ölçmek istediğiniz operatörleri de dahil 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 Eğitim

Artık yeni giriş ve çıkışlarınıza sahip olduğunuza göre, keras'ı kullanarak bir kez daha eğitebilirsiniz.

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 970us/step - loss: 2.5384
Epoch 2/30
1/1 [==============================] - 0s 728us/step - loss: 1.6466
Epoch 3/30
1/1 [==============================] - 0s 710us/step - loss: 1.1451
Epoch 4/30
1/1 [==============================] - 0s 672us/step - loss: 0.8246
Epoch 5/30
1/1 [==============================] - 0s 677us/step - loss: 0.5611
Epoch 6/30
1/1 [==============================] - 0s 619us/step - loss: 0.3559
Epoch 7/30
1/1 [==============================] - 0s 571us/step - loss: 0.2129
Epoch 8/30
1/1 [==============================] - 0s 600us/step - loss: 0.1164
Epoch 9/30
1/1 [==============================] - 0s 601us/step - loss: 0.0545
Epoch 10/30
1/1 [==============================] - 0s 614us/step - loss: 0.0224
Epoch 11/30
1/1 [==============================] - 0s 624us/step - loss: 0.0103
Epoch 12/30
1/1 [==============================] - 0s 595us/step - loss: 0.0079
Epoch 13/30
1/1 [==============================] - 0s 572us/step - loss: 0.0107
Epoch 14/30
1/1 [==============================] - 0s 593us/step - loss: 0.0192
Epoch 15/30
1/1 [==============================] - 0s 588us/step - loss: 0.0345
Epoch 16/30
1/1 [==============================] - 0s 618us/step - loss: 0.0544
Epoch 17/30
1/1 [==============================] - 0s 638us/step - loss: 0.0730
Epoch 18/30
1/1 [==============================] - 0s 622us/step - loss: 0.0843
Epoch 19/30
1/1 [==============================] - 0s 602us/step - loss: 0.0820
Epoch 20/30
1/1 [==============================] - 0s 600us/step - loss: 0.0663
Epoch 21/30
1/1 [==============================] - 0s 610us/step - loss: 0.0458
Epoch 22/30
1/1 [==============================] - 0s 621us/step - loss: 0.0281
Epoch 23/30
1/1 [==============================] - 0s 610us/step - loss: 0.0153
Epoch 24/30
1/1 [==============================] - 0s 622us/step - loss: 0.0074
Epoch 25/30
1/1 [==============================] - 0s 628us/step - loss: 0.0031
Epoch 26/30
1/1 [==============================] - 0s 656us/step - loss: 0.0011
Epoch 27/30
1/1 [==============================] - 0s 663us/step - loss: 2.9912e-04
Epoch 28/30
1/1 [==============================] - 0s 627us/step - loss: 6.1668e-05
Epoch 29/30
1/1 [==============================] - 0s 588us/step - loss: 1.3870e-05
Epoch 30/30
1/1 [==============================] - 0s 663us/step - loss: 1.4859e-05
plt.plot(history.history['loss'])
plt.title("Learning to Control a Qubit")
plt.xlabel("Iterations")
plt.ylabel("Error in Control")
plt.show()

png

Kayıp işlevi sıfıra düştü.

controller bağımsız bir model olarak mevcuttur. Denetleyiciyi arayın ve her komut sinyaline verdiği yanıtı kontrol edin. Bu çıktıları random_rotations içeriğiyle doğru bir şekilde karşılaştırmak biraz çalışma random_rotations .

controller.predict(np.array([0,1]))
array([[-2.4193525 , -0.11989626, -0.5875844 ],
       [-2.5004668 , -1.613323  , -3.0799127 ]], dtype=float32)