Entraînement Adversarial (FGSM/PGD) : Robustesse des Réseaux de Neurones face aux Attaques par Perturbations
Résumé
L’entraînement adversarial est une technique fondamentale en apprentissage profond visant à renforcer la robustesse des modèles face à des exemples adversariaux — des entrées intentionnellement perturbées pour tromper les réseaux de neurones. Cette méthode, introduite par Goodfellow et al. en 2014, repose sur un principe simple mais puissamment efficace : intégrer directement des exemples attaqués dans le processus d’entraînement du modèle, à la manière d’un vaccin qui exposerait le système immunitaire à des agents pathogènes affaiblis pour le préparer aux infections réelles.
Les deux attaques les plus emblématiques utilisées dans ce cadre sont le FGSM (Fast Gradient Sign Method) et le PGD (Projected Gradient Descent). Le FGSM réalise une perturbation en une seule étape en suivant le signe du gradient de la fonction de perte par rapport à l’entrée. Le PGD, quant à lui, généralise cette approche en itérant le processus plusieurs fois avec des pas plus petits, projetant le résultat dans une boule de contrainte à chaque itération. L’entraînement adversarial combine ces attaques avec l’optimisation des paramètres du modèle pour produire un classifieur capable de résister aux tentatives de manipulation délibérée et de maintenir des performances fiables sur des données corrompues.
Principe Mathématique
L’attaque FGSM (Fast Gradient Sign Method)
L’idée centrale du FGSM, proposée par Ian Goodfellow et ses collaborateurs en 2014, est d’exploiter le gradient de la fonction de perte par rapport aux données d’entrée — et non par rapport aux paramètres du modèle comme dans la descente de gradient classique. Le principe peut se résumer en une formule élégante :
$$x_{\text{adv}} = x + \varepsilon \cdot \text{sign}(\nabla_x L(f_\theta(x), y))$$
où :
- $x$ représente l’image ou l’entrée originale ;
- $\varepsilon$ (epsilon) est un petit scalaire contrôlant l’amplitude de la perturbation ;
- $\nabla_x L(f_\theta(x), y)$ est le gradient de la fonction de perte $L$ par rapport à l’entrée $x$ ;
- $\text{sign}(\cdot)$ désigne la fonction signe, appliquée élément par élément ;
- $x_{\text{adv}}$ est l’exemple adversarial résultant, visuellement quasi identique à $x$.
L’intuition derrière cette formule est remarquablement intuitive : au lieu de modifier les poids du réseau pour réduire la perte (ce que fait la descente de gradient classique), on modifie l’entrée dans la direction qui maximise la perte, mais avec une amplitude suffisamment faible pour rester imperceptible à l’œil humain. Cette perturbation directionnelle exploitée une seule fois constitue l’attaque la plus rapide et la plus simple en matière d’attaques adversariales, d’où son nom « Fast Gradient Sign Method ».
L’attaque PGD (Projected Gradient Descent)
Madry et al. (2017) ont démontré que le FGSM, bien qu’efficace et très rapide, ne constitue qu’une attaque d’ordre un (une seule étape). Pour obtenir des adversaires réellement puissants et robustes, ils ont proposé le PGD, qui généralise le FGSM en itérant la mise à jour adversariale plusieurs fois avec un pas réduit, tout en projetant le résultat dans une boule centrée sur l’entrée originale à chaque itération :
$$x^{(t+1)} = \Pi_{[x-\varepsilon, x+\varepsilon]}(x^{(t)} + \alpha \cdot \text{sign}(\nabla_x L(f_\theta(x^{(t)}), y)))$$
où :
- $x^{(0)}$ est initialisé soit par $x$ (attaque zéro-perturbation), soit par $x$ auquel on ajoute un bruit aléatoire uniforme (recommandé pour une attaque plus agressive) ;
- $\alpha$ représente la taille du pas à chaque itération, généralement fixée à $\alpha = \varepsilon / K$ ;
- $K$ est le nombre total d’itérations (typiquement 10, 20 ou 40) ;
- $\Pi_{[x-\varepsilon, x+\varepsilon]}(\cdot)$ est l’opérateur de projection sur la boule $\ell_\infty$ de rayon $\varepsilon$ centrée sur $x$, c’est-à-dire $\max(x-\varepsilon, \min(x^{(t)} + \alpha \cdot \text{sign}(\nabla), x+\varepsilon))$.
Le PGD est considéré comme l’attaque de référence dans la littérature en apprentissage automatique. En effet, Madry et ses coauteurs l’ont qualifié d’« attaque du premier ordre la plus forte » sous contrainte de norme $\ell_\infty$, en raison de sa simplicité conceptuelle et de sa remarquable efficacité pratique.
Formulation de l’Entraînement Adversarial
L’entraînement adversarial s’exprime formellement comme un problème d’optimisation minimax (min-max), où l’attaquant cherche à maximiser la perte tout en respectant une contrainte de perturbation, tandis que le défenseur (le modèle) cherche à minimiser cette perte maximale :
$$\min_\theta \; \mathbb{E}{(x, y) \sim \mathcal{D}}\left[ \max{|\delta|\infty \leq \varepsilon} L(f\theta(x + \delta), y) \right]$$
Dans cette formulation :
- $\theta$ désigne les paramètres du modèle (poids et biais du réseau de neurones) ;
- $\mathcal{D}$ est la distribution des données d’entraînement ;
- $\delta$ est la perturbation adversariale appliquée à l’entrée, contrainte par une norme $\ell_\infty$ bornée par $\varepsilon$ ;
- L’opérateur maximum ($\max$) représente l’attaque interne : pour chaque exemple $(x, y)$, on cherche la perturbation $\delta$ la plus nuisible possible dans la boule autorisée ;
- L’opérateur minimum ($\min$) représente l’optimisation externe : on ajuste les paramètres $\theta$ pour minimiser la perte sur les pires cas adversariaux.
En pratique, le problème interne (la maximisation par rapport à $\delta$) est résolu approximativement par le PGD avec $K$ étapes, tandis que le problème externe (la minimisation par rapport à $\theta$) est traité par un optimiseur standard tel que SGD ou Adam. Cette approche bi-niveaux constitue véritablement le fondement de la robustesse en apprentissage profond moderne.
Intuition
Imaginez un réseau de neurones comme un étudiant qui apprend à reconnaître des chiffres manuscrits à partir d’images. Avec un entraînement classique, l’étudiant voit uniquement des exemples propres et bien formés. Mais que se passe-t-il si, lors de l’examen, on ajoute un bruit presque invisible aux images ? L’étudiant non préparé pourrait facilement se tromper et classer un « 7 » comme un « 9 ».
L’entraînement adversarial, c’est comme injecter délibérément ce bruit pendant les révisions. On génère des versions altérées des images d’entraînement — des versions où une perturbation imperceptible a été ajoutée de manière calculée pour tromper le modèle — et on force le réseau à apprendre à les classer correctement malgré tout. C’est le principe exact de la vaccination : on expose le système à des menaces contrôlées pour qu’il développe des défenses robustes.
De manière plus concrète, le FGSM calcule la direction exacte dans l’espace des pixels qui, si l’on perturbe l’image dans cette direction, maximise l’erreur du modèle. Le PGD affine cette stratégie en faisant plusieurs petits pas dans cette direction, recalculant le gradient à chaque étape pour s’adapter aux changements du modèle (le gradient évolue au fur et à mesure que l’entrée est modifiée). L’entraînement adversarial utilise donc ces attaques non pas pour briser le modèle, mais pour le rendre plus fort.
Il existe un compromis fondamental — un trade-off inévitable — entre précision sur des données propres (accuracy) et robustesse face aux attaques. En général, plus un modèle est robuste aux exemples adversariaux, plus sa précision sur des données non perturbées tend à légèrement diminuer. C’est un compromis que les praticiens doivent gérer avec soin selon le contexte d’utilisation.
Implémentation Python (PyTorch)
Voici une implémentation complète et commentée en Python avec PyTorch, couvrant l’attaque FGSM, l’attaque PGD et la boucle d’entraînement adversarial.
Attaque FGSM
import torch
import torch.nn as nn
def fgsm_attack(model, images, labels, epsilon, loss_fn=nn.CrossEntropyLoss()):
"""Generate adversarial examples using Fast Gradient Sign Method."""
images_adv = images.clone().detach().requires_grad_(True)
outputs = model(images_adv)
loss = loss_fn(outputs, labels)
model.zero_grad()
loss.backward()
data_grad = images_adv.grad.data.sign()
perturbation = epsilon * data_grad
adversarial_images = images + perturbation
adversarial_images = torch.clamp(adversarial_images, 0, 1)
return adversarial_images
Attaque PGD
def pgd_attack(model, images, labels, epsilon, alpha, num_steps,
loss_fn=nn.CrossEntropyLoss(), random_init=True):
"""Generate adversarial examples using Projected Gradient Descent."""
if random_init:
adversarial_images = images.clone().detach() + \
torch.randn_like(images) * epsilon
adversarial_images = torch.clamp(adversarial_images, 0, 1).detach()
else:
adversarial_images = images.clone().detach()
adversarial_images.requires_grad_(True)
for step in range(num_steps):
outputs = model(adversarial_images)
loss = loss_fn(outputs, labels)
model.zero_grad()
loss.backward()
grad_sign = adversarial_images.grad.data.sign()
adversarial_images = adversarial_images.detach() + alpha * grad_sign
delta = adversarial_images - images
delta = torch.clamp(delta, -epsilon, epsilon)
adversarial_images = torch.clamp(images + delta, 0, 1).detach()
adversarial_images.requires_grad_(True)
return adversarial_images
Boucle d’Entraînement Adversarial
def adversarial_training(model, train_loader, optimizer, num_epochs,
epsilon=0.03, alpha=0.007, pgd_steps=10,
device='cuda', use_pgd=True):
"""Adversarial training loop using FGSM or PGD."""
model.to(device)
model.train()
criterion = nn.CrossEntropyLoss()
for epoch in range(num_epochs):
running_loss = 0.0
correct_adv = 0
total = 0
for batch_images, batch_labels in train_loader:
batch_images = batch_images.to(device)
batch_labels = batch_labels.to(device)
if use_pgd:
adv_images = pgd_attack(
model, batch_images, batch_labels,
epsilon=epsilon, alpha=alpha,
num_steps=pgd_steps, random_init=True
)
else:
adv_images = fgsm_attack(
model, batch_images, batch_labels, epsilon=epsilon
)
optimizer.zero_grad()
adv_outputs = model(adv_images)
loss = criterion(adv_outputs, batch_labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
_, predicted = adv_outputs.max(1)
total += batch_labels.size(0)
correct_adv += predicted.eq(batch_labels).sum().item()
avg_loss = running_loss / len(train_loader)
adv_accuracy = 100.0 * correct_adv / total
print(f"Epoch {epoch+1}/{num_epochs} | "
f"Loss: {avg_loss:.4f} | "
f"Adv Accuracy: {adv_accuracy:.2f}%")
return model
Hyperparamètres Clés
Le succès de l’entraînement adversarial dépend crucialement du choix des hyperparamètres suivants :
| Hyperparamètre | Description | Valeurs typiques | Impact |
|---|---|---|---|
| Epsilon (ε) | Amplitude maximale de la perturbation (norme ℓ∞) | 0.03, 0.05, 0.1 (sur des images normalisées [0,1]) | Plus ε est élevé, plus l’attaque est forte et le modèle robuste, mais la précision sur données propres diminue |
| Alpha (α) | Taille du pas à chaque itération du PGD | ε/K (typiquement 0.003–0.01) | Un α trop grand rend la convergence instable ; un α trop petit ralentit l’attaque |
| K (nombre d’étapes PGD) | Nombre d’itérations de l’attaque PGD | 10, 20, 40 | Plus K est élevé, plus l’attaque est forte (et coûteuse en calcul). K=10 est un bon compromis standard. |
| Algorithme d’attaque | FGSM ou PGD lors de l’entraînement | PGD recommandé | Le PGD produit un modèle nettement plus robuste que le FGSM, au prix d’un temps 10–40x plus long |
| Initialisation aléatoire | Ajout de bruit aléatoire avant le PGD | True/False | Recommandé pour éviter le surapprentissage à une trajectoire d’attaque déterministe |
Recommandation pratique : Pour un équilibre optimal entre robustesse et précision, utilisez PGD avec ε = 0.03, α = 0.003 (soit ε/10), K = 10 étapes, et une initialisation aléatoire. C’est le réglage standard utilisé dans la majorité des articles de recherche et des benchmarks de robustesse contemporains.
Avantages et Limites
Avantages
- Robustesse prouvée empiriquement : L’entraînement adversarial est la seule méthode ayant démontré une résistance significative contre les attaques adaptatives les plus sophistiquées. Les modèles ainsi entraînés maintiennent des performances satisfaisantes même sous attaque PGD forte, là où les modèles standards s’effondrent complètement.
- Simplicité conceptuelle : Le principe fondamental est remarquablement élégant — il suffit de générer des exemples perturbés et d’entraîner le modèle dessus. Aucune architecture spécialisée ni modification structurelle complexe n’est requise, ce qui rend la méthode universellement applicable.
- Applicable à toute architecture : La méthode fonctionne avec n’importe quel modèle différentiable — des réseaux convolutifs (CNN) aux transformers, en passant par les réseaux de neurones récurrents (RNN) et les graph neural networks (GNN). La seule exigence est la capacité à calculer le gradient par rapport à l’entrée, ce qui est universellement disponible dans les frameworks modernes.
- Amélioration de la généralisation : De manière surprenante, l’entraînement adversarial agit parfois comme une forme de régularisation, améliorant légèrement la généralisation du modèle sur des données non vues, au-delà de la simple robustesse aux attaques.
Limites
- Coût computationnel très élevé : L’entraînement adversarial avec PGD multiplie le temps d’entraînement par un facteur de 10 à 40 (ou plus) par rapport à un entraînement standard, car chaque exemple nécessite K passes avant supplémentaires pour générer la perturbation. Sur des ensembles de grande taille comme ImageNet, ce coût peut devenir prohibitif.
- Compromis précision-robustesse (trade-off) : L’amélioration de la robustesse s’accompagne presque systématiquement d’une légère diminution de la précision sur des données propres et non perturbées. Ce compromis fondamental est inhérent à la nature minimax de l’optimisation et ne peut être complètement éliminé, seulement atténué par des techniques avancées.
- Robustesse transférable limitée : Un modèle entraîné contre une attaque spécifique (par exemple FGSM avec ε = 0.03) peut ne pas être robuste à d’autres types de perturbations (bruit gaussien, rotations, variations de luminosité). La robustesse n’est pas universelle et reste partiellement dépendante du type d’attaque utilisé pendant l’entraînement.
- Difficulté théorique de certification : Bien que l’entraînement adversarial fonctionne bien en pratique, il ne fournit aucune garantie formelle de robustesse. Des méthodes de certification formelle existent mais sont limitées à de petits réseaux ou à des ensembles de données modestes pour des raisons de complexité combinatoire.
4 Cas d’Usage Concrets
1. Véhicules Autonomes et Systèmes de Perception
Dans les systèmes de véhicules autonomes, les réseaux de neurones sont chargés de détecter les panneaux de signalisation, les piétons, les obstacles et les marquages routiers à partir de flux vidéo en temps réel. Des chercheurs ont démontré que des autocollants presque invisibles apposés sur un panneau « STOP » peuvent le faire classifier comme « Limitation de vitesse 45 km/h » par un modèle non protégé. L’entraînement adversarial permet de robustifier ces systèmes de perception pour qu’ils résistent à de telles manipulations physiques malveillantes, garantissant ainsi la sécurité des usagers de la route.
2. Détection de Malwares et Cybersécurité
Les pirates informatiques utilisent de plus en plus des techniques adversariales pour créer des variantes de logiciels malveillants (malwares) qui échappent à la détection par les modèles d’analyse basés sur l’apprentissage automatique. En entraînant ces détecteurs de manière adversariale — c’est-à-dire en générant activement des échantillons de malwares perturbés qui tentent de tromper le classifieur — les entreprises de cybersécurité peuvent construire des systèmes de détection plus résilients face aux tentatives d’évasion sophistiquées et aux attaques zero-day.
3. Filtres Anti-Spam et Modération de Contenu
Les plateformes en ligne utilisent des modèles de classification pour détecter automatiquement les emails de spam, les messages haineux et les contenus inappropriés. Les attaquants contournent ces filtres en utilisant des techniques adversariales subtiles : remplacement de caractères par des homographes, insertion de mots-clés innocents, ou modification imperceptible du formatage textuel. L’entraînement adversarial textuel (appliquant des perturbations au niveau des embeddings de mots) permet de renforcer la robustesse de ces systèmes et de maintenir leur efficacité face à des tentatives de contournement de plus en plus élaborées.
4. Protection des Systèmes Biométriques et de Reconnaissance Faciale
Les systèmes de reconnaissance faciale sont vulnérables aux attaques adversariales physiques, où des motifs spécialement conçus imprimés sur des lunettes ou apposés sur des murs peuvent tromper le système pour authentifier une personne non autorisée ou masquer l’identité d’un individu dans une caméra de surveillance. L’entraînement adversarial, en exposant le modèle à des variations adversariales simulées pendant la phase d’apprentissage, le rend plus robuste à ces tentatives de contournement et renforce la fiabilité des systèmes d’authentification biométrique dans des environnements potentiellement hostiles.
Voir Aussi
- Algorithme de Manacher: Découvrez Comment Trouver Toutes les Sous-Palindromes en Python en O(N)
- Calcul de la Distance Confortable en Python : Techniques et Applications Pratiques

