Migrace ze serverového na klientský Sampler a Estimator
Tento průvodce popisuje, jak migrovat ze serverových implementací IBM Quantum®
Sampler a Estimator na jejich nové klientské implementace v
qiskit-ibm-runtime. Rozhraní a možnosti zůstávají z velké části beze změny, takže většina kódu
funguje beze změn, ale je třeba porozumět některým rozdílům v chování.
Kontext
Sampler a Estimator jsou primitivní rozhraní definovaná v Qiskit. Služba IBM Quantum
Compute Service (dříve Qiskit Runtime) historicky poskytovala implementaci
těchto primitiv uvnitř svého runtime prostředí. Když zavoláš sampler.run() nebo
estimator.run(), požadavek je odeslán službě a veškeré výpočty — včetně
potlačení a zmírnění chyb — probíhají na straně serveru.
Tato zkušenost typu black-box je pohodlná: nemusíš se starat o detaily implementace. Ale zároveň to ztěžuje ladění, přizpůsobení nebo učení se z primitiv, protože nevidíš, co se děje během zpracování.
Nově zavedený model řízeného spouštění zaujímá opačný přístup a poskytuje přístup typu white-box. Veškeré záměry návrhu jsou zachyceny na straně klienta, a jediné serverové primitivum Executor zpracovává tyto vstupy přesně podle zadání — nedělá za tebe žádná implicitní rozhodnutí.
Počínaje qiskit-ibm-runtime v0.50.0 jsou Sampler a Estimator znovu implementovány
na straně klienta nad Executorem. Poskytují stejné pohodlí a
abstrakci jako dříve, a nyní si můžeš prohlédnout detaily implementace, když je potřebuješ.
Protože rozhraní a možnosti zůstávají z velké části stejné, migrace by měla být
bezproblémová.
Poznámka: IBM Quantum podporuje pouze verzi 2 rozhraní Sampler a Estimator (BaseSamplerV2 a BaseEstimatorV2). Proto jsou v tomto průvodci jednoduše označovány jako Sampler a Estimator.
Aktualizace importů
Dnes musíš explicitně importovat nové implementace z jejich vyhrazených modulů:
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import Estimator
V blízké budoucnosti se importy nejvyšší úrovně budou přesměrovávat na nové klientské implementace a nebude potřeba žádná změna kódu:
# Coming soon — the following code will import the new client-side implementations.
from qiskit_ibm_runtime import Sampler, Estimator
Podobně, pokud vytváříš typované objekty možností, musíš je importovat z
qiskit_ibm_runtime.options_models, nebo jednoduše předat obyčejný vnořený slovník:
from qiskit_ibm_runtime.options_models import SamplerOptions, EstimatorOptions
Co zůstává stejné
-
Vytváření primitiv pomocí
modeaoptions. -
Signatura
run()a formát PUB. -
Strom možností (
options.twirling,options.resilience,options.default_shots, a tak dále). -
Struktura dat výsledku vrácená
job.result().
Nekompatibilní změny v novém Sampleru
| Změna | Akce při migraci |
|---|---|
Základním primitivem je nyní Executor. Uživatelské rozhraní IBM Quantum Platform i job.primitive_id nyní zobrazí executor místo sampler. | Aktualizuj veškerý kód, který odkazuje na job.primitive_id. |
Nová implementace mapuje vstupy Sampleru na vstupy Executoru, takže job.inputs vrací vstupy Executoru. | Aktualizuj veškerý kód, který odkazuje na job.inputs. Viz Vstupy úlohy. |
Na straně klienta nyní probíhá více předzpracování a následného zpracování, takže sampler.run() a job.result() mohou trvat déle než dříve. | Povol protokolování na úrovni INFO, abys mohl sledovat průběh zpracování na straně klienta. Viz Povolení protokolování INFO. |
Metadata obvodu se kopírují do metadat výsledku. Typy dat povolené v metadatech výsledku jsou nyní omezeny na str, float, int, bool a seznamy nebo slovníky těchto typů. | Pokud potřebuješ jiné datové typy, nejprve je zakóduj jako řetězec (například pomocí base64). |
Třídy možností (options_models.SamplerOptions a podobné) jsou nyní modely Pydantic místo dataclasses, takže je již nelze převést na slovníky Pythonu pomocí asdict(). | Místo toho použij options.model_dump(). |
Třídy možností, které dříve měly příponu V2 (ExecutionOptionsV2 a podobné), ji již nemají, protože primitivy V1 již nejsou podporovány. | Odstraň příponu V2 u těchto tříd možností: nahraď ExecutionOptionsV2 za ExecutionOptions, ResilienceOptionsV2 za ResilienceOptions a SamplerExecutionOptionsV2 za SamplerExecutionOptions. |
Pokud je povoleno twirling a jsou zároveň zadány shots (v PUBech nebo v run()), shots_per_randomization a num_randomizations, má num_randomizations * shots_per_randomization přednost před shots. | Vynech num_randomizations a shots_per_randomization, pokud chceš použít hodnotu shots. |
Některá validace vstupů se přesunula na stranu serveru a nyní vyvolává RuntimeError místo IBMInputValueError. | Aktualizuj typy výjimek, které tvůj kód zachytává. |
| Smíšené hodnoty shots v jedné úloze již nejsou podporovány. | Odešli samostatnou úlohu pro každou hodnotu shots. Úvahy k tomuto tématu najdeš v části Rozdělení úloh. |
Execution spans (result.metadata["execution"]["execution_spans"]) jsou nahrazeny časováním chunků podkladové úlohy Executoru v result.metadata["executor"].chunk_timing. ExecutionSpan.mask() nemá žádnou obdobu. | Čti časování z result.metadata["executor"].chunk_timing a vizualizuj ho pomocí draw_chunk_timings místo draw_execution_spans. Viz Execution spans. |
Nekompatibilní změny v novém Estimatoru
| Změna | Akce při migraci |
|---|---|
Základním primitivem je nyní Executor. Uživatelské rozhraní IBM Quantum Platform i job.primitive_id nyní zobrazí executor místo estimator. | Aktualizuj veškerý kód, který odkazuje na job.primitive_id. |
Nová implementace mapuje vstupy Estimatoru na vstupy Executoru, takže job.inputs vrací vstupy Executoru. | Aktualizuj veškerý kód, který odkazuje na job.inputs. Viz Vstupy úlohy. |
Na straně klienta nyní probíhá více předzpracování a následného zpracování, takže estimator.run() a job.result() mohou trvat déle než dříve. | Povol protokolování na úrovni INFO, abys mohl sledovat průběh zpracování na straně klienta. Viz Povolení protokolování INFO. |
Metadata obvodu se kopírují do metadat výsledku. Typy dat povolené v metadatech výsledku jsou nyní omezeny na str, float, int, bool a seznamy nebo slovníky těchto typů. | Pokud potřebuješ jiné datové typy, nejprve je zakóduj jako řetězec (například pomocí base64). |
Třídy možností (options_models.EstimatorOptions a podobné) jsou nyní modely Pydantic místo dataclasses, takže je již nelze převést na slovníky Pythonu pomocí asdict(). | Místo toho použij options.model_dump(). |
Třídy možností, které dříve měly příponu V2 (ExecutionOptionsV2 a podobné), ji již nemají, protože primitivy V1 již nejsou podporovány. | Odstraň příponu V2 u těchto tříd možností: nahraď ExecutionOptionsV2 za ExecutionOptions a ResilienceOptionsV2 za ResilienceOptions. |
| Všechny vstupní možnosti se nyní vracejí v metadatech výsledku, nikoli jen vybraná podmnožina. | Žádná akce — jedná se pouze o informaci. |
Některá validace vstupů se přesunula na stranu serveru a nyní vyvolává RuntimeError místo IBMInputValueError. | Aktualizuj typy výjimek, které tvůj kód zachytává. |
| Již se neprovádí implicitní učení šumu pro PEA a PEC. Učení šumu měření pro TREX je stále podporováno. | Nauč modely šumu samostatně a předej je Estimatoru. Viz Provedení explicitního učení šumu pro PEA a PEC. |
Vstupní typ ResilienceOptions.layer_noise_model je jiný a lze jej sestavit z výsledků NoiseLearnerV3. | Viz Provedení explicitního učení šumu pro PEA a PEC, kde se dozvíš, jak naučit modely šumu pomocí NoiseLearnerV3 a předat je Estimatoru. |
MeasureNoiseLearningOptions.shots_per_randomization již není podporováno. | Pro všechny obvody v úloze, včetně obvodů pro učení šumu měření, se používá jedna hodnota shots. Pokud musíš použít jinou hodnotu shots, použij TREX pomocí qiskit-mitigation mimo Estimator. |
| Smíšené hodnoty přesnosti v jedné úloze již nejsou podporovány. | Odešli samostatnou úlohu pro každou požadovanou přesnost. Úvahy k tomuto tématu najdeš v části Rozdělení úloh. |
Možnost seed_estimator již není podporována. | Odstraň jakékoli přiřazení options.seed_estimator (jeho nastavení vyvolá ValidationError). Neexistuje žádný ekvivalent na straně klienta, takže výsledky již nejsou reprodukovatelné pomocí tohoto seedu. |
Povolení protokolování INFO
Protože nyní více práce probíhá na straně klienta, je užitečné vidět postup tohoto
zpracování. Povol protokolování na úrovni INFO pro logger qiskit_ibm_runtime:
import logging
logger = logging.getLogger("qiskit_ibm_runtime")
logger.setLevel(logging.INFO)
Provedení explicitního učení šumu pro PEA a PEC
Nový Estimator již neprovádí implicitní učení šumu, když je vybrána metoda zmírnění chyb
PEA nebo PEC. Musíš modely šumu naučit explicitně a předat je.
Použij nový NoiseLearnerV3 k řízení toho, jak se obvody
rozdělí do vrstev. Přijímá seznam zabalených instrukcí obvodu (například
jedinečných vrstev) jako vstup.
PEA a PEC nyní tento explicitní postup vyžadují. Nevynechávej krok učení šumu, jinak tvůj kód selže. Učení šumu měření pro TREX není ovlivněno a funguje jako dříve.
Podobně, pokud tvůj kód používá NoiseLearner a předává výsledný model šumu serverovému Estimatoru, potřebuješ migrovat na NoiseLearnerV3. NEPOUŽÍVEJ starší NoiseLearner, který není kompatibilní s novým Estimatorem.
Všechny možnosti učení šumu v serverovém Estimatoru (LayerNoiseLearningOptions) se mapují přímo na možnost NoiseLearnerV3 (NoiseLearnerV3Options), s výjimkou max_layers_to_learn. Počet vrstev k naučení je místo toho založen na počtu vrstev předaných do NoiseLearnerV3.
Například:
Serverový Estimator (s povoleným 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)
Klientský Estimator (s povoleným 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)
Migrace z NoiseLearner na NoiseLearnerV3
NoiseLearner funguje pouze se serverovou implementací Estimator. Pokud tedy tvůj kód používá NoiseLearner k naučení modelu šumu a jeho předání Estimator, potřebuješ aktualizovat kód tak, aby používal NoiseLearnerV3.
Podrobnosti najdeš v průvodci Migrace z NoiseLearner na NoiseLearnerV3.
Rozdělení úloh
Když musíš rozdělit jednu úlohu na několik, protože smíšené hodnoty shots nebo přesnosti v jedné úloze již nejsou podporovány, zvaž následující:
-
Seskup PUB podle jejich cílové hodnoty — jedna úloha na každou odlišnou hodnotu, ne jedna úloha na každý PUB. Rozdělení je přeskupení, takže celkový počet PUB, které odesíláš, se nemění. Například při
[A@0.01, B@0.05, C@0.01]odešli dvě úlohy:[A, C]sprecision=0.01a[B]sprecision=0.05. OdesláníAaCjako samostatných úloh je méně efektivní, protože každá úloha má pevnou režii. -
Nauč modely šumu jen jednou a použij je ve všech rozdělených úlohách. Je efektivnější spustit jedinou úlohu
NoiseLearnerV3nad sjednocením všech vrstev. Výsledek úlohy učení šumu obsahuje seznam objektůNoiseLearnerV3Result, po jednom pro každou vstupní instrukci, a je ve stejném pořadí jako vstupní seznam. Výstup této úlohy učení šumu můžeš použít ve všech rozdělených (Estimator) úlohách a modely šumu pro vrstvy, které nejsou v PUB rozdělené úlohy, jsou ignorovány. -
Odešli nejprve všechny rozdělené úlohy v
Batch, poté shromáždi jejich výsledky. Režim spouštěníBatchposkytuje efektivní paralelní spouštění, když existuje více úloh. Nicménějob.result()je blokující, takže jeho volání uvnitř smyčky odesílání serializuje úlohy a ruší výhody použitíBatch. Ujisti se, že používáš vzor „odeslat vše, pak shromáždit“ (ukázaný níže).
V následujícím příkladu pub1 a pub2 vyžadují precision=0.5, zatímco pub3 vyžaduje 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]
Execution spans
Sampler na straně serveru vracel informace o časování provádění jako objekt ExecutionSpans v result.metadata["execution"]["execution_spans"]. Sampler a Estimator na straně klienta místo toho vracejí časování podkladové úlohy Executoru pod klíčem "executor" v metadatech výsledku.
Úloha Executoru provádí svou práci na QPU v chunkech. result.metadata["executor"].chunk_timing je seznam, který obsahuje jeden ChunkSpan na každý chunk, s následujícími rozdíly oproti původním execution spans:
-
Časové značky jsou přesné.
startastopjsou skutečné okamžiky, kdy chunk začal a přestal běžet na QPU, nikoli horní a dolní meze. -
Práce je popsána po položkách, ne po shotech. Místo metody
mask(), která vrací booleovskou masku přes shoty, má každýChunkSpanseznamparts. Každá část uvádí index položky programu Executoru (idx_item) a počet konfigurací z této položky (size), které se v chunku provedly. U Sampleru jeidx_itemindex PUB. U Estimatoru nemusí nutně odpovídat indexu PUB, protože Estimator může přidávat položky programu, například kalibrační obvody chyb měření pro TREX. -
Použij jinou vizualizační funkci. Nahraď
draw_execution_spansfunkcídraw_chunk_timings, která přijímá seznamchunk_timingpřímo.
Například:
Sampler na straně serveru:
from qiskit_ibm_runtime.visualization import draw_execution_spans
spans = job.result().metadata["execution"]["execution_spans"]
print("Total duration (s):", spans.duration)
fig = draw_execution_spans(spans)
Sampler nebo Estimator na straně klienta:
from qiskit_ibm_runtime.visualization import draw_chunk_timings
chunk_timing = job.result().metadata["executor"].chunk_timing
for span in chunk_timing:
print(span.start, span.stop, [(p.idx_item, p.size) for p in span.parts])
fig = draw_chunk_timings(chunk_timing)
Další podrobnosti, včetně toho, proč se v grafu mohou mezi chunky objevit mezery, najdeš v části Zobrazení execution spans v průvodci vstupy a výstupy Executoru.
Struktura vstupů úlohy
Nová implementace mapuje vstupy Sampleru nebo Estimatoru na vstupy Executoru, takže job.inputs vrací slovník obsahující vstupy Executoru. Tento slovník má následující klíče:
-
options: VstupníExecutorOption. -
quantum_program: VstupníQuantumProgram -
schema_version: Použitá verze schématu na straně serveru.
Pokud tvůj kód používal job.inputs['options'] k vyhledání možností specifikovaných pro úlohu, nyní můžeš místo toho použít job.result().metadata['options'].
Testování lokálně s falešným backendem
Před odesláním na hardware můžeš ověřit migrovaný kód proti backendu Fake*,
abys včas zachytil případné syntaktické chyby. Všimni si následujících podrobností o lokálním testovacím režimu:
-
Nereprodukuje výsledky hardwaru. Lokální simulace se šumem dokonale nereplikuje šum skutečného zařízení, a proto se výstupy mohou lišit. Spuštění ale ověří, že cesty možností a typy hodnot jsou správné.
-
NoiseLearnerV3nemá žádný lokální testovací režim: jehomodepřijímá pouze skutečnýBackend,SessionneboBatch, takže krok učení šumu nemůžeš vyzkoušet proti falešnému backendu. Ověř tuto část svého kódu proti referenční dokumentaci APINoiseLearnerV3. Potvrď, že konstruktor, tvar vstupurun(instructions)a jakýkoli pomocník (například pomocník pro jedinečné vrstvy) jsou používány tak, jak je zdokumentováno.
Cliffordizace obvodu pro efektivní lokální simulaci
Falešný backend používá simulátor statevector (se šumem), jehož náklady rostou exponenciálně s
počtem qubitů a hloubkou. Realistický pracovní obvod tedy může zamrznout nebo vyčerpat paměť. Protože
lokální testování potřebuje pouze vyzkoušet cesty možností (nikoli reprodukovat fyzikální výsledky),
nejprve zredukuj obvod na Cliffordův pomocí
ConvertISAToClifford,
který zaokrouhlí každý úhel RZ/RZZ/RX na nejbližší násobek π/2. Cliffordovy obvody
se simulují efektivně (stabilizátorová simulace) bez ohledu na velikost.
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 vyžaduje jako vstup ISA obvod (výstup
generate_preset_pass_manager(...).run(...) cílený na backend). Při vytváření lokálního PUB musíš
zohlednit následující důsledky:
-
Atribut
.layoutje zahozen. Cliffordizovaný obvod si zachovává stejný počet qubitů, aleclifford.layoutjeNone, takžeobservable.apply_layout(clifford.layout)selže. Místo toho aplikuj layout na observable podle ISA obvodu před cliffordizací:isa_obs = observable.apply_layout(isa_circuit.layout), poté spusť(clifford, isa_obs). -
Parametry zmizí (jsou dosazeny). Zaokrouhlení úhlů rotace mění parametrický ISA obvod na konkrétní Cliffordův, takže
clifford.num_parametersse stane0. PUB, který stále nese pole hodnot parametrů, selže při vynucení typu. Pro lokální spuštění odstraň pole parametrů z PUB; spuštění na hardwaru si ponechá původní parametrický obvod a jeho hodnoty.