Saltar al contenido principal

Recursos de cómputo y gestión de recursos

Modelo de recursos y recursos clásicos

En esta sección, presentamos un marco para comprender los entornos de cómputo, desde una computadora portátil hasta los supercomputadores. Al final de esta sección, conocerás los componentes básicos de un entorno de cómputo y cómo se relacionan entre sí. Iskandar Sitdikov ofrece una visión general en el siguiente video.

Modelo de recursos

Cada entorno de cómputo clásico consta de múltiples recursos interconectados que trabajan juntos para ejecutar aplicaciones de manera eficiente. Los recursos más importantes suelen incluir:

  • CPU (Unidad Central de Procesamiento): La CPU es la unidad central de procesamiento que interpreta y ejecuta las instrucciones del programa. Realiza operaciones lógicas, aritméticas y de control, siendo esencialmente el "cerebro" del sistema.

  • Caché de CPU (L1, L2, L3): Es la memoria más rápida del sistema, integrada directamente en el núcleo de la CPU o construida muy cerca de él. Almacena pequeñas cantidades de datos e instrucciones que la CPU necesita de forma inmediata. Los diferentes niveles (L1, L2, L3) representan un compromiso: L1 es el más pequeño y rápido, L3 es el más grande y lento, pero aún así órdenes de magnitud más rápido que la RAM.

  • RAM (Memoria de Acceso Aleatorio): Memoria volátil que proporciona un gran espacio de almacenamiento temporal para instrucciones de programas y datos en uso activo. Garantiza que la CPU pueda acceder rápidamente a la información necesaria durante la ejecución, sin depender constantemente de dispositivos de almacenamiento más lentos.

  • Almacenamiento (local y en red): El almacenamiento preserva datos y software incluso cuando el sistema está apagado, proporcionando persistencia a largo plazo para grandes conjuntos de datos y aplicaciones. En centros de computación de alto rendimiento, las soluciones de almacenamiento deben procesar enormes cantidades de datos científicos o analíticos de forma rápida y fiable. El almacenamiento local incluye unidades de estado sólido (SSD) y discos duros (HDD); se prefieren los SSD por su menor latencia y mayor velocidad de transferencia. Para el procesamiento de grandes volúmenes de datos, los sistemas de archivos paralelos, el almacenamiento en red compartido y los sistemas basados en objetos permiten un acceso rápido a través de muchos nodos de cómputo, mientras que el almacenamiento en la nube y de archivo soportan la retención a largo plazo y la escalabilidad.

  • GPU (Unidad de Procesamiento Gráfico): Aunque originalmente diseñadas para la representación gráfica, las GPU modernas son potentes procesadores paralelos. Se utilizan frecuentemente para tareas que requieren muchos cálculos simultáneos, como el aprendizaje profundo, las simulaciones de física y el análisis de big data. Es importante señalar que las GPU no reemplazan a las CPU: las CPU controlan la lógica del programa a nivel superior, mientras que las GPU aceleran los pasos altamente paralelos.

  • Interconexiones/Buses: Son las vías de comunicación que conectan CPU, memoria, almacenamiento de datos y dispositivos periféricos entre sí. Los buses permiten la transferencia de datos y la coordinación entre los componentes del sistema, asegurando una comunicación fluida dentro del entorno de cómputo. En los sistemas HPC, componentes como CPU, GPU y dispositivos de almacenamiento están conectados mediante interconexiones de alta velocidad que permiten un intercambio rápido de datos. Las GPU generalmente se conectan al sistema a través de PCIe, una interfaz estándar con múltiples líneas de datos para una comunicación eficiente. Para mayor rendimiento, NVLink proporciona una conexión directa de alto ancho de banda entre GPU o entre GPU y CPU, lo que reduce la latencia y acelera las cargas de trabajo paralelas.

  • Sistema de archivos: El sistema de archivos organiza los datos en los dispositivos de almacenamiento. Crea una estructura para almacenar, recuperar y gestionar archivos, permitiendo que programas y usuarios accedan a la información de manera consistente y lógicamente organizada.

Cada tipo de recurso tiene sus propias unidades de medida de rendimiento. Por ejemplo, las CPU se evalúan típicamente por "núcleos" y "frecuencia de reloj". Al comprar una computadora portátil, estas especificaciones suelen estar incluidas en los datos técnicos. Del mismo modo, los nodos de cómputo en un centro de datos tienen asignado un número determinado de núcleos. Los entornos de cómputo que abarcan múltiples tipos de recursos (CPU, GPU e incluso QPU) se denominan entornos de cómputo heterogéneos. Estas configuraciones procesan diferentes cargas de trabajo de manera más eficiente al aprovechar las fortalezas de cada tipo de procesador; por ejemplo, las CPU para tareas generales y las GPU para el procesamiento paralelo. En el contexto de la gestión de recursos y la planificación, especialmente para entornos de cómputo heterogéneos, pueden ser necesarias unidades de medida adicionales.

Para la memoria, la unidad de medida es Mega-/Giga-/Terabytes.

