Skip to main content
IBM Quantum Platform

Umstellung von serverseitigem auf clientseitigen Sampler und Estimator

In diesem Leitfaden wird beschrieben, wie Sie von den serverseitigen Implementierungen vonIBM Quantum® Sampler und zuEstimator deren neuen clientseitigen Implementierungen in qiskit-ibm-runtime migrieren können. Die Schnittstellen und Optionen sind weitgehend unverändert geblieben, sodass der Großteil des Codes ohne Änderungen läuft, allerdings gibt es einige Unterschiede im Verhalten, die man beachten muss.


Hintergrund

„Sampler“ und „Estimator“ sind in Qiskit definierte primitive Schnittstellen. Der IBM Quantum Compute Service (ehemals Qiskit Runtime ) hat in der Vergangenheit die Implementierung dieser Primitiven innerhalb seiner Laufzeitumgebung bereitgestellt. Wenn Sie oder sampler.run() aufrufenestimator.run(), wird die Anfrage an den Dienst gesendet, und alle Berechnungen – einschließlich der Fehlerunterdrückung und -behebung – erfolgen serverseitig.

Diese „Black-Box“-Lösung ist praktisch: Man muss sich keine Gedanken über die Implementierungsdetails machen. Das macht es jedoch auch schwierig, die Primitive zu debuggen, anzupassen oder daraus zu lernen, da man nicht sehen kann, was während der Verarbeitung geschieht.

Das neu eingeführte Modell der gerichteten Ausführung verfolgt den gegenteiligen Ansatz und bietet eine White-Box-Erfahrung. Alle Entwurfsabsichten werden auf der Client-Seite erfasst, und ein einziger serverseitiger, einfacher Executor verarbeitet diese Eingaben genau wie vorgeschrieben – er trifft keine impliziten Entscheidungen in Ihrem Namen.

Ab der Version v0.50.0qiskit-ibm-runtime wurden „Sampler“ und „Estimator“ auf der Clientseite auf Basis von „Executor“ neu implementiert. Sie bieten denselben Komfort und dieselbe Abstraktion wie bisher, und Sie können nun bei Bedarf die Implementierungsdetails einsehen. Da die Benutzeroberflächen und Optionen weitgehend unverändert bleiben, sollte die Migration nahtlos verlaufen.

Hinweis: „ IBM Quantum “ unterstützt nur Version 2 der Sampler- und Estimator-Schnittstellen (BaseSamplerV2 und BaseEstimatorV2). Daher werden sie in diesem Leitfaden einfach als „Sampler“ und „Estimator“ bezeichnet.


Die Importe aktualisieren

Heute müssen Sie die neuen Implementierungen explizit aus den dafür vorgesehenen Modulen importieren:

from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import Estimator

In naher Zukunft werden die Top-Level-Importe auf die neuen clientseitigen Implementierungen verweisen, und es sind keine Codeänderungen erforderlich:

# Coming soon — the following code will import the new client-side implementations.
from qiskit_ibm_runtime import Sampler, Estimator

Ebenso müssen Sie, wenn Sie typisierte Optionsobjekte erstellen, diese stattdessen qiskit_ibm_runtime.options_models importieren oder einfach ein einfaches verschachteltes Dict übergeben:

from qiskit_ibm_runtime.options_models import SamplerOptions, EstimatorOptions

Was bleibt unverändert?

  • Primitive Konstruktion mit a und mode options.
  • Das Format für die Signatur run() und „ PUB “.
  • Der Optionsbaum (options.twirling, options.resilience, options.default_shots, usw.).
  • Die von job.result(). zurückgegebene Datenstruktur für die Ergebnisse.

Inkompatible Änderungen im neuen Sampler

