Migrar del Sampler y el Estimator del lado del servidor al lado del cliente
Esta guía describe cómo migrar de las implementaciones del lado del servidor
de IBM Quantum®
Sampler
y Estimator
a sus nuevas implementaciones del lado del cliente
en
qiskit-ibm-runtime
. Las interfaces y las opciones prácticamente no han cambiado, por lo que la mayor parte del código
funciona tal cual, pero hay algunas diferencias de comportamiento que conviene tener en cuenta.
En segundo plano
«Sampler» y «Estimator» son interfaces primitivas definidas en Qiskit. El servicio «IBM Quantum
Compute
» (antes «Qiskit Runtime
») ha proporcionado tradicionalmente la implementación
de estas primitivas dentro de su entorno de ejecución. Cuando llamas a o sampler.run()
estimator.run(), la solicitud se envía al servicio, y todo el procesamiento —incluida
la supresión y mitigación de errores— se lleva a cabo en el lado del servidor.
Esta experiencia de «caja negra» resulta muy práctica: no tienes que preocuparte por los detalles de implementación. Pero esto también hace que resulte difícil depurar, personalizar o aprender de las primitivas, ya que no se puede ver lo que ocurre durante el procesamiento.
El modelo de ejecución dirigida, recientemente introducido, adopta el enfoque contrario y ofrece una experiencia de caja abierta. Todas las intenciones de diseño se recogen en el lado del cliente, y un único «Executor» primitivo del lado del servidor procesa esas entradas exactamente tal y como se le indica; no toma ninguna decisión implícita en tu nombre.
A partir de la versión v0.50.0qiskit-ibm-runtime , Sampler y Estimator se han reimplementado
en el lado del cliente sobre la base de Executor. Ofrecen la misma comodidad y
abstracción que antes, y ahora puedes examinar los detalles de la implementación cuando lo necesites
. Dado que las interfaces y las opciones se mantienen prácticamente iguales, la migración debería ser
fluida.
Nota: « IBM Quantum » solo es compatible con la versión 2 de las interfaces «Sampler» y «Estimator» (BaseSamplerV2 y BaseEstimatorV2). Por lo tanto, en esta guía se les denomina simplemente «muestreador» y «estimador».
Actualiza las importaciones
Hoy en día, hay que importar explícitamente las nuevas implementaciones desde sus módulos específicos:
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import EstimatorEn un futuro próximo, las importaciones de nivel superior se resolverán en las nuevas implementaciones del lado del cliente, y no será necesario modificar el código:
# Coming soon — the following code will import the new client-side implementations.
from qiskit_ibm_runtime import Sampler, EstimatorDel mismo modo, si creas objetos de opciones tipados, debes importarlos desde
qiskit_ibm_runtime.options_models , o simplemente pasar un diccionario anidado sin más:
from qiskit_ibm_runtime.options_models import SamplerOptions, EstimatorOptionsQué sigue igual
- Construcción primitiva con un
modey unoptions. - La firma
run()y el formato « PUB ». - El árbol de opciones (
options.twirling,options.resilience,options.default_shots, y así sucesivamente). - La estructura de datos de resultados devuelta por
job.result().
Cambios incompatibles en el nuevo Sampler
Cambiar | Medidas en materia de migración |
|---|---|
La primitiva subyacente es ahora Executor. Tanto la interfaz de usuario de IBM Quantum Platform como job.primitive_id mostrarán executor en lugar de sampler. | Actualiza cualquier código que haga referencia a job.primitive_id. |
La nueva implementación asigna las entradas del Sampler a las del Executor, por lo que job.inputs devuelve entradas del Executor. | Actualiza cualquier código que haga referencia a job.inputs. Consulta los datos de entrada del trabajo. |
Ahora se realizan más tareas de preprocesamiento y posprocesamiento en el lado del cliente, por lo que y sampler.run() pueden job.result() tardar más que antes. | Activa el registro de información para seguir el progreso del procesamiento en el lado del cliente. Consulta «Habilitar el registro de información ». |
Los metadatos del circuito se copian en los metadatos del resultado. Los tipos de datos permitidos en los metadatos de los resultados se limitan ahora a str, float, int, bool, así como a listas o diccionarios de dichos tipos. | Si necesitas otros tipos de datos, codifícalos primero como cadena (por ejemplo, con base64 ). |
Las clases de opciones (options_models.SamplerOptions y demás) son ahora modelos de Pydantic en lugar de dataclasses, por lo que ya no se pueden convertir en diccionarios de « Python » utilizando asdict(). | En su lugar, utilice options.model_dump(). |
Las clases de opciones que antes tenían el sufijo V2 (ExecutionOptionsV2 y así sucesivamente) ya no lo tienen, ya que las primitivas de V1 ya no son compatibles. | Elimina el sufijo V2 de estas clases de opciones: sustituye ExecutionOptionsV2 por ExecutionOptions, ResilienceOptionsV2 por ResilienceOptionsy SamplerExecutionOptionsV2 por SamplerExecutionOptions. |
Si twirling está activado y shots (en los PUB o en run()), shots_per_randomization, y num_randomizations están todos especificados, entonces num_randomizations * shots_per_randomization tiene prioridad sobre shots. | Omite y num_randomizations shots_per_randomization si quieres que se utilice el valor shots . |
Parte de la validación de datos de entrada se ha trasladado al lado del servidor y ahora genera un error RuntimeError en lugar de IBMInputValueError. | Actualiza los tipos de excepción que tu código captura. |
| Ya no se admiten valores mixtos de tomas en un mismo trabajo. | Envía un trabajo independiente para cada valor de toma. Consulta la sección «División de puestos de trabajo» para conocer los aspectos a tener en cuenta. |
Cambios incompatibles en el nuevo Estimador
Cambiar | Medidas en materia de migración |
|---|---|
La primitiva subyacente es ahora Executor. Tanto la interfaz de usuario de IBM Quantum Platform como job.primitive_id mostrarán executor en lugar de estimator. | Actualiza cualquier código que haga referencia a job.primitive_id. |
La nueva implementación asigna los parámetros de entrada del Estimador a los del Ejecutor, por lo que devuelve job.inputs los parámetros de entrada del Ejecutor. | Actualiza cualquier código que haga referencia a job.inputs. Consulta los datos de entrada del trabajo. |
Ahora se realizan más tareas de preprocesamiento y posprocesamiento en el lado del cliente, por lo que y estimator.run() pueden job.result() tardar más que antes. | Activa el registro de información para seguir el progreso del procesamiento en el lado del cliente. Consulta «Habilitar el registro de información ». |
Los metadatos del circuito se copian en los metadatos del resultado. Los tipos de datos permitidos en los metadatos de los resultados se limitan ahora a str, float, int, bool, así como a listas o diccionarios de dichos tipos. | Si necesitas otros tipos de datos, codifícalos primero como cadena (por ejemplo, con base64 ). |
Las clases de opciones (options_models.EstimatorOptions y demás) son ahora modelos de Pydantic en lugar de dataclasses, por lo que ya no se pueden convertir en diccionarios de Python utilizando asdict(). | En su lugar, utilice options.model_dump(). |
Las clases de opciones que antes tenían el sufijo V2 «before» (ExecutionOptionsV2 y demás) ya no lo tienen, ya que las primitivas de V1 han dejado de ser compatibles. | Elimina el sufijo V2 de estas clases de opciones: sustituye ExecutionOptionsV2 por ExecutionOptions y ResilienceOptionsV2 por ResilienceOptions. |
| Todas las opciones de entrada se devuelven en los metadatos del resultado, en lugar de un subconjunto seleccionado. | Ninguna — esto es solo a título informativo. |
Parte de la validación de datos de entrada se ha trasladado al lado del servidor y ahora genera un error RuntimeError en lugar de IBMInputValueError. | Actualiza los tipos de excepción que tu código captura. |
| Se ha eliminado el aprendizaje implícito del ruido para PEA y PEC. Se sigue admitiendo el aprendizaje del ruido de medición para TREX. | Aprende los modelos de ruido por separado y pásalos a Estimator. Consulta «Realizar un aprendizaje explícito del ruido para PEA y PEC ». |
El tipo de entrada de es ResilienceOptions.layer_noise_model diferente y puede construirse a partir de los resultados NoiseLearnerV3 de. | Consulta «Realizar un aprendizaje explícito del ruido para PEA y PEC» para saber cómo aprender los modelos de ruido utilizando y NoiseLearnerV3 pasarlos a Estimator. |
MeasureNoiseLearningOptions.shots_per_randomization ya no es compatible. | Se utiliza un único valor de disparo para todos los circuitos del trabajo, incluidos los circuitos de aprendizaje del ruido de medición. Si tienes que utilizar un valor de toma diferente, aplica TREX con el Estimador externo qiskit-mitigation . |
| Ya no se admiten valores de precisión mixta en un mismo trabajo. | Envía un trabajo independiente para cada nivel de precisión deseado. Consulta la sección «División de puestos de trabajo» para conocer los aspectos a tener en cuenta. |
Esta opción seed_estimator ya no es compatible. | Elimina cualquier options.seed_estimator asignación (si se establece, se produce un error ValidationError). No existe un equivalente del lado del cliente, por lo que los resultados ya no se pueden reproducir mediante esta semilla. |
Activar el registro de información
Dado que ahora gran parte del trabajo se realiza en el lado del cliente, resulta útil poder ver el progreso de ese
procesamiento. Activa el registro de nivel INFO para el qiskit_ibm_runtime registrador:
import logging
logger = logging.getLogger("qiskit_ibm_runtime")
logger.setLevel(logging.INFO)Realizar un aprendizaje explícito del ruido para PEA y PEC
El nuevo Estimador ya no realiza el aprendizaje implícito del ruido cuando se selecciona el método de mitigación de errores PEA o PEC Debes aprender los modelos de ruido de forma explícita y pasarlos
como parámetros. Utiliza la nueva función NoiseLearnerV3 para controlar cómo
se organizan los circuitos en capas. Toma como entrada una lista de instrucciones de circuitos en recuadros (por ejemplo,
las capas únicas).
PEA y PEC exigen ahora este patrón explícito. No te saltes el paso de aprendizaje del ruido, o tu código fallará. El aprendizaje del ruido de medición para TREX no se ve afectado y sigue funcionando como hasta ahora.
Del mismo modo, si tu código utiliza y NoiseLearner pasa el modelo de ruido resultante al Estimador del lado del servidor, debes migrar a NoiseLearnerV3. NO utilices la versión anterior NoiseLearner, ya que es incompatible con el nuevo Estimador.
Todas las opciones de aprendizaje con ruido del Estimador (LayerNoiseLearningOptions) del lado del servidor se corresponden directamente con la NoiseLearnerV3 opción (NoiseLearnerV3Options), a excepción de max_layers_to_learn. El número de capas que se van a entrenar se basa, en cambio, en el número de capas que se pasan a NoiseLearnerV3.
Por ejemplo:
Estimador del lado del servidor (con PEC activado):
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)Estimador del lado del cliente (con PEC activado):
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)Migrar de a NoiseLearner NoiseLearnerV3
NoiseLearner solo funciona con la implementación del lado del servidor de Estimator. Por lo tanto, si tu código utiliza NoiseLearner para aprender el modelo de ruido y pasárselo a Estimator, debes actualizar tu código para que utilice NoiseLearnerV3.
Consulta la guía Migrar de a NoiseLearner NoiseLearnerV3 para obtener más información.
División de puestos de trabajo
Cuando tengas que dividir un trabajo en varios porque ya no se admiten valores mixtos de «shot» o «precisión» en un mismo trabajo, ten en cuenta lo siguiente:
-
Agrupa los PUB según su valor objetivo: un trabajo por cada valor distinto, no un trabajo por cada uno PUB. La división es una reagrupación, por lo que el número total de PUB que envías no varía. Por ejemplo, dado
[[email protected], [email protected], [email protected]], envía dos trabajos:[A, C]a las yprecision=0.01[B]a lasprecision=0.05. Enviar yACcomo trabajos independientes resulta menos eficiente, ya que cada trabajo conlleva una sobrecarga fija. -
Apréndetelos una vez y utiliza los modelos de ruido en todos los trabajos divididos. Es más eficiente ejecutar un único
NoiseLearnerV3trabajo sobre la unión de todas las capas. El resultado de una tarea de «noise learner» contiene una lista de objetosNoiseLearnerV3Result, uno por cada instrucción de entrada, y sigue el mismo orden que la lista de entrada. Puedes utilizar el resultado de este trabajo de aprendizaje de ruido en todos los trabajos de división (Estimador), y los modelos de ruido correspondientes a capas que no figuren en los PUB de un trabajo de división se ignoran. -
Envía primero
Batchtodos los trabajos divididos y, a continuación, recopila sus resultados. El modo de ejecuciónBatchpermite una ejecución paralela eficiente cuando hay varios trabajos. Sin embargo,job.result()es un proceso bloqueante, por lo que llamarlo dentro del bucle de envío serializa los trabajos y anula las ventajas de utilizarBatch. Asegúrate de seguir el patrón de «enviar todo y luego recopilar» (que se muestra a continuación).
En el siguiente ejemplo, pub1 y pub2 requieren precision=0.5, mientras que requiere 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]Estructura de los datos de entrada del trabajo
La nueva implementación asigna las entradas del «Sampler» o del «Estimator» a las entradas del «Executor», por lo que job.inputs devuelve un diccionario que contiene las entradas del «Executor». Este diccionario contiene las siguientes claves:
options: La entradaExecutorOption.quantum_program: La entradaQuantumProgramschema_version: La versión del esquema utilizada en el lado del servidor.
Si tu código solía utilizar job.inputs['options'] para buscar las opciones especificadas para la tarea, ahora puedes utilizar job.result().metadata['options'] en su lugar.
Realiza pruebas localmente con un backend ficticio
Antes de pasar a la fase de hardware, puedes validar el código migrado con un Fake*
backend para detectar a tiempo cualquier error de sintaxis. Ten en cuenta los siguientes detalles sobre el modo de prueba local:
- No reproduce los resultados del hardware. La simulación de ruido local no reproduce a la perfección el ruido real del dispositivo, por lo que los resultados pueden variar. Al ejecutarlo, se comprueba que las rutas de las opciones y los tipos de valores sean correctos.
NoiseLearnerV3No dispone de modo de prueba local: solo aceptamodeun valor realBackend«»Session, «» o «»Batch, por lo que no es posible ejecutar la etapa de aprendizaje del ruido con un backend ficticio. Comprueba esa parte de tu código consultando laNoiseLearnerV3referencia de la API. Comprueba que el constructor, la forma de entradarun(instructions)y cualquier ayudante (como el ayudante de capa única) se utilicen tal y como se indica en la documentación.
Aplicar el método de Clifford al circuito para lograr una simulación local eficiente
Un backend simulado utiliza un simulador de vectores de estado (con ruido), cuyo coste crece exponencialmente con
el número de qubits y la profundidad. Por lo tanto, un circuito de carga de trabajo realista puede bloquearse o agotar la memoria. Dado que
las pruebas locales solo necesitan comprobar las rutas de las opciones (sin reproducir resultados físicos),
primero hay que reducir el circuito a uno de Clifford mediante
ConvertISAToClifford,
lo que redondea cada RZ``RZZ//RX ángulo al múltiplo más cercano de π/2. Los circuitos de Clifford
se simulan de forma eficiente (simulación de estabilizadores) independientemente de su tamaño.
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 primitiveConvertISAToClifford requiere un circuito ISA como entrada (la salida de
generate_preset_pass_manager(...).run(...) que se dirige al backend). Debes tener en cuenta las siguientes consecuencias
al crear el PUB local:
- Se omite el atributo
.layout. El circuito «cliffordizado» mantiene el mismo número de qubits, peroclifford.layoutesNone, por lo queobservable.apply_layout(clifford.layout)falla. En su lugar, define la variable observable a partir del circuito ISA anterior a Clifford :isa_obs = observable.apply_layout(isa_circuit.layout), y luego ejecuta(clifford, isa_obs). - Los parámetros se han vinculado. Al redondear los ángulos de rotación, un circuito ISA paramétrico
se convierte en un circuito de Clifford concreto, por lo que se convierte
clifford.num_parametersen0. Un objetoPUBque aún contenga una matriz de valores de parámetros no supera la coerción. Para la ejecución local, elimina el matriz de parámetros de la PUB; la ejecución en hardware conserva el circuito paramétrico original y sus valores.
Próximos pasos
- Modelo de ejecución dirigida
- Entradas y salidas del estimador
- Especificar las opciones del estimador
- Entradas y salidas del sampler
- Especificar las opciones del muestreador
- Ayuda para el aprendizaje del ruido ( NoiseLearnerV3 )
- NoiseLearnerV3 Referencia de la API
ConvertISAToCliffordpaso del transpilador- Técnicas de mitigación y supresión de errores