Para tarjetas gráficas y otros aceleradores, la unidad de medida depende del contexto. Mientras que su capacidad de cómputo real se describe mediante métricas detalladas —número de núcleos de procesamiento, tamaño de memoria y ancho de banda de memoria—, en discusiones de alto nivel sobre recursos de clúster o planificación de trabajos, las GPU y aceleradores similares se cuantifican a nivel de dispositivo, es decir, por el número de dispositivos completos asignados (por ejemplo, tres GPU).

La red/conectividad/buses son aspectos cruciales de cualquier infraestructura de cómputo, ya que determinan la velocidad con la que se transfieren datos entre los componentes de cómputo. Desde la CPU a la caché de la CPU, a la RAM, a las tarjetas PCI y hasta los dispositivos conectados en red, todo es comunicación, y un modelo mental preciso de esto es esencial para desarrollar algoritmos altamente optimizados para HPC.

Una imagen que muestra que cada nodo de cómputo puede contener muchos tipos diferentes de recursos.

Escalamiento de recursos clásicos

La Computación de Alto Rendimiento (HPC) implica el escalamiento de estos recursos clásicos para lograr tiempos de procesamiento más rápidos o aumentar la cantidad de datos que se pueden procesar simultáneamente (por ejemplo, para ampliar el espacio de soluciones que se puede explorar). Esto se puede lograr mediante:

  • Escalamiento vertical: Aumento del rendimiento de recursos individuales, por ejemplo, mediante una CPU más potente o memoria adicional dentro de un nodo físico, donde un nodo es una unidad de un clúster de cómputo que agrupa múltiples recursos de cómputo.

  • Escalamiento horizontal: Adición de más recursos, como múltiples CPU o GPU, que trabajan juntos en un solo nodo o, más comúnmente, en múltiples nodos para permitir la computación distribuida.

Una imagen que muestra el escalamiento vertical mediante la adición de recursos como memoria dentro de un solo nodo, y el escalamiento horizontal mediante el aumento del número de nodos conectados con diferentes tipos de recursos.

Algunos de los conceptos de escalamiento de esta sección se transfieren a la siguiente sección sobre recursos de cómputo cuántico. Otros aspectos de los recursos cuánticos se cuantifican de maneras nuevas.

Preguntas de comprensión

A partir de las descripciones anteriores, deduce algunas ventajas y desventajas de los diferentes enfoques de escalamiento: ¿escalamiento vertical y horizontal?

Respuesta:

Puede haber muchas respuestas correctas. El escalamiento vertical suele ser más sencillo, especialmente si tienes cargas de trabajo predecibles con un requerimiento fijo de recursos. Sin embargo, puede ser más costoso de actualizar, ya que la unidad básica de cómputo no se puede dividir tan fácilmente como en el escalamiento horizontal. El escalamiento horizontal es más complejo de gestionar, y a veces surgen dificultades o latencias por las conexiones entre nodos. A cambio, se adapta mucho mejor a requisitos de recursos variables y es modular cuando se necesitan actualizaciones.

Nuevo tipo de recurso: QPU (Unidad de Procesamiento Cuántico)

En esta sección, presentamos un nuevo tipo de recurso —un recurso cuántico— y exploramos su definición, unidades de medida y conectividad con la infraestructura clásica.

Definición de QPU

  • Unidad de Procesamiento Cuántico (QPU): Una QPU abarca todo el hardware responsable de recibir un conjunto ejecutable de instrucciones cuánticas o un circuito cuántico y devolver un resultado preciso.

Esto significa que la QPU incluye uno o más chips cuánticos (por ejemplo, Heron), los diversos componentes adicionales en el refrigerador de dilución como los amplificadores cuánticos, la electrónica de control y la capacidad de cómputo clásico necesaria para tareas como mantener instrucciones y formas de onda en memoria, acumular resultados y la futura decodificación de corrección de errores. Aunque se requiere un refrigerador de dilución para estas tareas, lo excluimos de esta definición para permitir el caso de múltiples QPU en el mismo refrigerador.

  • Computador cuántico: Un computador cuántico consiste en la QPU más la capacidad de cómputo clásico que aloja el entorno de ejecución.

  • Entorno de ejecución: La combinación de hardware y software que permite ejecutar un programa.

Capas en circuitos cuánticos

Tanto en la computación clásica como en la cuántica, los procesos pueden ejecutarse de forma secuencial o en paralelo. Dado que los qubits tienen un espacio de estados más rico que los bits clásicos, a veces tiene sentido ejecutar múltiples puertas de un solo qubit secuencialmente en un qubit (por ejemplo, una puerta R_x seguida de una puerta R_z). Como el entrelazamiento entre qubits es esencial para la computación cuántica, un circuito cuántico frecuentemente contiene un conjunto de puertas de entrelazamiento que actúan sobre muchos qubits. Estos y otros factores hacen habitual identificar procesos que pueden ejecutarse en paralelo a nivel de operaciones individuales de puertas en un circuito cuántico. En la computación clásica, el paralelismo a nivel de bits también es posible, pero se considera menos frecuentemente a nivel de puertas; es más común describir procesos paralelos y secuenciales a una escala mayor.

