> "Can quantum computers learn? The answer is yes — but whether they can learn anything useful faster than classical computers remains one of the most debated questions in the field."
In This Chapter
- Learning Objectives
- 21.1 Why Quantum Machine Learning?
- 21.2 Parameterized Quantum Circuits as ML Models
- 21.3 Training Quantum Neural Networks
- 21.4 Quantum Kernel Methods
- 21.5 Quantum Convolutional Neural Networks (QCNN)
- 21.6 Quantum Generative Models
- 21.6b Quantum Transfer Learning
- 21.7 Classical Shadows for Efficient Readout
- 21.8 Complete Quantum Classifier Implementation
- 21.9 The Current State of QML: Honest Assessment
Chapter 21: Quantum Machine Learning — Variational Circuits, Quantum Kernels, and the Search for Quantum Advantage in ML
"Can quantum computers learn? The answer is yes — but whether they can learn anything useful faster than classical computers remains one of the most debated questions in the field."
Learning Objectives
After completing this chapter, you will be able to:
- Construct parameterized quantum circuits as machine learning models and explain their representational capacity, including universal approximation properties.
- Implement data encoding strategies: angle encoding, amplitude encoding, IQP encoding, and data re-uploading, with detailed analysis of their expressiveness.
- Derive quantum kernel methods and implement a quantum support vector machine (QSVM), including analysis of when quantum kernels can provide advantage.
- Diagnose and mitigate barren plateaus in quantum neural network training, with theoretical understanding of their origins.
- Describe quantum convolutional neural networks (QCNNs) and quantum generative models, including quantum circuit Born machines and quantum GANs.
- Implement complete quantum classifiers using Qiskit Machine Learning.
- Apply classical shadows for efficient readout of quantum states, including the mathematical derivation of the measurement channel and its inverse.
- Implement quantum transfer learning by combining pre-trained classical models with trainable quantum layers.
- Critically evaluate the current evidence for (and against) quantum advantage in machine learning.
- Understand the theoretical limits of quantum kernel methods, including the kernel alignment perspective.
- Compute kernel-target alignment numerically and interpret the results for feature map selection.
21.1 Why Quantum Machine Learning?
21.1.1 The ML Landscape and Quantum Potential
Machine learning has transformed computing: language models, image recognition, drug discovery, recommendation systems. The core computational primitives — matrix multiplication, gradient descent, kernel evaluation — are linear algebra operations. Since quantum computing is natively linear algebra in an exponentially large Hilbert space, the question naturally arises: can quantum computers accelerate machine learning?
The promise of quantum machine learning (QML) rests on several conjectured advantages:
-
Quantum linear algebra speedups. The HHL algorithm (quantum matrix inversion) and related routines offer exponential speedups for certain linear algebra tasks — but with significant caveats (data loading, condition number dependence, output sparsity).
-
Quantum kernel methods. Quantum circuits can define kernel functions $k(x, x') = |\langle \phi(x) | \phi(x') \rangle|^2$ that may be classically intractable to compute, potentially enabling SVMs with superior decision boundaries.
-
Efficient representation of quantum data. If the data itself is quantum (e.g., from a quantum sensor or quantum simulation), a quantum learner can process it natively without the classical measurement bottleneck.
-
Variational quantum circuits as neural networks. Parameterized quantum circuits can serve as trainable models, with the Hilbert space providing an exponentially large feature space.
21.1.2 The Reality Check
Recurring Theme: We're at the Beginning. As of 2025, no QML algorithm has demonstrated a provable, practical advantage over classical ML for a real-world problem. The field is in an exploratory phase — building prototypes, establishing theory, and searching for the killer application. This chapter gives you the tools to participate in that search, with honest assessment of where the field stands.
The key challenges: - Data loading bottleneck: Encoding classical data into quantum states costs $O(N)$ operations for $N$ data points, potentially eliminating any speedup. - Classical simulability: Many proposed quantum kernels and QNNs can be efficiently simulated classically (via tensor networks, Clifford expansions, or kernel-target alignment analysis). - Barren plateaus: Training variational quantum circuits becomes exponentially hard as the system size grows. - Limited qubit counts: Current devices have hundreds of noisy qubits, far below what's needed for most proposed QML applications.
21.1.3 Historical Context
Quantum machine learning emerged from two directions. In the early 2000s, quantum algorithms for linear algebra (HHL, 2009) promised exponential speedups for tasks like matrix inversion and solving linear systems. However, these required fault-tolerant quantum computers and had restrictive assumptions about data structure. Starting around 2015, variational quantum algorithms (VQE, QAOA) offered a NISQ-friendly approach, and researchers began adapting these frameworks for machine learning tasks. The field has since seen a proliferation of proposals, many of which have been "dequantized" — shown to have efficient classical simulations.
Common Misconception: "Quantum computers will replace GPUs for machine learning." This is extremely unlikely in the foreseeable future. Classical ML hardware (GPUs, TPUs) benefits from decades of optimization, massive parallelism, and enormous training datasets. Quantum advantage in ML, if it comes, will be for specific, carefully chosen problem instances — not wholesale replacement of classical ML.
21.2 Parameterized Quantum Circuits as ML Models
A quantum neural network (QNN) is a parameterized quantum circuit $U(\boldsymbol{\theta})$ that maps input data $\mathbf{x}$ to a prediction $\hat{y}$:
$$\hat{y}(\mathbf{x}; \boldsymbol{\theta}) = \langle 0 | U^\dagger(\mathbf{x}, \boldsymbol{\theta}) \, O \, U(\mathbf{x}, \boldsymbol{\theta}) | 0 \rangle$$
where $O$ is a measurement observable (typically a Pauli-$Z$ on the first qubit) and $U(\mathbf{x}, \boldsymbol{\theta})$ encodes both the data and the trainable parameters.
21.2.1 Model Architecture
┌─────────────────────────────────────────────────────────┐
│ |0⟩ ──[Data Encoding]──[Variational Block]──[Measure] │
│ |0⟩ ──[ S(x) ]──[ V(θ) ]──[Measure] │
│ |0⟩ ──[ ]──[ ]──[Measure] │
│ ... │
│ │
│ Repeat L times (data re-uploading) │
└─────────────────────────────────────────────────────────┘
The circuit consists of alternating data encoding layers $S(\mathbf{x})$ and variational layers $V(\boldsymbol{\theta}_\ell)$. This structure — called data re-uploading — increases the model's expressiveness by embedding the data multiple times at different stages of the quantum computation.
21.2.2 Data Encoding Strategies
Angle Encoding: Each component of $\mathbf{x} \in \mathbb{R}^d$ is encoded as a rotation angle:
$$S(\mathbf{x}) = \bigotimes_{i=1}^{d} R_Y(x_i) \quad \text{or} \quad S(\mathbf{x}) = \bigotimes_{i=1}^{d} R_Z(\arctan(x_i)) R_Y(\arcsin(x_i))$$
Requires $d$ qubits for $d$ features. Simple and NISQ-friendly.
Detailed derivation of angle encoding:
For a single feature $x$, the two-angle encoding $R_Z(\arctan(x)) R_Y(\arcsin(x))|0\rangle$ maps to:
$$|\psi(x)\rangle = \cos\left(\frac{\arcsin(x)}{2}\right)|0\rangle + e^{i\arctan(x)}\sin\left(\frac{\arcsin(x)}{2}\right)|1\rangle$$
This provides a one-to-one mapping between $x \in [-1, 1]$ and a point on the Bloch sphere, ensuring no information is lost in the encoding.
Amplitude Encoding: The data vector $\mathbf{x}$ (normalized to unit norm) is encoded in the amplitudes of a quantum state:
$$|\psi_{\mathbf{x}}\rangle = \sum_{i=0}^{2^n - 1} x_i |i\rangle$$
Requires only $\lceil \log_2 d \rceil$ qubits — exponentially efficient in qubit count. However, preparing an arbitrary amplitude-encoded state requires $O(d)$ gates in general, negating the exponential advantage unless the data has special structure.
Worked Example 21.1: Amplitude Encoding for Iris Data
The Iris dataset has 4 features per sample. Using amplitude encoding:
$$|\psi_{\mathbf{x}}\rangle = x_0|00\rangle + x_1|01\rangle + x_2|10\rangle + x_3|11\rangle$$
This requires only 2 qubits! However, the state preparation circuit requires up to $O(2^2) = O(4)$ gates. For a dataset with 256 features, amplitude encoding uses only 8 qubits but requires $O(256)$ gates for state preparation.
IQP Encoding (Instantaneous Quantum Polynomial): Applies gates of the form $e^{-i x_i H}$ where $H$ is a fixed Hamiltonian. The encoding circuit is:
$$S(\mathbf{x}) = \prod_{i} e^{-i x_i Z_i} \prod_{(i,j)} e^{-i x_i x_j Z_i Z_j}$$
This encoding is conjectured to be classically hard to simulate, making it a candidate for quantum advantage in kernel methods. The IQP encoding creates entanglement between features — the $ZZ$ terms create correlations between different data dimensions that cannot be represented by single-qubit rotations alone.
Hamiltonian Evolution Encoding: Encodes data by evolving under a data-dependent Hamiltonian:
$$S(\mathbf{x}) = e^{-i H(\mathbf{x}) t}$$
where $H(\mathbf{x}) = \sum_i x_i H_i$. This is the most general encoding and subsumes the others.
Comparison of encoding strategies:
| Encoding | Qubits | Depth | Expressiveness | Classical Simulability |
|---|---|---|---|---|
| Angle | $O(d)$ | $O(1)$ | Limited | Easy |
| Amplitude | $O(\log d)$ | $O(d)$ | High | Hard (general) |
| IQP | $O(d)$ | $O(1)$–$O(d^2)$ | High | Conjectured hard |
| Hamiltonian | $O(\log d)$–$O(d)$ | Variable | Highest | Generally hard |
Try It Yourself — Data Encoding Exploration: Implement all four encoding strategies (angle, amplitude, IQP, Hamiltonian evolution) for the following 3-dimensional data point: $\mathbf{x} = (0.5, 1.2, -0.3)$. For each encoding: (a) construct the state $|\psi(\mathbf{x})\rangle$ on a quantum circuit, (b) compute the fidelity $|\langle\psi(\mathbf{x})|\psi(\mathbf{x} + \epsilon)\rangle|^2$ for $\epsilon = 0.01$ along each axis, (c) verify that angle encoding produces a continuous mapping while amplitude encoding can produce discontinuities in the state as features vary. Which encoding preserves the most local structure of the data?
21.2.3 Variational Layers
The variational layers $V(\boldsymbol{\theta})$ are typically hardware-efficient circuits: layers of single-qubit rotations and entangling gates:
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter, ParameterVector
import numpy as np
def variational_layer(qc, qubits, theta_params):
"""Add a hardware-efficient variational layer."""
n = len(qubits)
# Single-qubit rotations
for i in range(n):
qc.ry(theta_params[3*i], qubits[i])
qc.rz(theta_params[3*i + 1], qubits[i])
qc.ry(theta_params[3*i + 2], qubits[i])
# Entangling ladder
for i in range(n - 1):
qc.cx(qubits[i], qubits[i + 1])
qc.cx(qubits[-1], qubits[0]) # Cyclic connection
21.2.4 Universal Approximation of QNNs
A natural question is: can QNNs approximate any function? The answer is yes, under certain conditions.
Theorem (Universal Approximation for QNNs): Let $f: \mathbb{R}^d \to \mathbb{R}$ be a continuous function on a compact domain. Then for any $\epsilon > 0$, there exists a parameterized quantum circuit $U(\mathbf{x}, \boldsymbol{\theta})$ with sufficient depth and data re-uploading rounds such that:
$$|f(\mathbf{x}) - \langle 0 | U^\dagger(\mathbf{x}, \boldsymbol{\theta}) O U(\mathbf{x}, \boldsymbol{\theta}) | 0 \rangle| < \epsilon \quad \forall \mathbf{x}$$
The key requirement is data re-uploading — encoding the input data at multiple points in the circuit. Without re-uploading, a single data encoding step followed by a variational layer cannot approximate arbitrary functions (the output becomes a linear function of the data in the feature space defined by the encoding).
This is analogous to the universal approximation theorem for classical neural networks — existence does not guarantee trainability or efficiency.
Common Misconception: "QNNs can learn any function because they operate in an exponentially large Hilbert space." While the Hilbert space is exponentially large, the number of trainable parameters is polynomial. The effective expressiveness depends on the ansatz structure, not just the dimension of the Hilbert space. A poorly structured ansatz in a large Hilbert space can still have limited expressiveness.
Common Misconception: "Amplitude encoding gives an exponential advantage because it uses only $\log_2(d)$ qubits for $d$ features." This is misleading. While amplitude encoding uses exponentially fewer qubits, the circuit depth to prepare an arbitrary amplitude-encoded state is $O(d)$ — the same as the number of classical data points. The qubit savings do not translate to computational savings unless the state has special structure (e.g., it is a product state or has low entanglement) that enables efficient preparation. The data loading bottleneck remains: you cannot compress $d$ classical features into $\log_2(d)$ qubits without spending at least $O(d)$ quantum gates.
21.2.5 Expressibility and Entangling Capacity
Two quantitative metrics characterize the power of a parameterized quantum circuit as a ML model:
Expressibility measures how well the circuit's output distribution covers the Hilbert space. Formally, it is quantified by the distance between the distribution of circuit outputs over random parameters and the Haar-uniform distribution on the unitary group:
$$\mathcal{E} = D_{\text{KL}}(P_{\text{circuit}} \| P_{\text{Haar}})$$
where $P_{\text{circuit}}$ is the distribution of fidelities $|\langle \psi_i | \psi_j \rangle|^2$ for randomly parameterized circuit outputs, and $P_{\text{Haar}}$ is the corresponding distribution for Haar-random states. A low KL divergence indicates high expressibility.
Step-by-step computation of expressibility:
- Sample $K$ random parameter sets $\{\boldsymbol{\theta}_1, \ldots, \boldsymbol{\theta}_K\}$.
- Compute the pairwise fidelities $|\langle \psi(\boldsymbol{\theta}_i) | \psi(\boldsymbol{\theta}_j) \rangle|^2$ for all $i < j$.
- Construct the histogram of fidelities and compare with the Haar distribution $P_{\text{Haar}}(F) = (2^n - 1)(1 - F)^{2^n - 2}$ for $n$-qubit states.
- Compute the KL divergence between the empirical and Haar distributions.
For $n$ qubits, the Haar distribution of fidelities has mean $\langle F \rangle = 1/(2^n)$ and concentrates sharply around this mean for large $n$.
Entangling capacity measures the amount of entanglement the circuit can generate. It is quantified by the Meyer-Wallach entanglement measure:
$$Q(\boldsymbol{\theta}) = \frac{4}{n}\sum_{k=1}^{n} D\left(\text{Tr}_{\bar{k}}[|\psi(\boldsymbol{\theta})\rangle\langle\psi(\boldsymbol{\theta})|]\right)$$
where $D(\rho) = 1 - \text{Tr}(\rho^2)$ is the linear entropy of qubit $k$'s reduced state. $Q = 0$ for product states (no entanglement) and $Q = 1$ for maximally entangled states.
Worked Example 21.1b: Expressibility of Different Ansatzes
Consider three 4-qubit ansatzes: - Ansatz A: Hardware-efficient, 1 layer ($R_Y R_Z$ + CNOT ladder). Expressibility: LOW. The distribution of fidelities is concentrated near 1 (most random parameters produce similar states). - Ansatz B: Hardware-efficient, 4 layers. Expressibility: HIGH. The fidelity distribution approaches the Haar distribution. - Ansatz C: UCCSD-inspired. Expressibility: MODERATE. The circuit is structured by chemistry, so it doesn't cover all of Hilbert space, but it covers the relevant subspace.
The trade-off is clear: high expressibility (necessary for universality) leads to barren plateaus (exponentially small gradients), while low expressibility may not reach the target function. The ideal ansatz for a given problem is expressive enough to represent the target but structured enough to remain trainable.
Try It Yourself: For $n = 2, 3, 4$ qubits, compute the expressibility (KL divergence from Haar) of a hardware-efficient ansatz with 1, 2, 3, and 4 layers. Plot expressibility vs. number of layers. At what depth does the ansatz become "Haar-like" (KL divergence $< 0.01$)?
21.3 Training Quantum Neural Networks
21.3.1 Loss Functions
For binary classification with labels $y \in \{0, 1\}$, the prediction is:
$$\hat{y}(\mathbf{x}; \boldsymbol{\theta}) = \frac{1 + \langle Z_0 \rangle}{2} \in [0, 1]$$
Common loss functions:
- Mean Squared Error: $\mathcal{L}(\boldsymbol{\theta}) = \frac{1}{N} \sum_{i=1}^{N} (\hat{y}_i - y_i)^2$
- Binary Cross-Entropy: $\mathcal{L}(\boldsymbol{\theta}) = -\frac{1}{N} \sum_i [y_i \log \hat{y}_i + (1-y_i) \log(1-\hat{y}_i)]$
For multi-class classification with $K$ classes, one measures multiple qubits or uses multiple observables:
$$\hat{y}_k = \text{softmax}_k\left(\langle Z^{(1)}\rangle, \ldots, \langle Z^{(K)}\rangle\right)$$
21.3.2 Gradient Computation
The parameter-shift rule (Chapter 19) applies directly:
$$\frac{\partial \langle O \rangle}{\partial \theta_k} = \frac{1}{2}\Big[\langle O \rangle_{\theta_k + \pi/2} - \langle O \rangle_{\theta_k - \pi/2}\Big]$$
Worked Example 21.2: Parameter-Shift Rule for a Single Qubit
Consider the circuit $U(\theta) = R_Y(\theta)|0\rangle$ with observable $O = Z$. The expectation value is:
$$\langle Z \rangle = \cos(\theta)$$
Using the parameter-shift rule:
$$\frac{\partial \langle Z \rangle}{\partial \theta} = \frac{1}{2}[\cos(\theta + \pi/2) - \cos(\theta - \pi/2)] = \frac{1}{2}[-\sin(\theta) - \sin(\theta)] = -\sin(\theta)$$
This matches the analytical derivative $\frac{d}{d\theta}\cos(\theta) = -\sin(\theta)$. $\square$
For $p$ parameters, each gradient evaluation requires $2p$ circuit executions. This is the dominant cost in QNN training.
Recurring Theme: Quantum Is Linear Algebra, Not Magic. The parameter-shift rule is not a quantum trick — it is a consequence of the structure of $SU(2)$ rotations. Any single-qubit rotation $e^{-i\theta P/2}$ with $P^2 = I$ satisfies this rule. It works because of the algebraic properties of Pauli matrices, not because of any exotic quantum phenomenon.
21.3.3 The Barren Plateau Problem
The most serious obstacle to scaling QNNs is the barren plateau phenomenon. For a wide class of parameterized quantum circuits, the gradient variance vanishes exponentially with the number of qubits:
$$\text{Var}\left[\frac{\partial \mathcal{L}}{\partial \theta_k}\right] \sim O\left(\frac{1}{2^n}\right)$$
This means that for $n \gtrsim 20$, the training landscape is essentially flat — gradient descent cannot find a direction to descend, and training requires exponentially many measurements to resolve the gradient from statistical noise.
When do barren plateaus occur? - Deep, unstructured ansatzes (random circuits). - Global cost functions (measuring all qubits). - High entanglement between qubits. - Excessive expressiveness (the circuit forms a 2-design).
Detailed analysis of barren plateaus:
McClean et al. (2018) showed that for any cost function $C(\boldsymbol{\theta}) = \langle\psi(\boldsymbol{\theta})|H|\psi(\boldsymbol{\theta})\rangle$ where the ansatz $U(\boldsymbol{\theta})$ is drawn from a 2-design:
$$\text{Var}[C] = \frac{\text{Tr}(H^2) - \frac{(\text{Tr}H)^2}{2^n}}{2^n(2^n + 1)}$$
$$\text{Var}\left[\frac{\partial C}{\partial \theta_k}\right] = \frac{\text{Var}[C]}{2^n(2^n + 1)}$$
This vanishes doubly exponentially: the variance of the cost function is $O(1/2^n)$ and the variance of the gradient is $O(1/4^n)$.
Step-by-step derivation of the barren plateau variance:
The gradient of the cost function with respect to parameter $\theta_k$ is:
$$\frac{\partial C}{\partial \theta_k} = \langle\psi|H U_k^\dagger P_k U_k|\psi\rangle - \langle\psi|U_k^\dagger P_k U_k|\psi\rangle \langle\psi|H|\psi\rangle$$
where $U_k$ is the unitary preceding parameter $\theta_k$ and $P_k$ is the associated Pauli generator. Using the Haar measure properties of the 2-design:
$$\mathbb{E}_{\boldsymbol{\theta}}\left[\frac{\partial C}{\partial \theta_k}\right] = 0$$
$$\mathbb{E}_{\boldsymbol{\theta}}\left[\left(\frac{\partial C}{\partial \theta_k}\right)^2\right] = \frac{\text{Tr}(H^2) - \frac{(\text{Tr}H)^2}{2^n}}{2^n(2^n + 1)}$$
The exponential suppression in $n$ arises because each qubit adds a factor of $1/2$ to the overlap between the gradient and any fixed direction. This is a fundamental geometric property of high-dimensional Hilbert spaces, not an artifact of the ansatz.
Mitigation strategies: - Local cost functions: Measure only a few qubits rather than all. Local cost functions $\langle h_i \rangle$ with $h_i$ acting on a constant number of qubits have gradient variance $O(1/\text{poly}(n))$, avoiding barren plateaus. - Shallow circuits: Limit depth to $O(\log n)$. Shallow circuits with limited entanglement avoid the 2-design property. - Correlated parameters: Use parameter structures that avoid the 2-design property. Examples include layerwise training, structured initialization, and hardware-efficient ansatzes with limited connectivity. - Layerwise training: Train one layer at a time, freezing previous layers. This keeps the circuit shallow during each training phase. - Classical initialization: Start from parameters that encode a classical approximation (e.g., transfer learning from a classical neural network).
Worked Example 21.2b: Quantifying the Barren Plateau
Consider a 10-qubit hardware-efficient ansatz with 5 layers, measured with the global observable $H = Z^{\otimes 10}$. For a 2-design:
$$\text{Var}[C] = \frac{\text{Tr}(H^2) - (\text{Tr}H)^2/2^{10}}{2^{10}(2^{10}+1)} = \frac{2^{10} - 0}{2^{10}(2^{10}+1)} \approx 10^{-3}$$
The gradient variance is:
$$\text{Var}\left[\frac{\partial C}{\partial \theta_k}\right] = \frac{\text{Var}[C]}{2^{10}(2^{10}+1)} \approx \frac{10^{-3}}{10^6} \approx 10^{-9}$$
This means each gradient component has a standard deviation of $\sim 10^{-4.5}$, which is below the resolution of typical shot noise ($\sim 10^{-3}$ for $10^6$ shots). The gradient is effectively invisible — the optimizer cannot determine which direction to move.
Now consider a local observable $H = Z_1$ (acting on a single qubit):
$$\text{Var}[C]_{\text{local}} = \frac{\text{Tr}(Z_1^2) - (\text{Tr}Z_1)^2/2^{10}}{2^{10}(2^{10}+1)} = \frac{2^{10} - 0}{2^{10}(2^{10}+1)} \approx 10^{-3}$$
The gradient variance for local observables is:
$$\text{Var}\left[\frac{\partial C_{\text{local}}}{\partial \theta_k}\right] \sim O\left(\frac{1}{n}\right) = O(0.1)$$
This is 6 orders of magnitude larger than for global observables! Local cost functions are dramatically more trainable.
Try It Yourself: Implement a function that estimates the gradient variance for a hardware-efficient ansatz with $n = 2, 4, 6, 8, 10$ qubits. For each $n$, sample 500 random parameter sets and compute $\text{Var}[\partial \mathcal{L} / \partial \theta_1]$. Plot the variance vs. $n$ on a log scale. At what $n$ does the variance become smaller than $10^{-6}$?
21.4 Quantum Kernel Methods
An alternative to training variational circuits is to use quantum circuits to define kernel functions for classical ML models (SVMs, kernel ridge regression).
21.4.1 Quantum Feature Maps
A quantum feature map $\phi: \mathbb{R}^d \to \mathcal{H}$ maps classical data $\mathbf{x}$ to a quantum state $|\phi(\mathbf{x})\rangle$ in a Hilbert space $\mathcal{H}$ of dimension $2^n$:
$$|\phi(\mathbf{x})\rangle = U_{\phi}(\mathbf{x}) |0\rangle^{\otimes n}$$
The quantum kernel is the inner product (fidelity) between two feature states:
$$k(\mathbf{x}, \mathbf{x}') = |\langle \phi(\mathbf{x}) | \phi(\mathbf{x}') \rangle|^2 = |\langle 0 | U_{\phi}^\dagger(\mathbf{x}) U_{\phi}(\mathbf{x}') | 0 \rangle|^2$$
This kernel can be estimated on a quantum computer by measuring the probability of the all-zero outcome after applying $U_{\phi}^\dagger(\mathbf{x}) U_{\phi}(\mathbf{x}')$:
Kernel estimation circuit:
|0⟩^n ──[ U_φ(x) ]──[ U_φ†(x') ]── Measure all qubits
k(x, x') = P(measure |0...0⟩)
Why quantum kernels might help: The quantum feature map embeds data into a $2^n$-dimensional Hilbert space. If this embedding creates complex, nonlinear decision boundaries that are hard to compute classically, the resulting kernel may enable superior classification.
21.4.2 The Kernel Alignment Perspective
Not all quantum kernels are useful. The key question is: does the quantum kernel capture the structure of the data?
Kernel-target alignment measures how well a kernel $k$ aligns with the target labels:
$$A(k, y) = \frac{\sum_{i,j} k(\mathbf{x}_i, \mathbf{x}_j) y_i y_j}{\sqrt{\sum_{i,j} k(\mathbf{x}_i, \mathbf{x}_j)^2 \sum_{i,j} y_i^2 y_j^2}}$$
A high alignment means the kernel separates the classes well. A random kernel (e.g., from a random quantum circuit) will have near-zero alignment — it embeds data into a random high-dimensional space, but this does not help classification.
Common Misconception: "Any quantum kernel that is hard to compute classically provides advantage." This is false. A kernel can be computationally hard to compute AND useless for learning. What matters is whether the kernel captures the structure of the data, not whether it's hard to compute. Hard-to-compute kernels that have high alignment with the target are the ones that matter.
21.4.3 Quantum Support Vector Machine (QSVM)
A QSVM uses a quantum kernel within the classical SVM framework. The decision function is:
$$f(\mathbf{x}) = \text{sign}\left(\sum_{i=1}^{N} \alpha_i y_i k(\mathbf{x}_i, \mathbf{x}) + b\right)$$
where $\alpha_i$ are the dual coefficients (solved classically) and $k$ is the quantum kernel. The "quantum" part is only the kernel evaluation; the SVM optimization is entirely classical.
The potential advantage: If $k(\mathbf{x}, \mathbf{x}')$ is classically intractable to compute (i.e., no classical algorithm can estimate it in polynomial time), then the QSVM can access a kernel that no classical SVM can. This is the quantum kernel advantage hypothesis.
The challenge: For the advantage to be real, the data must be such that the quantum kernel is both (a) classically hard to compute and (b) actually useful for the learning task. Finding such data is an open problem.
21.4.4 Complete QSVM Implementation
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter, ParameterVector
from qiskit_aer import AerSimulator
from qiskit_machine_learning.kernels import FidelityQuantumKernel
from qiskit_machine_learning.algorithms import QSVC
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
# ── Step 1: Generate dataset ──
X, y = make_moons(n_samples=200, noise=0.15, random_state=42)
y = 2 * y - 1 # Convert to {-1, +1} for SVM
# Normalize features to [0, 2π] for angle encoding
X_scaled = StandardScaler().fit_transform(X)
X_scaled = np.pi * (X_scaled - X_scaled.min(axis=0)) / \
(X_scaled.max(axis=0) - X_scaled.min(axis=0))
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.3, random_state=42
)
print(f"Training samples: {len(X_train)}")
print(f"Test samples: {len(X_test)}")
# ── Step 2: Define the quantum feature map ──
def create_feature_map(n_qubits=2, reps=2):
"""
Create a ZZFeatureMap: an IQP-style encoding circuit.
Circuit structure (reps=2):
|0⟩ ─[H]─[P(x_0)]──●──────────●──[H]─[P(x_0)]──●──────────●──
│ │ │ │
|0⟩ ─[H]─[P(x_1)]──┼──●───────┼──[H]─[P(x_1)]──┼──●───────┼──
│ │ │ │ │ │
[ZZ(x_0*x_1)]│ [ZZ(x_0*x_1)]│
│ │
[ZZ(x_0*x_1)] [ZZ(x_0*x_1)]
"""
x_params = ParameterVector('x', n_qubits)
qc = QuantumCircuit(n_qubits)
for _ in range(reps):
for i in range(n_qubits):
qc.h(i)
qc.p(x_params[i], i)
for i in range(n_qubits):
for j in range(i + 1, n_qubits):
qc.cx(i, j)
qc.p(2 * x_params[i] * x_params[j], j)
qc.cx(i, j)
return qc, x_params
feature_map, x_params = create_feature_map(n_qubits=2, reps=2)
print(f"\nFeature map circuit:")
print(f" Qubits: {feature_map.num_qubits}")
print(f" Depth: {feature_map.depth()}")
print(f" Parameters: {feature_map.num_parameters}")
# ── Step 3: Create the quantum kernel ──
quantum_kernel = FidelityQuantumKernel(
feature_map=feature_map,
# fidelity is computed as |⟨0|U†(x')U(x)|0⟩|²
)
# ── Step 4: Train QSVC ──
qsvc = QSVC(quantum_kernel=quantum_kernel)
qsvc.fit(X_train, y_train)
# ── Step 5: Evaluate ──
train_score = qsvc.score(X_train, y_train)
test_score = qsvc.score(X_test, y_test)
print(f"\n{'='*60}")
print(f"QSVM Results")
print(f"{'='*60}")
print(f"Training accuracy: {train_score:.4f}")
print(f"Test accuracy: {test_score:.4f}")
# ── Step 6: Visualize decision boundary ──
xx, yy = np.meshgrid(
np.linspace(X_scaled[:, 0].min() - 0.1, X_scaled[:, 0].max() + 0.1, 50),
np.linspace(X_scaled[:, 1].min() - 0.1, X_scaled[:, 1].max() + 0.1, 50)
)
grid = np.c_[xx.ravel(), yy.ravel()]
Z = qsvc.predict(grid).reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train,
cmap='coolwarm', edgecolors='k', label='Train')
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test,
cmap='coolwarm', edgecolors='k', marker='s', s=80, label='Test')
plt.title(f'QSVM on Moons Dataset\nTest Accuracy: {test_score:.3f}')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.tight_layout()
plt.savefig('qsvm_decision_boundary.png', dpi=150)
print("Decision boundary saved to qsvm_decision_boundary.png")
21.4.5 When Can Quantum Kernels Provide Advantage?
Huang et al. (2021) provided a rigorous framework for assessing quantum kernel advantage. The key result is:
Theorem (Kernel Advantage Condition): A quantum kernel provides advantage over classical kernels if and only if: 1. The kernel is hard to compute classically (computational advantage), AND 2. The kernel has high alignment with the target function (statistical advantage).
Condition 2 can be formalized: the kernel-target alignment must be significantly above random. If the quantum kernel has low alignment, it is no better than a random feature map — even if it's hard to compute classically.
Dequantization results: Several proposals for quantum kernel advantage have been "dequantized" — shown to have efficient classical simulations. The general lesson is that kernel methods based on low-depth circuits (which are necessary for NISQ) tend to be classically simulable. Only kernels requiring deep, entangling circuits are plausibly hard to simulate, but these are also harder to train and more susceptible to noise.
21.4.6 Quantum Kernel Advantage: Sufficient Conditions
Recent theoretical work has established clearer conditions for when quantum kernels can outperform classical kernels:
Theorem (Liu et al., 2021): A quantum kernel $k(\mathbf{x}, \mathbf{x}') = |\langle \phi(\mathbf{x}) | \phi(\mathbf{x}')\rangle|^2$ provides a rigorous advantage for a learning task if:
- The kernel is computationally hard to estimate classically (i.e., computing $|\langle \phi(\mathbf{x}) | \phi(\mathbf{x}')\rangle|^2$ requires superpolynomial time on a classical computer).
- There exists a classical description of the data that allows efficient generalization from the kernel matrix.
Condition 1 ensures computational advantage, while condition 2 ensures that the learning problem is tractable (not just the kernel evaluation).
Worked Example 21.3b: Kernel Alignment for Feature Map Selection
Consider two feature maps for a binary classification task with labels $y \in \{-1, +1\}$:
Feature Map A (ZZ feature map): $$|\phi_A(\mathbf{x})\rangle = e^{-i x_1 Z_1} e^{-i x_2 Z_2} e^{-i x_1 x_2 Z_1 Z_2} |+\rangle^{\otimes 2}$$
Feature Map B (Random unitary): $$|\phi_B(\mathbf{x})\rangle = U_{\text{rand}} \cdot e^{-i x_1 Z_1} e^{-i x_2 Z_2} |+\rangle^{\otimes 2}$$
For a dataset with labels determined by $y = \text{sign}(x_1 x_2)$ (a nonlinear decision boundary):
Kernel A alignment: The ZZ feature map creates the kernel $k_A(\mathbf{x}, \mathbf{x}') = \cos(x_1 - x_1')\cos(x_2 - x_2')\cos(x_1 x_2 - x_1' x_2')$, which has high alignment with the $x_1 x_2$ label structure. The kernel-target alignment $A(k_A, y) \approx 0.85$.
Kernel B alignment: The random unitary scrambles the feature map, producing a kernel that is essentially random. The kernel-target alignment $A(k_B, y) \approx 0.05$ (close to zero).
This illustrates that kernel alignment — not computational hardness — determines practical utility. A classically simulable kernel (Feature Map A) with high alignment is far more useful than a classically hard kernel (Feature Map B) with low alignment.
Common Misconception: "A quantum kernel that is hard to compute classically automatically provides an advantage." The kernel must also be aligned with the learning task. A random quantum kernel is hard to compute classically but useless for learning — it projects data into a random high-dimensional space where no structure is preserved.
21.4.7 Worked Example: Kernel Alignment Calculation
We now walk through a complete kernel alignment calculation step by step, including the code to reproduce it.
Setup: Consider a 2D binary classification dataset with 4 training points:
$$\mathbf{x}_1 = (0.5, 0.5), \quad y_1 = +1$$ $$\mathbf{x}_2 = (1.0, 0.5), \quad y_2 = +1$$ $$\mathbf{x}_3 = (-0.5, -0.5), \quad y_3 = -1$$ $$\mathbf{x}_4 = (-1.0, -0.5), \quad y_4 = -1$$
The decision boundary is roughly $x_1 > 0$ — the first feature separates the classes.
Step 1: Compute the quantum kernel matrix. We use the ZZ feature map with 2 repetitions:
$$|\phi(\mathbf{x})\rangle = U_{ZZ}(\mathbf{x})|0\rangle^{\otimes 2}$$
where $U_{ZZ}$ applies Hadamard gates followed by phase gates $e^{-ix_i Z_i}$ and entangling gates $e^{-ix_i x_j Z_i Z_j}$.
The kernel matrix $K$ has entries $K_{ij} = |\langle\phi(\mathbf{x}_i)|\phi(\mathbf{x}_j)\rangle|^2$. For the ZZ feature map, this can be computed analytically:
$$k(\mathbf{x}, \mathbf{x}') = \prod_{i} \cos\!\left(\frac{x_i - x_i'}{2}\right)^2 \cdot \prod_{i (simplified for Step 2: Compute kernel-target alignment. The target matrix is $Y_{ij} = y_i \cdot y_j$: $$Y = \begin{pmatrix} 1 & 1 & -1 & -1 \\ 1 & 1 & -1 & -1 \\ -1 & -1 & 1 & 1 \\ -1 & -1 & 1 & 1 \end{pmatrix}$$ The alignment is: $$A(k, y) = \frac{\langle K, Y \rangle_F}{\|K\|_F \cdot \|Y\|_F} = \frac{\sum_{i,j} K_{ij} Y_{ij}}{\sqrt{\sum_{i,j} K_{ij}^2} \cdot \sqrt{\sum_{i,j} Y_{ij}^2}}$$ For a well-aligned kernel, same-class pairs have $K_{ij} \approx 1$ (large) and different-class pairs have $K_{ij} \approx 0$ (small), making the numerator large and the alignment close to 1. Step 3: Numerical calculation. We implement this in Qiskit: Typical output for this dataset:
- ZZ feature map alignment: $\approx 0.75$–$0.90$ (high — the ZZ encoding captures the $x_1 x_2$ correlation that separates the classes)
- Random unitary alignment: $\approx 0.05$–$0.15$ (near zero — the random encoding destroys class structure) This dramatic difference confirms that kernel alignment, not computational hardness, determines practical utility. QCNNs are the quantum analog of classical convolutional neural networks. They are designed to process quantum data with a hierarchical, translationally invariant structure — ideal for tasks like quantum phase recognition and quantum error correction. A QCNN consists of three types of layers, applied in a tree-like structure: Convolution layer: A parameterized unitary $V(\boldsymbol{\theta})$ applied to small clusters of neighboring qubits. This is the quantum analog of a convolutional filter. Pooling layer: A parameterized unitary followed by measurement of a subset of qubits. The measured outcomes control single-qubit rotations on the remaining qubits, reducing the system size by a factor of 2 at each pooling layer. This is the quantum analog of pooling/striding. Fully connected layer: After several convolution-pooling stages, the remaining few qubits are processed by a final unitary and measured to produce the output. Translational invariance: The same convolution unitary $V$ is applied across all positions, giving the QCNN the ability to recognize patterns regardless of their location. Logarithmic depth: The number of layers scales as $O(\log n)$, making QCNNs naturally shallow and NISQ-friendly. For $n$ qubits, there are $\log_2 n$ convolution-pooling stages. No barren plateaus (for local cost functions): The hierarchical structure and local measurements protect QCNNs from barren plateaus. Zheng et al. (2023) proved that QCNNs with local cost functions have gradient variance $\Omega(1/\text{poly}(n))$, ensuring trainability at scale. Common Misconception: "QCNNs are just classical CNNs implemented on a quantum computer." This is wrong on two counts. First, QCNNs are designed to process quantum data (quantum states), not classical images — the convolution and pooling operations act on quantum superpositions, producing entanglement and interference effects that have no classical analog. Second, even when processing classical data, the QCNN's convolution filters are unitary operators acting on Hilbert space, which is fundamentally different from classical convolution in Euclidean space. The name "convolutional" refers to the structural analogy (local operations + hierarchical pooling), not the computational mechanism. Quantum computers can also generate data — learning the underlying probability distribution of a dataset and producing new samples. A QCBM is a parameterized quantum circuit whose output distribution (via the Born rule) is trained to match a target data distribution: $$p_{\boldsymbol{\theta}}(\mathbf{x}) = |\langle \mathbf{x} | \psi(\boldsymbol{\theta}) \rangle|^2$$ Training minimizes a divergence measure between $p_{\boldsymbol{\theta}}$ and the target distribution $p_{\text{data}}$: Maximum Likelihood Training:
$$\mathcal{L}(\boldsymbol{\theta}) = -\sum_{\mathbf{x}} p_{\text{data}}(\mathbf{x}) \log p_{\boldsymbol{\theta}}(\mathbf{x})$$ KL Divergence Training:
$$\mathcal{L}(\boldsymbol{\theta}) = D_{\text{KL}}(p_{\text{data}} \| p_{\boldsymbol{\theta}}) = \sum_{\mathbf{x}} p_{\text{data}}(\mathbf{x}) \log \frac{p_{\text{data}}(\mathbf{x})}{p_{\boldsymbol{\theta}}(\mathbf{x})}$$ Maximum Mean Discrepancy (MMD) Training:
$$\mathcal{L}(\boldsymbol{\theta}) = \text{MMD}^2(p_{\text{data}}, p_{\boldsymbol{\theta}}) = \mathbb{E}_{\mathbf{x}, \mathbf{x}' \sim p_{\text{data}}} k(\mathbf{x}, \mathbf{x}') - 2\mathbb{E}_{\mathbf{x} \sim p_{\text{data}}, \mathbf{y} \sim p_{\boldsymbol{\theta}}} k(\mathbf{x}, \mathbf{y}) + \mathbb{E}_{\mathbf{y}, \mathbf{y}' \sim p_{\boldsymbol{\theta}}} k(\mathbf{y}, \mathbf{y}')$$ where $k$ is a kernel function (typically Gaussian). MMD is a common choice because it avoids the "zero gradient" problem of log-likelihood when $p_{\boldsymbol{\theta}}(\mathbf{x}) = 0$ for some data points. A QGAN pits a quantum generator $G(\boldsymbol{\theta}_G)$ against a classical (or quantum) discriminator $D(\boldsymbol{\theta}_D)$: $$\min_{\boldsymbol{\theta}_G} \max_{\boldsymbol{\theta}_D} \mathbb{E}_{\mathbf{x} \sim p_{\text{data}}}[\log D(\mathbf{x})] + \mathbb{E}_{\mathbf{z} \sim p_{\text{prior}}}[\log(1 - D(G(\mathbf{z})))]$$ The generator takes random noise $\mathbf{z}$ and produces synthetic data; the discriminator tries to distinguish real from synthetic. Both are trained adversarially. Worked Example 21.3: QGAN for Distribution Learning Consider a 2-qubit QCBM generating samples from $\{00, 01, 10, 11\}$ with probabilities $p_{\boldsymbol{\theta}}$. The target distribution is uniform: $p_{\text{data}} = [0.25, 0.25, 0.25, 0.25]$. The QCBM circuit: $|0\rangle^{\otimes 2} \xrightarrow{R_Y(\theta_1) \otimes R_Y(\theta_2)} \xrightarrow{\text{CNOT}} |\psi(\boldsymbol{\theta})\rangle$ At the optimal solution $\theta_1 = \theta_2 = \pi/2$, the circuit produces the uniform distribution. Training via MMD or KL divergence should converge to these parameters. One of the most practical approaches to near-term quantum machine learning is quantum transfer learning: combining pre-trained classical neural networks with trainable quantum layers. Rather than training a full quantum model from scratch (which suffers from barren plateaus and limited qubit counts), transfer learning leverages the representational power of existing classical models and augments them with a quantum layer that operates in a high-dimensional feature space. Classical deep learning models — particularly convolutional networks trained on ImageNet, BERT-style language models, and similar architectures — have learned rich, general-purpose feature representations from massive datasets. These models contain thousands to billions of parameters and have been optimized over millions of GPU-hours. Replacing them entirely with a quantum model is neither feasible nor desirable on current hardware. Quantum transfer learning takes a pragmatic approach: freeze the classical feature extractor, replace only the final classification layer with a parameterized quantum circuit, and train the quantum layer on the downstream task. The key insight is that the classical network produces a low-dimensional feature vector $z \in \mathbb{R}^d$ (typically $d = 4$ to $64$), which can be efficiently encoded into a quantum state using angle encoding. The quantum layer then operates on this encoded state, producing a prediction that combines the classical network's feature extraction with the quantum circuit's nonlinear transformations in an exponentially large feature space. Let $f_{\text{classical}}: \mathcal{X} \to \mathbb{R}^d$ be a pre-trained classical feature extractor (with frozen weights), and let $U(\boldsymbol{\theta}): \mathbb{R}^d \to \mathbb{R}$ be a parameterized quantum circuit. The hybrid model is: $$\hat{y}(\mathbf{x}; \boldsymbol{\theta}) = \langle 0 | U^\dagger(f_{\text{classical}}(\mathbf{x}), \boldsymbol{\theta}) \, Z_0 \, U(f_{\text{classical}}(\mathbf{x}), \boldsymbol{\theta}) | 0 \rangle$$ The loss function is the standard cross-entropy or MSE, and only the quantum parameters $\boldsymbol{\theta}$ are updated during training. This has several advantages: Reduced parameter count: Only the quantum parameters (typically 10–100) need training, dramatically reducing the optimization landscape compared to training a full neural network. Better conditioning: The classical feature extractor maps raw data to a structured latent space where the quantum layer can operate effectively, avoiding barren plateaus associated with random feature maps. Efficient data loading: The classical features are low-dimensional ($d \ll$ original input dimension), so angle encoding requires only $d$ qubits — well within current hardware limits. Leverage classical pre-training: The bulk of the representation learning is done classically, where we have massive datasets and mature training infrastructure. The addition of a quantum layer is not automatically beneficial. The quantum layer provides value only when: The classical features are structured in a way that a quantum feature map can exploit. If the classical features are already in a linearly separable space, a quantum layer adds nothing (and introduces noise). The quantum layer can represent correlations that are difficult for a linear or shallow classical layer. The quantum circuit computes nonlinear functions of the input features via the entangling gates — these are hard to replicate with a single classical linear layer. The number of quantum parameters is small enough to train. This is the key constraint: the quantum layer must be shallow enough to avoid barren plateaus while expressive enough to add value beyond the classical features. Common Misconception: "Adding a quantum layer to a classical model always improves performance." In practice, the quantum layer often performs no better than an equivalently-sized classical neural network layer (a few fully-connected layers with nonlinear activations). The quantum layer provides value only when the specific structure of the quantum feature map (entanglement, quantum correlations) is well-matched to the task. Rigorous benchmarks against classical baselines of equivalent parameter count are essential. Empirical results: Mari et al. (2020) demonstrated quantum transfer learning on a binary classification task using a pre-trained ResNet-18 feature extractor and a 4-qubit quantum layer, achieving comparable accuracy to a fully classical transfer learning baseline. The quantum layer did not outperform the classical baseline, but the framework demonstrates the viability of the approach and provides a clear benchmarking methodology for future improvements as hardware scales. A major bottleneck in QML is extracting classical information from quantum states. Measuring $M$ observables on an $n$-qubit state requires $O(M/\epsilon^2)$ shots for precision $\epsilon$. Classical shadows is a technique that constructs a classical representation of a quantum state from a modest number of randomized measurements, enabling the estimation of many observables simultaneously. The fundamental idea is elegant: instead of measuring the same observable many times (which only gives information about that observable), we perform random measurements and store the results. Each random measurement provides partial information about all observables compatible with that measurement basis. By combining many such partial observations, we can estimate any observable — even ones we did not explicitly measure. The classical shadow is the set $\{(U_1, b_1), \ldots, (U_T, b_T)\}$. From this, we can estimate any observable $O$: $$\hat{o} = \frac{1}{T} \sum_{t=1}^{T} \text{Tr}\left[O \, \mathcal{M}^{-1}(U_t^\dagger |b_t\rangle\langle b_t| U_t)\right]$$ where $\mathcal{M}^{-1}$ is the inverse of the measurement channel (analytically computable for standard ensembles). We provide a complete derivation of the classical shadows protocol, including the measurement channel and its inverse. Step 1: The Measurement Channel. When we apply a random unitary $U$ and measure in the computational basis, we are sampling from the distribution: $$\Pr(b | U, \rho) = \langle b | U \rho U^\dagger | b \rangle$$ The effective measurement channel $\mathcal{M}$ maps the state $\rho$ to the expectation of the observed snapshot: $$\mathcal{M}(\rho) = \mathbb{E}_U \left[\sum_b \langle b | U \rho U^\dagger | b \rangle \cdot U^\dagger |b\rangle\langle b| U \right]$$ Step 2: Compute $\mathcal{M}$ for single-qubit Pauli measurements. For a single qubit, we measure in one of three Pauli bases ($X$, $Y$, or $Z$), chosen uniformly at random. Each basis measurement produces one of two outcomes: $|\pm\rangle$ for $X$, $|\pm i\rangle$ for $Y$, $|0/1\rangle$ for $Z$. When we measure in a random Pauli basis and observe outcome $|b\rangle$, the snapshot is $\hat{\rho} = 3 U^\dagger |b\rangle\langle b| U - I$, which is the inverse channel applied to the raw observation. To derive $\mathcal{M}$, we use the twirling property. For uniformly random single-qubit unitaries from the Clifford group: $$\mathcal{M}(\rho) = \frac{1}{3}\left(\text{Tr}(\rho) I + 2\rho\right)$$ Derivation: For a single qubit, the Clifford group acts as a 2-design on the unitary group. Using the identity for the depolarizing channel induced by a 2-design: $$\mathbb{E}_U \left[U^\dagger |b\rangle\langle b| U \, \langle b | U \rho U^\dagger | b \rangle\right] = \frac{I + 2\rho}{3}$$ This follows from the fact that for a 1-design, $\mathbb{E}_U[U^\dagger |b\rangle\langle b| U] = I/2$ (averaging over all outcomes in all bases gives the maximally mixed state), and for the second moment: $$\mathbb{E}_U[U^\dagger |b\rangle\langle b| U \langle b | \rho | b \rangle_U] = \frac{I}{2} \cdot \text{Tr}(\rho) \cdot \frac{1}{2} + \text{correction from correlations}$$ More carefully, expanding in the Pauli basis $\{I, X, Y, Z\}$: $$\mathcal{M}(\rho) = \mathcal{M}\left(\frac{I + \vec{r} \cdot \vec{\sigma}}{2}\right)$$ where $\vec{\sigma} = (X, Y, Z)$ and $\vec{r}$ is the Bloch vector. A single Pauli measurement projects onto one axis: if we measure $Z$, we learn $r_z$ but lose $r_x$ and $r_y$. Since each Pauli direction is chosen with probability $1/3$: $$\mathcal{M}\left(\frac{I + r_x X + r_y Y + r_z Z}{2}\right) = \frac{1}{3} \cdot \frac{I + 2r_z Z}{2} + \frac{1}{3} \cdot \frac{I + 2r_x X}{2} + \frac{1}{3} \cdot \frac{I + 2r_y Y}{2}$$ $$= \frac{I}{2} + \frac{2}{3} \cdot \frac{r_x X + r_y Y + r_z Z}{2} = \frac{I + \frac{2}{3}\vec{r} \cdot \vec{\sigma}}{2}$$ $$= \frac{1}{3}(I + 2\rho)$$ Wait — let us be more precise. The channel $\mathcal{M}$ maps $\rho$ to: $$\mathcal{M}(\rho) = \frac{I + 2\rho}{3}$$ This is a depolarizing channel with parameter $2/3$. Step 3: Compute $\mathcal{M}^{-1}$. The inverse channel is: $$\mathcal{M}^{-1}(\sigma) = 3\sigma - \text{Tr}(\sigma) I = 3\sigma - I$$ since $\mathcal{M}(\rho) = \frac{I + 2\rho}{3}$, we verify: $\mathcal{M}^{-1}(\mathcal{M}(\rho)) = 3 \cdot \frac{I + 2\rho}{3} - I = I + 2\rho - I = 2\rho$. Wait — that doesn't work. Let us redo this carefully. $\mathcal{M}(\rho) = \frac{1}{3}I + \frac{2}{3}\rho$. This is an affine map on the density matrix. To invert: $$\sigma = \frac{1}{3}I + \frac{2}{3}\rho \implies \rho = \frac{3}{2}\left(\sigma - \frac{1}{3}I\right) = \frac{3\sigma - I}{2}$$ So $\mathcal{M}^{-1}(\sigma) = \frac{3\sigma - I}{2}$. But wait — we should be more careful. The "snapshot" is $U^\dagger |b\rangle\langle b| U$, which is a pure state. The estimator for $\rho$ from a single snapshot is: $$\hat{\rho}_t = \mathcal{M}^{-1}(U_t^\dagger |b_t\rangle\langle b_t| U_t) = \frac{3 U_t^\dagger |b_t\rangle\langle b_t| U_t - I}{2}$$ And the estimator for an observable $O$ is: $$\hat{o}_t = \text{Tr}(O \hat{\rho}_t) = \frac{3\,\text{Tr}(O\, U_t^\dagger |b_t\rangle\langle b_t| U_t) - \text{Tr}(O)}{2}$$ The final estimate is the median of means: $\hat{o} = \text{median}\{\text{mean}(\hat{o}_t)\}$ over $K$ groups of $T/K$ snapshots. Step 4: Multi-qubit extension. For $n$ qubits with independent random Pauli measurements on each qubit, the measurement channel factorizes: $$\mathcal{M}^{\otimes n}(\rho) = \bigotimes_{i=1}^n \mathcal{M}_i(\rho)$$ and the inverse is: $$\left(\mathcal{M}^{\otimes n}\right)^{-1}(\sigma) = \bigotimes_{i=1}^n \left(3\sigma_i - I_i\right) / 2$$ where $\sigma_i$ is the reduced state on qubit $i$ obtained by tracing out all other qubits from $\sigma$. For a local observable $O = O_A \otimes I_{\bar{A}}$ acting on at most $k$ qubits, the snapshot estimator simplifies. Only the qubits in $A$ contribute, and we need all $k$ qubits to be measured in the correct basis. The probability that all $k$ qubits are measured in the right Pauli basis is $(1/3)^k$. For Pauli observables, the number of snapshots needed for precision $\epsilon$ on $M$ observables scales as: $$T = O\left(\frac{\log M}{\epsilon^2} \max_i \|O_i\|_{\text{shadow}}^2\right)$$ where $\|O_i\|_{\text{shadow}}$ is the shadow norm. For local observables (acting on $k$ qubits), $\|O\|_{\text{shadow}} = 3^k$, giving $T = O(3^k \log M / \epsilon^2)$. For global observables, the shadow norm is exponentially large, and classical shadows offer no advantage. Comparison with direct measurement: To estimate $M$ local observables each to precision $\epsilon$, direct measurement requires $O(M/\epsilon^2)$ shots. Classical shadows requires only $O(3^k \log M / \epsilon^2)$ shots. When $M \gg 3^k$, this is an exponential improvement in $M$. For example, estimating all $O(n^2)$ two-qubit correlations ($k=2$, $M = n^2$) requires $O(9 \log(n^2)/\epsilon^2) = O(\log n / \epsilon^2)$ shots via shadows versus $O(n^2/\epsilon^2)$ via direct measurement. This implementation demonstrates the key properties of classical shadows:
- Local observables (single-qubit or two-qubit) can be estimated from a modest number of snapshots.
- The estimate converges as $O(1/\sqrt{T})$, consistent with the theoretical sample complexity.
- Global observables (acting on all qubits) require exponentially many snapshots — shadows are not advantageous for them. Consider the Bell state $|\Phi^+\rangle = (|00\rangle + |11\rangle)/\sqrt{2}$. We want to estimate $\langle Z_0 Z_1 \rangle$. Using random Pauli measurements, each snapshot gives: The classical shadow for snapshot $(U_t, b_t)$ contributes to $\langle Z_0 Z_1 \rangle$ only when both qubits are measured in the $Z$-basis (probability 1/9 for random Pauli measurements on 2 qubits). For these snapshots, the estimator is $z_0 \cdot z_1$ where $z_i = \pm 1$. With $T$ snapshots, approximately $T/9$ contribute to the $ZZ$ estimate. The estimate improves as $O(\sqrt{T})$. The Qiskit implementation above demonstrates this convergence numerically — with 5000 snapshots, the estimate of $\langle ZZ \rangle$ is within 0.02 of the true value of 1.0. We now build a complete quantum neural network classifier using Qiskit Machine Learning, training it on a real dataset. Recurring Theme: Quantum Advantage Is Problem-Specific. The history of quantum computing has consistently shown that advantage comes from carefully chosen problem instances, not general superiority. QML is unlikely to be an exception — if advantage exists, it will be for specific data distributions or problem structures that are classically hard. The most promising avenues for genuine quantum advantage in ML are: Learning from genuinely quantum data. If the data is produced by a quantum process (quantum sensor, quantum simulation, quantum communication), a quantum learner processes it natively without the classical measurement bottleneck. This is the strongest case for quantum advantage. Quantum kernels that are provably hard to simulate classically. The IQP encoding and similar constructions are candidates, but the resulting kernels must also be useful for learning — hardness alone is insufficient. Quantum reinforcement learning. Quantum agents interacting with quantum environments may exploit quantum parallelism for faster exploration. Quantum generative models for quantum data. Generating quantum states that match a target distribution is a natively quantum task. Learning with noisy data. Some evidence suggests that quantum models may be more robust to noise in the training data than classical models, though this is still speculative.reps=1; higher repetitions introduce more nonlinear interactions).import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit_aer import AerSimulator
from qiskit.quantum_info import Statevector
from itertools import product
def zz_feature_map(x_params, n_qubits, reps=2):
"""Build a ZZ feature map circuit."""
qc = QuantumCircuit(n_qubits)
for _ in range(reps):
for i in range(n_qubits):
qc.h(i)
qc.p(x_params[i], i)
for i in range(n_qubits):
for j in range(i + 1, n_qubits):
qc.cx(i, j)
qc.p(2 * x_params[i] * x_params[j], j)
qc.cx(i, j)
return qc
def compute_kernel_matrix(X, n_qubits=2, reps=2):
"""Compute the quantum kernel matrix K_ij = |<phi(x_i)|phi(x_j)>|^2."""
n_samples = X.shape[0]
K = np.zeros((n_samples, n_samples))
for i, j in product(range(n_samples), repeat=2):
x_params_i = ParameterVector('xi', n_qubits)
qc_i = zz_feature_map(x_params_i, n_qubits, reps)
bound_i = qc_i.assign_parameters(dict(zip(x_params_i, X[i])))
state_i = Statevector.from_instruction(bound_i)
x_params_j = ParameterVector('xj', n_qubits)
qc_j = zz_feature_map(x_params_j, n_qubits, reps)
bound_j = qc_j.assign_parameters(dict(zip(x_params_j, X[j])))
state_j = Statevector.from_instruction(bound_j)
K[i, j] = abs(state_i.inner(state_j)) ** 2
return K
def kernel_target_alignment(K, y):
"""Compute kernel-target alignment A(k, y)."""
Y = np.outer(y, y)
numerator = np.sum(K * Y)
denominator = np.sqrt(np.sum(K ** 2)) * np.sqrt(np.sum(Y ** 2))
return numerator / denominator
# ── Dataset ──
X = np.array([[0.5, 0.5], [1.0, 0.5], [-0.5, -0.5], [-1.0, -0.5]])
y = np.array([1, 1, -1, -1])
# ── Compute kernel matrix and alignment ──
K_zz = compute_kernel_matrix(X, n_qubits=2, reps=2)
alignment_zz = kernel_target_alignment(K_zz, y)
print("ZZ Feature Map Kernel Matrix:")
print(np.round(K_zz, 4))
print(f"\nKernel-Target Alignment (ZZ): {alignment_zz:.4f}")
# ── Compare with random feature map ──
from qiskit.quantum_info import random_unitary
def random_kernel_matrix(X, n_qubits=2, seed=42):
"""Kernel matrix using a random unitary after angle encoding."""
rng = np.random.RandomState(seed)
U_rand = random_unitary(2**n_qubits, seed=seed)
n_samples = X.shape[0]
K = np.zeros((n_samples, n_samples))
for i, j in product(range(n_samples), repeat=2):
qc_i = QuantumCircuit(n_qubits)
for q in range(n_qubits):
qc_i.ry(X[i, q], q)
qc_i.compose(U_rand.to_instruction(), inplace=True)
state_i = Statevector.from_instruction(qc_i)
qc_j = QuantumCircuit(n_qubits)
for q in range(n_qubits):
qc_j.ry(X[j, q], q)
qc_j.compose(U_rand.to_instruction(), inplace=True)
state_j = Statevector.from_instruction(qc_j)
K[i, j] = abs(state_i.inner(state_j)) ** 2
return K
K_rand = random_kernel_matrix(X, n_qubits=2)
alignment_rand = kernel_target_alignment(K_rand, y)
print("\nRandom Feature Map Kernel Matrix:")
print(np.round(K_rand, 4))
print(f"\nKernel-Target Alignment (Random): {alignment_rand:.4f}")
print(f"\nAlignment ratio (ZZ / Random): {alignment_zz / max(alignment_rand, 1e-10):.1f}x")
21.5 Quantum Convolutional Neural Networks (QCNN)
21.5.1 QCNN Architecture
QCNN Circuit (8 qubits → 2 qubits):
Layer 1 (Convolution + Pooling):
q_0: ──[V_1]──●──[V_1]──●────────────────────────────
│ │
q_1: ──[V_1]──┼──[V_1]──┼────────────────────────────
│ │
q_2: ──[V_1]──┼──[V_1]──┼──●──[V_1]──●──────────────
│ │ │ │
q_3: ──[V_1]──┼──[V_1]──┼──┼──[V_1]──┼──────────────
│ │ │ │
q_4: ──[V_1]──┼──[V_1]──┼──┼──[V_1]──┼──●──[V_1]──●──
│ │ │ │ │ │
q_5: ──[V_1]──┼──[V_1]──┼──┼──[V_1]──┼──┼──[V_1]──┼──
│ │ │ │ │ │
q_6: ──[V_1]──┼──[V_1]──┼──┼──[V_1]──┼──┼──[V_1]──┼──
│ │ │ │ │ │
q_7: ──[V_1]──┼──[V_1]──┼──┼──[V_1]──┼──┼──[V_1]──┼──
(pooling: measure and discard half the qubits)
Layer 2 (on remaining 4 qubits):
... similar structure ...
Layer 3 (on remaining 2 qubits):
... final convolution + measurement ...
21.5.2 Properties
21.5.3 QCNN Implementation
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
def qcnn_circuit(n_qubits, conv_params, pool_params):
"""
Build a QCNN circuit with convolution and pooling layers.
Args:
n_qubits: Total number of input qubits (must be power of 2)
conv_params: List of ParameterVectors for convolution layers
pool_params: List of ParameterVectors for pooling layers
Returns:
QuantumCircuit for QCNN
"""
qc = QuantumCircuit(n_qubits)
current_qubits = list(range(n_qubits))
layer = 0
while len(current_qubits) > 1:
# Convolution: apply 2-qubit unitary to all adjacent pairs
for i in range(0, len(current_qubits) - 1, 2):
q1, q2 = current_qubits[i], current_qubits[i + 1]
# Simple parameterized 2-qubit gate
for j, param in enumerate(conv_params[layer]):
qc.ry(param, q1)
qc.rz(param, q2)
qc.cx(q1, q2)
# Pooling: measure half the qubits, apply controlled rotations
next_qubits = []
for i in range(0, len(current_qubits) - 1, 2):
q1, q2 = current_qubits[i], current_qubits[i + 1]
# Measure q2, apply rotation on q1 conditioned on q2
qc.ry(pool_params[layer][i // 2], q1)
next_qubits.append(q1)
current_qubits = next_qubits
layer += 1
return qc
21.6 Quantum Generative Models
21.6.1 Quantum Circuit Born Machine (QCBM)
21.6.2 Quantum Generative Adversarial Network (QGAN)
21.6.3 Comparison of Quantum Generative Models
Model
Training Objective
Advantages
Disadvantages
QCBM
MMD or KL divergence
Exact sampling, no mode collapse
Scaling beyond few qubits
QGAN
Adversarial
Flexible, can handle continuous data
Training instability, quantum-classical interface
Quantum Boltzmann Machine
Likelihood
Principled, connections to physics
Intractable partition function
21.6b Quantum Transfer Learning
21.6b.1 Motivation and Architecture
┌────────────────────────────────────────────────────────────┐
│ Quantum Transfer Learning Architecture │
│ │
│ Input ──► [Classical Feature Extractor (frozen)] │
│ │ │
│ ▼ │
│ Classical features z ∈ ℝᵈ │
│ │ │
│ ▼ │
│ [Data Encoding: z → |φ(z)⟩] │
│ │ │
│ ▼ │
│ [Variational Quantum Circuit V(θ)] │
│ │ │
│ ▼ │
│ [Measurement → ŷ] │
│ │
│ Only θ is trained; classical weights are frozen. │
└────────────────────────────────────────────────────────────┘
21.6b.2 Formal Framework
21.6b.3 Implementation with Qiskit and PyTorch
import torch
import torch.nn as nn
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit_machine_learning.connectors import TorchConnector
from qiskit_machine_learning.neural_networks import SamplerQNN
class QuantumTransferModel(nn.Module):
"""
Hybrid classical-quantum model for transfer learning.
Architecture:
1. Pre-trained classical feature extractor (frozen)
2. Classical dimensionality reduction to n_qubits features
3. Quantum variational layer (trainable)
"""
def __init__(self, n_qubits=4, n_features=512):
super().__init__()
# ── Pre-trained feature extractor (frozen) ──
# In practice, load a pre-trained model (e.g., ResNet, VGG)
self.feature_extractor = nn.Sequential(
nn.Linear(n_features, 128),
nn.ReLU(),
nn.Linear(128, n_qubits),
nn.Tanh() # Map to [-1, 1] for angle encoding
)
# Freeze the feature extractor
for param in self.feature_extractor.parameters():
param.requires_grad = False
# ── Quantum layer ──
self.n_qubits = n_qubits
self.feature_map, self.ansatz, self.qnn = self._build_qnn(n_qubits)
# ── Map quantum output to final prediction ──
self.classifier = nn.Linear(2**n_qubits, 2) # Binary classification
def _build_qnn(self, n_qubits):
"""Build the quantum neural network layer."""
from qiskit.circuit.library import ZZFeatureMap, RealAmplitudes
feature_map = ZZFeatureMap(feature_dimension=n_qubits, reps=1)
ansatz = RealAmplitudes(num_qubits=n_qubits, reps=2)
qc = QuantumCircuit(n_qubits)
qc.compose(feature_map, inplace=True)
qc.compose(ansatz, inplace=True)
qnn = SamplerQNN(
circuit=qc,
input_params=feature_map.parameters,
weight_params=ansatz.parameters,
)
return feature_map, ansatz, qnn
def forward(self, x):
# Classical feature extraction (frozen)
features = self.feature_extractor(x)
# Quantum layer
quantum_output = self.qnn(features)
# Final classification
return self.classifier(quantum_output)
# ── Training loop ──
def train_quantum_transfer_learning(model, train_loader, epochs=20, lr=0.01):
"""
Train only the quantum parameters of a transfer learning model.
"""
# Only train quantum parameters and final classifier
trainable_params = []
for name, param in model.named_parameters():
if param.requires_grad:
trainable_params.append(param)
optimizer = torch.optim.Adam(trainable_params, lr=lr)
criterion = nn.CrossEntropyLoss()
model.train()
for epoch in range(epochs):
total_loss = 0
correct = 0
total = 0
for batch_x, batch_y in train_loader:
optimizer.zero_grad()
output = model(batch_x)
loss = criterion(output, batch_y)
loss.backward()
optimizer.step()
total_loss += loss.item()
_, predicted = torch.max(output, 1)
correct += (predicted == batch_y).sum().item()
total += batch_y.size(0)
acc = correct / total
print(f"Epoch {epoch+1}/{epochs}: Loss={total_loss:.4f}, Acc={acc:.4f}")
return model
21.6b.4 When Does Quantum Transfer Learning Help?
21.7 Classical Shadows for Efficient Readout
21.7.1 The Protocol
21.7.2 Detailed Derivation of Classical Shadows
21.7.3 Sample Complexity
21.7.4 Complete Qiskit Implementation of Classical Shadows
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, SparsePauliOp, random_clifford
def compute_classical_shadow(state, n_qubits, n_snapshots=1000, seed=None):
"""
Compute the classical shadow of a quantum state using
random single-qubit Clifford measurements.
Args:
state: Statevector of the quantum state
n_qubits: Number of qubits
n_snapshots: Number of randomized measurements
seed: Random seed for reproducibility
Returns:
List of (pauli_indices, eigenvalues) tuples, where
pauli_indices[j] ∈ {0,1,2} for {X,Y,Z} and
eigenvalues[j] ∈ {+1, -1} for the measurement outcome.
"""
rng = np.random.RandomState(seed)
shadow = []
for _ in range(n_snapshots):
# Choose random Pauli basis for each qubit
pauli_indices = rng.choice([0, 1, 2], size=n_qubits) # 0=X, 1=Y, 2=Z
pauli_names = ['X', 'Y', 'Z']
# Build measurement circuit: rotate into chosen Pauli basis
qc = QuantumCircuit(n_qubits)
for i in range(n_qubits):
if pauli_indices[i] == 0: # X basis
qc.h(i)
elif pauli_indices[i] == 1: # Y basis
qc.sdg(i)
qc.h(i)
# Z basis: no rotation needed
# Evolve state and measure
evolved = state.evolve(qc)
probs = np.abs(evolved.data) ** 2
outcome = rng.choice(2**n_qubits, p=probs)
bitstring = format(outcome, f'0{n_qubits}b')
# Convert bitstring to ±1 eigenvalues
eigenvalues = np.array([1 if b == '0' else -1 for b in bitstring])
shadow.append((pauli_indices, eigenvalues))
return shadow
def estimate_observable_shadow(shadow, n_qubits, observable_paulis):
"""
Estimate expectation values of Pauli observables from a classical shadow.
Args:
shadow: Output of compute_classical_shadow
n_qubits: Number of qubits
observable_paulis: List of (coefficient, pauli_string) tuples.
pauli_string uses 'I','X','Y','Z' for each qubit.
e.g., [(1.0, 'ZZ'), (0.5, 'XI')]
Returns:
Dictionary mapping pauli_string -> estimated expectation value.
"""
results = {}
for coeff, pauli_string in observable_paulis:
estimates = []
for pauli_indices, eigenvalues in shadow:
contrib = coeff
valid = True
for i, p_char in enumerate(pauli_string):
if p_char == 'I':
continue
pauli_map = {'X': 0, 'Y': 1, 'Z': 2}
if pauli_indices[i] != pauli_map[p_char]:
valid = False
break
if valid:
product_eigenvalues = 1
for i, p_char in enumerate(pauli_string):
if p_char != 'I':
product_eigenvalues *= eigenvalues[i]
estimates.append(3**sum(1 for p in pauli_string if p != 'I') * product_eigenvalues)
else:
estimates.append(0)
results[pauli_string] = np.mean(estimates)
return results
def shadow_fidelity(shadow1, shadow2, n_qubits):
"""
Estimate the fidelity |<ψ₁|ψ₂>|² between two states from their shadows.
Uses the formula: F = Tr(ρ₁ρ₂) estimated via shadow overlap.
"""
total = 0
count = 0
for (p_idx1, e_val1), (p_idx2, e_val2) in zip(shadow1, shadow2):
if np.array_equal(p_idx1, p_idx2):
overlap = 1
for i in range(n_qubits):
overlap *= (3 * e_val1[i] * e_val2[i] + 1) / 4
total += overlap
count += 1
if count == 0:
return 0.0
return total / count
# ── Demonstration: Estimate observables for a Bell state ──
from qiskit.quantum_info import Statevector
# Create Bell state |Φ+⟩ = (|00⟩ + |11⟩)/√2
bell_circuit = QuantumCircuit(2)
bell_circuit.h(0)
bell_circuit.cx(0, 1)
bell_state = Statevector.from_instruction(bell_circuit)
# Compute classical shadow
n_snapshots = 5000
shadow = compute_classical_shadow(bell_state, n_qubits=2, n_snapshots=n_snapshots, seed=42)
# Estimate key observables
observables = [
(1.0, 'ZZ'), # ⟨Z₁Z₂⟩ should be +1
(1.0, 'XX'), # ⟨X₁X₂⟩ should be +1
(1.0, 'YY'), # ⟨Y₁Y₂⟩ should be -1
(1.0, 'ZX'), # ⟨Z₁X₂⟩ should be 0
(1.0, 'IZ'), # ⟨I⊗Z⟩ should be 0
(1.0, 'ZI'), # ⟨Z⊗I⟩ should be 0
]
estimated = estimate_observable_shadow(shadow, 2, observables)
print("Bell State Observable Estimates via Classical Shadows")
print("="*55)
print(f"{'Observable':<15} {'Estimated':<15} {'Exact':<15}")
print("-"*55)
exact_values = {'ZZ': 1.0, 'XX': 1.0, 'YY': -1.0, 'ZX': 0.0, 'IZ': 0.0, 'ZI': 0.0}
for coeff, pauli in observables:
est = estimated[pauli]
ex = exact_values[pauli]
print(f" ⟨{pauli}⟩ {est:+.4f} {ex:+.1f}")
# ── Demonstrate convergence with number of snapshots ──
print("\nConvergence of ⟨ZZ⟩ estimate vs. number of snapshots:")
for T in [100, 500, 1000, 5000, 10000]:
shadow_T = compute_classical_shadow(bell_state, 2, n_snapshots=T, seed=42)
result_T = estimate_observable_shadow(shadow_T, 2, [(1.0, 'ZZ')])
error = abs(result_T['ZZ'] - 1.0)
print(f" T = {T:>6d}: ⟨ZZ⟩ = {result_T['ZZ']:+.4f}, error = {error:.4f}")
21.7.5 Worked Example 21.4: Classical Shadows for a 2-Qubit State
21.8 Complete Quantum Classifier Implementation
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import ZZFeatureMap, RealAmplitudes
from qiskit_aer import AerSimulator
from qiskit_machine_learning.neural_networks import EstimatorQNN, SamplerQNN
from qiskit_machine_learning.algorithms.classifiers import NeuralNetworkClassifier
from qiskit_algorithms.optimizers import COBYLA, SPSA
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import accuracy_score, classification_report
# ── Step 1: Generate synthetic classification dataset ──
X, y = make_classification(
n_samples=300, n_features=4, n_informative=4,
n_redundant=0, n_clusters_per_class=1,
random_state=42
)
# Scale features to [0, π] for angle encoding
scaler = MinMaxScaler(feature_range=(0, np.pi))
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.3, random_state=42, stratify=y
)
print(f"Training samples: {len(X_train)}, Test samples: {len(X_test)}")
print(f"Features: {X.shape[1]}, Classes: {len(np.unique(y))}")
# ── Step 2: Build the quantum circuit ──
n_qubits = 4 # One qubit per feature
n_layers = 3 # Data re-uploading layers
# Feature map (data encoding)
feature_map = ZZFeatureMap(
feature_dimension=n_qubits,
reps=2,
entanglement='linear'
)
# Variational ansatz
ansatz = RealAmplitudes(
num_qubits=n_qubits,
reps=n_layers,
entanglement='circular'
)
# Combine: feature map → ansatz
qc = QuantumCircuit(n_qubits)
qc.compose(feature_map, inplace=True)
qc.compose(ansatz, inplace=True)
print(f"\nQuantum Circuit:")
print(f" Qubits: {qc.num_qubits}")
print(f" Depth: {qc.depth()}")
print(f" Trainable parameters: {ansatz.num_parameters}")
print(f" Input parameters: {feature_map.num_parameters}")
# ── Step 3: Define the QNN ──
# EstimatorQNN: measures expectation value of an observable
# We measure Z on the first qubit → output in [-1, +1]
qnn = EstimatorQNN(
circuit=qc,
input_params=feature_map.parameters,
weight_params=ansatz.parameters,
observables=[('Z', [0])] # Measure Z on qubit 0
)
# ── Step 4: Create and train the classifier ──
optimizer = COBYLA(maxiter=200)
classifier = NeuralNetworkClassifier(
neural_network=qnn,
optimizer=optimizer,
initial_point=np.random.uniform(-0.1, 0.1, ansatz.num_parameters),
callback=lambda weights, obj: print(f" Iteration: obj = {obj:.4f}")
)
print("\nTraining classifier...")
classifier.fit(X_train, y_train)
# ── Step 5: Evaluate ──
y_pred_train = classifier.predict(X_train)
y_pred_test = classifier.predict(X_test)
train_acc = accuracy_score(y_train, y_pred_train)
test_acc = accuracy_score(y_test, y_pred_test)
print(f"\n{'='*60}")
print(f"Quantum Neural Network Classifier Results")
print(f"{'='*60}")
print(f"Training accuracy: {train_acc:.4f}")
print(f"Test accuracy: {test_acc:.4f}")
print(f"\nClassification Report (Test):")
print(classification_report(y_test, y_pred_test,
target_names=['Class 0', 'Class 1']))
# ── Step 6: Compare with classical baseline ──
from sklearn.svm import SVC
svm = SVC(kernel='rbf', random_state=42)
svm.fit(X_train, y_train)
svm_acc = svm.score(X_test, y_test)
print(f"\nClassical SVM (RBF kernel) test accuracy: {svm_acc:.4f}")
print(f"QNN vs. SVM difference: {test_acc - svm_acc:+.4f}")
21.8.1 Second Qiskit Example: Barren Plateau Detection
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import EstimatorV2 as Estimator
from qiskit.quantum_info import SparsePauliOp
def measure_gradient_variance(n_qubits, n_layers, n_samples=200):
"""
Estimate the gradient variance for a hardware-efficient ansatz.
Returns the variance of ∂⟨H⟩/∂θ_1 for random parameter sets.
"""
# Build the ansatz
qc = QuantumCircuit(n_qubits)
params = ParameterVector('θ', n_qubits * n_layers * 2)
idx = 0
for layer in range(n_layers):
for q in range(n_qubits):
qc.ry(params[idx], q)
idx += 1
for q in range(n_qubits):
qc.rz(params[idx], q)
idx += 1
for q in range(n_qubits - 1):
qc.cx(q, q + 1)
qc.cx(n_qubits - 1, 0)
# Observable: global Z...Z
H = SparsePauliOp.from_list([('Z' * n_qubits, 1.0)])
# Sample gradient variance
estimator = Estimator()
gradients = []
for _ in range(n_samples):
theta = np.random.uniform(0, 2*np.pi, len(params))
# Parameter-shift rule for θ_0
theta_plus = theta.copy()
theta_plus[0] += np.pi / 2
theta_minus = theta.copy()
theta_minus[0] -= np.pi / 2
bound_plus = qc.assign_parameters(dict(zip(params, theta_plus)))
bound_minus = qc.assign_parameters(dict(zip(params, theta_minus)))
e_plus = estimator.run([(bound_plus, H)]).result()[0].data.evs
e_minus = estimator.run([(bound_minus, H)]).result()[0].data.evs
grad = 0.5 * (e_plus - e_minus)
gradients.append(grad)
return np.var(gradients)
# Run for different qubit counts
qubit_counts = [2, 4, 6, 8]
variances = []
for n in qubit_counts:
var = measure_gradient_variance(n, n_layers=3, n_samples=100)
variances.append(var)
print(f"n = {n}: Var[∂E/∂θ] = {var:.6e}")
# Plot on log scale
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 5))
plt.semilogy(qubit_counts, variances, 'bo-', markersize=10)
plt.xlabel('Number of Qubits')
plt.ylabel('Gradient Variance (log scale)')
plt.title('Barren Plateau: Gradient Variance vs. Qubit Count')
plt.grid(True, alpha=0.3)
plt.savefig('barren_plateau.png', dpi=150)
print("Barren plateau plot saved.")
21.9 The Current State of QML: Honest Assessment
21.9.1 What Has Been Achieved
21.9.2 What Has Not Been Achieved
21.9.3 Where Advantage Might Emerge