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

Ruído

O ruído está presente em computadores quânticos modernos. Qubits são suscetíveis à interferência do ambiente ao redor, fabricação imperfeita, TLS e, às vezes, até raios gama. Para obter a correção de erros em grande escala, os algoritmos atuais precisam manter a funcionalidade na presença de ruído. Por isso, testar algoritmos com ruído é um passo importante para validar o funcionamento de algoritmos / modelos quânticos nos computadores quânticos da atualidade.

Neste tutorial, você explorará as noções básicas da simulação de circuito ruidoso no TFQ pela API tfq.layers de alto nível.

Configuração

!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. Sobre o ruído quântico

1.1 Ruído de circuito básico

O ruído em um computador quântico afeta as amostras de bitstring que você consegue medir nele. De maneira intuitiva, você pode considerar que um computador quântico ruidoso "insere", "exclui" ou "substitui" portas em locais aleatórios, como o diagrama abaixo:

Com base nessa intuição, ao lidar com ruído, você não está mais usando um ψ|\psi \rangle de estado puro único, e sim um conjunto de todas as realizações ruidosas possíveis do seu circuito desejado: ρ=jpjψjψj\rho = \sum_j p_j |\psi_j \rangle \langle \psi_j |, em que pjp_j fornece a probabilidade de o sistema estar em ψj|\psi_j \rangle .

Revendo a foto acima, se soubéssemos antes que a execução do sistema era perfeita em 90% do tempo ou apresentava erros em 10% do tempo com apenas esse modo de falha, nosso conjunto seria:

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

Se houvesse mais de uma forma para o circuito falhar, então o conjunto ρ\rho conteria mais do que apenas dois termos (um para cada nova realização ruidosa que poderia ocorrer). ρ\rho é chamado de matriz densidade, que descreve seu sistema ruidoso.

1.2 Uso de canais para modelar o ruído do circuito

Infelizmente, na prática, é praticamente impossível saber todas as maneiras que o circuito pode falhar e suas probabilidades exatas. Para simplificar, você pode supor que, após cada operação no circuito, há algum tipo de canal que captura mais ou menos como essa operação pode falhar. Você pode criar rapidamente um circuito com um pouco de ruído:

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

Você pode examinar a matriz densidade sem ruído ρ\rho com:

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

E a matriz densidade ruidosa ρ\rho com:

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

Ao comparar os dois ρ \rho s diferentes, você pode ver que o ruído afetou as amplitudes do estado (e, consequentemente, as probabilidades da amostragem). No caso sem ruído, é sempre esperada a amostragem do estado 11 |11\rangle . No entanto, no estado ruidoso, há agora uma probabilidade diferente de zero para a amostragem de 00 |00\rangle ou 01 |01\rangle ou 10 |10\rangle também:

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

Sem nenhum ruído, você sempre obterá 11|11\rangle:

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

Ao aumentar o ruído um pouco mais, ficará cada vez mais difícil distinguir o comportamento desejado (fazendo a amostragem de 11|11\rangle) e o ruído:

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

Observação: teste canais diferentes no circuito para gerar ruído. Encontre canais comuns compatíveis com ambos o Cirq e o TFQ aqui.

2. Ruído básico no TFQ

Com essa compreensão de como o ruído pode afetar a execução do circuito, você pode explorar como o ruído funciona no TFQ. O TensorFlow Quantum usa a simulação baseada em monte-carlo / trajetória como alternativa à simulação de matriz densidade. Isso ocorre porque a complexidade de memória da simulação de matriz densidade limita grandes simulações a <= 20 qubits com métodos tradicionais de simulação de matriz densidade total. O monte-carlo / trajetória troca esse custo da memória pelo custo adicional de tempo. A opção backend='noisy' está disponível para todas as tfq.layers.Sample, tfq.layers.SampledExpectation e tfq.layers.Expectation (no caso de Expectation, é necessário um parâmetro repetitions).

2.1 Amostragem de ruído no TFQ

Para recriar as plotagens acima usando o TFQ e a simulação de trajetória, é possível 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 Expectativa baseada em amostra de ruído

Para calcular a expectativa baseada em amostra de ruído, é possível 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

Compute as estimativas da expectativa sem ruído com a amostragem do circuito:

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

Compare isso às versões 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()

É possível ver que o ruído afetou especialmente a exatidão de ψZψ\langle \psi | Z | \psi \rangle, com a concentração rápida de my_really_noisy_circuit em direção a 0.

2.3 Cálculo da expectativa analítica ruidosa

Os cálculos da expectativa analítica ruidosa são praticamente idênticos ao acima:

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. Ruído de dados quânticos e modelos híbridos

Agora que você implementou algumas simulações de circuitos ruidosos no TFQ, pode testar como os modelos clássicos-quânticos híbridos e quânticos são afetados pelo ruído, comparando e contrastando o desempenho com e sem ruído. Uma verificação inicial para ver se um modelo ou algoritmo é robusto ao ruído é testar com um modelo despolarizador em todo o circuito, que é algo assim:

Em que cada fatia de tempo do circuito (às vezes chamada de "momento") tem um canal despolarizador anexado após cada operação de porta dela. O canal despolarizador aplicará um dos {X,Y,Z}\{X, Y, Z \} com a probabilidade pp ou não aplicará nada (manterá a operação original) com a probabilidade 1p1-p.

3.1 Dados

Para este exemplo, você pode usar alguns circuitos preparados no módulo tfq.datasets como dados de treinamento:

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

Escrever uma pequena função helper ajudará a gerar os dados para o caso ruidoso x sem ruído:

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 Defina um circuito do modelo

Agora que você tem os dados quânticos em formato de circuitos, precisará de um circuito para modelar esses dados, assim como é possível escrever uma função helper com os dados para gerar esse circuito opcionalmente com ruído:

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 Criação e treinamento do modelo

Depois de criar os dados e o circuito do modelo, a função helper final necessária é uma que formará um tf.keras.Model quântico híbrido com e sem ruído:

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. Compare o desempenho

4.1 Referência sem ruído

Com o código de criação do modelo e geração de dados, você agora pode comparar e contrastar o desempenho do modelo nos cenários com e sem ruído. Primeiro, é possível realizar um treinamento sem ruído de referência:

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)

Explore os resultados e a exatidão:

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 Comparação ruidosa

Agora, você pode criar um novo modelo com a estrutura ruidosa e compará-lo ao acima. O código é praticamente igual:

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)

Observação: no diagrama do modelo, agora há uma tfq.layers.NoisyPQC em vez de tfq.layers.PQC, porque a probabilidade de despolarização não é mais zero. O treinamento levará muito mais tempo, já que a simulação ruidosa é muito mais cara do que a sem ruído.

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)

Sucesso: ainda foi possível treinar o modelo ruidoso com um leve ruído de despolarização. Experimente diferentes modelos de ruído para ver como e quando o treinamento falhará. Também fique atento à funcionalidade ruidosa em tfq.layers e tfq.noise.