En la computación cuántica, una "capa" se refiere a un conjunto de puertas que pueden ejecutarse todas simultáneamente. En muchas aplicaciones, es útil ejecutar primero un conjunto de rotaciones en todos los qubits y luego puertas de entrelazamiento entre pares de qubits. En estos contextos, se habla de una "capa de rotación" (una capa con puertas como R_x, R_y y/o R_z) y una "capa de entrelazamiento" (por ejemplo, con puertas CNOT). El número de capas en un circuito es la "profundidad del circuito", una medida importante ya que una mayor profundidad implica más capas de ruido y errores acumulados.

Las capas de puertas son difíciles de identificar visualmente cuando no están alineadas por barreras. En Qiskit, una barrera sirve como instrucción en circuitos cuánticos que actúa tanto como separador visual como restricción de compilación. Al dibujar y ejecutar el circuito, ninguna puerta se desplaza más allá de la barrera. Esto es importante en contextos como el Dynamical Decoupling, donde se implementan intencionalmente puertas que se simplifican a la identidad para suprimir ciertos tipos de errores. Puedes encontrar más información sobre el Dynamical Decoupling en esta guía. Para el efecto visual de las barreras, compara estas dos imágenes del mismo circuito: la primera sin barreras y la segunda con barreras para forzar la alineación de las capas.

Circuito cuántico de cuatro qubits sin barreras para alinear las capas; las puertas aparecen algo desordenadas en su alineación.

Circuito cuántico de cuatro qubits con barreras que fuerzan la alineación de las capas. Contar las capas es ahora mucho más fácil.

Estos son los mismos circuitos con el mismo número de capas. Sin embargo, en el segundo, la alineación facilita ver que el circuito contiene:

  • Dos capas de rotación: una alrededor del eje Y por π/5\pi/5, una alrededor del eje Z por π/4\pi/4.
  • Tres capas de entrelazamiento. Ten en cuenta que se puede contar cada CNOT como su propia "capa", ya que los CNOT no pueden reordenarse sin cambiar la operación lógica.
  • Dos capas de rotación más: una alrededor del eje Y por π/3\pi/3, una alrededor del eje Z por π/2\pi/2.
  • Dos capas de entrelazamiento más. Esta vez, la primera capa se ha paralelizado un poco más que en el primer grupo de capas de entrelazamiento.

La profundidad de cada circuito es 9.

Unidades de medida

En la computación cuántica, las capacidades de un sistema cuántico se evalúan típicamente mediante tres métricas de rendimiento esenciales: escala, calidad y velocidad. Estas métricas no solo describen el potencial computacional de un dispositivo cuántico, sino que también proporcionan información sobre cómo se gestionan y planifican los recursos en la práctica.

  • La escala se refiere al número de bits cuánticos (qubits) en el sistema e indica cuánta información cuántica puede contener el dispositivo. En la gestión de recursos, esto influye directamente en el ancho del circuito: el número de qubits necesarios para una tarea cuántica determinada. Una unidad cuántica debe disponer de suficientes qubits para soportar la tarea asignada.

  • La calidad describe cuán precisamente se ejecutan las operaciones cuánticas. A menudo se cuantifica mediante la fidelidad de capa (Layer Fidelity), que mide la precisión al ejecutar una capa completa de puertas cuánticas sobre todos los qubits. Desde la perspectiva de planificación, una mayor fidelidad permite la ejecución fiable de circuitos más profundos, lo que influye en la necesidad de mitigación de errores o descomposición de tareas.

  • La velocidad se mide mediante CLOPS (Operaciones de Capa de Circuito por Segundo) e indica cuántas capas de operaciones cuánticas puede ejecutar el sistema por segundo. Esto afecta el rendimiento y la latencia en la ejecución de tareas y ayuda a determinar qué tan rápido una unidad cuántica puede completar una carga de trabajo determinada. Esta velocidad es particularmente importante en un computador cuántico, ya que los qubits se ven más afectados por el ruido y los errores que sus contrapartes clásicas. El período durante el cual pueden mantener su información cuántica de manera útil se describe mediante el tiempo de coherencia y es típicamente de aproximadamente 200–300 μs\mu\text{s} para los procesadores Heron-r3.

Diferencias entre métricas cuánticas y clásicas

Puedes considerar CLOPS como un equivalente cuántico aproximado de FLOPS, pero con algunas diferencias importantes. CLOPS mide la velocidad a la que un procesador cuántico puede ejecutar circuitos cuánticos, específicamente capas de operaciones dentro de los circuitos, incluyendo tanto los cálculos cuánticos como los cálculos clásicos necesarios al ejecutar circuitos. Fue desarrollado por IBM Quantum como una medida holística de la velocidad de ejecución de un computador cuántico e incluye el tiempo de ejecución cuántica así como el procesamiento clásico en tiempo real para actualizaciones de circuitos, a diferencia de FLOPS, que mide puramente la capacidad de aritmética de punto flotante de los procesadores clásicos.

