Skip to main contentIBM Quantum Documentation Preview

Manage Qiskit Serverless compute and data resources

Qiskit Serverless allows you to manage compute and data across your Qiskit pattern, including CPUs, QPUs, and other compute accelerators.


Parallel workflows

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_remote.py example from the Write your first Qiskit Serverless program topic:

[2] :
%%writefile ./source_files/transpile_remote.py
 
from qiskit.transpiler.preset_passmanagers 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_circuit

Output:

Writing ./source_files/transpile_remote.py

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:

[3] :
%%writefile --append ./source_files/transpile_remote.py
 
from qiskit_serverless import get, get_arguments, save_result
 
arguments = get_arguments()
circuit = arguments.get("circuit")
optimization_level = arguments.get("optimization_level")
backend = arguments.get("backend")
 
transpile_worker_reference = transpile_remote(
    circuit,
    optimization_level,
    backend
)
result = get(transpile_worker_reference)
save_result(result)

Output:

Appending to ./source_files/transpile_remote.py

You can also create and run multiple parallel tasks as follows:

[5] :
%%writefile --append ./source_files/transpile_remote.py
 
transpile_worker_references = [
    transpile_remote(circuit, optimization_level, backend)
    for circuit in arguments.get("circuit_list")
]
 
results = get(transpile_worker_references)
save_result(results)  # Overwrites any previously saved results

Output:

Appending to ./source_files/transpile_remote.py

Explore different task configurations

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.

CPU cores can be allocated as full CPU cores, or even fractional allocations, as shown in the following.

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.

[8] :
%%writefile --append ./source_files/transpile_remote.py
 
@distribute_task(target={
    "cpu": 16,
    "mem": 2 * 1024 * 1024 * 1024
})
def transpile_remote(circuit, optimization_level, backend):
    return None

Output:

Overwriting ./source_files/transpile_remote.py

Manage data across your program

Qiskit Serverless allows you to manage files in the /data directory across all your programs. This includes several limitations:

  • Only tar and h5 files are supported today
  • This is only a flat /data storage, and cannot have /data/folder/ subdirectories

The following shows how to upload files. Be sure you have authenticated to Qiskit Serverless with your IBM Quantum account (see Deploy to IBM Quantum Platform for instructions).

[12] :
import tarfile
 
# Create a tar
filename = "transpile_demo.tar"
file = tarfile.open(filename,"w")
file.add("./source_files/transpile_remote.py")
file.close()
 
# Upload the tar to Serverless data directory
from qiskit_serverless import IBMServerlessClient
serverless = IBMServerlessClient()
serverless.file_upload(filename)

Output:

'{"message":"/usr/src/app/media/5e1f442128cdf60018496a04/transpile_demo.tar"}'

Next, you can list all the files in your data directory. This data is accessible to all programs.

[13] :
serverless.files()

Output:

['transpile_demo.tar']

This can be done from a program by using file_download() to download the file to the program environment, and uncompressing the tar.

[14] :
%%writefile ./source_files/extract_tarfile.py
 
import tarfile
from qiskit_serverless import IBMServerlessClient
from qiskit_ibm_runtime import QiskitRuntimeService
 
service = QiskitRuntimeService()
serverless = IBMServerlessClient(
    token=service.active_account()['token']
)
files = serverless.files()
demo_file = files[0]
downloaded_tar = serverless.file_download(demo_file)
 
with tarfile.open(downloaded_tar, 'r') as tar:
    tar.extractall()

Output:

Appending to ./source_files/tarfile_example.py

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.


Next steps

Recommendations