Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/quantum/tutorials/noise.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.

Ruido

El ruido está presente en las computadoras cuánticas modernas de hoy en día. Los bits cuánticos son sensibles a las interferencias que produzca el entorno, la fabricación imperfecta, la TLS y, a veces, incluso los rayos gamma. Hasta que se logre la corrección de errores a gran escala, los algoritmos deberán poder seguir siendo funcionales aún con ruido. Es el motivo por el que las pruebas con algoritmos con ruido resultan muy importantes para validar que los modelos o algoritmos cuánticos funcionan con las computadoras cuánticas actuales.

En este tutorial exploraremos los conceptos básicos de la simulación de circuitos con ruido en TFQ con la API tfq.layers de alto nivel.

Preparación

!pip install tensorflow==2.7.0 tensorflow-quantum==0.7.2
!pip install -q git+https://github.com/tensorflow/docs
# Update package resources to account for version changes. import importlib, pkg_resources importlib.reload(pkg_resources)
import random import cirq import sympy import tensorflow_quantum as tfq import tensorflow as tf import numpy as np # Plotting import matplotlib.pyplot as plt import tensorflow_docs as tfdocs import tensorflow_docs.plots

1. Comprensión del ruido cuántico

1.1 Ruido de circuito básico

El ruido de las computadoras cuánticas impacta en las muestras de strings de bits a partir de las que se pueden hacer las mediciones. Una forma intuitiva de empezar a pensarlo es entendiendo que una computadora cuántica ruidosa "insertará", "eliminará" o "reemplazará" las puertas en lugares aleatorios, como en el diagrama que se encuentra a continuación:

Si partimos de esta intuición, cuando trabajamos con el ruido, ya no usamos un ψ|\psi \rangle de estado puro solo, sino un ensamble de todas las implementaciones ruidosas posibles del circuito deseado: ρ=jpjψjψj\rho = \sum_j p_j |\psi_j \rangle \langle \psi_j | . Donde pjp_j arroja la probabilidad de que el sistema esté en ψj|\psi_j \rangle .

Volviendo a la imagen anterior, si supiéramos de antemano que el 90% del tiempo nuestro sistema se ejecuta a la perfección o que produce errores el 10% del tiempo, solamente con este único modo de fallo, nuestro ensamble sería el siguiente:

ρ=0.9ψdesiredψdesired+0.1ψnoisyψnoisy\rho = 0.9 |\psi_\text{desired} \rangle \langle \psi_\text{desired}| + 0.1 |\psi_\text{noisy} \rangle \langle \psi_\text{noisy}|

Si hubiera más de una sola manera en que nuestro circuito produjera errores, entonces, el ensamble ρ\rho contendría más de dos términos solos (uno para cada una de las ocurrencias ruidosas nuevas que pudieran surgir). ρ\rho se conoce como la matriz de densidad que describe el sistema ruidoso.

1.2 Uso de los canales para modelar el ruido del circuito

Lamentablemente, en la práctica resulta casi imposible conocer todas las maneras en que el circuito puede producir errores ni cuáles son las probabilidades exactas de que esto suceda. Un supuesto simplista que se puede hacer es pensar que después de cada operación en el circuito hay algún tipo de canal que captura a grandes rasgos cómo se podría dar el error en esa operación. Podemos crear rápidamente un circuito con algo de ruido:

def x_circuit(qubits): """Produces an X wall circuit on `qubits`.""" return cirq.Circuit(cirq.X.on_each(*qubits)) def make_noisy(circuit, p): """Add a depolarization channel to all qubits in `circuit` before measurement.""" return circuit + cirq.Circuit(cirq.depolarize(p).on_each(*circuit.all_qubits())) my_qubits = cirq.GridQubit.rect(1, 2) my_circuit = x_circuit(my_qubits) my_noisy_circuit = make_noisy(my_circuit, 0.5) my_circuit
my_noisy_circuit

Podemos examinar la matriz de densidad ρ\rho sin ruido con:

rho = cirq.final_density_matrix(my_circuit) np.round(rho, 3)