CLOPS proporciona una métrica de rendimiento medible que puede evaluarse en hardware existente. IBM Quantum ha utilizado CLOPS para comparar diferentes procesadores cuánticos; los valores se pueden encontrar en la página Compute resources de IBM Quantum Platform. Los valores de CLOPS dependen de las capacidades del hardware, las velocidades de las puertas, la velocidad de procesamiento clásico y su interacción.

El número de qubits es un número fijo para una QPU dada. CLOPS y la calidad dependen de la calibración y el mantenimiento regular, y pueden variar ligeramente con el tiempo, incluso para una sola QPU.

En conjunto, estas métricas guían la asignación y planificación de sistemas cuánticos. En muchos casos, el sistema cuántico completo se trata como una sola unidad. Sin embargo, si una tarea excede la capacidad de una unidad —ya sea en número de qubits, profundidad de circuito o velocidad de ejecución—, se pueden emplear técnicas como el Circuit Cutting/Knitting. El Circuit Cutting se refiere al proceso de dividir grandes tareas cuánticas en subtareas más pequeñas y manejables que pueden distribuirse entre múltiples chips cuánticos para permitir cálculos cuánticos escalables a pesar de las limitaciones del hardware. El Circuit Knitting se refiere al proceso posterior: el paso de posprocesamiento clásico que recompone los resultados de los subcircuitos más pequeños.

Los computadores cuánticos no tienen memoria tradicional en el sentido de almacenamiento persistente y direccionable como la RAM o la memoria de GPU. Los recursos de cómputo clásicos tienen bits discretos almacenados en memoria, por lo que los datos pueden guardarse, recuperarse y reutilizarse durante el cálculo. Los recursos cuánticos utilizan qubits, que no almacenan memoria en el sentido clásico. En cambio, los qubits existen en estados cuánticos que representan superposiciones de 0 y 1 simultáneamente, lo que permite un paralelismo exponencial en el espacio de estados. Sin embargo, los estados de los qubits son frágiles y no pueden clonarse ni leerse de manera determinista en pasos intermedios sin colapsar el estado cuántico, por lo que no existe un comportamiento similar a la memoria persistente durante el cálculo. Los qubits deben mantenerse en un estado coherente durante toda la ejecución, y la "memoria" es esencialmente el propio estado cuántico. La memoria clásica solo puede utilizarse junto a un procesador cuántico, no como memoria cuántica interna. Esto tiene implicaciones significativas: los recursos de cómputo clásicos pueden reutilizar y almacenar libremente resultados intermedios; los recursos cuánticos no pueden hacerlo sin realizar mediciones que perturban el cálculo.

Conectividad con la infraestructura clásica

Las QPU pueden conectarse a la infraestructura clásica a través de redes y diversas interfaces de programación de aplicaciones (API) que permiten a los desarrolladores de software interactuar programáticamente con las QPU. Estas API generalmente están ocultas detrás de kits de desarrollo de software (SDK) y bibliotecas (como Qiskit) y se ponen a disposición de los científicos computacionales en forma de abstracciones de programación (como los Qiskit Primitives, de los que hablaremos en el Capítulo 3: Modelos de programación).

Vale la pena distinguir entre la integración estrecha y la integración flexible de recursos cuánticos y clásicos. Actualmente, las QPU no se encuentran en el mismo nodo que los recursos de cómputo clásicos. De hecho, las QPU están actualmente conectadas a través de la red, no mediante PCIe. Esto podría cambiar en el futuro, pero existen desafíos técnicos relacionados con las diferentes condiciones ambientales óptimas para las QPU y los recursos de cómputo clásicos.

Escalamiento de recursos cuánticos

El escalamiento de recursos cuánticos también se puede clasificar en escalamiento vertical y horizontal.

  • El escalamiento vertical sería aumentar el número de qubits por chip o mejorar la fidelidad de los dispositivos.
  • El escalamiento horizontal sería conectar chips con acopladores o mediante interconexiones clásicas.

Una imagen que muestra el escalamiento vertical de recursos cuánticos como más qubits en un chip, y el escalamiento horizontal como la conexión de muchos chips con acopladores.

Preguntas de comprensión

¿Cuáles son los equivalentes cuánticos de (a) los bits de información clásicos y (b) la velocidad del procesador?

Respuesta:

(a) Bits cuánticos o qubits: unidades de información que, a diferencia de sus contrapartes clásicas (que solo pueden tomar el estado 0 o 1), pueden estar simultáneamente en una superposición de 0 y 1.

(b) Operaciones de Capa de Circuito por Segundo o CLOPS: el número de operaciones secuenciales que la QPU puede ejecutar por segundo, incluyendo algunas interfaces con recursos de cómputo clásicos, como la carga de parámetros del circuito.

Gestión de recursos

