Réseaux Siamois : Guide Complet — Similarité par Réseaux Jumeaux

Réseaux Siamois : Guide Complet — Similarité par Réseaux Jumeaux

Réseaux Siamois : Guide complet — Similarité par Réseaux Jumeaux

Résumé — Les réseaux siamois (Siamese Networks) sont des architectures de deep learning conçues pour comparer des paires d’entrées et apprendre une mesure de similarité. Introduits par Bromley et al. en 1993 pour la vérification de signatures, ils consistent en deux sous-réseaux identiques (partageant les mêmes poids) qui transforment chaque entrée en un embedding, puis comparent ces embeddings via une fonction de distance. L’avantage clé: au lieu de classifier N catégories, le réseau apprend à dire “similaire ou différent”, ce qui fonctionne même pour des classes jamais vues pendant l’entraînement.


Principe mathématique

1. Architecture à poids partagés

Un réseau siamois est composé de deux branches identiques f_θ:

embed_1 = f_θ(x1)
embed_2 = f_θ(x2)  # Mêmes paramètres θ

Les deux branches partagent exactement les mêmes poids: elles ne sont qu’un seul réseau appliqué deux fois.

2. Fonction de distance

La similarité entre x1 et x2 est mesurée par la distance euclidienne entre leurs embeddings:

d(x1, x2) = ||f_θ(x1) - f_θ(x2)||²

3. Contrastive Loss

La fonction de perte contrastive pousse les paires similaires à être proches et les dissimilaires à être éloignées:

L = y · d²
  + (1-y) · max(0, m - d)²

Où y = 1 si similaire et y = 0 si dissimilaire, et m est la marge (distance minimale désirée entre paires différentes). Le terme max(0, m – d)² signifie: si la distance dépasse déjà la marge, pas de pénalité. Sinon, on pénalise.

4. Triplet Loss

Une alternative populaire: le triplet loss prend un triplet (ancre, positif, négatif):

L = max(0, ||f(a) - f(p)||² - ||f(a) - f(n)||² + m)

L’ancre et le positif sont similaires (même classe), le négatif est différent. Le réseau apprend à rendre l’ancre plus proche du positif que du négatif, avec une marge m de séparation.

5. One-shot et few-shot learning

L’application la plus puissante des réseaux siamois: la reconnaissance avec un seul exemple. Si on a une seule photo de référence de chaque personne, on compare la nouvelle photo à toutes les références via la distance des embeddings:

classe(x_nouveau) = argmin_référence d(f(x_nouveau), f(référence))

Cela fonctionne pour des classes jamais vues pendant l’entraînement, car la fonction de similarité est générique, pas spécifique à une classe.


Intuition

Un réseau siamois, c’est comme un jumeau qui compare deux visages. Il ne reconnaît pas spécifiquement « c’est Pierre » ou « c’est Marie ». Il se demande juste: “est-ce que ces deux visages sont le même oui ou non?”.

C’est pourquoi c’est si puissant pour la reconnaissance avec un seul exemple: on n’a pas besoin de milliers de photos de chaque personne, juste d’une photo de référence et on compare. C’est la différence entre mémoriser un annuaire (classification classique) et savoir comparer deux personnes (réseau siamois).


Implémentation Python

1. Architecture siamoise with PyTorch

import torch
import torch.nn as nn
import torch.nn.functional as F


class SiameseNetwork(nn.Module):
    """Réseau siamois à deux branches partageant les mêmes poids."""
    def __init__(self, input_dim=784, embed_dim=128):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, 256), nn.ReLU(),
            nn.Linear(256, 128), nn.ReLU(),
            nn.Linear(128, embed_dim)
        )

    def forward_once(self, x):
        return self.encoder(x)

    def forward(self, x1, x2):
        """Retourne les embeddings des deux entrées."""
        return self.forward_once(x1), self.forward_once(x2)


def contrastive_loss(embed1, embed2, label, margin=1.0):
    """Contrastive: label=1 si similaire, 0 si différent."""
    dist = torch.sum((embed1 - embed2) ** 2, dim=1)
    loss_pos = label * dist
    loss_neg = (1 - label) * torch.max(
        torch.zeros_like(dist),
        (margin - torch.sqrt(dist + 1e-8)) ** 2
    )
    return (loss_pos + loss_neg).mean()


def triplet_loss(anchor, positive, negative, margin=0.3):
    """Triplet loss: ancre, positif, négatif."""
    dist_pos = torch.sum((anchor - positive) ** 2, dim=1)
    dist_neg = torch.sum((anchor - negative) ** 2, dim=1)
    return torch.mean(torch.clamp(dist_pos - dist_neg + margin, min=0.0))


# Création et entraînement
model = SiameseNetwork(input_dim=784, embed_dim=64)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

