Aller au contenu principal

Visualiser des embeddings

Objectifs

  • Réduire des vecteurs haute dimension pour les visualiser en 2D/3D
  • Utiliser t-SNE et UMAP pour la visualisation
  • Interpréter les clusters visuels

Le défi : 3 072 dimensions

Les embeddings vivent dans un espace à 3 072 dimensions. Pour les visualiser, il faut projeter cet espace en 2D ou 3D tout en préservant les relations de proximité.

Réduction de dimension avec t-SNE

t-SNE (t-distributed Stochastic Neighbor Embedding) est la méthode classique pour visualiser des données haute dimension :

from openai import OpenAI
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import numpy as np

client = OpenAI()

# Corpus d'exemple
textes = [
    # Cluster IA
    "L'apprentissage profond utilise des réseaux de neurones",
    "Le machine learning transforme la data science",
    "Les transformers ont révolutionné le NLP",
    "GPT-5 est un grand modèle de langage",
    # Cluster cuisine
    "La recette du gâteau au chocolat",
    "Comment préparer une ratatouille",
    "Les bases de la pâtisserie française",
    "Techniques de cuisson au four",
    # Cluster sport
    "Le marathon de Paris attire des milliers de coureurs",
    "Entraînement fractionné pour la course à pied",
    "Les règles du football expliquées",
    "Nutrition sportive et performance",
]

categories = (["IA"] * 4 + ["Cuisine"] * 4 + ["Sport"] * 4)

# Générer les embeddings
response = client.embeddings.create(
    input=textes,
    model="text-embedding-3-large"
)
embeddings = np.array([d.embedding for d in response.data])

# Réduction t-SNE en 2D
tsne = TSNE(n_components=2, random_state=42, perplexity=4)
coords = tsne.fit_transform(embeddings)

# Visualisation
couleurs = {"IA": "#2563eb", "Cuisine": "#dc2626", "Sport": "#16a34a"}
fig, ax = plt.subplots(figsize=(10, 8))

for cat in couleurs:
    mask = [c == cat for c in categories]
    ax.scatter(
        coords[mask, 0], coords[mask, 1],
        c=couleurs[cat], label=cat, s=100, alpha=0.8
    )
    for i, (x, y) in enumerate(coords[mask]):
        idx = [j for j, m in enumerate(mask) if m][i]
        ax.annotate(
            textes[idx][:30] + "...",
            (x, y), fontsize=7, alpha=0.7
        )

ax.legend()
ax.set_title("Visualisation t-SNE des embeddings")
plt.tight_layout()
plt.savefig("tsne_embeddings.png", dpi=150)
plt.show()

Paramètres clés de t-SNE

  • perplexity : contrôle l’équilibre entre structure locale et globale. Valeurs typiques : 5–50
  • n_iter : nombre d’itérations d’optimisation. Minimum 250, idéalement 1 000+
  • random_state : pour la reproductibilité

Réduction avec UMAP

UMAP (Uniform Manifold Approximation and Projection) est souvent préféré à t-SNE car il est plus rapide et préserve mieux la structure globale :

import umap

# Réduction UMAP en 2D
reducer = umap.UMAP(n_components=2, random_state=42, n_neighbors=5)
coords_umap = reducer.fit_transform(embeddings)

fig, ax = plt.subplots(figsize=(10, 8))

for cat in couleurs:
    mask = [c == cat for c in categories]
    ax.scatter(
        coords_umap[mask, 0], coords_umap[mask, 1],
        c=couleurs[cat], label=cat, s=100, alpha=0.8
    )

ax.legend()
ax.set_title("Visualisation UMAP des embeddings")
plt.tight_layout()
plt.savefig("umap_embeddings.png", dpi=150)
plt.show()

t-SNE vs UMAP

Critèret-SNEUMAP
VitesseLent (O(n²))Rapide
Structure globaleMal préservéeBien préservée
ReproductibilitéVariableStable
Paramètresperplexityn_neighbors, min_dist

Visualisation 3D interactive

Pour une exploration interactive, utilisez Plotly :

import plotly.express as px
import pandas as pd

# Réduction en 3D
reducer_3d = umap.UMAP(n_components=3, random_state=42, n_neighbors=5)
coords_3d = reducer_3d.fit_transform(embeddings)

df = pd.DataFrame({
    "x": coords_3d[:, 0],
    "y": coords_3d[:, 1],
    "z": coords_3d[:, 2],
    "catégorie": categories,
    "texte": [t[:50] for t in textes]
})

fig = px.scatter_3d(
    df, x="x", y="y", z="z",
    color="catégorie",
    hover_data=["texte"],
    title="Embeddings en 3D"
)
fig.write_html("embeddings_3d.html")
fig.show()

Visualiser l’effet de la réduction de dimensions

Comparez la qualité de séparation selon le nombre de dimensions demandées à l’API :

dimensions_a_tester = [256, 512, 1536, 3072]

fig, axes = plt.subplots(1, 4, figsize=(24, 5))

for ax, dim in zip(axes, dimensions_a_tester):
    resp = client.embeddings.create(
        input=textes,
        model="text-embedding-3-large",
        dimensions=dim
    )
    embs = np.array([d.embedding for d in resp.data])
    tsne = TSNE(n_components=2, random_state=42, perplexity=4)
    coords = tsne.fit_transform(embs)

    for cat in couleurs:
        mask = [c == cat for c in categories]
        ax.scatter(coords[mask, 0], coords[mask, 1],
                   c=couleurs[cat], label=cat, s=60)
    ax.set_title(f"{dim} dimensions")
    ax.legend(fontsize=7)

plt.tight_layout()
plt.savefig("comparaison_dimensions.png", dpi=150)
plt.show()

Résumé

  • t-SNE et UMAP projettent les embeddings en 2D/3D pour la visualisation
  • UMAP est généralement préféré pour sa vitesse et sa fidélité
  • Plotly permet des visualisations 3D interactives
  • La visualisation aide à valider la qualité de vos embeddings et à détecter des anomalies