Ändern
Migrationsmaßnahme
Die zugrunde liegende Primitive ist nun „Executor“. Sowohl die Benutzeroberfläche von „ IBM Quantum Platform “ als auch zeigen executor anstelle von an job.primitive_id``sampler .Aktualisieren Sie jeglichen Code, der auf. verweist job.primitive_id.
Die neue Implementierung ordnet Sampler-Eingaben den Executor-Eingaben zu und job.inputs gibt daher Executor-Eingaben zurück.Aktualisieren Sie jeglichen Code, der auf. verweist job.inputs. Siehe „Job-Eingaben “.
Ein Großteil der Vor- und Nachbearbeitung findet nun auf der Client-Seite statt, sodass sampler.run() und möglicherweise job.result() länger dauern als zuvor.Aktivieren Sie die INFO-Protokollierung, um den Fortschritt der clientseitigen Verarbeitung zu verfolgen. Siehe „INFO-Protokollierung aktivieren “.
Die Metadaten der Schaltung werden in die Metadaten des Ergebnisses kopiert. Die in den Ergebnis-Metadaten zulässigen Datentypen sind nun auf str, float, int, bool, sowie Listen oder Wörterbücher dieser Typen beschränkt.Wenn Sie andere Datentypen benötigen, kodieren Sie diese zunächst als Zeichenfolge (beispielsweise mit „ base64 “).
Options-Klassen (options_models.SamplerOptions usw.) sind nun Pydantic-Modelle anstelle von Dataklassen, sodass sie nicht mehr mithilfe von in „ Python “-Dictionaries konvertiert werden können asdict().Verwenden Sie stattdessen options.model_dump().
Options-Klassen, die zuvor das Suffix V2 (ExecutionOptionsV2 usw.) hatten, weisen dieses nun nicht mehr auf, da V1 -Primitive nicht mehr unterstützt werden.Entfernen Sie die Endung V2 dieser Optionsklassen: Ersetzen Sie ExecutionOptionsV2 durch ExecutionOptions, ResilienceOptionsV2 durch ResilienceOptionsund SamplerExecutionOptionsV2 durch SamplerExecutionOptions.
Wenn aktiviert twirling ist und shots (in den PUBs oder in run()), shots_per_randomization, und alle angegeben num_randomizations sind, num_randomizations * shots_per_randomization hat Vorrang vor shots.Lassen Sie und num_randomizations weg, wenn shots_per_randomization der Wert shots verwendet werden soll.
Ein Teil der Eingabevalidierung wurde auf die Serverseite verlagert und löst nun RuntimeError anstelle von aus IBMInputValueError.Aktualisieren Sie die Ausnahmetypen, die Ihr Code abfängt.
Gemischte Schusswerte innerhalb eines einzelnen Auftrags werden nicht mehr unterstützt.Reichen Sie für jeden Aufnahmewert einen separaten Auftrag ein. Siehe „Aufteilung der Arbeit“ für weitere Überlegungen.

Inkompatible Änderungen im neuen Estimator

Ändern
Migrationsmaßnahme
Die zugrunde liegende Primitive ist nun „Executor“. Sowohl die Benutzeroberfläche von „ IBM Quantum Platform “ als auch zeigen executor anstelle von an job.primitive_id``estimator .Aktualisieren Sie jeglichen Code, der auf. verweist job.primitive_id.
Die neue Implementierung ordnet die Eingaben des Estimators den Eingaben des Executors zu und job.inputs gibt daher die Eingaben des Executors zurück.Aktualisieren Sie jeglichen Code, der auf. verweist job.inputs. Siehe „Job-Eingaben “.
Ein Großteil der Vor- und Nachbearbeitung findet nun auf der Client-Seite statt, sodass estimator.run() und möglicherweise job.result() länger dauern als zuvor.Aktivieren Sie die INFO-Protokollierung, um den Fortschritt der clientseitigen Verarbeitung zu verfolgen. Siehe „INFO-Protokollierung aktivieren “.
Die Metadaten der Schaltung werden in die Metadaten des Ergebnisses kopiert. Die in den Ergebnis-Metadaten zulässigen Datentypen sind nun auf str, float, int, bool, sowie Listen oder Wörterbücher dieser Typen beschränkt.Wenn Sie andere Datentypen benötigen, kodieren Sie diese zunächst als Zeichenfolge (beispielsweise mit „ base64 “).
Options-Klassen (options_models.EstimatorOptions usw.) sind nun Pydantic-Modelle anstelle von Dataclasses, sodass sie nicht mehr mithilfe von. in „ Python “-Dictionaries konvertiert werden können asdict().Verwenden Sie stattdessen options.model_dump().
Options-Klassen, die zuvor ein Suffix V2 hatten (ExecutionOptionsV2 usw.), weisen dieses nun nicht mehr auf, da Primitive vom Typ „ V1 “ nicht mehr unterstützt werden.Entfernen Sie die V2 Endungen dieser Optionsklassen: Ersetzen Sie ExecutionOptionsV2 durch ExecutionOptions und ResilienceOptionsV2 durch ResilienceOptions.
Es werden alle Eingabeoptionen in den Metadaten des Ergebnisses zurückgegeben, nicht nur eine ausgewählte Teilmenge.Keine – dies dient nur zu Informationszwecken.
Ein Teil der Eingabevalidierung wurde auf die Serverseite verlagert und löst nun RuntimeError anstelle von aus IBMInputValueError.Aktualisieren Sie die Ausnahmetypen, die Ihr Code abfängt.
Kein implizites Rauschlernen mehr für PEA und PEC. Das Lernen von Messrauschen für TREX wird weiterhin unterstützt.Lernen Sie die Rauschmodelle separat ein und übergeben Sie sie an den Schätzer. Siehe „Explizites Rauschlernen für PEA und PEC durchführen “.
Der Eingabetyp von ResilienceOptions.layer_noise_model ist anders und lässt sich aus den Ergebnissen NoiseLearnerV3 von ableiten.Unter „Explizites Rauschlernen für PEA und PEC durchführen “ erfahren Sie, wie Sie die Rauschmodelle mithilfe von trainieren NoiseLearnerV3 und an den Schätzer übergeben.
MeasureNoiseLearningOptions.shots_per_randomization wird nicht mehr unterstützt.Für alle Schaltungen im Auftrag wird ein einziger Messwert verwendet, einschließlich der Schaltungen zum Erlernen von Messrauschen. Falls Sie einen anderen Schusswert verwenden müssen, wenden Sie TREX außerhalb qiskit-mitigation des Estimators an.
Werte mit gemischter Genauigkeit innerhalb eines einzelnen Auftrags werden nicht mehr unterstützt.Reichen Sie für jede gewünschte Genauigkeit einen separaten Auftrag ein. Siehe „Aufteilung der Arbeit“ für weitere Überlegungen.
Die Option seed_estimator wird nicht mehr unterstützt.Entfernen Sie alle Zuweisungen options.seed_estimator (das Setzen einer solchen löst einen aus ValidationError). Da es kein clientseitiges Äquivalent gibt, lassen sich die Ergebnisse mit diesem Startwert nicht mehr reproduzieren.