Tanto los recursos HPC como los cuánticos son valiosos y complejos; deben gestionarse cuidadosamente. En esta sección, explicamos cómo se gestionan los recursos para los programas de los usuarios. La gestión de recursos en infraestructuras de cómputo se refiere al proceso de (1) planificación, (2) asignación y (3) control/gestión del uso de recursos de cómputo como CPU, memoria, almacenamiento de datos y ancho de banda de red, para garantizar un uso eficiente y efectivo de los recursos.

Planificación – Estimación de recursos

Cada programa consume recursos, y estimar la necesidad de recursos requeridos es crucial para una gestión eficiente de los mismos. Esto incluye la estimación de los requisitos de CPU, memoria y otros recursos para ejecutar un programa. Lo mismo aplica para los recursos cuánticos. Sin embargo, los recursos cuánticos existen en una escala completamente diferente. Los procesadores cuánticos IBM Quantum® Heron-r3 tienen 156 qubits, comparados con los miles de millones de bits clásicos en una computadora portátil común. El tiempo y el costo también deben considerarse. Actualmente, IBM Quantum ofrece un plan gratuito, el Open Plan, que permite a los usuarios explorar la computación cuántica con 10 minutos de tiempo de QPU por mes. Algunas organizaciones de investigación necesitan tanto tiempo de QPU que tienen un computador cuántico dedicado de IBM instalado en sus instalaciones.

Un paso en la estimación de recursos que es único para la computación cuántica es la profundidad del circuito. Como se menciónó anteriormente, cada puerta cuántica y cada tiempo de espera entre operaciones introduce ruido y una cierta probabilidad de error. Cuanto más profundo sea el circuito cuántico, mayor será el ruido. Hay dos sutilezas: las puertas de dos qubits tienen tasas de error mucho mayores que las puertas de un solo qubit, por lo que a menudo se puede ignorar la profundidad de un solo qubit. Además, no todos los qubits en un chip cuántico están directamente conectados entre sí. A veces es necesario intercambiar información de qubit a qubit para poder realizar los entrelazamientos requeridos, y este proceso de intercambio en sí requiere puertas de dos qubits. Este intercambio se realiza en un proceso llamado "transpilación", un proceso complejo que también sirve para otros propósitos; esto se abordará con más detalle en la próxima lección. La cantidad limitante relevante es, por lo tanto, la profundidad transpilada de dos qubits. La profundidad máxima exacta a la que se pueden obtener resultados de alta precisión depende del circuito. Sin embargo, con las técnicas modernas de mitigación de errores, se pueden lograr resultados de alta precisión con profundidades transpiladas de dos qubits de 80 o más.

Asignación – Planificación de trabajos (Scheduling)

El scheduling es el proceso de asignación de recursos a programas y la gestión de su ejecución. Esto incluye:

  • Envío de trabajos: El proceso mediante el cual un usuario envía una solicitud (trabajo) al sistema HPC, especificando qué trabajo de cómputo y qué recursos se necesitan para la ejecución.
  • Asignación de recursos: La asignación de recursos disponibles del sistema HPC (como nodos, CPU, memoria) a un trabajo enviado según sus requisitos.
  • Ejecución de trabajos: La ejecución real de las tareas de cómputo definidas por el trabajo en los recursos HPC asignados.

Para los computadores cuánticos, existen equivalentes de todos estos procesos.

  • Los trabajos se envían por el usuario a través de Qiskit Runtime, típicamente usando un primitivo de Qiskit Runtime como Sampler, Estimator u otros.
  • El usuario selecciona de una lista de backends a los que tiene acceso. La lista completa de backends disponibles se encuentra en la página Compute resources de IBM Quantum Platform. Generalmente se utiliza simplemente el computador cuántico menos ocupado. Sin embargo, hay casos en los que puede ser importante usar uno específico, por ejemplo, por consideraciones de diseño del dispositivo, reproducción de cálculos anteriores, etc.
  • La ejecución de trabajos cuánticos es similar al caso HPC. Aunque ya se han expuesto algunas diferencias, vale la pena repetir algunas aquí. Las QPU generalmente no se encuentran en el mismo nodo que los recursos de cómputo clásicos, sino que están conectadas a través de una red. Esto puede tener implicaciones para el scheduling. Además, los computadores cuánticos pueden tener tiempos de espera en cola considerables, que varían y dificultan una gestión precisa del tiempo. Esta situación puede ser diferente para sistemas dedicados; depende de la gestión interna del computador cuántico.

Control/Gestión – Gestión de cargas de trabajo

La gestión de cargas de trabajo, también llamada orquestación, es el proceso de gestionar múltiples programas y sus requisitos de recursos. Esto incluye:

  • Aprovisionamiento de recursos: El proceso de preparación y puesta a disposición de recursos HPC para su uso por los trabajos, incluyendo la configuración de hardware y software. Como veremos más adelante, las QPU son recursos de cómputo que pueden aprovisionarse de manera similar a los recursos HPC clásicos, con las restricciones de la sección anterior.
  • Planificación de trabajos (Job Scheduling): La actividad del software de planificación que decide qué trabajos se ejecutan, cuándo y en qué recursos, gestionando prioridades y colas para utilizar el sistema HPC de manera eficiente. Aunque esta declaración de alto nivel se aplica a los recursos cuánticos, el control sobre el timing puede ser menos preciso que con otros recursos.

