Les quatre régimes du QML & NISQ vs tolérant aux pannes
Cartographier les quatre régimes du Quantum Machine Learning et comprendre pourquoi l'ère NISQ impose la boucle variationnelle hybride — avec du code Qiskit exécutable sur simulateur.
Les quatre régimes du QML
L’idée en une phrase
Le Quantum Machine Learning recouvre quatre régimes distincts selon que les données et le traitement sont classiques ou quantiques — et la boucle variationnelle hybride (encodage → ansatz → mesure → optimisation classique) est la stratégie dominante du régime CQ, celui qui exploite le matériel NISQ disponible aujourd’hui.
Analogie : Considérons une cuisine avec deux types d’ingrédients (frais du marché ou surgelés industriels) et deux modes de cuisson (four classique ou four à micro-ondes). On obtient quatre combinaisons, chacune avec ses contraintes et ses recettes. En QML, les « ingrédients » sont les données (classiques ou quantiques) et le « mode de cuisson » est le traitement (classique ou quantique). La majorité des praticiens travaillent aujourd’hui avec des ingrédients classiques cuits au micro-ondes quantique — le régime CQ.
Points clés
- CC (Classical-Classical) : données classiques, traitement classique. C’est le ML standard — réseaux de neurones, SVM, arbres de décision. Aucun QPU n’intervient. Ce régime sert de référence pour évaluer tout avantage quantique éventuel.
- CQ (Classical-Quantum) : données classiques, traitement quantique. C’est le régime central de ce livre. On encode des vecteurs classiques x dans un circuit quantique paramétré
U(θ), la mesure extrait une prédiction, et un optimiseur classique met à jour θ. Comme vu au chapitre 1, le circuit joue le rôle deF(x, θ); comme vu au chapitre 2, la descente de gradient (via le Parameter Shift Rule) ajuste θ. - QC (Quantum-Classical) : les données proviennent d’un processus quantique (capteur, simulateur, expérience de physique), mais le traitement est classique. Exemples : tomographie d’état avec un réseau de neurones classique, protocole des classical shadows, classification de phases quantiques par SVM.
- QQ (Quantum-Quantum) : données et traitement sont quantiques. Exemples : décodage de codes correcteurs d’erreurs quantiques, distillation d’états, simulation de Hamiltoniens. Ce régime deviendra central dans l’ère post-NISQ.
Exemple concret
Une entreprise veut prédire la fraude bancaire à partir de 3 features classiques (montant, heure, localisation). Elle dispose d’un QPU NISQ de 20 qubits. Le workflow CQ se déroule ainsi : (1) normaliser les 3 features en angles dans l’intervalle [0, π], (2) encoder via des rotations Ry dans un circuit à 3 qubits, (3) appliquer un ansatz de 2 couches — portes CNOT pour l’intrication, rotations paramétrées pour l’expressivité, (4) mesurer le qubit 0 comme indicateur fraude / non-fraude, (5) calculer la cross-entropy sur un ordinateur classique, (6) mettre à jour les ~12 paramètres θ par descente de gradient via le Parameter Shift Rule. Le QPU n’intervient que dans les étapes 2 à 4 ; le reste est classique — c’est l’hybridation.
Les quatre régimes — taxonomie
| Régime | Données | Traitement | Exemples | Ère cible |
|---|---|---|---|---|
| CC | Classiques | Classique | CNN, SVM, Random Forest | Actuelle |
| CQ | Classiques | Quantique | VQC, QSVM, QNN | NISQ |
| QC | Quantiques | Classique | Classical shadows, tomographie + ML | NISQ / Post-NISQ |
| Quantiques | Quantique | Décodage QEC, simulation quantique | Post-NISQ |
Code Python — le pipeline CQ minimal
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
# Régime CQ : donnée classique x → circuit quantique → prédiction classique
def pipeline_cq(x: float, theta: float) -> float:
"""Encoder une donnée classique x, appliquer un ansatz θ, retourner P(|1⟩)."""
qc = QuantumCircuit(1)
# Étape 1 — Encodage : la donnée classique x devient une rotation
qc.ry(x, 0)
# Étape 2 — Ansatz : le paramètre entraînable θ transforme l'état
qc.ry(theta, 0)
# Étape 3 — Mesure (simulée) : extraire la probabilité P(|1⟩)
sv = Statevector.from_instruction(qc)
return float(sv.probabilities()[1])
# Le résultat analytique est P(|1⟩) = sin²((x + θ) / 2)
for x, theta in [(0.0, 0.0), (np.pi, 0.0), (np.pi / 2, np.pi / 2)]:
p = pipeline_cq(x, theta)
expected = np.sin((x + theta) / 2) ** 2
print(f"x={x:.2f}, θ={theta:.2f} → P(|1⟩) = {p:.4f} (attendu: {expected:.4f})")
# x=0.00, θ=0.00 → P(|1⟩) = 0.0000 (rien encodé, rien transformé)
# x=3.14, θ=0.00 → P(|1⟩) = 1.0000 (x=π encode |1⟩)
# x=1.57, θ=1.57 → P(|1⟩) = 1.0000 (x+θ = π → |1⟩)
Piège courant : « Le QML utilise toujours un ordinateur quantique » est inexact. Le régime CC (ML classique) n’en a pas besoin du tout, et le régime QC utilise le QPU uniquement comme source de données, pas comme processeur ML. En pratique NISQ, seul le régime CQ mobilise le QPU pour le traitement — et même dans ce cas, l’optimiseur qui ajuste θ reste purement classique.
NISQ vs tolérant aux pannes
L’idée en une phrase
L’ère NISQ (Noisy Intermediate-Scale Quantum), définie par John Preskill en 2018, caractérise les processeurs quantiques actuels — quelques dizaines à quelques milliers de qubits physiques, sans correction d’erreur, avec un bruit qui limite la profondeur des circuits — et c’est précisément cette contrainte qui impose la boucle variationnelle hybride : des circuits courts paramétrés dont l’optimisation est déléguée à un processeur classique.
Analogie : Comparer un QPU NISQ à un atelier de menuiserie rudimentaire : on dispose de bois, de scies et de clous, mais les scies sont imprécises et les clous se tordent souvent. On ne peut pas construire un immeuble de 20 étages (circuit profond), mais on peut fabriquer des meubles utiles (circuits peu profonds) à condition de concevoir chaque pièce pour tolérer les imperfections. L’ère tolérante aux pannes correspond à un atelier industriel avec des machines CNC de précision — on pourra alors construire l’immeuble.
Points clés
- NISQ : 50 à ~1 000 qubits physiques, taux d’erreur par porte de l’ordre de 0,1 % à 1 %, pas de correction d’erreur quantique (QEC). La profondeur de circuit utile est limitée à quelques dizaines de couches avant que la décohérence ne détruise l’information.
- Tolérant aux pannes : des milliers à des millions de qubits physiques encodent des qubits logiques protégés par QEC (codes de surface, codes de couleur). La profondeur de circuit est virtuellement illimitée, ce qui rend possibles des algorithmes comme Shor (factorisation), Grover (recherche) ou HHL (systèmes linéaires).
- Le compromis expressivité ↔ entraînabilité prend ici une forme concrète : ajouter des couches au circuit augmente l’espace des fonctions représentables (expressivité), mais chaque couche supplémentaire accumule du bruit en ère NISQ et rapproche des plateaus de Barren (gradients exponentiellement petits, traités au chapitre 12).
- Les algorithmes variationnels (VQE, QAOA, VQC) sont la stratégie NISQ par excellence : ils minimisent la profondeur du circuit en déportant la complexité vers l’optimiseur classique. La descente de gradient vue au chapitre 2 s’applique directement, le Parameter Shift Rule remplaçant la rétropropagation.
- La frontière NISQ / tolérant aux pannes n’est pas binaire. Des avancées récentes en correction d’erreur partielle (QEC « de surface » sur quelques dizaines de qubits) ouvrent une zone intermédiaire, parfois appelée « early fault-tolerant ».
Exemple concret
On prépare un état de Bell (|00⟩ + |11⟩) / √2 — idéalement, les seuls résultats de mesure possibles sont 00 et 11, chacun avec 50 % de probabilité. Sur un simulateur idéal, c’est exactement ce qu’on obtient. Sur un simulateur bruité modélisant un QPU NISQ (5 % d’erreur de dépolarisation par porte 1-qubit, 10 % par porte 2-qubits), on observe l’apparition d’états parasites 01 et 10 : environ 7 à 9 % des mesures donnent un résultat « impossible » dans le cas idéal. Si l’on empile 10 couches identiques au lieu d’une seule, ces résultats parasites dominent — illustration directe de la contrainte de profondeur NISQ.
NISQ vs tolérant aux pannes — comparaison
| Critère | NISQ | Tolérant aux pannes |
|---|---|---|
| Qubits | 50 – ~1 000 physiques | Milliers à millions (physiques → logiques) |
| Taux d’erreur par porte | 0,1 % – 1 % | < 10⁻¹⁰ après correction |
| Profondeur de circuit utile | Dizaines de couches | Virtuellement illimitée |
| Correction d’erreur | Non | Oui (codes de surface, codes de couleur) |
| Stratégie ML dominante | Variationnelle hybride (VQC, VQE, QAOA) | Algorithmes quantiques complets (HHL, etc.) |
| Horizon temporel estimé | Maintenant – ~2030 | 2030+ (estimation optimiste) |
Code Python — l’impact du bruit NISQ sur un état de Bell
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel, depolarizing_error
# Préparer l'état de Bell (|00⟩ + |11⟩)/√2
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
# --- Simulation idéale ---
sv = Statevector.from_instruction(qc)
probs_ideal = sv.probabilities_dict()
print("Idéal :", probs_ideal)
# {'00': 0.5, '11': 0.5} — aucun état parasite
# --- Simulation bruitée (NISQ) ---
noise = NoiseModel()
# Erreur de dépolarisation : 5 % sur les portes 1-qubit, 10 % sur les 2-qubits
noise.add_all_qubit_quantum_error(depolarizing_error(0.05), ['h'])
noise.add_all_qubit_quantum_error(depolarizing_error(0.10), ['cx'])
qc_meas = qc.copy()
qc_meas.measure_all()
sim = AerSimulator(noise_model=noise)
counts = sim.run(qc_meas, shots=10_000).result().get_counts()
total = sum(counts.values())
probs_noisy = {k: counts.get(k, 0) / total for k in ['00', '01', '10', '11']}
print("Bruité :", {k: f"{v:.3f}" for k, v in probs_noisy.items()})
# Des états 01 et 10 apparaissent — signature du bruit NISQ
# Typiquement : {'00': ~0.46, '01': ~0.04, '10': ~0.04, '11': ~0.46}
Piège courant : « NISQ signifie que les ordinateurs quantiques sont inutiles » est une conclusion hâtive. Les algorithmes variationnels contournent la limitation de profondeur en utilisant des circuits courts et en déléguant l’optimisation au classique. Le bruit est un obstacle, pas un barrage. En revanche, affirmer un « avantage quantique » en régime NISQ sur des tâches de ML classique reste un sujet de recherche ouvert — la prudence s’impose dans les deux sens.
Fil rouge — la frontière quantique/classique
Ce chapitre pose la carte d’orientation du livre. Dans le régime CQ — celui qui occupe les dix prochains chapitres — le QPU n’intervient que dans la portion « encoder → transformer → mesurer » du pipeline ; tout le reste (collecte des données, calcul du coût, optimisation de θ) reste classique. L’ère NISQ renforce cette répartition : le bruit interdit les circuits profonds, donc on confie au QPU le strict minimum — un circuit peu profond mais expressif — et on compense par la puissance de l’optimiseur classique. Le compromis expressivité ↔ entraînabilité se lit ici comme un compromis profondeur ↔ fidélité : chaque couche ajoutée gagne en expressivité mais perd en fidélité à cause du bruit accumulé.
Kata Qiskit — le pipeline CQ minimal
Objectif : construire le plus simple pipeline CQ : encoder une donnée classique x comme rotation quantique, appliquer un ansatz paramétré θ, et extraire la probabilité de mesurer |1⟩.
Squelette :
# kata_day_5_6.py
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
def cq_pipeline(x: float, theta: float) -> float:
"""Pipeline CQ minimal : encoder x, appliquer ansatz θ, retourner P(|1⟩).
Le circuit applique Ry(x) (encodage) puis Ry(θ) (ansatz) sur un qubit,
et retourne la probabilité de mesurer |1⟩.
"""
# TODO 1 : créer un circuit quantique à 1 qubit
# TODO 2 : appliquer Ry(x) sur le qubit 0 pour encoder la donnée classique
# TODO 3 : appliquer Ry(theta) sur le qubit 0 comme ansatz paramétré
# TODO 4 : obtenir le vecteur d'état via Statevector.from_instruction()
# et retourner la probabilité de l'état |1⟩ (indice 1)
return 0.0
Auto-correction :
# test_kata_day_5_6.py
import numpy as np
from kata_day_5_6 import cq_pipeline
# Test 1 : x=0, theta=0 → qubit reste |0⟩, P(|1⟩) = 0
p = cq_pipeline(0.0, 0.0)
assert abs(p) < 1e-8, f"P(|1⟩) avec x=0, θ=0 devrait être 0, obtenu {p}"
# Test 2 : x=π, theta=0 → rotation complète, P(|1⟩) = 1
p = cq_pipeline(np.pi, 0.0)
assert abs(p - 1.0) < 1e-8, f"P(|1⟩) avec x=π, θ=0 devrait être 1, obtenu {p}"
# Test 3 : x=0, theta=π → l'ansatz seul fait la rotation, P(|1⟩) = 1
p = cq_pipeline(0.0, np.pi)
assert abs(p - 1.0) < 1e-8, f"P(|1⟩) avec x=0, θ=π devrait être 1, obtenu {p}"
# Test 4 : x=π/2, theta=0 → P(|1⟩) = sin²(π/4) = 0.5
p = cq_pipeline(np.pi / 2, 0.0)
assert abs(p - 0.5) < 1e-8, f"P(|1⟩) avec x=π/2, θ=0 devrait être 0.5, obtenu {p}"
# Test 5 : formule générale P(|1⟩) = sin²((x+θ)/2)
for x, theta in [(1.0, 0.5), (2.0, 1.0), (0.3, 2.7)]:
p = cq_pipeline(x, theta)
expected = np.sin((x + theta) / 2) ** 2
assert abs(p - expected) < 1e-8, \
f"P(|1⟩) avec x={x}, θ={theta} : attendu {expected:.6f}, obtenu {p:.6f}"
print("Kata validé !")
Solution et explication
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
import numpy as np
def cq_pipeline(x: float, theta: float) -> float:
"""Pipeline CQ minimal : encoder x, appliquer ansatz θ, retourner P(|1⟩)."""
qc = QuantumCircuit(1)
qc.ry(x, 0) # Encodage : la donnée classique x devient une rotation
qc.ry(theta, 0) # Ansatz : le paramètre entraînable θ transforme l'état
sv = Statevector.from_instruction(qc)
return float(sv.probabilities()[1])Pourquoi : ce kata isole les trois étapes atomiques du régime CQ — encoder, transformer, mesurer — dans le circuit le plus simple possible (1 qubit, 2 portes). La porte Ry(x) encode la donnée classique : Ry(x)|0⟩ = cos(x/2)|0⟩ + sin(x/2)|1⟩. La porte Ry(θ) joue le rôle de l’ansatz paramétré. La composition des deux rotations donne P(|1⟩) = sin²((x + θ) / 2), ce qui montre que la prédiction dépend conjointement de la donnée et du paramètre — exactement le comportement de F(x, θ) vu au chapitre 1.