309 lines
9.7 KiB
Plaintext
309 lines
9.7 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6b7abc7b-b435-43d1-9fd8-c349ee8710f3",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Manage Qiskit Serverless compute and data resources"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3b0771d6-95c9-46dc-955a-f8702f6a2632",
|
|
"metadata": {
|
|
"tags": [
|
|
"version-info"
|
|
]
|
|
},
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "95b2f280-f685-455f-83e9-b172445d7c6a",
|
|
"metadata": {},
|
|
"source": [
|
|
"Qiskit Serverless allows you to manage compute and data across your [Qiskit pattern](./intro-to-patterns), including CPUs, QPUs, and other compute accelerators.\n",
|
|
"\n",
|
|
"## Parallel workflows"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b2d40a63-3359-46e9-8f1b-4746b449b407",
|
|
"metadata": {},
|
|
"source": [
|
|
"For classical tasks that can be parallelized, use the `@distribute_task` decorater to define compute requirements needed to perform a task. Start by recalling the `transpile_parallel.py` example from the [Write your first Qiskit Serverless program](./serverless-first-program) topic:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "475d82f0-15cc-4db3-b3b0-54b07822b2a0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%writefile ./source_files/transpile_remote.py\n",
|
|
"\n",
|
|
"from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
|
|
"from qiskit_ibm_runtime import QiskitRuntimeService\n",
|
|
"from qiskit_serverless import distribute_task\n",
|
|
"\n",
|
|
"service = QiskitRuntimeService()\n",
|
|
"\n",
|
|
"@distribute_task(target={\"cpu\": 1})\n",
|
|
"def transpile_remote(circuit, optimization_level, backend):\n",
|
|
" \"\"\"Transpiles an abstract circuit (or list of circuits) into an ISA circuit for a given backend.\"\"\"\n",
|
|
" pass_manager = generate_preset_pass_manager(\n",
|
|
" optimization_level=optimization_level,\n",
|
|
" backend=service.backend(backend)\n",
|
|
" )\n",
|
|
" isa_circuit = pass_manager.run(circuit)\n",
|
|
" return isa_circuit"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a5914f1d-f898-4db4-8d1e-ccc8081883b9",
|
|
"metadata": {},
|
|
"source": [
|
|
"In this example, you decorated the `transpile_remote()` function with `@distribute_task(target={\"cpu\": 1})`. When run, this creates an asynchronous parallel worker task with a single CPU core, and returns with a reference to track the worker. To fetch the result, pass the reference to the `get()` function."
|
|
]
|
|
},
|
|
{
|
|
"id": "74fdcd4a-01cd-46ca-aa24-2a8a3605346f",
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%writefile --append ./source_files/transpile_remote.py\n",
|
|
"\n",
|
|
"from qiskit_serverless import get, get_arguments, save_result\n",
|
|
"\n",
|
|
"arguments = get_arguments()\n",
|
|
"circuit = arguments.get(\"circuit\")\n",
|
|
"optimization_level = arguments.get(\"optimization_level\")\n",
|
|
"backend = arguments.get(\"backend\")\n",
|
|
"\n",
|
|
"transpile_worker_reference = transpile_remote(\n",
|
|
" circuit,\n",
|
|
" optimization_level,\n",
|
|
" backend\n",
|
|
")\n",
|
|
"result = get(transpile_worker_reference)\n",
|
|
"save_result(result)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "268d5ef6-12cf-4ba5-95a3-f7460e4b3bfc",
|
|
"metadata": {},
|
|
"source": [
|
|
"You can also create and run multiple parallel tasks as follows."
|
|
]
|
|
},
|
|
{
|
|
"id": "ac99b4a0-4a42-4c43-869d-265344b70359",
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%writefile --append ./source_files/transpile_remote.py\n",
|
|
"\n",
|
|
"transpile_worker_references = [\n",
|
|
" transpile_remote(circuit, optimization_level, backend)\n",
|
|
" for circuit in arguments.get(\"circuit_list\")\n",
|
|
"]\n",
|
|
"\n",
|
|
"results = get(transpile_worker_references)\n",
|
|
"save_result(results) # Overwrites any previously saved results"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "611fe030-4494-46b5-9ea1-9678ac513210",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Explore different task configurations\n",
|
|
"\n",
|
|
"You can flexibly allocate CPU, GPU, and memory for your tasks via `@distribute_task()`. For Qiskit Serverless on IBM Quantum™ Platform, each program is equipped with 16 CPU cores and 32 GB RAM, which can be allocated dynamically as needed.\n",
|
|
"\n",
|
|
"CPU cores can be allocated as full CPU cores, or even fractional allocations, as shown in the following.\n",
|
|
"\n",
|
|
"Memory is allocated in number of bytes. Recall that there are 1024 bytes in a kilobyte, 1024 kilobytes in a megabyte, and 1024 megabytes in a gigabyte. To allocate 2 GB of memory for your worker, you need to allocate `\"mem\": 2 * 1024 * 1024 * 1024`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cea90969-cfbf-4181-9ffa-524f3709dc69",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%writefile --append ./source_files/transpile_remote.py\n",
|
|
"\n",
|
|
"@distribute_task(target={\n",
|
|
" \"cpu\": 16,\n",
|
|
" \"mem\": 2 * 1024 * 1024 * 1024\n",
|
|
"})\n",
|
|
"def transpile_remote(circuit, optimization_level, backend):\n",
|
|
" return None"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6bc45489-56d0-4f46-8659-9df4d1555516",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Manage data across your program\n",
|
|
"\n",
|
|
"Qiskit Serverless allows you to manage files in the `/data` directory across all your programs. This includes several limitations:\n",
|
|
"\n",
|
|
"- Only `tar` and `h5` files are supported today\n",
|
|
"- This is only a flat `/data` storage, and cannot have `/data/folder/` subdirectories\n",
|
|
"\n",
|
|
"The following shows how to upload files. Be sure you have authenticated to Qiskit Serverless with your [IBM Quantum account](https://quantum.ibm.com/account) (see [Deploy to IBM Quantum Platform](./serverless-first-program#deploy-to-ibm-quantum-platform) for instructions)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "0183278f-8ce3-4466-9255-097b2d211052",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"'{\"message\":\"/usr/src/app/media/5f37582aa306c50013fac285/transpile_demo.tar\"}'"
|
|
]
|
|
},
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"import tarfile\n",
|
|
"from qiskit_serverless import IBMServerlessClient\n",
|
|
"\n",
|
|
"# Create a tar\n",
|
|
"filename = \"transpile_demo.tar\"\n",
|
|
"file = tarfile.open(filename, \"w\")\n",
|
|
"file.add(\"./source_files/transpile_remote.py\")\n",
|
|
"file.close()\n",
|
|
"\n",
|
|
"# Upload the tar to Serverless data directory\n",
|
|
"serverless = IBMServerlessClient()\n",
|
|
"serverless.file_upload(filename)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "4f762470-945f-48d5-a65b-c60d3b2dae3f",
|
|
"metadata": {},
|
|
"source": [
|
|
"Next, you can list all the files in your `data` directory. This data is accessible to all programs."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "14241fc4-d0cb-4803-8752-a460e1f48708",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"['transpile_demo.tar']"
|
|
]
|
|
},
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"serverless.files()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a97bd83e-8250-43bb-b1c4-d40d822c7ba2",
|
|
"metadata": {},
|
|
"source": [
|
|
"This can be done from a program by using `file_download()` to download the file to the program environment, and uncompressing the `tar`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"id": "ef649b2a-ed95-4dd2-89d9-61438faa7c1e",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%writefile ./source_files/extract_tarfile.py\n",
|
|
"\n",
|
|
"import tarfile\n",
|
|
"from qiskit_serverless import IBMServerlessClient\n",
|
|
"\n",
|
|
"serverless = IBMServerlessClient(token=\"<YOUR_IBM_QUANTUM_TOKEN>\")\n",
|
|
"files = serverless.files()\n",
|
|
"demo_file = files[0]\n",
|
|
"downloaded_tar = serverless.file_download(demo_file)\n",
|
|
"\n",
|
|
"\n",
|
|
"with tarfile.open(downloaded_tar, 'r') as tar:\n",
|
|
" tar.extractall()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "5b93dbdb-2060-468b-8496-ba98142a780b",
|
|
"metadata": {},
|
|
"source": [
|
|
"At this point, your program can interact with the files, as you would a local experiment. `file_upload()` , `file_download()`, and `file_delete()` can be called from your local experiment, or your uploaded program, for consistent and flexible data management."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a004dd78-0e0a-4a3b-83cb-333469533ef6",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Next steps\n",
|
|
"\n",
|
|
"<Admonition type=\"info\" title=\"Recommendations\">\n",
|
|
"\n",
|
|
"- See a full example that [ports existing code to Qiskit Serverless ](./serverless-port-code).\n",
|
|
"- Read a paper in which researchers used Qiskit Serverless and quantum-centric supercomputing to [explore quantum chemistry](https://arxiv.org/abs/2405.05068v1).\n",
|
|
"\n",
|
|
"</Admonition>"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"description": "Manage compute and data across your Qiskit pattern with Qiskit Serverless.",
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3"
|
|
},
|
|
"title": "Manage Qiskit Serverless compute and data resources"
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|