Risorse di calcolo e gestione delle risorse
Modello di risorse e risorse classiche​
In questa sezione forniremo un framework per ragionare sugli ambienti di calcolo, applicabile sia a un laptop che scalabile fino ai supercomputer. Al termine di questa sezione, capirai i componenti fondamentali di un ambiente di calcolo e come si relazionano tra loro. Tutto questo è illustrato da Iskandar Sitdikov nel video seguente.
Modello di risorse​
Qualsiasi ambiente di calcolo classico è costruito da diverse risorse interconnesse che collaborano per eseguire le applicazioni in modo efficiente. Le risorse chiave includono tipicamente:
-
CPU (Unità di Elaborazione Centrale): La CPU è l'unità di elaborazione centrale che interpreta ed esegue le istruzioni del programma. Gestisce operazioni logiche, aritmetiche e di controllo, agendo essenzialmente come il "cervello" del sistema.
-
Cache della CPU (L1, L2, L3): È la memoria più veloce del sistema, integrata direttamente nel nucleo della CPU o molto vicina ad esso. Memorizza piccole porzioni di dati e istruzioni di cui la CPU ha bisogno immediatamente. I diversi livelli (L1, L2, L3) rappresentano un compromesso: L1 è la più piccola e veloce, mentre L3 è la più grande e lenta, ma comunque ordini di grandezza più veloce della RAM.
-
RAM (Memoria ad Accesso Casuale): Memoria volatile che fornisce un archivio temporaneo ampio per le istruzioni del programma e i dati in uso attivo. Garantisce che la CPU possa accedere rapidamente alle informazioni necessarie durante l'esecuzione, senza dipendere costantemente da dispositivi di archiviazione più lenti.
-
Archiviazione (locale e basata su rete): L'archiviazione conserva dati e software anche quando il sistema è spento, fornendo persistenza a lungo termine per grandi dataset e applicazioni. Nel calcolo ad alte prestazioni, le soluzioni di archiviazione devono gestire enormi quantità di dati scientifici o analitici con velocità e affidabilità . Lo storage locale include unità a stato solido (SSD) e dischi rigidi (HDD), con gli SSD preferiti per la loro bassa latenza e l'elevata velocità di trasferimento. Per la gestione dei dati su larga scala, i file system paralleli, lo storage di rete condiviso e i sistemi basati su oggetti consentono un accesso rapido su molti nodi di calcolo, mentre i livelli di storage cloud e archiviazione a lungo termine supportano la conservazione e la scalabilità nel tempo.
-
GPU (Unità di Elaborazione Grafica): Sebbene inizialmente progettata per il rendering grafico, le GPU moderne sono potenti processori paralleli. Sono ampiamente utilizzate per compiti che richiedono molti calcoli simultanei, come il deep learning, le simulazioni fisiche e l'analisi di grandi quantità di dati. È importante notare che le GPU non sostituiscono le CPU: le CPU gestiscono la logica del programma di livello superiore, mentre le GPU accelerano i passaggi altamente paralleli.
-
Connessioni/Bus: Sono i canali di comunicazione che collegano CPU, memoria, archiviazione e periferiche. I bus consentono il trasferimento di dati e il coordinamento tra le parti del sistema, garantendo una comunicazione fluida all'interno dell'ambiente di calcolo. Nei sistemi HPC, componenti come CPU, GPU e dispositivi di archiviazione sono collegati da interconnessioni ad alta velocità che consentono uno scambio rapido di dati. Le GPU si connettono comunemente al sistema tramite PCIe, un'interfaccia standard con più canali dati per una comunicazione efficiente. Per prestazioni più elevate, NVLink fornisce un collegamento diretto ad alta larghezza di banda tra GPU o tra GPU e CPU, riducendo la latenza e accelerando i carichi di lavoro paralleli.
-
File system: Il file system organizza i dati sui dispositivi di archiviazione. Fornisce una struttura per archiviare, recuperare e gestire i file, consentendo a programmi e utenti di accedere alle informazioni in modo coerente e logico.
Ogni tipo di risorsa ha le proprie unità di misura legate alle prestazioni. Ad esempio, le CPU sono tipicamente misurate in "core" e "velocità di clock". Quando si acquista un laptop, le sue specifiche includono solitamente il numero di core. Un concetto simile si applica ai nodi computazionali in un data center, dove ogni nodo è associato a un numero specifico di core. Gli ambienti di calcolo che includono più tipi di risorse (CPU, GPU, persino QPU) sono detti ambienti di calcolo eterogenei. Questi setup gestiscono carichi di lavoro diversi in modo più efficiente, sfruttando i punti di forza di ciascun tipo di processore. Ad esempio, le CPU vengono utilizzate per le attività generali e le GPU per l'elaborazione parallela. Nel contesto della gestione delle risorse e della pianificazione — specialmente per gli ambienti di calcolo eterogenei — potrebbero essere necessarie unità di misura aggiuntive rispetto a quelle descritte qui.
Per la memoria, l'unità di misura sarebbero i Mega/Giga/Terabyte.
Per le schede grafiche e altri acceleratori, l'unità di misura dipende dal contesto. Sebbene la loro vera capacità di calcolo sia misurata da metriche dettagliate — numero di core di elaborazione, dimensione della memoria e larghezza di banda della memoria — nelle discussioni di alto livello sulle risorse del cluster o sulla pianificazione dei job, le GPU e gli acceleratori simili possono essere quantificati a livello di dispositivo in base al numero di dispositivi interi assegnati (ad esempio, tre GPU).
Rete/connettività /bus sono aspetti cruciali di qualsiasi infrastruttura di calcolo poiché determinano la velocità di trasferimento dei dati tra i componenti. Dalla CPU alla cache della CPU, alla RAM, alle schede PCI, ai dispositivi connessi in rete: tutto è comunicazione, ed è essenziale avere un modello mentale preciso di essa per progettare algoritmi altamente ottimizzati per l'HPC.
Ridimensionamento delle risorse classiche​
Il calcolo ad alte prestazioni (HPC) consiste nel ridimensionare queste risorse classiche per ottenere tempi di elaborazione più rapidi o aumentare i dati che possono essere gestiti simultaneamente (ad esempio, per aumentare la dimensione degli spazi di soluzioni che possono essere esplorati). Ciò può essere ottenuto tramite:
-
Scaling verticale: Aumentare la potenza delle singole risorse, come l'utilizzo di una CPU più potente o l'aggiunta di più memoria all'interno di un singolo nodo fisico, dove un nodo è un'unità di un cluster di calcolo che racchiude più risorse di calcolo al suo interno.
-
Scaling orizzontale: Aggiungere più risorse, come più CPU o GPU, per collaborare su un singolo nodo o, più comunemente, su più nodi, abilitando il calcolo distribuito.
Alcuni dei concetti di scaling di questa sezione saranno applicabili alla prossima sezione sulle risorse di calcolo quantistico. Alcuni altri aspetti delle risorse quantistiche saranno quantificati in modi nuovi.
Verifica la tua comprensione​
Usa le descrizioni precedenti per dedurre alcuni vantaggi e svantaggi dei diversi approcci di scaling: verticale e orizzontale.
Risposta:
Possono esserci molte risposte corrette. Lo scaling verticale è spesso più semplice, soprattutto se hai carichi di lavoro prevedibili che richiedono una quantità fissa di risorse. Ma lo scaling verticale potrebbe essere più costoso da aggiornare, poiché l'unità fondamentale di calcolo non può essere suddivisa con la stessa facilità dello scaling orizzontale. Lo scaling orizzontale è più complesso da gestire e a volte ci sono difficoltà o latenze legate alle connessioni tra i nodi. È però molto più adattabile ai requisiti di risorse variabili ed è modulare quando sono necessari aggiornamenti.
Nuovo tipo di risorsa: QPU (Quantum Processing Unit)​
In questa sezione introdurremo un nuovo tipo di risorsa — una risorsa quantistica — e ne esploreremo la definizione, le unità di misura e la connettività con l'infrastruttura classica.
Definizione di QPU​
- Quantum processing unit (QPU): Una QPU comprende tutto l'hardware responsabile dell'accettazione di un insieme di istruzioni quantistiche eseguibili, o di un circuito quantistico, e della restituzione di una risposta accurata.
Ciò significa che la QPU include uno o più chip quantistici (ad es. Heron), i numerosi componenti aggiuntivi nel frigorifero a diluizione come gli amplificatori quantistici, l'elettronica di controllo e il calcolo classico necessario per attività come il mantenimento in memoria delle istruzioni e delle forme d'onda, l'accumulo dei risultati e la futura decodifica della correzione degli errori. Sebbene sia necessario un frigorifero a diluizione per svolgere queste attività , lo escludiamo da questa definizione per consentire il caso di più QPU nello stesso frigorifero.
-
Computer quantistico: Un computer quantistico è composto dalla QPU più il calcolo classico che ospita l'ambiente di runtime.
-
Ambiente di runtime: La combinazione di hardware e software che rende possibile l'esecuzione di un programma.
Layer nei circuiti quantistici​
Sia nel calcolo classico che in quello quantistico, i processi possono essere eseguiti in modo sequenziale o parallelo. Poiché i qubit hanno uno spazio di stato più ricco rispetto ai bit classici, a volte ha senso eseguire più gate a singolo qubit su un qubit in sequenza (come un gate R_x seguito da un gate R_z). Poiché l'entanglement tra qubit è fondamentale per il calcolo quantistico, è anche comune che un circuito quantistico abbia un insieme di gate di entanglement che agiscono su molti qubit. Questi e altri fattori rendono comune identificare processi che possono essere eseguiti in parallelo alla scala delle singole operazioni di gate in un circuito quantistico. Nel calcolo classico, il parallelismo a livello di bit è anch'esso possibile, ma è meno comunemente considerato a livello di gate; è più comune fare riferimento a processi paralleli e sequenziali su scala più ampia.
Nel calcolo quantistico, si parla di un "layer" di gate che possono essere eseguiti tutti simultaneamente. In molte applicazioni è utile eseguire un insieme di rotazioni su tutti i qubit e poi gate di entanglement tra coppie di qubit. In questi contesti, si parla di "rotation layer" (un layer di gate come R_x, R_y e/o R_z) e di "entangling layer" (come uno con gate CNOT). Il numero di layer in un circuito è la "profondità del circuito" (circuit depth), una misura importante poiché una maggiore profondità significa più layer di rumore ed errori cumulativi.
Può essere difficile identificare visivamente i layer di gate quando i layer non sono allineati usando barriere. In Qiskit, una barriera è un'istruzione nei circuiti quantistici che funge da separatore visivo e da vincolo durante la compilazione. Sia nel disegnare il circuito che nell'eseguirlo, nessun gate verrà spostato oltre la barriera. Questo può essere importante in contesti come il decoupling dinamico, in cui si implementano intenzionalmente gate che si semplificano in un'identità per sopprimere certi tipi di errore. Per saperne di più sul decoupling dinamico consulta questa guida. Per l'effetto visivo delle barriere, confronta queste due immagini dello stesso circuito, la prima senza barriere e la seconda con barriere per forzare l'allineamento dei layer.
Si tratta dello stesso circuito e hanno lo stesso numero di layer. Ma nel secondo, l'allineamento rende facile vedere che il circuito ha:
- Due rotation layer: uno attorno all'asse Y di , uno attorno all'asse Z di .
- Tre entangling layer. Nota che ciascun CNOT può essere chiamato un "layer" a sé, poiché i CNOT non possono essere riordinati per essere paralleli senza modificare l'operazione logica.
- Altri due rotation layer: uno attorno all'asse Y di , uno attorno all'asse Z di .
- Altri due entangling layer. Nota che questa volta il primo layer è stato leggermente più parallelizzato rispetto al primo insieme di entangling layer.
La profondità di ciascun circuito è 9.
Unità di misura​
Nel calcolo quantistico, le capacità di un sistema quantistico sono tipicamente valutate usando tre metriche di prestazione chiave: scala, qualità e velocità . Queste metriche non solo descrivono il potenziale computazionale di un dispositivo quantistico, ma informano anche come le risorse vengono gestite e pianificate nelle applicazioni pratiche.
-
La scala si riferisce al numero di bit quantistici (qubit) nel sistema, che rappresenta quanta informazione quantistica il dispositivo può contenere. Nella gestione delle risorse, questo impatta direttamente sulla larghezza del circuito — il numero di qubit necessari per eseguire un determinato task quantistico. Un'unità quantistica deve avere qubit sufficienti a supportare il task assegnato.
-
La qualità descrive quanto accuratamente vengono eseguite le operazioni quantistiche. È spesso quantificata dalla fedeltà di layer (layer fidelity), che misura l'accuratezza dell'esecuzione di un layer completo di gate quantistici su tutti i qubit. Dal punto di vista della pianificazione, una maggiore fedeltà consente l'esecuzione affidabile di circuiti più profondi, influenzando la necessità di mitigazione degli errori o di scomposizione dei task.
-
La velocità è misurata in CLOPS (Circuit Layer Operations Per Second), che indica quanti layer di operazioni quantistiche il sistema può eseguire al secondo. Questo influisce sul throughput e sulla latenza nell'esecuzione dei task, e aiuta a determinare quanto rapidamente un'unità quantistica può completare un dato carico di lavoro. Questa velocità è particolarmente importante su un computer quantistico, poiché i qubit subiscono rumore ed errori in misura molto maggiore rispetto alle loro controparti classiche. Il tempo per cui possono mantenere la loro informazione quantistica in modo utile è descritto dal tempo di coerenza, tipicamente dell'ordine di 200-300 per i processori Heron r3.
Differenze tra metriche quantistiche e classiche​
Potresti pensare ai CLOPS come a un analogo quantistico approssimativo dei FLOPS, ma con alcune differenze fondamentali. I CLOPS misurano la velocità con cui un processore quantistico può eseguire circuiti quantistici, in particolare i layer di operazioni all'interno dei circuiti, incluso sia il calcolo quantistico che quello classico necessario per eseguire i circuiti. Sono stati sviluppati da IBM Quantum come misura olistica della velocità di esecuzione di un computer quantistico, coprendo il tempo di esecuzione quantistico e l'elaborazione classica in tempo reale necessaria per gli aggiornamenti dei circuiti, a differenza dei FLOPS che misurano puramente la capacità aritmetica in virgola mobile nei processori classici.
I CLOPS forniscono una metrica di prestazione misurabile che può essere testata sull'hardware esistente. IBM Quantum ha usato i CLOPS per confrontare diversi processori quantistici e i valori possono essere trovati nella pagina Compute resources su IBM Quantum Platform. I valori CLOPS dipendono dalle capacità hardware, dalla velocità dei gate, dalla velocità di elaborazione classica e dalla loro integrazione.
Il numero di qubit è un numero fisso per una data QPU. I CLOPS e la qualità dipendono dalla calibrazione e dalla manutenzione regolare e possono variare leggermente nel tempo, anche per una singola QPU.
Insieme, queste metriche guidano come i sistemi quantistici vengono allocati e pianificati. In molti casi, l'intero sistema quantistico viene trattato come un'unica unità . Tuttavia, quando un task supera la capacità di un'unità — sia in termini di numero di qubit, di profondità del circuito o di velocità di esecuzione — è possibile utilizzare tecniche come il circuit cutting/knitting. Il circuit cutting è il processo di suddivisione di grandi task quantistici in sottotask più piccoli e gestibili che possono essere distribuiti su più chip quantistici, consentendo un calcolo quantistico scalabile nonostante le limitazioni hardware. Il circuit knitting si riferisce al processo che segue il circuit cutting — la fase di post-elaborazione classica che "unisce" o combina i risultati dei sottocircuiti più piccoli.
I computer quantistici non hanno memoria tradizionale, nel senso di un'archiviazione persistente e indirizzabile come la RAM o la memoria GPU. Le risorse di calcolo classiche hanno bit discreti memorizzati nella memoria, consentendo il salvataggio, il recupero e il riutilizzo dei dati durante il calcolo. Le risorse quantistiche utilizzano qubit che non memorizzano dati nel senso classico del termine. I qubit esistono invece in stati quantistici che rappresentano sovrapposizioni di 0 e 1 simultaneamente, consentendo un parallelismo esponenziale nello spazio degli stati. Tuttavia, gli stati dei qubit sono fragili e non possono essere clonati o letti deterministicamente nei passaggi intermedi senza collassare lo stato quantistico, quindi un comportamento simile alla memoria persistente durante il calcolo non esiste. I qubit devono essere mantenuti in uno stato coerente durante tutta l'esecuzione, e la "memoria" è essenzialmente lo stato quantistico stesso. La memoria classica può essere utilizzata solo a fianco di un processore quantistico, non come memoria quantistica interna. Questo ha implicazioni significative: le risorse di calcolo classiche possono riutilizzare e memorizzare liberamente i risultati intermedi; le risorse quantistiche non possono farlo senza misurazioni che perturbano il calcolo.
Connettività con l'infrastruttura classica​
Le QPU possono essere connesse all'infrastruttura classica attraverso reti e varie interfacce di programmazione delle applicazioni (API) che consentono agli sviluppatori software di interagire con le QPU in modo programmatico. Queste API sono solitamente nascoste dietro kit di sviluppo software (SDK) e librerie (come Qiskit) ed esposte agli scienziati computazionali sotto forma di astrazioni di programmazione (come i Qiskit Primitives, di cui parleremo nel Capitolo 3: modelli di programmazione).
Vale la pena distinguere tra integrazione stretta e lassa di risorse quantistiche e classiche. Attualmente le QPU non si trovano sullo stesso nodo delle risorse di calcolo classiche. Anzi, le QPU non sono attualmente collegate tramite PCIe, ma tramite la rete. Questo potrebbe cambiare in futuro, ma ci sono sfide ingegneristiche legate alle condizioni ambientali ottimali per le QPU e le risorse di calcolo classiche.
Scaling delle risorse quantistiche​
Anche lo scaling delle risorse quantistiche può essere classificato in verticale e orizzontale.
- Lo scaling verticale consisterebbe nell'aumentare il numero di qubit per chip o nel migliorare la fedeltà dei dispositivi.
- Lo scaling orizzontale consisterebbe nel connettere chip con accoppiatori o con interconnessioni classiche.
Verifica la tua comprensione​
Quali sono gli analoghi quantistici classici di (a) bit di informazione e (b) velocità del processore?
Risposta:
(a) Bit quantistici o qubit — unità di informazione che, a differenza delle loro controparti classiche (che possono assumere solo lo stato 0 o 1), possono trovarsi in una sovrapposizione di 0 e 1 simultaneamente.
(b) Operazioni di layer di circuito al secondo o CLOPS — numero di operazioni sequenziali che la QPU può eseguire ogni secondo, inclusa una certa interfaccia con le risorse di calcolo classiche, come il caricamento dei parametri dal circuito.
Gestione delle risorse​
Sia le risorse HPC che quelle quantistiche sono preziose e complesse; devono essere gestite con cura. In questa sezione spiegheremo come gestire le risorse per i programmi utente. La gestione delle risorse nell'infrastruttura di calcolo si riferisce al processo di (1) pianificazione, (2) allocazione e (3) controllo/gestione dell'uso delle risorse di calcolo come CPU, memoria, archiviazione e larghezza di banda di rete, per garantire un utilizzo efficiente ed efficace delle risorse.
Pianificazione — stima delle risorse​
Qualsiasi programma consuma risorse, e stimare le risorse necessarie è fondamentale per una gestione efficiente. Ciò include la stima della quantità di CPU, memoria e altre risorse necessarie per eseguire un programma. Lo stesso vale per le risorse quantistiche. Tuttavia, le risorse quantistiche esistono su una scala completamente diversa. I processori quantistici IBM Quantum® Heron r3 hanno 156 qubit, rispetto ai molti miliardi di bit classici su un comune laptop. Anche il tempo e i costi sono considerazioni da tenere in conto. Attualmente, IBM Quantum ha un piano gratuito, l'Open Plan, che consente agli utenti di esplorare il calcolo quantistico utilizzando 10 minuti di tempo QPU al mese. Alcune organizzazioni di ricerca richiedono così tanto tempo QPU da avere un computer quantistico IBM dedicato in loco.
Un passaggio nella stima delle risorse unico del calcolo quantistico è la profondità del circuito. Come accennato in precedenza, ogni gate quantistico e ogni tempo di ritardo tra le operazioni comporta rumore e una certa probabilità di errore. Più il circuito quantistico è profondo, maggiore è il rumore. Ci sono due sottigliezze in questo: i gate a due qubit hanno tassi di errore molto più elevati dei gate a singolo qubit, quindi spesso si può ignorare la profondità a singolo qubit. Inoltre, non tutti i qubit su un chip quantistico sono direttamente connessi. A volte le informazioni devono essere scambiate da qubit a qubit per eseguire gli entanglement richiesti, e questo processo di scambio richiede esso stesso gate a due qubit. Quello scambio è gestito in un processo chiamato "transpilazione", un processo complesso che serve anche ad altri scopi; questo è discusso in modo più dettagliato nella prossima lezione. La quantità limitante rilevante è quindi la profondità a due qubit transpilata. La profondità massima esatta a cui si possono ottenere risultati ad alta fedeltà dipende dal circuito. Ma sfruttando le moderne tecniche di mitigazione degli errori, è possibile ottenere risultati ad alta fedeltà con profondità a due qubit transpilate di 80 o più.
Allocazione — pianificazione dei job​
La pianificazione è il processo di allocazione delle risorse ai programmi e di gestione della loro esecuzione. Questo comporta:
- Invio del job: Il processo con cui un utente invia una richiesta (job) al sistema HPC, specificando quali lavori computazionali e risorse sono necessari per l'esecuzione.
- Allocazione delle risorse: L'assegnazione delle risorse disponibili del sistema HPC (come nodi, CPU, memoria) a un job inviato in base ai suoi requisiti.
- Esecuzione del job: L'effettiva esecuzione dei task computazionali definiti dal job sulle risorse HPC allocate.
Esistono analoghi di tutti questi processi per i computer quantistici.
- I job vengono inviati dall'utente, sfruttando Qiskit Runtime, e tipicamente utilizzando una primitiva Qiskit Runtime, come
Sampler,Estimatoro altri. - L'utente seleziona da un elenco di backend a cui ha accesso. L'elenco completo dei backend disponibili può essere visto nella pagina Compute resources su IBM Quantum Platform. È comune semplicemente utilizzare il computer quantistico meno occupato. Ma ci sono casi in cui potrebbe essere importante usarne uno specifico per considerazioni relative al layout del dispositivo, alla replica di calcoli precedenti e così via.
- L'esecuzione dei job quantistici è simile al caso HPC. Sebbene alcune differenze siano già state delineate, alcune vale la pena ripetere qui. Le QPU attualmente non sono generalmente situate sullo stesso nodo delle risorse di calcolo classiche ma sono connesse tramite una rete. Questo può avere implicazioni sulla pianificazione. Inoltre, i computer quantistici possono avere tempi di attesa in coda sostanziali, e questi tempi variano, rendendo difficile un controllo preciso dei tempi. Questa situazione può essere diversa per i sistemi dedicati; dipende dall'amministrazione interna del computer quantistico.
Controllo/Gestione — gestione del carico di lavoro​
La gestione del carico di lavoro, nota anche come orchestrazione, è il processo di gestione di più programmi e dei loro requisiti di risorse. Questo comporta:
- Provisioning delle risorse: Il processo di preparazione e messa a disposizione delle risorse HPC per i job, inclusa la configurazione hardware e software. Come vedremo in seguito, le QPU sono risorse di calcolo che possono essere provisionate in modo simile alle risorse HPC classiche, con le avvertenze della sezione precedente.
- Pianificazione dei job: L'attività del software di scheduling nel decidere quali job vengono eseguiti, quando e su quali risorse, gestendo priorità e code per utilizzare in modo efficiente il sistema HPC. Sebbene questa affermazione generale si applichi alle risorse quantistiche, potrebbe esserci meno controllo sui tempi rispetto ad altre risorse.
Esempio:
Considera un task ben noto come contesto per comprendere la gestione delle risorse: trovare i fattori primi di numeri grandi. Supponiamo inoltre che l'algoritmo utilizzato si basi sul controllo a forza bruta di ogni potenziale divisore. Sebbene questo non sia spesso il metodo più efficiente, è facile capire come il carico di lavoro potrebbe essere gestito.
Pianificazione — stima delle risorse
- Stimare quanto tempo CPU e memoria potrebbe richiedere la fattorizzazione prima.
- Pianificare la parallelizzazione del task — quante CPU/core utilizzerai?
Allocazione — pianificazione dei job
- All'invio del job, lo scheduler assegna core CPU e memoria al task di fattorizzazione prima. Ad esempio, potrebbe allocare tutti i potenziali divisori che terminano con le cifre
1, 3, 7, 9a ognuno dei quattro core, rispettivamente. - Esecuzione del job: L'algoritmo di fattorizzazione prima viene eseguito, eseguendo divisioni o altri passaggi di fattorizzazione sulle risorse allocate fino al completamento del task.
Controllo/Gestione — gestione del carico di lavoro
- Il sistema orchestra l'ordine e i tempi dei job di fattorizzazione prima per ottimizzare il throughput.
- Il caso più semplice da immaginare è che uno dei core trovi il fattore primo target. Questo dovrebbe fermare il calcolo sugli altri core in modo che possano essere usati per il task successivo.
Gli ambienti di calcolo ad alte prestazioni utilizzano software speciale per eseguire questi passaggi e gestire le risorse. Nella prossima sezione impareremo un sistema software di gestione delle risorse ampiamente adottato: Slurm.
Esempio con risorse quantistiche:
Un flusso di lavoro che sarà oggetto di altre lezioni in questo corso è la determinazione degli stati fondamentali e delle energie chimiche utilizzando la diagonalizzazione quantistica basata su campioni (SQD). Questo è trattato in modo più dettagliato nella Lezione 4, e puoi anche visitare questo corso sull'SQD e i metodi correlati su IBM Quantum Learning. Tutto ciò che dobbiamo sapere per questa discussione è che il flusso di lavoro prevede i seguenti passaggi:
- Preparare un circuito quantistico
- Misurare il circuito quantistico
- Utilizzare i risultati delle misurazioni per proiettare il problema in un sottospazio utile
- Diagonalizzare una matrice proiettata più piccola utilizzando risorse di calcolo classiche
- Iterazione, sia per garantire la coerenza interna attraverso considerazioni come la conservazione della carica, che possibili iterazioni del circuito quantistico se ha parametri variazionali.
Pianificazione — stima delle risorse
- Mappare gli orbitali elettronici sui qubit per stabilire il numero di qubit necessari.
- Combinare l'Hamiltoniano mappato del sistema e lo stato (eventualmente variazionale) in un circuito quantistico e verificare la profondità a due qubit transpilata. Assicurarsi che sia ragionevole.
- Stimare la dimensione del sottospazio in cui si proietterà ; da questo, stimare quanto tempo CPU e memoria potrebbe richiedere la diagonalizzazione.
- Pianificare la parallelizzazione del task — quante CPU/core utilizzerai?
Allocazione — pianificazione dei job
- L'utente seleziona la QPU; il processo di transpilazione mappa automaticamente i qubit nel tuo circuito quantistico astratto sui qubit fisici della QPU. Questo è importante poiché il circuito astratto può assumere una connettività diretta che non esiste sul chip, tra le altre ragioni.
- All'invio del job tramite Qiskit Runtime, il job entra nella coda per la QPU selezionata. L'utente non ha alcun controllo sul tempo di attesa in coda, anche se questo può essere diverso per i sistemi dedicati.
- Le risorse di calcolo classiche attendono i risultati quantistici.
- Un job di diagonalizzazione viene inviato alle risorse HPC; all'invio del job, lo scheduler assegna core CPU e memoria al task di diagonalizzazione.
- Esecuzione del job: L'algoritmo di diagonalizzazione viene eseguito, diagonalizzando la matrice proiettata più piccola fino al completamento del task.
Controllo/Gestione — gestione del carico di lavoro
- Il sistema orchestra l'ordine e i tempi dei passaggi quantistici e classici durante tutto il processo. Ad esempio, una volta che la matrice proiettata è stata diagonalizzata e ottenuta un'energia dello stato fondamentale, a seconda dei criteri di convergenza, il flusso di lavoro potrebbe tornare a un nuovo circuito quantistico (con un nuovo parametro variazionale).
- Quando i criteri di convergenza sono soddisfatti dall'energia dello stato fondamentale, il calcolo su tutti i core si ferma.
Gli ambienti di calcolo ad alte prestazioni utilizzano software speciale per eseguire questi passaggi e gestire le risorse. Nella prossima sezione impareremo un sistema software di gestione delle risorse ampiamente adottato: Slurm. È importante notare che Slurm non dispone di strumenti per tutti i passaggi descritti sopra. Slurm non fornisce supporto per la pianificazione dei job, né per una gestione dettagliata del carico di lavoro come la comunicazione tra i componenti del carico di lavoro. Questo è ben adatto allo stato attuale del calcolo quantistico nell'HPC, poiché le QPU sono tipicamente accessibili tramite la rete.
Verifica la tua comprensione​
Supponi di voler cercare in un database non ordinato un elemento che chiameremo 'target'. Per ciascuna delle seguenti azioni, indica a quale fase della gestione delle risorse corrisponde:
(a) Stimare la dimensione del database e il tempo necessario per controllare ogni elemento
(b) Garantire che trovare il target su una GPU fermi il processo sulle altre GPU per liberarle per il problema successivo.
(c) Suddividere lo spazio di ricerca in regioni per ciascuna delle tue (diciamo 10) GPU da cercare
Risposta:
(a) Pianificazione (b) Controllo/gestione (c) Allocazione/pianificazione
Software: Slurm​
In questa sezione applicheremo i concetti appresi in questo capitolo per esercitarci con il popolare sistema di gestione delle risorse Slurm.
Introduzione a Slurm​
Slurm è un sistema di gestione delle risorse open source ampiamente utilizzato negli ambienti di calcolo ad alte prestazioni. Fornisce un insieme completo di strumenti per gestire le risorse, pianificare i job e monitorare le prestazioni del sistema.
Tratteremo le basi dell'utilizzo di Slurm, tra cui:
- Invio dei job
- Allocazione delle risorse
- Monitoraggio dei job
Poiché è davvero difficile fornire risorse HPC a ogni studente di questo corso, ci avvaleremo di un piccolo stratagemma e ti forniremo un repository con immagini Docker che simulano un vero cluster HPC con Slurm, ma su piccola scala. Questo ci aiuterà a mettere in pratica i concetti appresi in ambienti sicuri e riproducibili.
Nota che attualmente tutte le risorse quantistiche e classiche sono allocate per la durata dell'intero esperimento. Attualmente non c'è allocazione interleaved di risorse miste. Un'ultima avvertenza è che anche una volta avviato il job, il sistema quantistico non sarà controllato direttamente come potrebbe aspettarsi un utente HPC frequente. Il job viene avviato su un nodo x86 arbitrario, che esegue il servizio Qiskit Runtime e quel servizio di runtime si connette a un altro scheduler su cui l'utente non ha controllo diretto. Questo flusso di lavoro e i problemi correlati possono essere noti agli utenti HPC che hanno avuto esperienza iniziale nel perseguire l'accesso esclusivo ai nodi GPU (l'uso originale di gres).
Istruzioni di installazione e panoramica della configurazione​
Per esercitarti a combinare risorse quantistiche e HPC, avrai bisogno di accesso a un vero ambiente HPC oppure dovrai simulare un ambiente HPC sulla tua macchina locale. Una guida all'installazione per la configurazione locale tramite Docker si trova in questo repository. La guida rimanda al supporto per configurare un account IBM Cloud® e installare il plugin SPANK per QRMI. Nello stesso repository sono presenti anche diversi file Python per testare il tuo ambiente.
Una volta completata l'installazione, utilizziamo il comando seguente per verificare la risorsa di calcolo di Slurm nel tuo terminale. Se l'installazione è avvenuta correttamente, dovresti poter confermare un totale di tre nodi virtuali.
$ 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
...
Abbiamo due partizioni o gruppi di nodi: normale e quantistica. La partizione normale è composta da nodi che hanno accesso solo alle risorse classiche. La partizione quantistica ha accesso alle risorse quantistiche. Puoi vedere i dettagli di ogni nodo eseguendo scontrol show nodes.
Esegui un semplice esempio hello world in Slurm​
Prima di tutto, eseguiamo un semplice esempio hello world classico con Slurm. Useremo Python per gli esempi. Creiamo hello_world.py, che è autoesplicativo.
$ vim hello_world.py
import time
time.sleep(10)
print("Hello, World!")
~
Ora dobbiamo indicare al resource manager di quali risorse abbiamo bisogno per eseguire questo programma. Slurm fornisce un modo per specificare tutti i metadati del job tramite uno script di invio, che è semplicemente uno script shell con annotazioni specifiche di Slurm. Queste annotazioni ti consentono di specificare i requisiti delle risorse, i parametri di pianificazione e altro ancora. Creiamo uno script shell hello_world.sh per questo.
$ 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
~
Esaminiamo il file di invio e vediamo cosa sta succedendo.
Le direttive #SBATCH sono annotazioni specifiche per indicare i requisiti dell'esecuzione del programma. Qui puoi specificare la quantità di risorse — il numero di nodi, il numero di task per nodo, il numero di task e CPU per nodo e task — e altre opzioni come il nome del file di output. Un elenco completo delle opzioni è disponibile nella documentazione di Slurm.
Ora è il momento di eseguire il nostro job Slurm. sbatch è un comando che accetta un file di invio e mette in coda il job per l'esecuzione in Slurm.
$ sbatch hello_world.sh
Submitted batch job 63
Verifichiamo lo stato del nostro programma usando il comando squeue.
$ squeue
# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_world root R 0:01 1 c1
Una volta completato il job, possiamo controllare il risultato guardando il file di output.
$ cat hello_world_logs.txt
Hello, World!
Verifica la tua comprensione​
Dato lo script shell Slurm seguente, qual è (a) il nome del job, (b) il nome del file Python e (c) il nome del file di output? (d) Infine, potrebbe usare risorse quantistiche 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
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
Risposta:
(a) hello-learner (b) hello-learner_qm.py (c) hello-learner.out (d) Sì, potrebbe. Sta usando la partizione quantistica.
Esegui un semplice esempio Qiskit hello world in Slurm​
Successivamente, proviamo a utilizzare anche le risorse quantistiche. Creiamo ed eseguiamo un semplice programma "Hello, Qiskit" che utilizza risorse quantistiche.
$ 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)
Qui utilizzeremo l'interfaccia di gestione delle risorse quantistiche (QRMI), un plugin SPANK di Slurm per il supporto delle risorse e dei job quantistici sviluppato congiuntamente da IBM, Pasqal, The Hartree Center e RPI. Abbiamo creato un semplice circuito pauli-2-design con valori iniziali casuali e un semplice osservabile, e lo eseguiremo usando Estimator per ottenere il valore di aspettazione. Per eseguirlo avremo di nuovo bisogno dello script di invio hello_qiskit.sh, che avrà le risorse quantistiche come 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
~
Esaminiamo il file di invio e vediamo cosa sta succedendo. Abbiamo una nuova opzione, che è gres. gres è un'opzione di Slurm per definire risorse computazionali aggiuntive. Nel nostro caso questa nuova risorsa sarebbe la nostra risorsa quantistica. Poiché abbiamo specificato le risorse e la partizione del nostro cluster dove sono disponibili le risorse quantistiche, le nostre primitive Qiskit utilizzeranno queste risorse allocate per eseguire il payload quantistico.
Ora è il momento di eseguire il nostro job Slurm.
$ sbatch hello_qiskit.sh
Quindi, verifichiamo lo stato del nostro programma usando il comando squeue.
$ squeue
# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_qiskit root R 0:01 1 q1
Possiamo esplorare log e risultati dopo che il job è terminato.
$ cat hello_qiskit.out | grep Exp
Expectation Value: 0.8372900070983516
Sommario​
Finora abbiamo imparato cosa sono le risorse computazionali e come usarle per eseguire programmi in ambienti eterogenei. Abbiamo anche creato ed eseguito due semplici programmi 'Hello World': uno per la risorsa classica e l'altro per una risorsa quantistica, e abbiamo imparato come creare script shell per inviare task e visualizzare i risultati.
Nella lezione seguente, costruiremo su questa conoscenza del controllo delle risorse per applicare modelli di programmazione alle risorse acquisite durante l'esecuzione del job.
Tutto il codice e gli script utilizzati in questo capitolo sono disponibili nel nostro repository GitHub.