Gérer les ressources informatiques et de données d' Qiskit Serverless
Le code de cette page a été développé en tenant compte des exigences suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.0.0 qiskit-ibm-runtime~=0.37.0 qiskit-serverless~=0.22.0
Qiskit Serverless est en cours de mise à niveau et ses fonctionnalités évoluent rapidement. Pendant cette phase de développement, vous trouverez les notes de mise à jour et la documentation la plus récente sur la page Qiskit ServerlessGitHub.
Avec Qiskit Serverless, vous pouvez gérer le calcul et les données à travers votre modèle Qiskit, y compris les CPU, QPU et autres accélérateurs de calcul.
Définir des statuts détaillés
Les charges de travail sans serveur comportent plusieurs étapes dans un flux de travail. Par défaut, les statuts suivants peuvent être consultés à l'adresse job.status():
- **
QUEUED**la charge de travail est en file d'attente pour les ressources classiques - **
INITIALIZING**la charge de travail : la charge de travail est mise en place RUNNING: la charge de travail s'exécute actuellement sur des ressources classiquesDONE: la charge de travail s'est achevée avec succès
Vous pouvez également définir des statuts personnalisés qui décrivent plus précisément l'étape spécifique du flux de travail, comme suit.
Si vous exécutez les cellules de code localement dans un notebook, vous verrez apparaître la commande %%writefile magique. L'exécution de cellules à l'aide de cette commande spéciale les enregistre sur le disque au lieu de les exécuter.
# If you include the preceding `%%writefile` command (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
from qiskit_serverless import update_status, Job
# # If your function has a mapping stage, particularly application functions, you can set the status
# to "RUNNING: MAPPING" as follows:
update_status(Job.MAPPING)
# # While handling transpilation, error suppression, and so forth, you can set the status to
# "RUNNING: OPTIMIZING_FOR_HARDWARE":
update_status(Job.OPTIMIZING_HARDWARE)
# # After you submit jobs to IBM Quantum Compute Service, the underlying quantum job will be queued. You can set
# status to "RUNNING: WAITING_FOR_QPU":
update_status(Job.WAITING_QPU)
# # When the Quantum Compute job starts running on the QPU, set the following status
# "RUNNING: EXECUTING_QPU":
update_status(Job.EXECUTING_QPU)
## Once QPU is completed and post-processing has begun, set the status "RUNNING: POST_PROCESSING":
update_status(Job.POST_PROCESSING)Une fois cette charge de travail terminée avec succès (avec save_result()), ce statut sera automatiquement mis à jour vers DONE .
Flux de travail parallèles
Pour les tâches classiques pouvant être parallélisées, utilisez le @distribute_task décorateur afin de définir les ressources de calcul nécessaires à l'exécution d'une tâche. Commencez par vous rappeler transpile_remote.py l'exemple présenté dans la rubrique « Écrivez votre premier programme Qiskit Serverless » à l'aide du code suivant.
Le code suivant suppose que vous ayez déjà enregistré vos données d'identification.
# If you include the preceding `%%writefile` command (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_serverless import distribute_task
service = QiskitRuntimeService()
@distribute_task(target={"cpu": 1})
def transpile_remote(circuit, optimization_level, backend):
"""
Transpiles an abstract circuit (or list of circuits)
into an ISA circuit for a given backend.
"""
pass_manager = generate_preset_pass_manager(
optimization_level=optimization_level,
backend=service.backend(backend)
)
isa_circuit = pass_manager.run(circuit)
return isa_circuitDans cet exemple, vous avez décoré la fonction transpile_remote() avec @distribute_task(target={"cpu": 1}). Lorsqu'il est exécuté, il crée une tâche de travail parallèle asynchrone avec un seul cœur de processeur et renvoie une référence pour suivre le travailleur. Pour récupérer le résultat, passez la référence à la fonction get() . Nous pouvons l'utiliser pour exécuter plusieurs tâches en parallèle :
# If you include the preceding `%%writefile` command
# (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than
# executing the code.
from time import time
from qiskit_serverless import get, get_arguments, save_result, update_status, Job
# Get arguments
arguments = get_arguments()
circuit = arguments.get("circuit")
optimization_level = arguments.get("optimization_level")
backend = arguments.get("backend")# If you include the preceding `%%writefile` command
# (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
# Start distributed transpilation
update_status(Job.OPTIMIZING_HARDWARE)
start_time = time()
transpile_worker_references = [
transpile_remote(circuit, optimization_level, backend)
for circuit in arguments.get("circuit_list")
]
transpiled_circuits = get(transpile_worker_references)
end_time = time()# If you include the preceding `%%writefile` command
# (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
# Save result, with metadata
result = {
"circuits": transpiled_circuits,
"metadata": {
"resource_usage": {
"RUNNING: OPTIMIZING_FOR_HARDWARE": {
"CPU_TIME": end_time - start_time,
"QPU_TIME": 0,
},
}
},
}
save_result(result)Explorez différentes configurations de tâches
Vous pouvez allouer de manière flexible le CPU, le GPU et la mémoire à vos tâches via @distribute_task(). Pour Qiskit Serverless sur IBM Quantum® Platform, chaque programme est équipé de 16 cœurs de CPU et de 32 Go de RAM, qui peuvent être alloués dynamiquement selon les besoins.
Les cœurs de CPU peuvent être alloués en tant que cœurs de CPU complets, ou même en tant qu'allocations fractionnaires, comme indiqué ci-dessous.
La mémoire est allouée en nombre d'octets. Rappelons qu'il y a 1024 octets dans un kilo-octet, 1024 kilo-octets dans un méga-octet et 1024 méga-octets dans un giga-octet. Pour allouer 2 Go de mémoire à votre travailleur, vous devez allouer "mem": 2 * 1024 * 1024 * 1024.
# If you include the preceding `%%writefile` command
# (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
@distribute_task(target={
"cpu": 16,
"mem": 2 * 1024 * 1024 * 1024
})
def transpile_remote(circuit, optimization_level, backend):
return NoneGérez les données dans l'ensemble de votre programme
Qiskit Serverless vous permet de gérer les fichiers dans le répertoire /data à travers tous vos programmes. Cela implique plusieurs limitations :
- Seuls les fichiers
tareth5sont pris en charge aujourd'hui - Il s'agit uniquement d'un espace de stockage plat
/data, qui ne peut pas comporter de sous-répertoires/data/folder/
Voici comment télécharger des fichiers. Assurez-vous d'être authentifié sur Qiskit Serverless avec votre compte IBM Quantum (voir Télécharger sur Qiskit Serverless pour obtenir des instructions).
import tarfile
from qiskit_serverless import IBMServerlessClient
# Create a tar
filename = "transpile_demo.tar"
file = tarfile.open(filename, "w")
file.add("./source_files/transpile_remote.py")
file.close()
# Get a reference to a QiskitFunction
serverless = IBMServerlessClient()
transpile_remote_demo = next(
program
for program in serverless.list()
if program.title == "transpile_remote_serverless"
)
# Upload the tar to Serverless data directory
serverless.file_upload(file=filename, function=transpile_remote_demo)Output:
'{"message":"/usr/src/app/media/5e1f442128cdf60018496a04/transpile_demo.tar"}'
Vous pouvez ensuite dresser la liste de tous les fichiers contenus dans votre répertoire data . Ces données sont accessibles à tous les programmes.
serverless.files(function=transpile_remote_demo)Output:
['classifier_name.pkl.tar', 'output.json.tar', 'transpile_demo.tar']
Cela peut se faire à partir d'un programme en utilisant file_download() pour télécharger le fichier dans l'environnement du programme, et en décompressant le fichier tar.
# If you include the preceding `%%writefile` command
# (visible only when you read this locally in a
# notebook), running this cell saves to disk rather than executing the code.
import tarfile
from qiskit_serverless import IBMServerlessClient
# For `token`, use the 44-character API_KEY you created
# and saved from the IBM Quantum Platform Home dashboard
serverless = IBMServerlessClient(token="<YOUR_API_KEY>")
files = serverless.files()
demo_file = files[0]
downloaded_tar = serverless.file_download(demo_file)
with tarfile.open(downloaded_tar, 'r') as tar:
tar.extractall()À ce stade, votre programme peut interagir avec les fichiers, comme vous le feriez avec une expérience locale. file_upload() les fichiers de données, file_download() et file_delete() peuvent être appelés à partir de votre expérience locale ou de votre programme téléchargé, pour une gestion cohérente et flexible des données.
Etapes suivantes
- Consultez un exemple complet de portage de code existant vers l' Qiskit Serverless.
- Lisez un article dans lequel des chercheurs ont utilisé Qiskit Serverless et le supercalculateur centré sur le quantique pour explorer la chimie quantique.