Y la matriz de densidad ρ\rho con ruido con:

rho = cirq.final_density_matrix(my_noisy_circuit) np.round(rho, 3)

Si comparamos las dos ρ \rho podemos ver que el ruido ha impactado las amplitudes del estado (y por consiguiente en las probabilidades de muestreo). En los casos sin ruido siempre se puede esperar tomar muestras del estado 11 |11\rangle . Pero en el estado con ruido ahora hay una probabilidad diferente de cero de muestrear 00 |00\rangle , 01 |01\rangle o 10 |10\rangle también:

"""Sample from my_noisy_circuit.""" def plot_samples(circuit): samples = cirq.sample(circuit + cirq.measure(*circuit.all_qubits(), key='bits'), repetitions=1000) freqs, _ = np.histogram(samples.data['bits'], bins=[i+0.01 for i in range(-1,2** len(my_qubits))]) plt.figure(figsize=(10,5)) plt.title('Noisy Circuit Sampling') plt.xlabel('Bitstring') plt.ylabel('Frequency') plt.bar([i for i in range(2** len(my_qubits))], freqs, tick_label=['00','01','10','11']) plot_samples(my_noisy_circuit)

Si ningún ruido siempre obtendremos 11|11\rangle:

"""Sample from my_circuit.""" plot_samples(my_circuit)

Si aumentamos el ruido un poco más será cada vez más difícil distinguir el comportamiento deseado (tomando una muestra 11|11\rangle ) del ruido:

my_really_noisy_circuit = make_noisy(my_circuit, 0.75) plot_samples(my_really_noisy_circuit)

Nota: Intente experimentar con canales diferentes del circuito para generar ruido. Los canales comunes compatibles con Cirq y TFQ se pueden encontrar aquí.

2. Ruido básico en TFQ

Ahora que ya sabemos qué impacto tiene el ruido en la ejecución del circuito, podemos explorar cómo funciona el ruido en TFQ. TensorFlow Quantum usa la simulación basada en trayectoria/monte-carlo como alternativa a la simulación de la matriz de densidad. El motivo es que la complejidad de la memoria de la simulación de la matriz de densidad limita las simulaciones grandes hasta <= 20 bits cuánticos con métodos de simulación de matriz de densidad completos tradicionales. Monte-carlo / trayectoria cambian este costo en la memoria por otro costo adicional en el tiempo. La opción backend='noisy' está disponible para todas las tfq.layers.Sample, tfq.layers.SampledExpectation y tfq.layers.Expectation (En caso de Expectation sí agrega el parámetro de repetitions requerido).

2.1 Muestreo ruidoso en TFQ

Para crear los gráficos anteriores con TFQ y la simulación de trayectoria, podemos usar tfq.layers.Sample

"""Draw bitstring samples from `my_noisy_circuit`""" bitstrings = tfq.layers.Sample(backend='noisy')(my_noisy_circuit, repetitions=1000)
numeric_values = np.einsum('ijk,k->ij', bitstrings.to_tensor().numpy(), [1, 2])[0] freqs, _ = np.histogram(numeric_values, bins=[i+0.01 for i in range(-1,2** len(my_qubits))]) plt.figure(figsize=(10,5)) plt.title('Noisy Circuit Sampling') plt.xlabel('Bitstring') plt.ylabel('Frequency') plt.bar([i for i in range(2** len(my_qubits))], freqs, tick_label=['00','01','10','11'])

2.2 Muestra ruidosa basada en esperanzas

Para hacer una muestra ruidosa basada en un cálculo de esperanzas, podemos usar tfq.layers.SampleExpectation:

some_observables = [cirq.X(my_qubits[0]), cirq.Z(my_qubits[0]), 3.0 * cirq.Y(my_qubits[1]) + 1] some_observables

Calculamos la estimación de la esperanza sin ruido con un muestreo del circuito:

noiseless_sampled_expectation = tfq.layers.SampledExpectation(backend='noiseless')( my_circuit, operators=some_observables, repetitions=10000 ) noiseless_sampled_expectation.numpy()

