cauchy

Optimiseur Quasi-Lorentzien via IRLS pour la Perte de Cauchy

Transformer un optimiseur standard (L-BFGS, SGD, Adam) en solveur robuste aux outliers

📋 Aperçu

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.

✨ Caractéristiques

1. quasi_lorentzien_irls.py (12 KB)

Script Python standalone exécutable.

🚀 Démarrage Rapide

Installation

# Dépendances
pip install numpy scipy

Exécution des Exemples

python quasi_lorentzien_irls.py

Exemple Basique en Python

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}")

📊 Résultats Numériques

Régression Linéaire (50 points, 8 outliers)

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%

Régression Quadratique (60 points, 6 outliers)

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%

🔑 Concepts Fondamentaux

Perte de Cauchy

L_Cauchy(θ) = Σ log(1 + r_i² / σ²)

Contrairement à MSE (r²), la perte de Cauchy croît logarithmiquement pour les outliers → moins d’influence numérique.

Poids Lorentziens Adaptatifs

w_i = 1 / (σ² + r_i²)

Schéma IRLS

  1. Initialiser θ⁽⁰⁾ (solution MSE ou prior)
  2. Pour k = 0 à K-1 :
    • Calculer résidus r_i⁽ᵏ⁾
    • Calculer poids w_i⁽ᵏ⁾
    • Minimiser perte quadratique pondérée
    • Mettre à jour σ (adaptatif)
    • Tester convergence

Chaque itération résout un problème convexe bien-conditionné → stabilité numérique garantie.

🏭 Applications Industrielles

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

📖 Théorie Complète

Pour comprendre en détail :

  1. Compilez le LaTeX :
    pdflatex quasi_lorentzien_irls.tex
    
  2. Comprenez le code Python :
    • Classe CauchyIRLSSolver
    • Méthodes solve_linear() et solve_nonlinear()
    • Historique de convergence dans self.history

💻 Intégration dans Vos Projets

Cas 1 : Régression Linéaire Robuste

from 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)

Cas 2 : Régression Non-Linéaire (ex. Neural Network)

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')

Cas 3 : Pose Estimation (Robotique)

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)

🎯 Recommandations Pratiques

Choix du Paramètre σ

Situation σ Adaptation
Bruit faible observé σ ≈ 0.5 × std(bruit) Fixe
Bruit inconnu σ = 1.0 (initial) Adaptative (recommandé)
Bruit très variable σ variable Adaptative + reset

Choix du Nombre d’Itérations K

Cas K Remarque
Régression simple 10 Converge vite
Petit dataset 15 Plus stable
Grand dataset 20 Plus de robustesse

Solveur Interne

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

Diagnostic de Qualité

# 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()

📚 Références

Théorie

❓ FAQ

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.

📝 Licence

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 ✓)