Una imagen que muestra cargas de trabajo (representadas como cajas) organizadas y dispuestas para encajar óptimamente en una cuadrícula bidimensional, con un eje para el tiempo y el otro para los recursos. Ejemplo:

Consideremos una tarea conocida como contexto para comprender la gestión de recursos: la búsqueda de los factores primos de números grandes. Supongamos además que el algoritmo utilizado se basa en la verificación bruta de cada posible divisor. Aunque a menudo este no es el método más eficiente, es fácil entender cómo podría gestionarse la carga de trabajo.

Planificación – Estimación de recursos

  • Estima cuánto tiempo de CPU y memoria podría necesitar la factorización en primos.
  • Planifica la paralelización de tu tarea: ¿cuántas CPU/núcleos vas a utilizar?

Asignación – Scheduling

  • En el envío del trabajo, el scheduler asigna núcleos de CPU y memoria a la tarea de factorización en primos. Por ejemplo, podría asignar todos los divisores potenciales que terminan en los dígitos 1, 3, 7, 9 a cada uno de cuatro núcleos.
  • Ejecución del trabajo: El algoritmo de factorización en primos se ejecuta, realizando divisiones u otros pasos de factorización en los recursos asignados hasta que la tarea se completa.

Control/Gestión – Gestión de cargas de trabajo

  • El sistema orquesta el orden y el timing de los trabajos de factorización en primos para optimizar el rendimiento.
  • El caso más simple imaginable es que uno de los núcleos encuentre el factor primo buscado. Esto debería detener el cálculo en los otros núcleos para que puedan utilizarse para la siguiente tarea.

Los entornos de computación de alto rendimiento utilizan software especializado para llevar a cabo estos pasos y gestionar los recursos. En la siguiente sección, conoceremos un sistema de gestión de recursos ampliamente utilizado: Slurm.

Ejemplo con recursos cuánticos:

Un flujo de trabajo que será tema de otras lecciones en este curso es la determinación de estados fundamentales y energías químicas mediante Sample-Based Quantum Diagonalization (SQD). Esto se trata con más detalle en la Lección 4; también puedes visitar este curso sobre SQD y métodos relacionados en IBM Quantum Learning. Todo lo que necesitamos saber para esta discusión es que el flujo de trabajo incluye:

  • Preparación de un circuito cuántico
  • Medición del circuito cuántico
  • Uso de los resultados de la medición para proyectar el problema en un subespacio útil
  • Diagonalización de una matriz más pequeña y proyectada con recursos de cómputo clásicos
  • Iteración, ya sea para garantizar la autoconsistencia mediante consideraciones como la conservación de la carga, y posibles iteraciones del circuito cuántico si tiene parámetros variacionales.

Planificación – Estimación de recursos

  • Asigna los orbitales electrónicos a qubits para determinar el número de qubits necesarios.
  • Combina el hamiltoniano mapeado del sistema y el estado (posiblemente variacional) en un circuito cuántico y verifica la profundidad transpilada de dos qubits. Asegúrate de que tenga sentido.
  • Estima el tamaño del subespacio en el que proyectarás; a partir de esto, estima cuánto tiempo de CPU y memoria podría necesitar la diagonalización.
  • Planifica la paralelización de tu tarea: ¿cuántas CPU/núcleos vas a utilizar?

Asignación – Scheduling

  • El usuario selecciona la QPU; el proceso de transpilación asigna automáticamente los qubits de tu circuito cuántico abstracto a qubits físicos en la QPU. Esto es importante, ya que el circuito abstracto puede asumir una conectividad directa que no está presente en el chip, entre otras cosas.
  • Al enviar el trabajo a través de Qiskit Runtime, el trabajo entra en la cola de la QPU seleccionada. El usuario no tiene control sobre el tiempo de espera en cola, aunque esto puede ser diferente para sistemas dedicados.
  • Los recursos de cómputo clásicos esperan los resultados cuánticos.
  • Se envía un trabajo de diagonalización a los recursos HPC; al enviar el trabajo, el scheduler asigna núcleos de CPU y memoria a la tarea de diagonalización.
  • Ejecución del trabajo: El algoritmo de diagonalización se ejecuta y diagonaliza la matriz proyectada más pequeña hasta que la tarea se completa.

Control/Gestión – Gestión de cargas de trabajo

  • El sistema orquesta el orden y el timing de los pasos cuánticos y clásicos de principio a fin. Por ejemplo, si la matriz proyectada se ha diagonalizado y se ha obtenido una energía del estado fundamental, el flujo de trabajo puede volver a un nuevo circuito cuántico (con un nuevo parámetro variacional) dependiendo de los criterios de convergencia.
  • Si los criterios de convergencia se cumplen con la energía del estado fundamental, el cálculo se detiene en todos los núcleos.

