353 lines
10 KiB
Plaintext
353 lines
10 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e17b430a-ec17-4a88-9a71-9ce365059bea",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Write your first Qiskit Serverless program\n",
|
||
"\n",
|
||
"This example demonstrates how to use `qiskit-serverless` tools to create a parallel transpilation program, and then implement `qiskit-ibm-catalog` to deploy your program to IBM Quantum™ Platform to use as a reusable remote service."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e3603a5c-78f4-40ec-9568-7a45664acfc7",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Example: remote transpilation with Qiskit Serverless\n",
|
||
"\n",
|
||
"Start with the following example that transpiles a `circuit` against a given `backend` and target `optimization_level`, and gradually add more elements to deploy your workload to Qiskit Serverless.\n",
|
||
"\n",
|
||
"This page uses the [`%%writefile`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cellmagic-writefile) \"magic\" command in Jupyter to write cell contents to a file rather than run them."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"id": "21ea3269-1946-40b4-9c0f-9431003c2d0b",
|
||
"metadata": {
|
||
"editable": true,
|
||
"slideshow": {
|
||
"slide_type": ""
|
||
},
|
||
"tags": [
|
||
"remove-cell"
|
||
]
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# This cell is hidden from users, it just creates a new folder\n",
|
||
"from pathlib import Path\n",
|
||
"Path('./source_files').mkdir(exist_ok=True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"id": "4b550093-1d73-4c15-905a-0caa12f7dcbe",
|
||
"metadata": {
|
||
"editable": true,
|
||
"slideshow": {
|
||
"slide_type": ""
|
||
},
|
||
"tags": []
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Writing ./source_files/transpile_remote.py\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%%writefile ./source_files/transpile_remote.py\n",
|
||
"\n",
|
||
"from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
|
||
"\n",
|
||
"def transpile_remote(circuit, optimization_level, backend):\n",
|
||
" \"\"\"Transpiles an abstract circuit into an ISA circuit for a given backend.\"\"\"\n",
|
||
" pass_manager = generate_preset_pass_manager(\n",
|
||
" optimization_level=optimization_level,\n",
|
||
"\t\tbackend=backend\n",
|
||
" )\n",
|
||
" isa_circuit = pass_manager.run(circuit)\n",
|
||
" return isa_circuit"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "ea182474-7566-4a13-96d8-cfcc8f16dd8f",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Set up your files\n",
|
||
"\n",
|
||
"Qiskit Serverless requires setting up your workload’s `.py` files into a dedicated directory. The following structure is an example of good practice:\n",
|
||
"\n",
|
||
"```text\n",
|
||
"serverless_program\n",
|
||
"|___ program_uploader.ipynb\n",
|
||
"|___ source_files\n",
|
||
" |___ transpile_remote.py\n",
|
||
" |___ *.py\n",
|
||
"```\n",
|
||
"\n",
|
||
"Serverless uploads the contents of `source_files` to run remotely. Once these are set up, you can adjust `transpile_remote.py` to fetch inputs and return outputs.\n",
|
||
"\n",
|
||
"### Get program arguments\n",
|
||
"\n",
|
||
"Your initial `transpile_parallel.py` has two inputs: `circuits` and `backend`. Serverless is currently limited to only accept serializable inputs and outputs. For this reason, you cannot pass in `backend` directly, so use `backend_name` as a string instead."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "54a8d2c6-a3f4-4169-9210-dd213e2273d2",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Appending to ./source_files/transpile_remote.py\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%%writefile --append ./source_files/transpile_remote.py\n",
|
||
"\n",
|
||
"from qiskit_serverless import get_arguments, save_result, distribute_task, get\n",
|
||
"\n",
|
||
"# Get program arguments\n",
|
||
"arguments = get_arguments()\n",
|
||
"circuits = arguments.get(\"circuits\")\n",
|
||
"backend_name = arguments.get(\"backend_name\")\n",
|
||
"optimization_level = arguments.get(\"optimization_level\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "bf57e8a8-4f64-4933-978d-c16bda4e0c0c",
|
||
"metadata": {},
|
||
"source": [
|
||
"At this point, you can get your backend with `QiskitRuntimeService`, and add your existing program:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "7077ba00-1571-4f99-8c53-b1a9ac280987",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Appending to ./source_files/transpile_remote.py\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%%writefile --append ./source_files/transpile_remote.py\n",
|
||
"\n",
|
||
"from qiskit_ibm_runtime import QiskitRuntimeService\n",
|
||
"\n",
|
||
"service = QiskitRuntimeService(channel=\"ibm_quantum\")\n",
|
||
"backend = service.get_backend(backend_name)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "8bd63bfc-0da5-46de-ace5-8463b5ad92f3",
|
||
"metadata": {},
|
||
"source": [
|
||
"Finally, you can run `transpile_remote()` across all `circuits` passed in, and return the `transpiled_circuits` as a result:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"id": "afdb6896-93b8-4006-b27b-49ebb16e7c1c",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Appending to ./source_files/transpile_remote.py\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%%writefile --append ./source_files/transpile_remote.py\n",
|
||
"\n",
|
||
"results = [\n",
|
||
" transpile_remote(circuit, backend)\n",
|
||
" for circuit in circuits\n",
|
||
"]\n",
|
||
"\n",
|
||
"save_result({\n",
|
||
" \"transpiled_circuits\": results\n",
|
||
"})"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "a05fa201-aabb-43a5-8a6a-f53c5c664fc4",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Deploy to IBM Quantum Platform\n",
|
||
"\n",
|
||
"Use `qiskit-ibm-catalog` to authenticate to `QiskitServerless` with your API token, which you can find in your [IBM Quantum account](https://quantum.ibm.com/account), and upload the program.\n",
|
||
"\n",
|
||
"You can use `save_account()` to save your credentials (See the \"Authenticate to the service\" step in the [Set up to use IBM Quantum Platform](./setup-channel#set-up-to-use-ibm-quantum-platform) section). Note that this writes your credentials to the same file as [`QiskitRuntimeService.save_account()`](/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#save_account)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"id": "cc9d5267-8019-4543-ab6a-679583d26340",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from qiskit_ibm_catalog import QiskitServerless, QiskitFunction\n",
|
||
"\n",
|
||
"# Authenticate to the remote cluster and submit the pattern for remote execution\n",
|
||
"serverless = QiskitServerless()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "7e8327dc-9105-4fb0-9cf0-c6e13ca32674",
|
||
"metadata": {},
|
||
"source": [
|
||
"Qiskit Serverless compresses the contents of `working_dir` (in this case, `source_files`) into a `tar`, which is uploaded and cleaned up after. The `entrypoint` identifies the main program executable for Qiskit Serverless to run. Additionally, if your program has custom `pip` dependencies, you can add them to a `dependencies` array:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "62738969-b19c-484e-8591-4f89c99990ed",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"transpile_remote_demo = QiskitFunction(\n",
|
||
" title=\"transpile_remote_serverless\",\n",
|
||
" entrypoint=\"transpile_remote.py\",\n",
|
||
" working_dir=\"./source_files/\",\n",
|
||
"\tdependencies=[\"qiskit-aer==0.14.1\"],\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"id": "ed72ee48-a643-4d2e-b245-6e9ab3673ddb",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'transpile_remote_serverless'"
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"serverless.upload(transpile_remote_demo)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "9a22d507-2489-4f2f-af78-c9249ed3fc3d",
|
||
"metadata": {},
|
||
"source": [
|
||
"To check if it successfully uploaded, use `serverless.list()`:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"id": "ff7d8283-ee72-4167-8a8a-1f07367ba6ef",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[QiskitFunction(transpile_remote_serverless)]"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"serverless.list()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "f8940b98-33f7-4029-ac77-60058c4aee78",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Next steps\n",
|
||
"\n",
|
||
"<Admonition type=\"info\" title=\"Recommendations\">\n",
|
||
"\n",
|
||
"- Learn how to pass inputs and run your program remotely in the [Run your first Qiskit Serverless workload remotely](./serverless-run-first-workload) topic.\n",
|
||
"\n",
|
||
"</Admonition>"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"id": "2992c8d5-f8f5-4602-8705-db1e20383459",
|
||
"metadata": {
|
||
"editable": true,
|
||
"slideshow": {
|
||
"slide_type": ""
|
||
},
|
||
"tags": [
|
||
"remove-cell"
|
||
]
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# This cell is hidden from users, it just deletes the working folder we created\n",
|
||
"import shutil\n",
|
||
"shutil.rmtree(\"./source_files/\")"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"description": "How to create a parallel transpilation program and deploy it to IBM Quantum Platform to use as a reusable remote service.",
|
||
"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": "Write your first Qiskit Serverless program"
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|