INFO-Protokollierung aktivieren

Da mittlerweile ein Großteil der Arbeit auf der Client-Seite stattfindet, ist es hilfreich, den Fortschritt dieser Verarbeitung zu verfolgen. Aktivieren Sie die Protokollierung auf der Stufe „INFO“ für den qiskit_ibm_runtime Logger:

import logging

logger = logging.getLogger("qiskit_ibm_runtime")
logger.setLevel(logging.INFO)

Führen Sie ein explizites Rauschlernen für PEA und PEC durch

Der neue Schätzer führt kein implizites Rauschlernen mehr durch, wenn die Fehlerminderungsmethode PEA oder PEC ausgewählt ist. Sie müssen die Rauschmodelle explizit erlernen und sie übergeben. Verwenden Sie die neue Funktion, NoiseLearnerV3 um zu steuern, wie Schaltkreise in Ebenen unterteilt werden. Als Eingabe benötigt es eine Liste von Anweisungen für Box-Schaltungen (zum Beispiel die einzelnen Ebenen).

Wichtig

PEA und PEC verlangen nun dieses explizite Muster. Überspringe den Schritt zum Erlernen von Rauschen nicht, sonst wird dein Code fehlschlagen. Das Lernen von Messrauschen für TREX bleibt davon unberührt und funktioniert weiterhin wie bisher.

Ebenso müssen Sie, wenn Ihr Code verwendet und NoiseLearner das daraus resultierende Rauschmodell an den serverseitigen Estimator übergibt, migration nach NoiseLearnerV3. Verwenden Sie NICHT die ältere Version NoiseLearner, da diese mit dem neuen Estimator nicht kompatibel ist.

Alle Optionen zum Rauschlernen im serverseitigen Estimator (LayerNoiseLearningOptions) entsprechen direkt der Option NoiseLearnerV3 (NoiseLearnerV3Options), mit Ausnahme von max_layers_to_learn. Die Anzahl der zu lernenden Schichten richtet sich stattdessen nach der Anzahl der an übergegebenen Schichten NoiseLearnerV3.

Zum Beispiel:

Serverseitiger Schätzer (mit aktiviertem PEC):

from qiskit_ibm_runtime import Estimator

pubs = [...]  # Your PUBs
estimator = Estimator(mode, options)
estimator.options.resilience.pec_mitigation = True  # or zne_mitigation + pea amplifier
estimator.options.resilience.layer_noise_learning.num_randomizations = 64

job = estimator.run(pubs)

