Active Learning : Guide Complet — Apprentissage Actif
Résumé
L’Active Learning — ou apprentissage actif — est une approche du machine learning où le modèle lui-même choisit les exemples les plus informatifs à soumettre à un annotateur humain. Plutôt que d’entraîner un algorithme passivement sur un vaste corpus de données déjà labellisées — un processus souvent coûteux et long — l’apprentissage actif demande au modèle de poser les bonnes questions et de cibler précisément les cas ambigus, incertains ou frontières.
Le résultat est spectaculaire : dans de nombreux scénarios, un modèle guidé par Active Learning atteint la même précision qu’un modèle passif avec seulement 20 % à 30 % des annotations nécessaires. Cette économie massive sur le coût d’annotation représente un avantage décisif lorsque l’étiquetage des données exige l’intervention d’experts spécialisés — médecins, juristes, linguistes ou analystes financiers.
Ce guide explore les fondements mathématiques, les différentes stratégies de sélection, l’implémentation pratique en Python avec la bibliothèque modAL, ainsi que les cas d’usage concrets qui font de l’Active Learning un outil indispensable du praticien moderne.
Principe mathématique de l’Active Learning
Le cœur de l’apprentissage actif repose sur un principe fondamental : la sélection itérative par maximisation d’une fonction d’utilité. Formellement, à chaque tour, le modèle choisit l’exemple $x^*$ dans le pool d’exemples non étiquetés qui maximise une fonction d’utilité $U(x)$ :
$$x^* = \underset{x}{\operatorname{argmax}} \; U(x)$$
où $U(x)$ mesure à quel point l’ajout de l’annotation de $x$ au jeu d’entraînement sera bénéfique pour le modèle. C’est cette fonction d’utilité qui distingue les différentes stratégies d’Active Learning.
Uncertainty Sampling — Échantillonnage par incertitude
La stratégie la plus intuitive sélectionne les exemples sur lesquels le modèle est le moins certain de sa prédiction. On utilise généralement l’entropie de la distribution de probabilité comme mesure d’incertitude :
$$H(p(y|x)) = -\sum_{y_i \in \mathcal{C}} p(y_i|x) \cdot \log p(y_i|x)$$
où $\mathcal{C}$ est l’ensemble des classes possibles et $p(y_i|x)$ est la probabilité estimée par le modèle que l’exemple $x$ appartienne à la classe $y_i$. L’entropie est maximale lorsque le modèle attribue des probabilités uniformes à toutes les classes : le modèle est alors totalement incertain. À l’inverse, une entropie nulle signifie que le modèle est absolument confiant dans sa prédiction.
Le modèle sélectionne ainsi l’exemple qui maximise l’entropie, c’est-à-dire celui where il hésite le plus entre plusieurs classes. Cette approche s’étend naturellement au margin sampling :
$$x^* = \underset{x}{\operatorname{argmin}} \left( p(y_1|x) – p(y_2|x) \right)$$
où $y_1$ et $y_2$ sont respectivement les deux classes les plus probables selon le modèle pour l’exemple $x$. Ici, on sélectionne l’exemple pour lequel la différence entre la probabilité de la classe la plus probable et celle de la deuxième classe la plus probable est minimale — en d’autres termes, celui où le modèle hésite le plus entre deux classes candidates.
Query-by-Committee — Interrogation par comité
Cette stratégie maintient une collection de modèles distincts (un « comité »), chacun entraîné sur le même jeu de données labellisées mais avec des initialisations différentes ou des sous-ensembles bootstrap distincts. Le comité sélectionne les exemples pour lesquels les modèles individuels sont le plus en désaccord.
La mesure d’accord repose sur l’entropie du vote (vote entropy) :
$$VE(x) = -\sum_{y_i \in \mathcal{C}} V(y_i) \cdot \log V(y_i)$$
où $V(y_i)$ est la fraction des membres du comité qui votent pour la classe $y_i$. Si tous les modèles du comité sont d’accord, $V(y_i) = 1$ pour une seule classe et l’entropie est nulle. Si les modèles sont divisés équitablement entre toutes les classes, l’entropie atteint son maximum.
L’avantage majeur du query-by-committee est qu’il capture non seulement l’incertitude individuelle d’un modèle mais également les zones structurales de désaccord entre différentes hypothèses — révélant ainsi des régions de l’espace des caractéristiques où le modèle manque cruellement d’information discriminante.
Expected Model Change — Changement de modèle attendu
Cette approche sélectionne les exemples qui modifieraient le plus le modèle s’ils étaient annotés et ajoutés au jeu d’entraînement. L’idée est profonde : plutôt que de mesurer l’incertitude actuelle du modèle, on estime directement l’impact futur de chaque annotation potentielle.
Plusieurs métriques existent pour quantifier ce changement :
- La norme du gradient attendu : on choisit l’exemple qui maximise la norme du gradient de la fonction de perte, indiquant une forte mise à jour des poids du modèle.
- La variation des prédictions : on estime de combien les probabilités prédites changeraient pour l’ensemble des données non étiquetées si cet exemple était ajouté.
- L’information attendue de Fisher : on sélectionne les exemples qui augmentent le plus la matrice d’information de Fisher, mesurant ainsi le gain d’information sur les paramètres du modèle.
Formellement, on cherche à maximiser l’espérance du changement :
$$x^* = \underset{x}{\operatorname{argmax}} \; \mathbb{E}{y \sim p(y|x)} \left[ | \theta | \right]$$} – \theta_{\text{actuel}
où $\theta_{x,y}$ représente les paramètres du modèle après l’inclusion de l’exemple $(x, y)$ dans l’entraînement.
Intuition — Pourquoi l’Active Learning fonctionne
Imaginez un étudiant qui prépare un examen en biologie marine. Face à des milliers de flashcards, il a deux stratégies possibles. La première est de tout parcourir dans l’ordre — des animaux évidents comme le poisson-clown ou la baleine bleue jusqu’aux espèces obscures. La seconde, bien plus intelligente, est de se concentrer sur les cas limites — ces créatures qui ressemblent à la fois à un requin et à une raie, ces mollusques ambigus, ces coraux dont la classification fait débat parmi les spécialistes. Chaque réponse à une question bien choisie vaut dix réponses à des questions évidentes. L’étudiant malin n’a pas besoin de voir mille photos de dauphins pour savoir ce qu’est un dauphin. Mais il a besoin de comprendre précisément ce qui distingue un marsouin d’un dauphin.
L’Active Learning fonctionne exactement ainsi. Au lieu d’apprendre passivement sur des milliers d’exemples tirés au hasard — dont une grande majorité seront triviaux ou redondants — le modèle identifie activement les instances qui se situent proche de la frontière de décision. Ces exemples frontières sont ceux où le modèle hésite, ceux qui révèlent le plus d’information sur la structure sous-jacente des données.
Chaque annotation obtenue par Active Learning apporte une valeur informationnelle disproportionnée. Un seul exemple bien choisi près de la frontière entre deux classes peut affiner cette frontière davantage que des centaines d’exemples loin de la frontière. C’est l’équivalent algorithmique de poser la question qui fait toute la différence.
Implémentation Python avec modAL
La bibliothèque modAL est le cadre de référence pour implémenter l’Active Learning en Python. Elle s’intègre parfaitement avec scikit-learn et offre une abstraction élégante pour les stratégies de requête. Voici une implémentation complète illustrant l’Active Learning appliqué à un problème de classification.
Installation des dépendances
pip install modAL scikit-learn numpy matplotlib
Exemple complet : Active Learning vs apprentissage aléatoire
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from modAL.models import ActiveLearner
from modAL.uncertainty import uncertainty_sampling
# Générer des données synthétiques
X, y = make_classification(
n_samples=1000,
n_features=20,
n_informative=15,
n_redundant=5,
n_classes=3,
random_state=42
)
# Séparation des données : pool non étiqueté et jeu de test
X_pool, X_test, y_pool, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# Initialisation avec un petit ensemble étiqueté (5 exemples par classe)
np.random.seed(42)
initial_idx = []
for classe in np.unique(y_pool):
indices_classe = np.where(y_pool == classe)[0]
idx_selectionnes = np.random.choice(indices_classe, size=5, replace=False)
initial_idx.extend(idx_selectionnes)
X_initial = X_pool[initial_idx]
y_initial = y_pool[initial_idx]
# Création du modèle de base
modele_rf = RandomForestClassifier(n_estimators=100, random_state=42)
# Initialisation du learner actif
learner = ActiveLearner(
estimator=modele_rf,
query_strategy=uncertainty_sampling,
X_training=X_initial,
y_training=y_initial
)
# Boucle de requête Active Learning
n_queries = 30
performances_actif = []
performances_aleatoire = []
for iteration in range(n_queries):
# Le modèle sélectionne les exemples les plus incertains
query_idx, query_instance = learner.query(X_pool)
# Annotation simulée (on utilise les vraies étiquettes)
y_nouvelles = y_pool[query_idx]
# Entraînement incrémental
learner.teach(X_pool[query_idx], y_nouvelles)
# Evaluation
y_pred = learner.predict(X_test)
perf = accuracy_score(y_test, y_pred)
performances_actif.append(perf)
# Parallèle : apprentissage aléatoire pour comparaison
modele_ref = RandomForestClassifier(n_estimators=100, random_state=42)
taille_entrainement = len(initial_idx) + (iteration + 1)
idx_aleatoires = np.random.choice(
len(X_pool), size=taille_entrainement, replace=False
)
modele_ref.fit(X_pool[idx_aleatoires], y_pool[idx_aleatoires])
y_pred_ref = modele_ref.predict(X_test)
perf_ref = accuracy_score(y_test, y_pred_ref)
performances_aleatoire.append(perf_ref)
print(f"Tour {iteration + 1:2d} | Actif: {perf:.4f} | Aleatoire: {perf_ref:.4f}")
# Visualisation
plt.figure(figsize=(10, 6))
plt.plot(
range(1, n_queries + 1), performances_actif,
'b-o', label='Active Learning (Uncertainty Sampling)', linewidth=2
)
plt.plot(
range(1, n_queries + 1), performances_aleatoire,
'r--s', label='Apprentissage aleatoire', linewidth=2
)
plt.xlabel("Nombre de requetes (lots d'annotations)", fontsize=12)
plt.ylabel("Precision sur le jeu de test", fontsize=12)
plt.title("Active Learning vs Apprentissage Aleatoire", fontsize=14)
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('active_learning_comparison.png', dpi=150)
plt.show()
Exemple avancé : Query-by-Committee avec modAL
from modAL.models import Committee
from modAL.disagreement import vote_entropy_sampling
# Creation d'un comité de classifieurs
n_committee = 5
classifieurs = [
RandomForestClassifier(n_estimators=50, random_state=i)
for i in range(n_committee)
]
comite = Committee(
learner_list=classifieurs,
query_strategy=vote_entropy_sampling
)
# Entraînement initial
comite.teach(X_initial, y_initial)
# Boucle de requête du comité
for iteration in range(20):
query_idx, _ = comite.query(X_pool)
comite.teach(X_pool[query_idx], y_pool[query_idx])
y_pred = comite.predict(X_test)
print(f"Committee - Tour {iteration + 1} : {accuracy_score(y_test, y_pred):.4f}")
L’approche par comité présente un avantage significatif dans les situations où un seul modèle pourrait converger prématurément vers une solution sous-optimale. Le désaccord entre membres du comité révèle des zones d’ambiguïté qu’un modèle isolé pourrait ne pas détecter.
Hyperparamètres essentiels
Le réglage fin des paramètres d’un pipeline d’Active Learning influence directement l’efficacité de la sélection. Voici les hyperparamètres clés à maîtriser.
n_queries — Nombre de tours de requête
Ce paramètre détermine combien de fois le modèle demandera de nouvelles annotations. Trop peu de requêtes — le modèle n’acquiert pas assez d’information. Trop de requêtes — les dernières annotations apportent un gain marginal négligeable (rendements décroissants). En pratique, on commence par 20 à 50 requêtes et on surveille la courbe de performance pour identifier le plateau.
batch_size — Taille du lot d’annotations
Au lieu de demander une seule annotation à la fois, on peut interroger sur un lot d’exemples. Le batch_size contrôle ce nombre. Un lot trop grand dilue la qualité de sélection (les derniers exemples du lot sont moins informatifs). Un lot de 5 à 20 exemples représente un compromis réaliste pour la plupart des applications. Le batch processing permet également de paralléliser l’annotation humaine — plusieurs annotateurs travaillent simultanément.
learner — Le classifieur de base
Le choix du modèle sous-jacent est crucial. Les Random Forests sont un excellent point de départ : ils fournissent des probabilités bien calibrées, sont robustes au surapprentissage sur les petits ensembles initiaux et fonctionnent bien avec l’uncertainty sampling. Les Support Vector Machines (SVM) — couplées au margin sampling — offrent d’excellents résultats lorsque les classes sont linéairement séparables dans un espace de caractéristiques transformé. Les réseaux de neurones peuvent être utilisés avec des techniques de Monte Carlo Dropout pour estimer l’incertitude épistémique, bien que cette approche soit plus complexe à implémenter et plus coûteuse computationnellement.
uncertainty_measure — Mesure d’incertitude
modAL propose plusieurs fonctions de sélection :
uncertainty_sampling: utilise la probabilité de la classe la plus probable (1 – p_classe_max)entropy_sampling: utilise l’entropie de Shannon de la distribution de probabilitémargin_sampling: utilise la différence entre les deux classes les plus probables
En pratique, le margin sampling tend à surpasser les deux autres sur les problèmes multi-classes, car il considère explicitement les deux classes candidates les plus probables au lieu de se focaliser uniquement sur la confiance maximale ou l’entropie globale.
Avantages et limites de l’Active Learning
Avantages
- Réduction massive du coût d’annotation — C’est l’avantage principal et le plus évident. En ciblant les exemples les plus informatifs, l’Active Learning atteint des performances équivalentes avec significativement moins de données étiquetées.
- Meilleure généralisation — Les exemples sélectionnés activement couvrent plus efficacement l’espace des caractéristiques, en particulier les régions frontières critiques pour la précision du modèle.
- Adaptabilité — Le modèle s’adapte dynamiquement à la distribution des données non étiquetées. Si la distribution change, la stratégie de sélection s’ajuste automatiquement.
- Synergie avec l’expertise humaine — L’annotateur humain se concentre exclusivement sur les cas ambigus qui nécessitent réellement son jugement, au lieu de perdre du temps sur des exemples triviaux.
Limites
- Biais de sélection — En sélectionnant uniquement les exemples frontaliers, on risque de négliger des régions de l’espace des caractéristiques qui, bien que denses, ne sont pas identifiées comme incertaines. Ce biais peut mener à un modèle imprécis pour les classes minoritaires ou les distributions atypiques.
- Sensibilité à l’initialisation — La qualité des premiers exemples étiquetés influence fortement les premières itérations. Une initialisation malheureuse peut orienter le modèle vers une mauvaise compréhension initiale.
- Coût computationnel — Chaque tour de requête nécessite de calculer l’incertitude sur l’ensemble du pool non étiqueté, ce qui peut devenir prohibitif avec des millions d’exemples.
- Dépendance à l’annotateur — Si l’annotateur commet des erreurs systématiques sur les cas difficiles — ce qui est précisément ce qu’on lui demande de labelliser — la qualité du modèle en souffre directement.
4 cas d’usage concrets
Cas d’usage n°1 : Classification de documents juridiques
Un cabinet d’avocats souhaite automatiquement catégoriser des milliers de décisions de justice par domaine légal. L’annotation nécessite l’expertise de juristes spécialisés — chaque document prend entre 10 et 30 minutes à analyser. Avec l’Active Learning, le modèle identifie les décisions frontalières entre deux domaines (par exemple, entre droit commercial et droit des sociétés). Les juristes annotent ces cas ambigus en priorité. Résultat : une précision de 92 % atteinte avec seulement 800 annotations au lieu des 4 000 requis par un échantillonnage aléatoire.
Cas d’usage n°2 : Détection d’anomalies en imagerie médicale
Un hôpital déploie un système de détection de pathologies rares sur des radiographies thoraciques. Les radiologistes disposent d’un temps limité pour labelliser des centaines de milliers d’images. L’Active Learning cible les images proches de la frontière entre sain et pathologique — les nodules difficiles, les infiltrats subtils, les ombres ambiguës. Chaque annotation ciblée affine considérablement la frontière de décision du modèle, permettant une détection précoce avec un nombre réduit de validations expertes.
Cas d’usage n°3 : Analyse de sentiments pour des langues peu dotées
Pour des langues disposant de peu de ressources annotées — comme le swahili, l’amharique ou le quechua — l’apprentissage Actif permet de construire des classifieurs de sentiment performants avec quelques centaines d’annotations seulement. Le modèle identifie les phrases dont le sentiment est ambivalent ou culturellement nuancé — ironie, double sens, expressions idiomatiques — et les soumet aux locuteurs natifs pour annotation.
Cas d’usage n°4 : Contrôle qualité en production industrielle
Une usine automobile souhaite détecter automatiquement les défauts sur des pièces métalliques par vision artificielle. Les défauts rares et subtils — micro-fissures, inclusions, déformations minimes — sont les plus difficiles à identifier et les plus critiques pour la sécurité. L’Active Learning concentre les inspections humaines sur les pièces dont l’apparence est ambiguë — ni clairement défectueuses ni clairement conformes — optimisant ainsi le temps des inspecteurs qualifiés et maximisant le taux de détection des défauts critiques.
Voir aussi
- Algorithme Bellman-Ford : Trouver les Plus Courts Chemins avec Poids Négatifs en Python
- Maîtriser les Suites de Totients de Puissances avec Python : Guide Complet et Astuces

