Transformer un optimiseur standard (L-BFGS, SGD, Adam) en solveur robuste aux outliers
Ce projet présente une méthode pratique et éprouvée pour transformer n’importe quel optimiseur standard en solveur quasi-lorentzien robuste via un schéma Iteratively Reweighted Least Squares (IRLS) adapté à la perte de Cauchy.
Script Python standalone exécutable.
CauchyIRLSSolver complète# Dépendances
pip install numpy scipy
python quasi_lorentzien_irls.py
from quasi_lorentzien_irls import CauchyIRLSSolver
import numpy as np
# Données
X = np.array([[1, -5], [1, -4], [1, -3], ...]) # Design matrix
y = np.array([2*x + 1 + noise + outliers for x in X[:, 1]])
# Solver
solver = CauchyIRLSSolver(sigma=1.0, max_iter=20, adaptive_sigma=True)
theta = solver.solve_linear(X, y, verbose=True)
print(f"Solution robuste: θ = {theta}")
| Méthode | θ₀ | θ₁ | Erreur θ₁ |
|---|---|---|---|
| Vraie valeur | 1.0000 | 2.0000 | — |
| MSE (standard) | 0.9147 | 2.1780 | 8.9% ❌ |
| IRLS Cauchy | 0.8014 | 1.9716 | 1.4% ✅ |
| Méthode | θ₀ | θ₁ | θ₂ | Erreur θ₂ |
|---|---|---|---|---|
| Vraie valeur | 1.0000 | -2.0000 | 0.5000 | — |
| MSE (standard) | 1.1230 | -2.0890 | 0.4552 | 8.96% ❌ |
| IRLS Cauchy | 1.0289 | -1.9893 | 0.4925 | 1.5% ✅ |
L_Cauchy(θ) = Σ log(1 + r_i² / σ²)
Contrairement à MSE (r²), la perte de Cauchy croît logarithmiquement pour les outliers → moins d’influence numérique.
w_i = 1 / (σ² + r_i²)
Chaque itération résout un problème convexe bien-conditionné → stabilité numérique garantie.
| Domaine | Cas d’usage | Logiciel |
|---|---|---|
| Vision 3D | Bundle Adjustment | Ceres Solver (Google) |
| SLAM | Navigation autonome | GTSAM (Georgia Tech) |
| Pose Estimation | Robotique | OpenCV |
| Photogrammétrie | Reconstruction 3D | Ceres + poids robustes |
Entreprises utilisant IRLS quotidiennement : Thales, AirBus, NASA, Tesla, Google
Pour comprendre en détail :
pdflatex quasi_lorentzien_irls.tex
CauchyIRLSSolversolve_linear() et solve_nonlinear()self.historyfrom quasi_lorentzien_irls import CauchyIRLSSolver
solver = CauchyIRLSSolver(sigma=1.0, max_iter=15, adaptive_sigma=True)
theta = solver.solve_linear(X_design, y_data, verbose=True)
def residual_fn(theta):
# theta: paramètres du modèle
y_pred = forward_pass(theta, X)
return y_data - y_pred
solver = CauchyIRLSSolver(sigma=0.5, max_iter=20)
theta_opt = solver.solve_nonlinear(residual_fn, theta0, method='L-BFGS-B')
def residual_fn(pose):
# pose: [R, t]
points_transformed = apply_pose(pose, points_3d)
reprojection_error = points_2d - project(points_transformed)
return reprojection_error.flatten()
solver = CauchyIRLSSolver(sigma=2.0, adaptive_sigma=True)
pose_opt = solver.solve_nonlinear(residual_fn, pose_init)
| Situation | σ | Adaptation |
|---|---|---|
| Bruit faible observé | σ ≈ 0.5 × std(bruit) | Fixe |
| Bruit inconnu | σ = 1.0 (initial) | Adaptative (recommandé) |
| Bruit très variable | σ variable | Adaptative + reset |
| Cas | K | Remarque |
|---|---|---|
| Régression simple | 10 | Converge vite |
| Petit dataset | 15 | Plus stable |
| Grand dataset | 20 | Plus de robustesse |
| Solveur | Recommandation | Cas |
|---|---|---|
| L-BFGS-B | ✅ Recommandé | Précision + stabilité (défaut) |
| Adam | Si N » 1M | Très grand dataset |
| Gauss-Newton | Si jacobienne disponible | Vision, géométrie |
# Après optimisation, vérifier outliers rejetés
weights_final = solver.lorentzian_weights(residuals_final)
n_outliers = np.sum(weights_final < 0.1)
print(f"Outliers rejetés : {n_outliers}/{len(weights_final)}")
# Historique de convergence
import matplotlib.pyplot as plt
plt.plot(solver.history['loss'])
plt.xlabel('Itération IRLS')
plt.ylabel('Perte de Cauchy')
plt.show()
Q: Pourquoi IRLS et pas un optimiseur lorentzien pur ? R: Un vrai “optimiseur lorentzien” n’existe pas réellement (la perte Cauchy est non-convexe). IRLS est la meilleure approche pratique : stabilité + robustesse.
Q: Combien d’itérations IRLS faut-il ? R: Typiquement 10–20. On peut utiliser un critère d’arrêt comme ||Δθ|| < 1e-6.
Q: IRLS fonctionne-t-il avec des réseaux de neurones ?
R: Oui ! Il faut passer une fonction residual_fn qui retourne les résidus, puis l’envelopper dans IRLS.
Q: Comment choisir σ ? R: Adaptatif (median des résidus) est recommandé. Sinon, σ ≈ écart-type du bruit observé.
Q: Est-ce plus lent que MSE ? R: Oui, ~K fois plus cher (K ≈ 10-20). Mais souvent le gain en robustesse en vaut la peine.
Utilisation libre pour recherche et éducation.
| Auteur : Thibaut LOMBARD | Date : Décembre 2025 |
Dernier test : Python 3.12, NumPy, SciPy (tous les packages testés ✓)