Comparémoslas con versiones ruidosas:

noisy_sampled_expectation = tfq.layers.SampledExpectation(backend='noisy')( [my_noisy_circuit, my_really_noisy_circuit], operators=some_observables, repetitions=10000 ) noisy_sampled_expectation.numpy()

Podemos observar que las ruidosas han impactado particularmente en la exactitud de ψZψ\langle \psi | Z | \psi \rangle, con my_really_noisy_circuit que se concentra rápidamente hacia 0.

2.3 Cálculo de esperanza analítica ruidosa

El cálculo de la esperanza analítica ruidosa es prácticamente idéntico al anterior:

noiseless_analytic_expectation = tfq.layers.Expectation(backend='noiseless')( my_circuit, operators=some_observables ) noiseless_analytic_expectation.numpy()
noisy_analytic_expectation = tfq.layers.Expectation(backend='noisy')( [my_noisy_circuit, my_really_noisy_circuit], operators=some_observables, repetitions=10000 ) noisy_analytic_expectation.numpy()

3. Modelos híbridos y ruido de datos cuánticos

Ahora que ya hemos implementado algunas simulaciones de circuitos ruidosos en TFQ, podemos experimentar con la manera en que impacta el ruido en los modelos cuánticos y en los híbridos. Con este fin, comparamos y contrastamos los desempeños con y sin ruido. Una buena forma de comprobar, en primera instancia, si un modelo o algoritmo es lo suficientemente robusto cuando hay ruido es haciendo pruebas con un modelo despolarizador del ancho de un circuito, que tendría el siguiente aspecto:

Donde cada intervalo de tiempo del circuito (a veces denominado momento) tiene un canal despolarizador anexo después de cada operación en la puerta, en ese intervalo de tiempo. El canal de despolarización aplicará de uno de los siguientes {X,Y,Z}\{X, Y, Z \}, con probabilidad pp o sin aplicar nada (se mantiene la operación original) con probabilidad 1p1-p.

3.1 Los datos

Para este ejemplo podemos usar algunos circuitos preparados en el módulo tfq.datasets como datos de entrenamiento:

qubits = cirq.GridQubit.rect(1, 8) circuits, labels, pauli_sums, _ = tfq.datasets.xxz_chain(qubits, 'closed') circuits[0]

Escribir una función ayudante nos ayudará a generar los datos para los casos en los que se compara con y sin ruido:

def get_data(qubits, depolarize_p=0.): """Return quantum data circuits and labels in `tf.Tensor` form.""" circuits, labels, pauli_sums, _ = tfq.datasets.xxz_chain(qubits, 'closed') if depolarize_p >= 1e-5: circuits = [circuit.with_noise(cirq.depolarize(depolarize_p)) for circuit in circuits] tmp = list(zip(circuits, labels)) random.shuffle(tmp) circuits_tensor = tfq.convert_to_tensor([x[0] for x in tmp]) labels_tensor = tf.convert_to_tensor([x[1] for x in tmp]) return circuits_tensor, labels_tensor

3.2 Definición de un circuito modelo

Una vez que tenemos los datos cuánticos en forma de circuitos, necesitaremos otro circuito para modelar estos datos, como con aquellos datos con los que se puede escribir una función ayudante para generar este circuito que, opcionalmente, puede contener ruido:

def modelling_circuit(qubits, depth, depolarize_p=0.): """A simple classifier circuit.""" dim = len(qubits) ret = cirq.Circuit(cirq.H.on_each(*qubits)) for i in range(depth): # Entangle layer. ret += cirq.Circuit(cirq.CX(q1, q2) for (q1, q2) in zip(qubits[::2], qubits[1::2])) ret += cirq.Circuit(cirq.CX(q1, q2) for (q1, q2) in zip(qubits[1::2], qubits[2::2])) # Learnable rotation layer. # i_params = sympy.symbols(f'layer-{i}-0:{dim}') param = sympy.Symbol(f'layer-{i}') single_qb = cirq.X if i % 2 == 1: single_qb = cirq.Y ret += cirq.Circuit(single_qb(q) ** param for q in qubits) if depolarize_p >= 1e-5: ret = ret.with_noise(cirq.depolarize(depolarize_p)) return ret, [op(q) for q in qubits for op in [cirq.X, cirq.Y, cirq.Z]] modelling_circuit(qubits, 3)[0]

