Un embedding, c'est quoi ? La similarité cosinus avec numpy
Du texte à un point dans l'espace
Un embedding (plongement, en français) est une liste de nombres à virgule, par exemple 768 nombres, qui représente le sens d'un texte. Le modèle d'embeddings a été entraîné pour que des textes de sens proche donnent des listes de nombres proches.
On peut imaginer chaque texte comme un point dans un espace à 768 dimensions. Impossible à dessiner, mais l'intuition en 2 dimensions fonctionne :
quadrantChart title "Vue simplifiée en 2 dimensions" x-axis "Cuisine" --> "Sport" y-axis "Objet" --> "Usage" quadrant-1 "Sport, usage" quadrant-2 "Cuisine, usage" quadrant-3 "Cuisine, objet" quadrant-4 "Sport, objet" "chaussure de course à pied": [0.85, 0.35] "running shoe": [0.8, 0.3] "bouilloire électrique": [0.15, 0.25] "préparer du thé": [0.2, 0.75]
Les deux chaussures, l'une en français, l'autre en anglais, tombent au même endroit : l'embedding encode le sens, pas la langue ni les mots exacts.
Mesurer la proximité : la similarité cosinus
Pour comparer deux vecteurs, on mesure l'angle entre eux. La similarité cosinus vaut :
- est le produit scalaire : on multiplie les nombres deux à deux et on additionne ;
- est la norme (la longueur) du vecteur.
Le résultat va de -1 (opposés) à 1 (même direction). Si les vecteurs sont normalisés (longueur 1), le cosinus est simplement le produit scalaire. C'est le cas des vecteurs de gemini-embedding-2, et le lab renormalise de toute façon par sécurité.
def normaliser(m: np.ndarray) -> np.ndarray:
return m / np.linalg.norm(m, axis=-1, keepdims=True)
def top_k(vecteurs, requete, k=5, exclure=()):
"""Similarité cosinus = produit scalaire, car tous les vecteurs sont normalisés."""
scores = vecteurs @ requete
for i in exclure:
scores[i] = -np.inf
meilleurs = np.argsort(-scores)[:k]
return [(int(i), float(scores[i])) for i in meilleurs]vecteurs @ requete calcule en une opération le produit scalaire de la requête avec les 60 fiches : c'est une multiplication matrice × vecteur.
| Mesure | Formule | Quand l'utiliser |
|---|---|---|
| Cosinus | angle entre vecteurs | le standard pour le texte |
| Produit scalaire | identique au cosinus si les vecteurs sont normalisés, et plus rapide | |
| Distance euclidienne | même classement que le cosinus sur des vecteurs normalisés |
Essayer
import numpy as np
from google import genai
from google.genai import types
client = genai.Client()
textes = ["chaussure de course à pied", "running shoe", "bouilloire électrique"]
r = client.models.embed_content(
model="gemini-embedding-2",
contents=[types.Content(parts=[types.Part(text=t)]) for t in textes],
config=types.EmbedContentConfig(output_dimensionality=768))
m = np.array([e.values for e in r.embeddings])
print(np.round(m @ m.T, 3)) # matrice des cosinus 3 x 3Deux vecteurs normalisés ont un produit scalaire de 0,86. Que vaut leur similarité cosinus ?
Si les normes valent 1, le dénominateur vaut 1 : cosinus et produit scalaire sont égaux.
Pourquoi « running shoe » est-il plus proche de « chaussure de course à pied » que de « bouilloire électrique » ?
Aucune traduction ni comparaison de lettres : le modèle a appris à placer des textes de même sens au même endroit de l'espace, y compris entre langues.
Exercice : cosinus à la main
Calculez à la main le cosinus entre et , puis vérifiez avec numpy.
Voir la solution
Produit scalaire : . Normes : pour les deux. Cosinus : .
import numpy as np
a, b = np.array([3, 4]), np.array([4, 3])
print(a @ b / (np.linalg.norm(a) * np.linalg.norm(b))) # 0.96Résultat obtenu
Démo exécutée le 2026-10-15 avec gemini-embedding-2 en 768 dimensions :
forme : (3, 768) normes : [1. 1. 1.]
5 premières valeurs : [ 0.0186 -0.0522 0.0222 0.0468 -0.0257]
[[1. 0.858 0.64 ]
[0.858 1. 0.561]
[0.64 0.561 1. ]]Ligne 1 : « chaussure de course à pied » est à 0,858 de « running shoe » et à 0,64 de « bouilloire électrique ». Les vecteurs sont déjà de norme 1.
Je sais faire
- Expliquer ce qu'est un embedding en une phrase
- Calculer une similarité cosinus avec numpy
- Expliquer pourquoi produit scalaire et cosinus coïncident sur des vecteurs normalisés
- Lire une matrice de similarités sans la prendre pour des probabilités