Le ML comme approximation de fonction & Les trois paradigmes d'apprentissage
Poser les fondations du Machine Learning — F(x,θ), recherche de paramètres, paradigmes supervisé, non supervisé et par renforcement — avant d'entrer dans le QML.
Le ML comme approximation de fonction F(x,θ)
L’idée en une phrase
Le Machine Learning consiste à trouver une fonction F(x, θ) qui transforme une entrée x en une prédiction utile, en ajustant un vecteur de paramètres θ pour minimiser l’écart entre les prédictions et les valeurs observées. Ce cadre — une fonction paramétrable dont on optimise les paramètres — est exactement celui que le QML reprendra : dans la boucle variationnelle hybride, le circuit quantique paramétré joue le rôle de F, et un optimiseur classique ajuste θ.
Analogie : Considérons un potier qui façonne un bol. L’argile correspond aux données d’entrée x. La forme du bol dépend des gestes du potier — ses paramètres θ (pression, angle, vitesse). Le modèle de référence est le bol commandé par le client. Le potier ajuste ses gestes jusqu’à ce que le bol produit corresponde au bol attendu. En ML, l’algorithme d’apprentissage joue le rôle du potier : il modifie θ de façon systématique pour réduire l’écart mesuré.
Points clés
- Un modèle ML est une fonction mathématique F(x, θ) : x est l’entrée (un vecteur de caractéristiques), θ est le vecteur de paramètres appris, et F(x, θ) est la sortie prédite.
- Apprendre signifie trouver les valeurs de θ qui minimisent une fonction de coût (ou perte) L(θ), laquelle mesure l’écart entre les prédictions F(x, θ) et les valeurs cibles y.
- La forme de F est choisie avant l’apprentissage : une droite (régression linéaire), un polynôme, un réseau de neurones, ou — dans le cas du QML — un circuit quantique paramétré. Ce choix s’appelle l’hypothèse de modèle.
- Plus F est riche (beaucoup de paramètres, architecture complexe), plus elle peut capturer de motifs dans les données, mais plus elle risque de coller au bruit plutôt qu’au signal. Ce compromis (expressivité vs généralisation) traverse tout le livre.
Exemple concret
On dispose de 5 mesures de température (x, en °C) et de volume d’un gaz (y, en litres) :
| x (°C) | 0 | 25 | 50 | 75 | 100 |
|---|---|---|---|---|---|
| y (L) | 22.4 | 24.5 | 26.7 | 28.8 | 30.9 |
On pose F(x, θ) = θ₀ + θ₁·x, une droite à 2 paramètres. On mesure l’écart par la Mean Squared Error (MSE) : L(θ) = (1/N) Σ(F(xᵢ, θ) − yᵢ)². L’apprentissage consiste à trouver θ₀ et θ₁ qui rendent L(θ) la plus faible possible. Ici, la solution exacte est θ₀ ≈ 22.4, θ₁ ≈ 0.085 : le volume augmente d’environ 0.085 litre par degré.
Modèle linéaire vs non linéaire
| Critère | Modèle linéaire F = θ₀ + θ₁x | Modèle non linéaire (réseau de neurones, circuit quantique) |
|---|---|---|
| Nombre de paramètres | 2 (θ₀, θ₁) | Des dizaines à des millions |
| Expressivité | Limité aux relations linéaires | Peut capturer des motifs complexes |
| Risque d’overfitting | Faible | Élevé si mal régularisé |
| Interprétabilité | Directe (pente, ordonnée) | Souvent opaque |
Code Python — régression linéaire en NumPy
import numpy as np
# Données : température (°C) → volume (L)
x = np.array([0, 25, 50, 75, 100], dtype=float)
y = np.array([22.4, 24.5, 26.7, 28.8, 30.9])
# Modèle : F(x, θ) = θ₀ + θ₁·x
# Résolution analytique par moindres carrés
X = np.column_stack([np.ones_like(x), x]) # matrice [1, x]
theta = np.linalg.lstsq(X, y, rcond=None)[0]
print(f"θ₀ = {theta[0]:.2f}, θ₁ = {theta[1]:.4f}")
# θ₀ = 22.38, θ₁ = 0.0854
# MSE sur les données d'entraînement
predictions = X @ theta
mse = np.mean((predictions - y) ** 2)
print(f"MSE = {mse:.6f}")
# MSE = 0.000200
Piège courant : « Le ML crée des formules à partir de rien » est inexact. L’humain choisit la structure du modèle (linéaire, polynomiale, réseau, circuit quantique) — l’algorithme ne fait qu’ajuster les paramètres θ à l’intérieur de cette structure. Si la structure est inadaptée (une droite pour des données sinusoïdales), aucune optimisation de θ ne produira de bonne prédiction.
Les trois paradigmes d’apprentissage
L’idée en une phrase
Tout problème de ML relève de l’un de trois paradigmes — supervisé, non supervisé ou par renforcement — qui diffèrent par la nature du retour d’information disponible pendant l’apprentissage. Le QML hérite de ces paradigmes : un classificateur variationnel (VQC) est supervisé, un algorithme de clustering quantique est non supervisé, et le quantum reinforcement learning suit le troisième paradigme.
Analogie : Considérons trois façons d’apprendre une langue. L’apprentissage supervisé est un cours avec un professeur qui corrige chaque phrase (entrée : phrase, étiquette : correct/incorrect). L’apprentissage non supervisé est l’immersion sans professeur : on repère des structures (groupes de mots similaires, motifs grammaticaux) sans qu’on nous dise lesquels. L’apprentissage par renforcement est l’apprentissage par la conversation : on reçoit des réactions (sourires ou incompréhension) qui récompensent ou pénalisent nos choix, mais personne ne donne la « bonne réponse » mot à mot.
Points clés
- Supervisé : on dispose de paires (x, y) où y est la réponse connue. Le modèle apprend à prédire y à partir de x. Si y est une catégorie (chat/chien), c’est de la classification ; si y est un nombre continu (prix d’un appartement), c’est de la régression.
- Non supervisé : on n’a que des x, sans étiquette y. L’objectif est de découvrir la structure latente des données : clusters (k-means), réduction de dimension (PCA), ou détection d’anomalies.
- Par renforcement : un agent prend des décisions séquentielles dans un environnement et reçoit des récompenses (positives ou négatives). L’objectif est de maximiser la récompense cumulée sur le long terme.
- En QML à l’ère NISQ, le paradigme supervisé domine très largement : le VQC et la QSVM (chapitres 4-9) en sont les exemples centraux. C’est là que la boucle variationnelle hybride prend tout son sens.
Exemple concret
Un hôpital dispose de 10 000 radiographies pulmonaires annotées « sain » ou « pathologique » par un radiologue. En supervisé, on entraîne un modèle F(x, θ) qui reçoit une image x et prédit la catégorie y. La perte est le nombre de classifications erronées. Si le même hôpital n’a pas d’annotations, il peut utiliser un algorithme non supervisé pour regrouper les radiographies en clusters et repérer celles qui diffèrent de la majorité — des anomalies potentielles.
Classification vs régression vs clustering
| Critère | Classification (supervisé) | Régression (supervisé) | Clustering (non supervisé) |
|---|---|---|---|
| Type de sortie | Catégorie (classe 0 ou 1) | Valeur continue | Groupe (cluster) |
| Étiquettes requises | Oui (y catégoriel) | Oui (y continu) | Non |
| Exemple | Spam / pas spam | Prix d’un bien | Segmentation clients |
| Perte typique | Cross-entropy | MSE | Inertie intra-cluster |
| Équivalent QML | VQC (chapitre 4) | Circuit de régression | Quantum k-means |
Code Python — classification supervisée minimale
import numpy as np
# Données supervisées : 2 caractéristiques, 2 classes
# Classe 0 : points autour de (1, 1) ; Classe 1 : points autour de (3, 3)
np.random.seed(42)
x_class0 = np.random.randn(50, 2) + [1, 1]
x_class1 = np.random.randn(50, 2) + [3, 3]
X = np.vstack([x_class0, x_class1]) # 100 × 2
y = np.array([0]*50 + [1]*50) # étiquettes
# Classificateur le plus simple : seuil sur la somme des features
# F(x, θ) = 1 si (x₁ + x₂) > θ, sinon 0
theta = 4.0 # seuil initial (à optimiser)
predictions = (X.sum(axis=1) > theta).astype(int)
accuracy = np.mean(predictions == y)
print(f"θ = {theta:.1f} → accuracy = {accuracy:.0%}")
# θ = 4.0 → accuracy = 89%
# Recherche du meilleur θ par balayage (brute force)
best_theta, best_acc = 0, 0
for t in np.arange(0, 8, 0.1):
acc = np.mean((X.sum(axis=1) > t).astype(int) == y)
if acc > best_acc:
best_theta, best_acc = t, acc
print(f"Meilleur θ = {best_theta:.1f} → accuracy = {best_acc:.0%}")
# Meilleur θ = 4.0 → accuracy = 89%
Piège courant : « Le non supervisé ne sert à rien si on peut étiqueter les données » est une simplification. Même en présence d’étiquettes, le clustering peut révéler des sous-groupes inattendus dans les données (sous-types de maladies, segments de marché) que les étiquettes existantes ne capturent pas. De plus, étiqueter des données est souvent coûteux — d’où l’intérêt de méthodes semi-supervisées qui combinent les deux paradigmes.
Fil rouge — la frontière quantique/classique
Ce premier chapitre est entièrement classique : il pose le vocabulaire (F(x, θ), perte, paradigmes) que le QML va réutiliser mot pour mot. Dans la boucle variationnelle hybride que l’on découvrira au chapitre 4, le circuit quantique paramétré remplace le modèle classique F — mais la structure reste identique : encoder x, appliquer les paramètres θ, mesurer une sortie, calculer une perte, et mettre à jour θ classiquement. Comprendre ce cadre classique est indispensable : on ne peut pas évaluer l’avantage quantique sans savoir contre quoi on se compare.
Kata Qiskit — du modèle classique au modèle quantique
Objectif : implémenter une fonction linéaire F(x, θ) = θ₀ + θ₁·x en Python pur, calculer la MSE sur un jeu de données, puis constater que le même cadre (entrée → paramètres → sortie → perte) s’applique identiquement. Ce kata pose les bases que le chapitre 4 transposera en circuit quantique.
Squelette :
# kata_day_1_2.py
import numpy as np
def model(x, theta):
"""Modèle linéaire F(x, θ) = θ₀ + θ₁·x."""
# TODO 1 : retourner θ₀ + θ₁ * x
# theta est un array [θ₀, θ₁], x est un array de valeurs
pass
def mse_loss(predictions, targets):
"""Mean Squared Error : L = (1/N) Σ (ŷᵢ - yᵢ)²."""
# TODO 2 : calculer et retourner la MSE
pass
def find_best_theta(x, y, theta0_range, theta1_range):
"""Trouver les meilleurs θ₀, θ₁ par recherche exhaustive (grid search)."""
best_theta = None
best_loss = float('inf')
# TODO 3 : parcourir toutes les combinaisons (θ₀, θ₁),
# calculer les prédictions avec model(), la perte avec mse_loss(),
# et garder la meilleure combinaison
return best_theta, best_loss
Auto-correction :
# test_kata_day_1_2.py
import numpy as np
from kata_day_1_2 import model, mse_loss, find_best_theta
# Test 1 : model
x = np.array([0.0, 1.0, 2.0])
theta = np.array([1.0, 0.5])
preds = model(x, theta)
assert preds is not None, "model() ne doit pas retourner None"
np.testing.assert_allclose(preds, [1.0, 1.5, 2.0], atol=1e-10,
err_msg="F([0,1,2], [1, 0.5]) devrait donner [1.0, 1.5, 2.0]")
# Test 2 : mse_loss
loss = mse_loss(np.array([1.0, 2.0, 3.0]), np.array([1.0, 2.0, 3.0]))
assert loss is not None, "mse_loss() ne doit pas retourner None"
assert abs(loss) < 1e-10, "MSE de prédictions parfaites doit être 0"
loss2 = mse_loss(np.array([1.0, 2.0]), np.array([2.0, 4.0]))
np.testing.assert_allclose(loss2, 2.5, atol=1e-10,
err_msg="MSE de [1,2] vs [2,4] devrait être ((1)²+(2)²)/2 = 2.5")
# Test 3 : find_best_theta
x_data = np.array([0, 25, 50, 75, 100], dtype=float)
y_data = np.array([22.4, 24.5, 26.7, 28.8, 30.9])
theta0_range = np.arange(20.0, 25.0, 0.1)
theta1_range = np.arange(0.0, 0.2, 0.005)
best_theta, best_loss = find_best_theta(x_data, y_data, theta0_range, theta1_range)
assert best_theta is not None, "find_best_theta() ne doit pas retourner None"
assert abs(best_theta[0] - 22.4) < 0.5, f"θ₀ attendu ≈ 22.4, obtenu {best_theta[0]:.2f}"
assert abs(best_theta[1] - 0.085) < 0.02, f"θ₁ attendu ≈ 0.085, obtenu {best_theta[1]:.4f}"
assert best_loss < 0.1, f"La MSE optimale devrait être < 0.1, obtenue {best_loss:.4f}"
print("Kata validé !")
Solution et explication
# kata_day_1_2.py
import numpy as np
def model(x, theta):
"""Modèle linéaire F(x, θ) = θ₀ + θ₁·x."""
return theta[0] + theta[1] * x
def mse_loss(predictions, targets):
"""Mean Squared Error : L = (1/N) Σ (ŷᵢ - yᵢ)²."""
return np.mean((predictions - targets) ** 2)
def find_best_theta(x, y, theta0_range, theta1_range):
"""Trouver les meilleurs θ₀, θ₁ par recherche exhaustive (grid search)."""
best_theta = None
best_loss = float('inf')
for t0 in theta0_range:
for t1 in theta1_range:
theta = np.array([t0, t1])
preds = model(x, theta)
loss = mse_loss(preds, y)
if loss < best_loss:
best_loss = loss
best_theta = theta.copy()
return best_theta, best_lossPourquoi : ce kata illustre le cadre F(x, θ) → perte → optimisation dans sa forme la plus simple. La recherche par grille (grid search) est la méthode d’optimisation la plus naïve : on essaie toutes les combinaisons. Aux chapitres suivants, on la remplacera par la descente de gradient (classique) puis par le Parameter Shift Rule (hybride quantique-classique). Mais le schéma reste identique : définir un modèle paramétré, mesurer l’erreur, chercher les meilleurs paramètres.