3.3 Construcción y entrenamiento del modelo

Con los datos y el circuito del modelo creado, la función ayudante final que falta es la que pueda ensamblar un tf.keras.Model cuántico híbrido con o sin ruido:

def build_keras_model(qubits, depolarize_p=0.): """Prepare a noisy hybrid quantum classical Keras model.""" spin_input = tf.keras.Input(shape=(), dtype=tf.dtypes.string) circuit_and_readout = modelling_circuit(qubits, 4, depolarize_p) if depolarize_p >= 1e-5: quantum_model = tfq.layers.NoisyPQC(*circuit_and_readout, sample_based=False, repetitions=10)(spin_input) else: quantum_model = tfq.layers.PQC(*circuit_and_readout)(spin_input) intermediate = tf.keras.layers.Dense(4, activation='sigmoid')(quantum_model) post_process = tf.keras.layers.Dense(1)(intermediate) return tf.keras.Model(inputs=[spin_input], outputs=[post_process])

4. Comparación del desempeño

4.1 Línea de base sin ruido

Con el código para la construcción del modelo y la generación de datos, ahora podemos comparar y contrastar el desempeño del modelo en entornos con y sin ruido. Primero, podemos ejecutar un entrenamiento de referencia sin ruido:

training_histories = dict() depolarize_p = 0. n_epochs = 50 phase_classifier = build_keras_model(qubits, depolarize_p) phase_classifier.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.02), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=['accuracy']) # Show the keras plot of the model tf.keras.utils.plot_model(phase_classifier, show_shapes=True, dpi=70)
noiseless_data, noiseless_labels = get_data(qubits, depolarize_p) training_histories['noiseless'] = phase_classifier.fit(x=noiseless_data, y=noiseless_labels, batch_size=16, epochs=n_epochs, validation_split=0.15, verbose=1)

Y explorar los resultados y la exactitud:

loss_plotter = tfdocs.plots.HistoryPlotter(metric = 'loss', smoothing_std=10) loss_plotter.plot(training_histories)
acc_plotter = tfdocs.plots.HistoryPlotter(metric = 'accuracy', smoothing_std=10) acc_plotter.plot(training_histories)

4.2 Comparación con ruido

Ahora podemos crear un modelo nuevo con una estructura ruidosa y compararlo con el que figura arriba. El código es casi idéntico:

depolarize_p = 0.001 n_epochs = 50 noisy_phase_classifier = build_keras_model(qubits, depolarize_p) noisy_phase_classifier.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.02), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=['accuracy']) # Show the keras plot of the model tf.keras.utils.plot_model(noisy_phase_classifier, show_shapes=True, dpi=70)

Nota: En el diagrama del modelo ahora hay un tfq.layers.NoisyPQC en vez de un tfq.layers.PQC, dado que la probabilidad de despolarización ya no es cero. El entrenamiento será más prolongado, ya que la simulación ruidosa tiene un costo mucho mayor que la que no tiene ruido.

noisy_data, noisy_labels = get_data(qubits, depolarize_p) training_histories['noisy'] = noisy_phase_classifier.fit(x=noisy_data, y=noisy_labels, batch_size=16, epochs=n_epochs, validation_split=0.15, verbose=1)
loss_plotter.plot(training_histories)
acc_plotter.plot(training_histories)

Excelente: el modelo ruidoso todavía puede entrenarse con algo de ruido de una despolarización leve. Intente experimentar con diferentes modelos con ruido para ver cómo y cuándo el entrenamiento podría fallar. También observe funcionalidades ruidosas para con tfq.layers y tfq.noise.