Clientseitiger Schätzer (mit aktivierter PEC):

from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime import NoiseLearnerV3

pubs = [...]  # Your PUBs
estimator = Estimator(mode, options)
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)
learner.options.num_randomizations = 64  # Same as layer_noise_learning.num_randomizations
learner_job = learner.run(layers)
learner_result = learner_job.result()

# Convert results to Pauli-Lindblad noise maps.
pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()

# Assign the learned noise maps so PEA/PEC uses them.
estimator.options.resilience.layer_noise_model = zip(layers, pauli_lindblad_maps)

# Now execute the target PUBs.
job = estimator.run(pubs)

Von nach NoiseLearner migrieren NoiseLearnerV3

NoiseLearner funktioniert nur bei einer serverseitigen Implementierung von Estimator. Wenn Ihr Code also verwendet, NoiseLearner um das Rauschmodell zu trainieren und es an zu übergeben Estimator, müssen Sie Ihren Code so anpassen, dass er verwendet NoiseLearnerV3.

Weitere Informationen finden Sie in der Anleitung Von nach NoiseLearner migrieren NoiseLearnerV3 .


Aufteilung der Arbeit

Wenn Sie einen Auftrag in mehrere Aufträge aufteilen müssen, weil gemischte „Shot“- oder „Precision“-Werte in einem einzelnen Auftrag nicht mehr unterstützt werden, beachten Sie Folgendes:

  • Gruppiere die PUBs nach ihrem Zielwert – ein Auftrag pro eindeutigem Wert, nicht ein Auftrag pro PUB. Eine Aufteilung ist eine Umgruppierung, daher ändert sich die Gesamtzahl der von Ihnen eingereichten PUBs nicht. Geben wir beispielsweise an [[email protected], [email protected], [email protected]]: Reichen Sie zwei Aufträge ein: [A, C] um und precision=0.01 [B]um precision=0.05. Das Einreichen von und A C als separate Aufträge ist weniger effizient, da jeder Auftrag mit einem festen Verwaltungsaufwand verbunden ist.

  • Einmal lernen und die Rauschmodelle in allen Split-Jobs verwenden. Es ist effizienter, einen einzigen NoiseLearnerV3 Job über die Vereinigung aller Ebenen auszuführen. Das Ergebnis eines „Noise Learner“-Jobs enthält eine Liste von NoiseLearnerV3Result Objekten, eines für jede Eingabeanweisung, und entspricht in der Reihenfolge der Eingabeliste. Sie können die Ausgabe dieses „Noise Learner“-Jobs in allen Split-Jobs (Estimator-Jobs) verwenden; Rauschmodelle für Schichten, die nicht in den PUBs eines Split-Jobs enthalten sind, werden ignoriert.

  • Führen Sie zunächst Batch alle aufgeteilten Aufträge aus und sammeln Sie anschließend deren Ergebnisse. Der Ausführungsmodus Batch ermöglicht eine effiziente parallele Ausführung, wenn mehrere Aufträge vorliegen. Allerdings job.result() ist dies blockierend, sodass ein Aufruf innerhalb der Übermittlungsschleife die Aufträge serialisiert und die Vorteile der Verwendung von zunichte macht Batch. Achten Sie darauf, das Muster „Zuerst alles übermitteln, dann sammeln“ (siehe unten) zu verwenden.

Im folgenden Beispiel benötigen pub2 und pub1 precision=0.5, während erfordert pub3 precision=0.1:

group1_pubs = [pub1, pub2]
group2_pubs = [pub3]

with Batch(backend=backend) as batch:
    estimator = Estimator(mode=batch)
    estimator.options.resilience.pec_mitigation = True

    # Learn once, over the union of every job's layers.
    all_layers = estimator.find_unique_layers(group1_pubs + group2_pubs)
    learner_job = NoiseLearnerV3(mode=batch).run(all_layers)
    learner_result = learner_job.result()
    pauli_lindblad_maps = learner_result.to_pauli_lindblad_maps()

    # Assign the learned noise maps. Any layers not found in the input PUBs are ignored.
    estimator.options.resilience.layer_noise_model = zip(all_layers, pauli_lindblad_maps)

    # Submit every split job with different precision values.
    jobs = []
    jobs.append(estimator.run(group1_pubs, precision=0.5))
    jobs.append(estimator.run(group2_pubs, precision=0.1))

    # Block once, at the end — the jobs run in parallel.
    results = [job.result() for job in jobs]