for epoch in range(20):
    model.train()
    total_loss = 0
    for x1, x2, labels in train_loader:
        embed1, embed2 = model(x1.view(x1.size(0), -1), x2.view(x2.size(0), -1))
        loss = contrastive_loss(embed1, embed2, labels, margin=1.0)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    avg = total_loss / len(train_loader)
    print(f'Epoch {epoch} | Loss: {avg:.4f}')

2. Recherche par similarité

def find_similar(query, database, model, k=5):
    """Trouve les k plus similaires dans la base de données."""
    model.eval()
    with torch.no_grad():
        q_embed = model.forward_once(query.view(1, -1))
        d_embeds = model.forward_once(database)
    distances = torch.sum((d_embeds - q_embed) ** 2, dim=1)
    _, indices = torch.topk(distances, k, largest=False)
    return indices.numpy()


# One-shot learning: tester sur un nouveau sujet
def one_shot_test(support_img, query_img, distractors, model):
    """Le modèle choisit l'image de même sujet parmi les distracteurs."""
    candidates = torch.cat([query_img.unsqueeze(0), distractors], dim=0)
    closest = find_similar(support_img, candidates, model, k=1)
    return (closest[0] == 0)  # La première est la bonne réponse

Hyperparamètres

Hyperparamètre Valeur typique Description
margin 0.3-1.0 Distance maximale désirée pour les paires similaires
embed_dim 64-512 Dimension de l’espace d’embedding
learning_rate 1e-4-1e-3 Taux d’apprentissage
ratio_pos_neg 1:3-1:5 Ratio des paires similaires/dissimilaires

Variantes et extensions

Réseaux siamois avec CNN

Pour les images, on remplace le MLP par un encodeur convolutionnel (plusieurs convolutions + pooling). Chaque branche est un CNN qui produit un embedding compact de l’image. L’architecture VGG ou ResNet pré-entraînée est souvent utilisée comme backbone.

Prototypical Networks

Une extension du concept siamois: au lieu de comparer à un seul exemple de référence, on calcule le prototype (moyenne des embeddings) de chaque classe dans le support set. La classification se fait par distance au prototype le plus proche.

Matching Networks

Utilisent un mécanisme d’attention pour pondérer les similarités entre la requête et chaque élément du support set. Plus sophistiqué que la simple distance euclidienne, surtout pour le few-shot learning avec plusieurs exemples par classe.


Avantages

  1. One-shot learning : Reconnaît des classes jamais vues avec un seul exemple de référence.
  2. Indépendant des classes : La fonction de similarité est générique, pas liée à un ensemble fixe de catégories.
  3. Ajout/suppression facile : Ajouter un nouveau sujet = une image de référence. Pas de réentraînement nécessaire.
  4. Applicabilité large : Images, texte, audio, signatures — tant qu’on peut construire des paires, ça fonctionne.

Limites

  1. Inférence coûteuse : Comparer une nouvelle entrée à toutes les références = O(N) embeddings et distances.
  2. Performance max inférieure : Sur un problème de classification standard avec beaucoup d’exemples, un classifieur classique bat souvent un réseau siamois.
  3. Qualité des paires critique : Le dataset de paires doit être bien équilibré et représentatif.

4 cas d’usage concrets

1. Vérification de signatures bancaires

L’application historique. Les banques comparent la signature d’un client sur un chèque avec sa référence. Le réseau siamois détecte les falsifications même lorsque les faussaires imitent habilement.

2. Reconnaissance faciale sur smartphone

FaceID d’Apple utilise un principe de similarité: l’empreinte faciale enregistrée (au setup) est comparée à la capture du visage. Si la distance des embeddings est suffisamment faible, le téléphone se déverrouille.

3. Recherche d’images par similarité visuelle

Google Images “rechercher par image”: on fournit une image de référence et le réseau siamois trouve les images les plus similaires visuellement dans un index de milliards de photos.

4. Détection de plagiat

Comparer des textes en les encodant via un réseau siamois (avec des embeddings de mots comme entrées) pour détecter les similarités sémantiques même quand le texte a été paraphrasé.

5. Recommandation de produits

Un réseau siamois peut apprendre à comparer les préférences de deux utilisateurs ou la similarité entre deux produits. Si un utilisateur A aime le produit X, le réseau recommande le produit Y le plus similaire à X dans l’espace d’embedding appris.

6. Réconciliation d’entités dans les bases de données

Quand deux bases de données contiennent des enregistrements sur les mêmes entités (clients, entreprises) mais avec des formats différents, un réseau siamois apprend à dire si deux enregistrements désignent la même entité réelle malgré les variations d’écriture.


Conclusion

Les réseaux siamois ont ouvert la voie à l’apprentissage de similarité par réseau neuronal. Leur principe fondamental — deux branches partageant les poids pour comparer des paires — est maintenant un élément standard du deep learning.

Les extensions modernes (triplet networks, contrastive pre-training pour les grands modèles de langage, prototypical networks) s’appuient tous sur la même idée centrale: apprendre une espace de représentation où la distance reflète la similarité sémantique.


Voir aussi


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.