Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 109 additions & 99 deletions docs/tutorials/quantum-kernel-training.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,39 @@
"description: Build a Qiskit pattern for evaluating entries into a quantum kernel matrix used for binary classification.\n",
"---\n",
"\n",
"{/* cspell:ignore mapsto forall */}\n",
"\n",
"# Quantum kernel training\n",
"*Usage estimate: under one minute on an Eagle r3 processor (NOTE: This is an estimate only. Your runtime might vary.)*"
"*Usage estimate: under one minute on a Heron r3 processor (NOTE: This is an estimate only. Your runtime might vary.)*"
]
},
{
"cell_type": "markdown",
"id": "bd3bec67",
"metadata": {},
"source": [
"## Learning outcomes\n",
"After completing this tutorial, you can expect to understand the following information:\n",
"\n",
" * kernel methods and their uses\n",
" * quantum kernels and how they can provide enhanced feature spaces\n",
" * quantum kernel circuit construction\n",
" * how to train a quantum kernel using a `Qiskit pattern`: map, optimize, execute, and post-process"
]
},
{
"cell_type": "markdown",
"id": "ba36136c",
"metadata": {},
"source": [
"## Prerequisites\n",
"It is recommended that you familiarize yourself with quantum kernels, why they are important and how they are used in practice.\n",
"\n",
" * [Covariant quantum kernels for data with group structure](https://arxiv.org/abs/2105.03406) (paper)\n",
" * [Introduction to Quantum Kernels and Support Vector Machines](https://www.youtube.com/watch?v=GVhCOTzAkCM) (video)\n",
" * [Quantum Kernels in Practice](https://www.youtube.com/watch?v=LmQcSxgINis) (video)\n",
"\n",
"It is also useful to have a basic understanding of group theory."
]
},
{
Expand All @@ -21,8 +51,22 @@
"metadata": {},
"source": [
"## Background\n",
"\n",
"This tutorial shows how to build a `Qiskit pattern` for evaluating entries into a quantum kernel matrix used for binary classification. For more information on `Qiskit patterns` and how `Qiskit Serverless` can be used to deploy them to the cloud for managed execution, visit our [docs page on IBM Quantum® Platform](/docs/guides/serverless)."
"Kernel methods are commonplace in machine learning applications.\n",
"In this context, \"kernel\" refers to the kernel matrix or individual entries therein.\n",
"In general, a kernel is a similarity measure between data encoded in a high-dimensional _feature space_ and can be utilized, for example, in classification tasks with support vector machines.\n",
"\n",
"Quantum kernel methods are those which use quantum computers to estimate a kernel.\n",
"It is known that quantum computers can encode data in quantum-enhanced feature spaces, effectively replacing classical analogs.\n",
"For $\\vec{x} \\in \\mathbb{R}$ and $\\Psi(\\vec{x}) \\in \\mathbb{R}^{d'}$, typically with $d' >d$, $\\Psi(\\vec{x})$ is a feature map, $\\vec{x} \\mapsto \\Psi(\\vec{x})$.\n",
"The goal of $\\Psi(\\vec{x})$ is to make categories of data separated by a hyperplane.\n",
"Taking the vectors in the feature-mapped space as arguments, kernel function $K(\\vec{x}, \\vec{y}) = \\langle{\\Psi(\\vec{x}) | \\Psi(\\vec{y}) \\rangle{}}$ returns their inner product: $K: \\mathbb{R}^d \\rightarrow$ $\\mathbb{R}^d$.\n",
"Classically, feature maps of interest are those in which the kernel function can be easily evaluated;\n",
"i.e., when the inner product in the feature-mapped space can be written in terms of the original data vectors and $\\Psi(\\vec{x})$ and $\\Psi(\\vec{y})$ do not need to be constructed.\n",
"In the case of quantum kernels, feature mapping is performed by a quantum circuit, and the kernel is estimated using the measurement probabilities sampled from the circuit.\n",
"\n",
"\n",
"In this lesson we will examine the depths of pre-coded encoding circuits that use substantial entanglement and compare those to depths of circuits we code by hand. This is not to advocate for one method over another. You may find that pre-coded circuits are too deep, and that the entanglement in the custom-built circuit is insufficient to be useful. Again, these are shown only to enable your exploration.\n",
"This tutorial shows how to build a `Qiskit pattern` for evaluating entries into a quantum kernel matrix used for binary classification."
]
},
{
Expand All @@ -33,8 +77,9 @@
"## Requirements\n",
"\n",
"Before starting this tutorial, be sure you have the following installed:\n",
"- Qiskit SDK v1.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n",
"- Qiskit Runtime v0.22 or later (`pip install qiskit-ibm-runtime`)"
"- Qiskit SDK v2.3.1 or later, with [visualization](/docs/api/qiskit/visualization) support\n",
"- Qiskit Runtime v0.44.0 or later (`pip install qiskit-ibm-runtime`)\n",
"- Qiskit IBM Catalog v0.14.0 or later (`pip install qiskit-ibm-catalog`)"
]
},
{
Expand All @@ -47,19 +92,25 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "4405f2da-ce6e-4b97-960a-bb04730cfb6d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2026-04-23 18:53:41-- https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv\n",
"Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.111.133, ...\n",
"Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 49405 (48K) [text/plain]\n",
"Saving to: ‘dataset_graph7.csv’\n",
"\n",
"dataset_graph7.csv 100%[===================>] 48.25K --.-KB/s in 0.009s \n",
"\n",
"\u001b7\u001b[1A\u001b[1G\u001b[27G[Files: 0 Bytes: 0 [0 B/s] Re]\u001b8\u001b7\u001b[2A\u001b[1G\u001b[27G[https://raw.githubusercontent.]\u001b8\u001b7\u001b[1S\u001b[3A\u001b[1G\u001b[0JSaving 'dataset_graph7.csv.1'\n",
"\u001b8\u001b7\u001b[2A\u001b[1Gdataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s\u001b8\u001b7\u001b[1S\u001b[3A\u001b[1G\u001b[0JHTTP response 200 [https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv]\n",
"\u001b8\u001b7\u001b[2A\u001b[1Gdataset_graph7.csv.1 100% [=============================>] 20.25K --.-KB/s\u001b8\u001b7\u001b[1A\u001b[1G\u001b[27G[Files: 1 Bytes: 20.25K [93.33]\u001b8\u001b[m\u001b[m\u001b[m\u001b[m"
"2026-04-23 18:53:42 (5.26 MB/s) - ‘dataset_graph7.csv’ saved [49405/49405]\n",
"\n"
]
}
],
Expand All @@ -74,14 +125,11 @@
"\n",
"\n",
"from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit\n",
"from qiskit.circuit.library import UnitaryOverlap\n",
"from qiskit.circuit.library import unitary_overlap\n",
"from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
"\n",
"from qiskit_ibm_runtime import QiskitRuntimeService, Sampler\n",
"\n",
"# from qiskit_serverless import IBMServerlessClient, QiskitFunction\n",
"from qiskit_ibm_catalog import QiskitServerless, QiskitFunction\n",
"\n",
"\n",
"def visualize_counts(res_counts, num_qubits, num_shots):\n",
" \"\"\"Visualize the outputs from the Qiskit Sampler primitive.\"\"\"\n",
Expand Down Expand Up @@ -122,19 +170,30 @@
"id": "6ddce42e-a365-451d-972d-24c1306ac47b",
"metadata": {},
"source": [
"## Step 1: Map classical inputs to a quantum problem\n",
"## Step 1: Map problem to quantum circuits and operators\n",
"\n",
"* Input: Training dataset.\n",
"* Output: Abstract circuit for calculating a kernel matrix entry.\n",
"\n",
"Create the quantum circuit used to evaluate one entry in the kernel matrix. We use the input data to determine the rotation angles for the circuit's parametrized gates. We will use data samples `x1=14` and `x2=19`.\n",
"The binary classification problem we aim to solve here is referred to as \"[_labeling cosets with error_](https://arxiv.org/abs/2105.03406).\" The input training dataset contains a group structure, consisting of two cosets formed by a group and subgroup.\n",
"The group is taken to be $G = SU(2)^{\\otimes n}$ for qubits, which is the special unitary group of\n",
"$2 \\times 2$ matrices and has wide applicability in nature; e.g., the Standard Model of particle physics.\n",
"We take the (graph-stabilizer) subgroup $S_\\text{graph} < G$ with $S_\\text{graph} = \\langle \\{ X_i \\otimes _{k:(k,i) \\in \\mathcal{E}} Z_k\\} _{i \\in \\mathcal{V}} \\} \\rangle$ for a graph with edges $\\mathcal{E}$ and vertices $\\mathcal{V}$.\n",
"Note that the stabilizers fix a stabilizer state such that $D_s | \\psi \\rangle = | \\psi \\rangle,~ \\forall s \\in S_\\text{graph}$.\n",
"Finally, we define two left-cosets $C_\\pm = c_\\pm S_\\text{graph}$ by drawing two $c_\\pm \\in G$ at random.\n",
"\n",
"For more details about the dataset and how it is generated, see [this notebook](https://github.com/qiskit-community/prototype-quantum-kernel-training/blob/main/docs/background/qkernels_and_data_w_group_structure.ipynb) from the [Quantum Kernel Training Toolkit](https://github.com/qiskit-community/prototype-quantum-kernel-training/tree/main).\n",
"\n",
"We create the quantum circuit used to evaluate one entry in the kernel matrix.\n",
"The input data is used to determine the rotation angles for the circuit's parametrized gates.\n",
"For simplicity, we will use data samples `x1=14` and `x2=19`.\n",
"\n",
"***Note: The dataset used in this tutorial can be downloaded [here](https://github.com/qiskit-community/prototype-quantum-kernel-training/blob/main/data/dataset_graph7.csv).***"
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"id": "70d6faff-9a56-44bb-b26f-f573a8c90889",
"metadata": {},
"outputs": [
Expand All @@ -144,7 +203,7 @@
"<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/70d6faff-9a56-44bb-b26f-f573a8c90889-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 3,
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -178,7 +237,7 @@
"unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])\n",
"\n",
"# Create the overlap circuit\n",
"overlap_circ = UnitaryOverlap(unitary1, unitary2)\n",
"overlap_circ = unitary_overlap(unitary1, unitary2)\n",
"overlap_circ.measure_all()\n",
"overlap_circ.draw(\"mpl\", scale=0.6, style=\"iqp\")"
]
Expand All @@ -188,7 +247,7 @@
"id": "158d8cec-1d92-4105-ac64-6f801dec4259",
"metadata": {},
"source": [
"## Step 2: Optimize problem for quantum hardware execution\n",
"## Step 2: Optimize for target hardware\n",
"\n",
"* Input: Abstract circuit, not optimized for a particular backend\n",
"* Output: Target circuit and observable, optimized for the selected QPU\n",
Expand All @@ -198,26 +257,34 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "49607b34-9723-493d-85da-bd97c1351104",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using backend: ibm_fez\n"
]
},
{
"data": {
"text/plain": [
"<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/49607b34-9723-493d-85da-bd97c1351104-0.avif\" alt=\"Output of the previous code cell\" />"
"<Image src=\"/docs/images/tutorials/quantum-kernel-training/extracted-outputs/49607b34-9723-493d-85da-bd97c1351104-1.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 4,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"service = QiskitRuntimeService()\n",
"service = QiskitRuntimeService(name=\"solutions_demo_premium\")\n",
"backend = service.least_busy(\n",
" operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits\n",
")\n",
"print(f\"Using backend: {backend.name}\")\n",
"pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
"overlap_ibm = pm.run(overlap_circ)\n",
"overlap_ibm.draw(\"mpl\", scale=0.6, idle_wires=False, fold=-1, style=\"iqp\")"
Expand All @@ -228,7 +295,7 @@
"id": "9359b92c-a130-44d1-ba11-752f8f4935a0",
"metadata": {},
"source": [
"## Step 3: Execute using Qiskit primitives\n",
"## Step 3: Execute on target hardware\n",
"\n",
"* Input: Target circuit\n",
"* Output: Quasi-probability distribution\n",
Expand All @@ -240,7 +307,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"id": "d2f4f6cf-067e-4d53-aa04-7ca9c803d3e1",
"metadata": {},
"outputs": [
Expand All @@ -255,21 +322,17 @@
}
],
"source": [
"num_shots = 10_000\n",
"\n",
"## Evaluate the problem using statevector-based primitives from Qiskit\n",
"# from qiskit.primitives import StatevectorSampler\n",
"\n",
"# sampler = StatevectorSampler()\n",
"# results = sampler.run([overlap_circ]).result()\n",
"# counts = results[0].data.meas.get_int_counts()\n",
"\n",
"# Evaluate the problem using a QPU via Qiskit IBM Runtime\n",
"\n",
"sampler = Sampler(mode=backend)\n",
"results = sampler.run([overlap_ibm]).result()\n",
"# Add tag to the job for reference\n",
"sampler.options.environment.job_tags = [\"quantum-kernel-training-demo\"]\n",
"\n",
"# Execute and get counts\n",
"num_shots = 10_000\n",
"results = sampler.run([overlap_ibm], shots=num_shots).result()\n",
"counts = results[0].data.meas.get_int_counts()\n",
"\n",
"# Plot counts\n",
"visualize_counts(counts, num_qubits, num_shots)"
]
},
Expand All @@ -278,25 +341,25 @@
"id": "1b750103-c369-4651-9092-db0385294c46",
"metadata": {},
"source": [
"## Step 4: Post-process and return result in desired classical format\n",
"## Step 4: Post-process results\n",
"\n",
"* Input: Probability distribution\n",
"* Output: A single kernel matrix element\n",
"\n",
"Calculate the probability of measuring |0> on the overlap circuit, and populate the kernel matrix in the position corresponding to the samples represented by this particular overlap circuit (row 15, column 20). In this visualization, darker red indicates fidelities closer to 1.0. To fill out the entire kernel matrix, we need to run a quantum experiment for each entry."
"Calculate the probability of measuring $|0 \\rangle$ on the overlap circuit, and populate the kernel matrix in the position corresponding to the samples represented by this particular overlap circuit (row 15, column 20). In this visualization, darker red indicates fidelities closer to 1.0. To fill out the entire kernel matrix, we need to run a quantum experiment for each entry."
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 5,
"id": "8efcb466-3110-4e60-82a6-185f0dca1771",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fidelity: 0.1279\n"
"Fidelity: 0.2949\n"
]
}
],
Expand All @@ -315,72 +378,19 @@
"![kernel_matrix.png](/docs/images/tutorials/quantum-kernel-training/kernel_matrix.avif)"
]
},
{
"cell_type": "markdown",
"id": "5b0397d6-6673-45cb-9d38-7e9faadba4a1",
"metadata": {},
"source": [
"## Deploy the Qiskit pattern to the cloud\n",
"\n",
"To do this, move the source code above to a file, `./source/generate_kernel_entry.py`, wrap the code in a script which takes inputs returns the final solution, and finally upload it to a remote cluster using the `QiskitFunction` class from `Qiskit Serverless`. For guidance on specifying external dependencies, passing input arguments, and more, check out the [Qiskit Serverless guides](https://qiskit.github.io/qiskit-serverless/getting_started/index.html).\n",
"\n",
"The input to the Pattern is a pair of data samples, `x1` and `x2`. The output is the fidelity between the two samples. This value will be used to populate the kernel matrix entry corresponding to these two samples."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8ce74c3c-4212-4c75-ae55-1394813c89a6",
"metadata": {},
"outputs": [],
"source": [
"serverless = QiskitServerless()\n",
"\n",
"kernel_entry_pattern = QiskitFunction(\n",
" title=\"generate-kernel-entry\",\n",
" entrypoint=\"generate_kernel_entry.py\",\n",
" working_dir=\"./source/\",\n",
")\n",
"\n",
"serverless.upload(kernel_entry_pattern)"
]
},
{
"cell_type": "markdown",
"id": "f5b1e64a-881e-459e-a425-7876e56d73de",
"metadata": {},
"source": [
"## Run the Qiskit pattern as a managed service\n",
"\n",
"Once we have uploaded the pattern to the cloud, we can easily run it using the `IBMServerlessProvider` client. For simplicity, we will use an exact quantum simulator in the cloud environment, so the fidelity we calculate will be exact."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c70725fe-57e9-42ed-a0a4-daf0222ddc3a",
"metadata": {},
"outputs": [],
"source": [
"generate_kernel_entry = serverless.load(\"generate-kernel-entry\")\n",
"job = generate_kernel_entry.run(\n",
" sample1=list(X_train[x1]), sample2=list(X_train[x2])\n",
")\n",
"\n",
"kernel_matrix[x1, x2] = job.result()[\"fidelity\"]\n",
"print(f\"fidelity: {kernel_matrix[x1, x2]}\")"
]
},
{
"cell_type": "markdown",
"id": "6847b837",
"metadata": {},
"source": [
"## Tutorial survey\n",
"## Next steps\n",
"\n",
"Please take this short survey to provide feedback on this tutorial. Your insights will help us improve our content offerings and user experience.\n",
"If you've found this work interesting, you might be interested in the following material:\n",
"\n",
"[Link to survey](https://your.feedback.ibm.com/jfe/form/SV_6xsFvUYV1pNHCqW)"
" * [Quantum Kernel Training Toolkit](https://github.com/qiskit-community/prototype-quantum-kernel-training/tree/main)\n",
" * [Quantum Kernel Training for Machine Learning Applications](https://qiskit-community.github.io/qiskit-machine-learning/tutorials/08_quantum_kernel_trainer.html)\n",
" * [Introduction to Quantum Machine Learning](https://quantum.cloud.ibm.com/learning/en/courses/quantum-machine-learning/introduction)\n",
" * [Quantum Machine Learning from IBM Research](https://research.ibm.com/topics/quantum-machine-learning)"
]
}
],
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading