Estimateur côté client
qiskit_ibm_runtime.executor_estimator
Présentation
qiskit_ibm_runtime.executor_estimator.Estimator Il s'agit d'une implémentation de l'interface EstimatorV2 Qiskit reposant sur la primitive Executor . Il estime les valeurs attendues des observables quantiques en exécutant des circuits ISA sur un backend « IBM Quantum ».
La principale différence entre l'ancienne implémentation côté serveur et Estimator cette nouvelle implémentation réside dans le fait que l'ensemble du prétraitement et du post-traitement s'effectue sur la machine cliente. Cela comprend la préparation des circuits (twirling, repliement de porte, découplage dynamique et injection de bruit) ainsi que le post-traitement des résultats (redimensionnement TREX, extrapolation ZNE et pondération par quasi-probabilité PEC). L'exécution de ces étapes en local permet d'obtenir des retours plus rapides lors du débogage et offre à l'utilisateur un meilleur contrôle.
Lorsqu'un utilisateur soumet une tâche via run(), le traitement sous-jacent se déroule comme suit :
- Forcer les blocs unifiés primitifs (PUB), définir les valeurs par défaut du niveau de résilience et déterminer le nombre de tirs.
- Conversion des PUB en
QuantumProgram, en appliquant des transformations de circuit (twirling, gate folding, DD, injection de bruit) selon les options spécifiées. - Appel de la fonction permettant de
Executorsoumettre le programme quantique au backend. - Une fois le travail terminé, estimer les valeurs attendues à partir des données brutes de mesure et appliquer, si nécessaire, un post-traitement visant à atténuer les erreurs.
Pour les charges de travail volumineuses ou complexes, les étapes de pré-traitement et de post-traitement côté client peuvent mobiliser d'importantes ressources et entraîner un délai avant que la tâche ne soit soumise. Configurez le module de journalisation qiskit_ibm_runtime INFO pour surveiller le traitement côté client :
import logging
logger = logging.getLogger("qiskit_ibm_runtime")
logger.setLevel(logging.INFO)Utilisation de base
Exemple 1 — Configuration minimale (sans atténuation des erreurs)
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.executor_estimator import Estimator
# Select a backend.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
observable = SparsePauliOp("ZZ")
# Transform the circuit and observable into ISA format.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
isa_obs = observable.apply_layout(isa_qc.layout)
estimator = Estimator(mode=backend)
estimator.options.resilience_level = 0
job = estimator.run([(isa_qc, isa_obs)])
result = job.result()
print(result[0].data.evs) # expectation valueExemple 2 — Niveau de résilience 2 (atténuation des erreurs de mesure + ZNE par repliement de porte)
estimator = Estimator(mode=backend)
estimator.options.resilience_level = 2 # TREX + ZNE (gate folding)
job = estimator.run([(isa_qc, isa_obs)])
result = job.result()
print(result[0].data.evs) # zero-noise extrapolated expectation value
print(result[0].data.evs_noise_factors) # raw values at each noise amplification levelExemple 3 — PEC (nécessite un apprentissage explicite du bruit)
Contrairement à l'implémentation côté serveur existante, cette implémentation côté client nécessite Estimator un apprentissage explicite du bruit pour les méthodes d'atténuation des erreurs qui requièrent un modèle de bruit (PEC et PEA).
Utilisez find_unique_layers() pour extraire les couches de grille uniques de vos fichiers PUB, transmettez ces couches à NoiseLearnerV3 afin d'apprendre leur bruit dans une tâche distincte, puis attribuez les cartes de bruit apprises à layer_noise_model.
from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3
pubs = [(isa_qc, isa_obs)]
estimator = Estimator(mode=backend)
estimator.options.resilience.pec_mitigation = True
# Step 1. Extract the unique boxed gate layers from your PUBs.
layers = estimator.find_unique_layers(pubs)
# Step 2. Learn the noise model for those layers.
nl_result = NoiseLearnerV3(mode=backend).run(layers).result()
# Step 3. Convert the NoiseLearnerV3 result to Pauli-Lindblad maps and pass them
# to the Estimator. The maps follow the same order as the input layers, so they can
# be zipped positionally.
pauli_lindblad_maps = nl_result.to_pauli_lindblad_maps()
estimator.options.resilience.layer_noise_model = zip(layers, pauli_lindblad_maps)
job = estimator.run(pubs)
result = job.result()
print(result[0].data.evs)Entrées
Chaque appel à run() prend en paramètre une liste de PUB. Chaque « PUB » se présente sous le format suivant :
(<single circuit>, <one or more observables>, <optional parameter values>, <optional precision>)Pour plus d'informations sur les données d'entrée et de sortie de l'estimateur, consultez la section « Données d'entrée et de sortie de l'estimateur ».
Les éléments issus des observables et des valeurs de paramètres sont combinés selon les règles de diffusion d' NumPy, telles que décrites dans la section « Entrées et sorties primitives ».
Options
Lors de l'instanciation de Estimator, vous pouvez passer des options à l'aide de EstimatorOptions ou d'un dictionnaire. Les options couramment utilisées, telles que resilience_level, se trouvent au premier niveau. Les autres options sont regroupées par catégories, telles que execution. Indiquez les options selon ce format : options.<category>.<option> = <value>. Par exemple : options.dynamical_decoupling.enable = True.
Consultez la section « Introduction aux options » pour obtenir un aperçu de la manière de définir les options primitives. Pour plus d'informations sur les options d'Estimator, consultez les sections « Spécifier les options d'Estimator » et « Configurer la gestion du bruit avec Estimator ».
Sorties
run() renvoie un RuntimeJobV2. La fonction call renvoie job.result() un ensemble PrimitiveResult d'objets EstimatorPubResult — un par PUB d'entrée :
result = job.result()
pub_result = result[0] # EstimatorPubResult for the first PUB
pub_result.data # DataBin holding numerical arrays
pub_result.metadata # dictionary with per-PUB metadata
result.metadata # dictionary with job-level metadataLe contenu de dépend pub_result.data de la technique d'atténuation spécifiée.
Aucune mesure d'atténuation / mesures d'atténuation uniquement (niveaux de résilience 0 et 1)
Tous les champs suivants ont la forme pub_shape, qui est broadcast(param_shape, obs_shape).
data.evs— Valeurs attendues.data.stds— Écarts-types. Reflète la dispersion entre les randomisations de « twirling » lorsque cette fonction est activée; vautensemble_standard_errorlorsque le « twirling » est désactivé.data.ensemble_standard_error— Erreur-type dans l'hypothèse d'un bruit de tir à distribution indépendante et identique (sans contribution de dérive).
Lorsque le système de correction des mesures (TREX) est activé, les valeurs evs sont corrigées des erreurs de lecture à l'aide d'un circuit d'étalonnage qui fonctionne automatiquement en parallèle avec les circuits principaux.
PEC
La PEC génère les trois mêmes champs que le scénario sans mesures d'atténuation : evs, stds, et ensemble_standard_error. Le facteur de quasi-probabilité gamma est appliqué en interne lors du post-traitement et n'apparaît pas comme un champ de sortie distinct.
Les valeurs stds sont multipliées par le facteur gamma; elles sont donc généralement plus élevées que dans le cas où aucune mesure d'atténuation n'est appliquée, pour un même nombre de prises. C'est là le coût fondamental de la méthode PEC : les estimations non biaisées s'accompagnent d'une variance accrue proportionnelle à la charge d'échantillonnage (gamma^2).
ZNE (pliage en accordéon) et PEA
Lorsque resilience.zne_mitigation=True, l'estimateur fait fonctionner le circuit à plusieurs niveaux d'amplification du bruit et ajuste une courbe afin d'extrapoler jusqu'à un niveau de bruit nul. Le résultat contient à la fois l'estimation extrapolée et les données brutes pour chaque niveau de bruit.
data.evs— Valeurs attendues extrapolées sans bruit (meilleur ajustement hétérogène — l'extrapolateur est choisi terme par terme pour les observables à plusieurs termes). Forme :pub_shape.data.stds— Écarts-types des valeurs extrapolées. De même forme queevs. Dérivé de la dispersion observée lors des randomisations par « twirling » lorsque cette fonction est activée.data.evs_noise_factors— Valeurs attendues brutes (non extrapolées) à chaque niveau d'amplification du bruit. Forme :(*pub_shape, num_noise_factors).data.stds_noise_factors— Écarts-types pour chaque facteur de bruit. De même forme queevs_noise_factors. Reflète la dispersion liée aux randomisations de « twirling » lorsque cette fonction est activée; est égal àensemble_stds_noise_factorslorsqu'elle est désactivée.data.ensemble_stds_noise_factors— Erreurs-types d’ensemble pour chaque facteur de bruit, dans l’hypothèse d’un bruit de shot indépendamment et identiquement distribué. Forme :(*pub_shape, num_noise_factors).data.evs_extrapolated— Valeurs attendues fournies par chaque extrapolateur sollicité, évaluées en chaque point deresilience.zne.extrapolated_noise_factors. Il s'agit d'ajustements homogènes forcés : le même extrapolateur est appliqué à tous les termes d'une observable à termes multiples, à raison d'un ajustement par extrapolateur. Forme :(*pub_shape, num_extrapolators, num_eval_points).data.stds_extrapolated— Écarts-types correspondant àevs_extrapolated. Même forme.
Pour les observables à termes multiples (par exemple, {"XX": 0.5, "XY": 0.5}), evs et stds utilisent un ajustement hétérogène : l'extrapolateur le mieux adapté est sélectionné indépendamment pour chaque terme de Pauli. evs_extrapolated et utiliser stds_extrapolated un ajustement homogène par extrapolateur, ce qui est utile pour comparer les modèles. Si votre analyse nécessite l'application cohérente d'un seul extrapolateur, divisez l'observable à plusieurs termes en observables à un seul terme, de sorte que chaque terme soit ajusté séparément.
Les résultats de ZNE peuvent être visualisés à l'aide de et draw_zne_evs() draw_zne_extrapolators() (nécessite plotly).
Métadonnées au niveau de l'emploi
result.metadata est un contenant dict :
"options"— la version définitiveEstimatorOptions, sous forme de dictionnaire. Les sous-options de résilience inactives sont supprimées (par exemple, le sous-dictionnairezneest omis lorsquezne_mitigation=False), et le modèle de bruit (s'il est fourni) est supprimé."target_precision"— la précision déterminée à partir des PUB et de l'argumentprecisionderun(), ouNonesi aucun des deux n'est spécifié. Dans ce cas, le nombre de tirs provient dedefault_shots, et on revient alors àdefault_precision."shots"— le nombre total de tirs utilisés pour l'exécution."executor"— les métadonnées du résultat de l'Executor sous-jacent.
Guide de migration
Cette implémentation de l'Estimator côté client remplace en grande partie l'ancienne version sans aucune modification. Suivez les étapes décrites ci-dessous pour effectuer la migration vers la nouvelle implémentation, en tenant compte des changements de comportement suivants :
- Le prétraitement et le post-traitement s'effectuent côté client. Dans l'Estimator traditionnel, toutes les transformations de circuit (twirling, gate folding et injection de bruit), ainsi que le post-traitement des résultats (extrapolation ZNE, redimensionnement TREX et pondération PEC), sont effectués côté serveur. Dans cette implémentation côté client, ces étapes s'exécutent entièrement sur l'ordinateur client.
- L'apprentissage du bruit constitue une étape distincte. Dans l'Estimator traditionnel, l'apprentissage du bruit pour PEC et PEA est intégré au processus Estimator lui-même et géré implicitement côté serveur. Dans cette nouvelle implémentation, l'apprentissage du bruit constitue un flux de travail distinct qui doit être exécuté de manière explicite.
- Les tâches de l'exécuteur ont été soumises. L'Estimator côté client utilise Executor pour soumettre des tâches, ce qui en fait des tâches Executor plutôt que des tâches Estimator. Les attributs de tâche, tels que et
primitive_idinputs, fournissent des informations sur la tâche Executor.
Étape 1 — Mettre à jour les importations.
Avant :
from qiskit_ibm_runtime import Estimator
from qiskit_ibm_runtime.options import EstimatorOptionsAprès :
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime.options_models import EstimatorOptionsÉtape 2 — Effectuer explicitement l'apprentissage du bruit (en cas d'utilisation de PEC ou de PEA).
Si votre code utilise PEC (pec_mitigation=True) ou ZNE avec PEA (zne.amplifier="pea"), vous devez effectuer explicitement l'apprentissage du bruit à l'aide de NoiseLearnerV3.
Avant :
from qiskit_ibm_runtime import Estimator
pubs = [...] # Your PUBs
estimator = Estimator(mode=backend)
estimator.options.resilience.pec_mitigation = True # or zne_mitigation + pea amplifier
job = estimator.run(pubs)Après :
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime import NoiseLearnerV3
pubs = [...] # Your PUBs
estimator = Estimator(mode=backend)
estimator.options.resilience.pec_mitigation = True # or zne_mitigation + pea amplifier
# Identify the unique layers to learn.
layers = estimator.find_unique_layers(pubs)
# Learn the noise model for those layers (runs as a separate job).
learner = NoiseLearnerV3(mode=backend)
learner_job = learner.run(layers)
learner_result = learner_job.result()
# Convert the result to Pauli-Lindblad noise maps.
pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()
# Assign the learned noise maps so PEA/PEC uses them.
# The result objects returned by NoiseLearnerV3 follow the same order as the input
# layers, so the positional zip can be used here.
estimator.options.resilience.layer_noise_model = zip(layers, pauli_lindblad_maps)
# Now execute the target PUBs.
job = estimator.run(pubs)Étape 3 — Divisez une tâche en plusieurs (si les PUB utilisent des valeurs de précision différentes).
Les précisions mixtes ne sont plus prises en charge : un travail ne peut plus contenir de PUB demandant des valeurs de précision différentes, et une exception est levée run() si IBMInputValueError c'est le cas. Regroupez les PUB par niveau de précision et envoyez une tâche par groupe, en utilisant un Batch afin que les groupes s'exécutent toujours simultanément.
Avant :
from qiskit_ibm_runtime import Estimator
# PUBs with different precision values.
pubs = [(isa_circuit, isa_obs, None, 0.1), (isa_circuit1, isa_obs1, None, 0.5)]
estimator = Estimator(mode=backend)
job = estimator.run(pubs)Après :
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime import Batch
# Group the PUBs by precision, one group per job.
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
jobs = [
estimator.run([(isa_circuit, isa_obs)], precision=0.1),
estimator.run([(isa_circuit1, isa_obs1)], precision=0.5),
]
results = [job.result() for job in jobs]Cours
Chronique « 1 » | Chronique « 2 » |
|---|---|
Estimator | Primitive « Estimator » côté client pour IBM Quantum Compute (anciennement Qiskit Runtime ). |
EstimatorV2 | alias de Estimator |