qiskit-documentation/docs/guides/qiskit-serverless.mdx

233 lines
10 KiB
Plaintext

---
title: Run workloads remotely with Qiskit Serverless
description: How to run quantum computing workloads remotely using Qiskit Serverless on IBM Quantum.
---
# Run workloads remotely with Qiskit Serverless
Premium users can build, deploy, and run their workloads remotely on classical compute made available through the IBM Quantum™ Platform.
Try out the tutorials in [IBM Quantum Learning](https://learning.quantum.ibm.com/catalog/tutorials?topics=qiskit-patterns) (note: these are accessible in the Premium Plan once you have logged into your IBM Quantum account) and explore more of the features of Qiskit Serverless in the [documentation](https://qiskit.github.io/qiskit-serverless/).
<Admonition type="note">
This is an experimental feature, subject to change.
</Admonition>
## Building Qiskit patterns with Qiskit Serverless
Creating utility-scale quantum applications generally requires a variety of compute resource requirements. You can use Qiskit Serverless to easily submit quantum workflows for remote, managed execution on IBM Quantum Platform. These quantum workflows can typically be implemented within a common pattern, called a Qiskit pattern. A Qiskit pattern is an intuitive, repeatable set of steps for implementing a quantum computing workflow.
Steps in a Qiskit pattern:
1. Map classical inputs to a quantum problem
2. Optimize problem for quantum execution
3. Execute using Qiskit Runtime primitives
4. Post-process, return result in classical format
Once you have built a Qiskit pattern, you can use Qiskit Serverless to deploy it and submit it for managed execution. Overall, the process of creating quantum software and submitting it for managed execution on a remote cluster can be broken down into three steps:
1. Build the Qiskit pattern
2. Deploy to the Qiskit Serverless
3. Run remotely on Qiskit Serverless
## Build a Qiskit pattern
Here is an example of computing the expectation value using the Qiskit Runtime Estimator primitive. This Python script should be saved in your working directory. (Warning! All contents of the working directory will be shipped to the cluster for execution.)
```python
# source_files/my_qiskit_pattern.py
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.random import random_circuit
from qiskit.quantum_info import SparsePauliOp
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_serverless import save_result
service = QiskitRuntimeService()
backend = service.least_busy(simulator=False)
# Step 1: Map quantum circuits and operators
abstract_circuit = random_circuit(2, 2, seed=1234)
observable = SparsePauliOp("IY")
# Step 2: Optimize the circuit for quantum execution
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
target_circuit = pm.run(abstract_circuit)
target_observable = observable.apply_layout(target_circuit.layout)
# Step 3: Execute the target circuit on Estimator V1
# from qiskit_ibm_runtime import Estimator
# estimator = Estimator(backend)
# job = estimator.run(target_circuit, target_observable)
# result = job.result()
# Step 3: Execute the target circuit on Estimator V2
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(backend)
job = estimator.run([(target_circuit, target_observable)])
result = job.result()
# Step 4: Postprocess the Estimator V1 results
# print(result)
# save results of program execution
# note: saved items must be serializable
# save_result(result.values)
# Step 4: Postprocess the Estimator V2 results
print(result)
# save results of program execution
# note: saved items must be serializable
save_result(result[0].data.evs)
```
Please refer to our guides on how to configure your pattern to [accept input arguments](https://qiskit.github.io/qiskit-serverless/getting_started/basic/02_arguments_and_results.html) and [handle external Python dependencies](https://qiskit.github.io/qiskit-serverless/getting_started/basic/03_dependencies.html).
After creating a workflow, authenticate to the `IBMServerlessClient` with your IBM Quantum token, which can be obtained from your [IBM Quantum account](https://quantum.ibm.com/account), and upload the script.
```python
# Authenticate to the IBM serverless client
from qiskit_serverless import IBMServerlessClient
serverless = IBMServerlessClient("YOUR_IBM_QUANTUM_TOKEN")
# Deploy the pattern
from qiskit_serverless import QiskitFunction
serverless.upload(
QiskitFunction(
title="My-Qiskit-Pattern",
entrypoint="my_qiskit_pattern.py",
working_dir="./source_files/"
)
)
```
## Run a Qiskit pattern remotely on Qiskit Serverless
Finally, the pattern is ready to run remotely.
```python
# Run pattern remotely
pattern = serverless.get("My-Qiskit-Pattern")
pattern.run()
# Retrieve status, logs, results
job.status()
job.logs()
job.result()
```
## Migration guide
Qiskit Runtime custom programs can be easily migrated to Qiskit Serverless via this [migration guide](https://qiskit.github.io/qiskit-serverless/migration/migration_from_qiskit_runtime_programs.html).
## Resource management (alpha)
Premium Plan users have access to an alpha release of resource management functionality through Qiskit Serverless. This enables automatic selection of quantum hardware for your workloads.
The example below demonstrates how to use `IBMQPUSelector` to automate the process of selecting which qubits will be used from a set of available systems. This illustrates how the selectors can be used within a four-step Qiskit pattern.
Instead of manually selecting a system, step 2 of the Qiskit pattern optimizes the circuits for execution by using the QPU selectors from Qiskit Serverless to automatically allocate a system according to desired criteria. Here, `IBMLeastNoisyQPUSelector` finds the system, among the ones available to you through your IBM Quantum account, that yields the least-noisy qubit subgraph for the input circuit. You can also use the `IBMLeastBusyQPUSelector` to find a system that can support the circuit width but with the shortest queue.
For each `IBMQPUSelector`, the context is set in the constructor. All `IBMQPUSelectors` require Qiskit Runtime credentials. The `IBMLeastNoisyQPUSelector` requires a circuit and transpile options specifying how the circuit should be optimized for each system when determining the most optimal QPU and qubit layout. All `IBMQPUSelector`s implement a `get_backend` method, which retrieves the optimal system with respect to the given context. The `get_backend` method also allows for additional filtering of the systems. It is implemented using the same interface as the [QiskitRuntimeService.backends method](/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#backends).
Then, in step 3 of the pattern, you execute the target circuit on the system chosen by the selector.
<Tabs>
<TabItem value="SamplerV2" label="Sampler V2">
```python
# source_files/my_qiskit_pattern_resource_management.py
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Samplerv2 as Sampler
from qiskit.circuit.random import random_circuit
from qiskit_serverless_tools.selectors import IBMLeastNoisyQPUSelector
service = QiskitRuntimeService()
# Step 1: Map quantum circuits and operators
abstract_circuit = random_circuit(
num_qubits=5, depth=4, measure=True, seed=1234
)
# Step 2: Optimize the circuit for quantum execution with automatically selected system
selector = IBMLeastNoisyQPUSelector(
service, circuit=abstract_circuit, transpile_options={"optimization_level": 3}
)
backend = selector.get_backend(min_num_qubits=127)
target_circuit = selector.optimized_circuit
## Alternatively, one can automatically select a system according to most available:
# from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# from qiskit_serverless_tools.selectors import IBMLeastBusyQPUSelector
#
# backend = IBMLeastBusyQPUSelector(service).get_backend(min_num_qubits=127)
# pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
# target_circuit = pm.run(abstract_circuit)
# Step 3: Execute the target circuit
sampler = Sampler(mode=backend, options={"default_shots": 1024})
job = sampler.run([target_circuit])
result = job.result()
# Step 4: Postprocess the results
print(f" > Counts: {result[0].data.meas.get_counts()}")
# save results of program execution
# note: saved items must be serializable
save_result(result)
```
</TabItem>
<TabItem value="SamplerV1" label="Sampler (V1)">
```python
# source_files/my_qiskit_pattern_resource_management.py
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Options
from qiskit.circuit.random import random_circuit
from qiskit_serverless_tools.selectors import IBMLeastNoisyQPUSelector
service = QiskitRuntimeService()
# Step 1: Map quantum circuits and operators
abstract_circuit = random_circuit(
num_qubits=5, depth=4, measure=True, seed=1234
)
# Step 2: Optimize the circuit for quantum execution with automatically selected system
selector = IBMLeastNoisyQPUSelector(
service, circuit=abstract_circuit, transpile_options={"optimization_level": 3}
)
backend = selector.get_backend(min_num_qubits=127)
target_circuit = selector.optimized_circuit
## Alternatively, one can automatically select a system according to most available:
# from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# from qiskit_serverless_tools.selectors import IBMLeastBusyQPUSelector
#
# backend = IBMLeastBusyQPUSelector(service).get_backend(min_num_qubits=127)
# pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
# target_circuit = pm.run(abstract_circuit)
# Step 3: Execute the target circuit
with Session(service, backend=backend) as session:
sampler = Sampler(
options=Options(
execution={"shots": 1024}, transpilation={"skip_transpilation": True}
)
)
result = sampler.run(target_circuit).result().quasi_dists[0]
# Step 4: Postprocess the results
print(result)
# save results of program execution
# note: saved items must be serializable
save_result(result)
```
</TabItem>
</Tabs>
After creating this pattern, you can deploy and run it remotely with Qiskit Serverless as described above.