Los entornos de computación de alto rendimiento utilizan software especializado para llevar a cabo estos pasos y gestionar los recursos. En la siguiente sección, conoceremos un sistema de gestión de recursos ampliamente utilizado: Slurm. Es importante señalar que Slurm no proporciona herramientas para todos los pasos descritos anteriormente. Slurm no ofrece soporte para la planificación de trabajos ni para la gestión detallada de cargas de trabajo como la comunicación entre componentes de cargas de trabajo. Esto encaja bien con el estado actual de la computación cuántica en HPC, ya que las QPU típicamente son accesibles a través de la red.

Preguntas de comprensión

Supón que estás intentando buscar en una base de datos no ordenada para encontrar un elemento que llamaremos "objetivo". Asigna cada una de las siguientes acciones a la fase correspondiente de la gestión de recursos: (a) Estimación del tamaño de la base de datos y del tiempo necesario para verificar cada elemento (b) Asegurarse de que encontrar el objetivo en una GPU detenga el proceso en otras GPU para liberarlas para el siguiente problema. (c) División del espacio de búsqueda en regiones para cada una de tus (digamos 10) GPU

Respuesta:

(a) Planificación (b) Control/Gestión (c) Asignación/Scheduling,

Software: Slurm

En esta sección, aplicamos los conceptos aprendidos en este capítulo para utilizar en la práctica el popular sistema de gestión de recursos Slurm.

Introducción a Slurm

Slurm es un sistema de gestión de recursos de código abierto ampliamente utilizado en entornos de computación de alto rendimiento. Proporciona un conjunto completo de herramientas para la gestión de recursos, la planificación de trabajos y la supervisión del rendimiento del sistema.

Cubriremos los conceptos básicos del uso de Slurm, incluyendo:

  • Envío de trabajos
  • Asignación de recursos
  • Supervisión de trabajos

Dado que es realmente difícil proporcionar recursos HPC a cada estudiante de este curso, hacemos un poco de trampa y te proporcionamos un repositorio con imágenes Docker que imitan un clúster HPC real con Slurm a pequeña escala. Esto nos ayuda a practicar los conceptos aprendidos en entornos seguros y reproducibles.

Ten en cuenta que actualmente todos los recursos cuánticos y clásicos se asignan durante toda la duración del experimento. No existe actualmente una asignación entrelazada de recursos mixtos. Una última advertencia es que, incluso después de iniciar el trabajo, el sistema cuántico no se controla directamente como lo esperaría un usuario HPC experimentado. El trabajo se inicia en cualquier nodo x86 que ejecute el servicio Qiskit Runtime, y este servicio Runtime se conecta a otro scheduler sobre el cual el usuario no tiene control directo. Este flujo de trabajo y problemas relacionados pueden ser familiares para los usuarios HPC que buscaron acceso exclusivo temprano a nodos GPU (el uso original de gres).

Instrucciones de instalación y descripción general de la configuración

Para practicar la combinación de recursos cuánticos y HPC, necesitas tener acceso a un entorno HPC real o simular un entorno HPC en tu máquina local. Puedes encontrar instrucciones de instalación para la configuración local con Docker en este repositorio. Las instrucciones hacen referencia a ayuda para configurar una cuenta de IBM Cloud® e instalar el plugin SPANK para QRMI. También en este repositorio se encuentran varios archivos Python para probar tu entorno.

Después de completar la instalación, verificamos los recursos de cómputo de Slurm en tu terminal con el siguiente comando. Si la instalación fue exitosa, deberías poder confirmar un total de tres nodos virtuales.

$ sinfo

PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
normal up 5-00:00:00 2 idle c[1-2]
quantum* up infinite 1 idle q1
$ scontrol show node

NodeNAME=q1 Arch=x86_64 CoresPerSocket=1
CPUAlloc=0 CPUTot=1 CPULoad=0.34
AvailableFeatures=(null)
ActiveFeatures=(null)
Gres=qpu:1
NodeAddr=q1 NodeHostName=q1 Version=21.08.6
...

Tenemos dos particiones o grupos de nodos: normal y quantum. La partición normal consiste en nodos que solo tienen acceso a recursos clásicos. La partición quantum tiene acceso a recursos cuánticos. Puedes ver los detalles de cada nodo ejecutando scontrol show nodes.

Ejecuta un ejemplo sencillo "Hello World" en Slurm

Primero, ejecutemos un ejemplo clásico sencillo de hello world con Slurm. Usaremos Python para los ejemplos. Creemos hello_world.py, que se explica por sí solo.

$ vim hello_world.py

import time
time.sleep(10)
print("Hello, World!")
~

Ahora debemos indicar al gestor de recursos qué recursos necesitamos para ejecutar este programa. Slurm ofrece una forma de especificar todos los metadatos del trabajo a través de un script de envío, que es simplemente un script de shell con anotaciones específicas de Slurm. Estas anotaciones te permiten especificar requisitos de recursos, parámetros de planificación y más. Creemos un script de shell hello_world.sh para esto.

$ vim hello_world.sh