Struktur der Auftragsdaten

Die neue Implementierung ordnet die Eingaben von „Sampler“ oder „Estimator“ den Eingaben von „Executor“ zu und job.inputs gibt somit ein Wörterbuch zurück, das die Eingaben von „Executor“ enthält. Dieses Wörterbuch enthält die folgenden Einträge:

  • options: Die Eingabe ExecutorOption.
  • quantum_program: Die Eingabe QuantumProgram
  • schema_version: Die verwendete serverseitige Schemaversion.

Wenn Ihr Code bisher verwendet hat, job.inputs['options'] um die für den Auftrag festgelegten Optionen zu ermitteln, können Sie nun job.result().metadata['options'] stattdessen verwenden.


Lokal mit einem simulierten Backend testen

Bevor Sie den Code an die Hardware übergeben, können Sie den migrierten Code anhand eines Fake* Backends überprüfen, um eventuelle Syntaxfehler frühzeitig zu erkennen. Beachten Sie die folgenden Details zum lokalen Testmodus:

  • Es gibt die Ergebnisse der Hardware nicht wieder. Die lokale Rauschsimulation bildet das tatsächliche Geräusch des Geräts nicht perfekt nach, weshalb die Ausgabeergebnisse abweichen können. Durch die Ausführung wird überprüft, ob die Optionspfade und Werttypen korrekt sind.
  • NoiseLearnerV3 verfügt über keinen lokalen Testmodus : Es mode akzeptiert nur ein echtes Backend, Session, oder Batch, sodass Sie den Schritt zum Erlernen von Rauschen nicht mit einem gefälschten Backend durchführen können. Überprüfen Sie diesen Teil Ihres Codes stattdessen anhand der NoiseLearnerV3 API-Referenz. Stellen Sie sicher, dass der Konstruktor, die run(instructions) Eingabeform und alle Hilfsfunktionen (wie z. B. die Hilfsfunktion „unique-layer“) gemäß der Dokumentation verwendet werden.

Cliffordisierung der Schaltung für eine effiziente lokale Simulation

Ein simuliertes Backend verwendet einen (verrauschten) Statevektor-Simulator, dessen Rechenaufwand exponentiell mit der Anzahl der Qubits und der Tiefe wächst. So kann eine realistische Arbeitslastschaltung zum Absturz führen oder den Speicher überlasten. Da bei lokalen Tests lediglich die Optionspfade durchgespielt werden müssen (und keine physikalischen Ergebnisse reproduziert werden müssen), reduziere den Schaltkreis zunächst auf einen Clifford-Schaltkreis mit ConvertISAToClifford, wodurch jeder RZ``RZZ//-WinkelRX auf das nächste Vielfache von π/2 gerundet wird. Clifford-Schaltungen lassen sich unabhängig von ihrer Größe effizient simulieren (Stabilisatorsimulation).

from qiskit.transpiler import PassManager
from qiskit_ibm_runtime.transpiler.passes import ConvertISAToClifford

clifford = PassManager([ConvertISAToClifford()]).run(isa_circuit)
# run `clifford` (not the original) through the fake-backend primitive

ConvertISAToClifford erfordert eine ISA-Schaltung als Eingang (den Ausgang von generate_preset_pass_manager(...).run(...) , der auf das Backend ausgerichtet ist). Sie müssen die folgenden Konsequenzen berücksichtigen, wenn Sie die lokale „ PUB “ erstellen:

  • Das Attribut .layout wird entfernt. Die „Cliffordisierte“ Schaltung behält die gleiche Anzahl an Qubits bei, clifford.layout ist jedoch None , und observable.apply_layout(clifford.layout) scheitert daher. Legen Sie stattdessen die Beobachtungsgröße aus der Pre-Clifford-ISA-Schaltung fest: isa_obs = observable.apply_layout(isa_circuit.layout), und führen Sie dann aus (clifford, isa_obs).
  • Die Parameter werden gebunden. Durch Abrunden der Rotationswinkel wird eine parametrische ISA-Schaltung zu einer konkreten Clifford-Schaltung, sodass zu wird clifford.num_parameters``0 . Ein PUB, das noch ein Array mit Parameterwerten enthält, scheitert bei der Typumwandlung. Für die lokale Ausführung entfernen Sie das Parameter-Array aus der Datei „ PUB “; bei der Hardware-Ausführung bleiben die ursprüngliche parametrische Schaltung und ihre Werte erhalten.

Nächste Schritte

War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.