#SBATCH --job-name=hello-world
#SBATCH --output=hello-world.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=normal

srun hello_world.py
~

Veamos el archivo de envío y analicemos lo que está pasando.

Las directivas #SBATCH son anotaciones específicas que indican los requisitos que tenemos para la ejecución del programa. Aquí puedes especificar la cantidad de recursos —el número de nodos, el número de tareas por nodo, el número de tareas y CPU por nodo y tarea— y otras opciones como el nombre del archivo de salida. Una lista completa de opciones está disponible en la documentación de Slurm.

Ahora es momento de ejecutar nuestro trabajo en Slurm. sbatch es un comando que acepta un archivo de envío y pone el trabajo en cola para su ejecución en Slurm.

$ sbatch hello_world.sh

Submitted batch job 63

Verifiquemos el estado de nuestro programa con el comando squeue.

$ squeue

# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_world root R 0:01 1 c1

Una vez completado el trabajo, podemos verificar el resultado en el archivo de salida.

$ cat hello_world_logs.txt
Hello, World!

Preguntas de comprensión

Dado el siguiente script de shell de Slurm: ¿Cuál es (a) el nombre del trabajo, (b) el nombre del archivo Python y (c) el nombre del archivo de salida? (d) ¿Podría este script utilizar recursos cuánticos o no?

vim hello_learner.sh

#SBATCH --job-name=hello-learner
#SBATCH --output=hello-learner.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=quantum

srun hello_learner_qm.py

Respuesta:

(a) hello-learner (b) hello-learner_qm.py (c) hello-learner.out (d) Sí, podría. Utiliza la partición quantum.

Ejecuta un ejemplo sencillo de Qiskit "Hello World" en Slurm

A continuación, intentemos utilizar también recursos cuánticos. Creemos y lancemos un programa sencillo "Hello, Qiskit" que utilice recursos cuánticos.

$ vim hello_qiskit.py

# hello_qiskit.py
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Create a new circuit with two qubits
qc = QuantumCircuit(2)

# Add a Hadamard gate to qubit 0
qc.h(0)

# Perform a controlled-X gate on qubit 1, controlled by qubit 0
qc.cx(0, 1)

observables_labels = ["IZ", "IX", "ZI", "XI", "ZZ", "XX"]
observables = [SparsePauliOp(label) for label in observables_labels]

# switch to QRMI service
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()

backend = service.backend("...")

# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)

# Construct the Estimator instance.

estimator = Estimator(mode=backend)
estimator.options.resilience_level = 1
estimator.options.default_shots = 5000

mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]

# One pub, with one circuit to run against five different observables.
job = estimator.run([(isa_circuit, mapped_observables)])

job_result = job.result()

pub_result = job.result()[0]

print("Result", pub_result)

Aquí utilizamos el Quantum Resource Management Interface (QRMI), un plugin SPANK de Slurm para el soporte de recursos y trabajos cuánticos, desarrollado conjuntamente por IBM, Pasqal, el Hartree Centre y RPI. Hemos creado un circuito Pauli-2-Design sencillo con valores iniciales aleatorios y un observable simple, y lo ejecutamos con el Estimator para obtener el valor esperado. Para ejecutarlo, necesitamos nuevamente el script de envío hello_qiskit.sh, que incluye recursos cuánticos como requisito.

$ vim hello_qiskit.sh

#SBATCH --job-name=hello-qiskit
#SBATCH --output=hello_qiskit.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=quantum
#SBATCH --gres=qpu:1

srun python /data/ch2/hello_qiskit/hello_qiskit.py
~

Veamos el archivo de envío y analicemos lo que está pasando. Tenemos una nueva opción: gres. gres es una opción de Slurm para definir recursos de cómputo adicionales. En nuestro caso, este nuevo recurso sería nuestro recurso cuántico. Dado que hemos especificado los recursos y la partición de nuestro clúster en la que los recursos cuánticos están disponibles, nuestros primitivos de Qiskit utilizarán estos recursos asignados para ejecutar la carga cuántica.

Ahora es momento de ejecutar nuestro trabajo en Slurm.

$ sbatch hello_qiskit.sh

Luego verificamos el estado de nuestro programa con el comando squeue.

$ squeue
# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_qiskit root R 0:01 1 q1

Podemos explorar los registros y resultados después de completar el trabajo.

$ cat hello_qiskit.out | grep Exp
Expectation Value: 0.8372900070983516

Resumen

Hasta ahora hemos aprendido qué son los recursos de cómputo y cómo utilizarlos para ejecutar programas en entornos heterogéneos. También hemos creado y ejecutado dos programas sencillos "Hello World": uno para un recurso clásico y otro para un recurso cuántico. Además, hemos aprendido cómo crear scripts de shell para enviar tareas y visualizar resultados.

En la siguiente lección, utilizaremos este conocimiento sobre el control de recursos para aplicar modelos de programación a los recursos que hemos adquirido durante la ejecución de trabajos.

Todo el código y los scripts de este capítulo están disponibles para ti en nuestro repositorio de GitHub.