Nous cherchons toujours des moyens de générer d’excellents noms de domaine. Presque chaque mot anglais possède un domaine .com associé, et de nombreuses paires de mots populaires, comme HelloWorld.com, sont également déjà prises. Vous pouvez traduire dans d’autres langues un mot important pour votre entreprise. Par exemple, fast se traduit par vite en français, rápida ou rápido en espagnol et veloce en italien. Ces mots ne sont pas anglais, mais les langues ont des racines communes et ils peuvent convenir à votre entreprise. Google Translate est un produit remarquable, mais son interface est fastidieuse lorsqu’il faut voir à quoi ressemble un mot dans d’autres langues. Nous avons voulu créer un outil capable de traduire instantanément un mot anglais dans plusieurs langues.
L’étude de la traduction automatique remonte aux années 1950 et continue d’évoluer. Nous voulons traduire instantanément de l’anglais vers plusieurs langues, sur du matériel courant et sans GPU ni autre équipement coûteux. Les noms de domaine doivent être courts ; nous avons donc voulu nous concentrer sur des mots isolés plutôt que sur des phrases. Nous avons déjà utilisé des vecteurs de mots pour trouver des domaines à vendre et avons constaté que Facebook Research avait publié un jeu de données qui aligne les vecteurs de mots d’une langue à l’autre.
Attendez, qu’est-ce qu’un vecteur de mots ?
Les vecteurs de mots sont produits par un réseau neuronal qui apprend les relations entre les mots à partir d’un vaste corpus, comme une exploration du Web ou Wikipédia. Allison Parrish, professeure adjointe à NYU, a partagé l’un des meilleurs parcours interactifs sur les vecteurs de mots que j’aie vus. Allez le consulter. Allison utilise les couleurs pour illustrer comment un mot peut être associé aux valeurs numériques de Rouge, Vert et Bleu. Les standards PNG et JPG prennent par exemple chacun en charge les couleurs sur 24 bits : de 0 à 255 pour R, V et B. Le rouge est représenté par 255,0,0, le vert par 0,255,0 et le bleu par 0,0,255. Vous apprenez à reconnaître dans du code qu’une valeur comme 250,0,0 désigne une couleur très rouge.
fastText
En 2016, Facebook Research a publié fastText avec plusieurs modèles préentraînés qui associent des millions de mots à une représentation numérique. Ces modèles représentent les mots par 300 nombres à virgule flottante de 32 bits. Cela capture beaucoup de détails et de nuances, mais il est bien plus difficile pour un humain de raisonner avec ces valeurs. Le vecteur fastText du mot red ressemble à ceci :
red -0.0331 -0.0465 0.1046 0.0201 0.0665 -0.0394 0.0515 -0.0598 0.0905 0.0738 0.0871 0.0062 0.0002 -0.0135 0.1012 -0.0092 -0.1063 -0.0967 0.0297 0.0790 -0.0429 -0.0470 -0.0926 -0.0227 -0.0240 -0.0768 0.0174 -0.0628 -0.0714 0.0413 0.0072 0.0746 0.0332 0.0780 0.0248 0.0083 -0.0807 -0.0272 0.0805 -0.0736 -0.0323 -0.0140 0.0081 0.0639 -0.0186 -0.0961 0.0240 -0.0159 0.0252 0.0425 0.0403 -0.1151 -0.0582 0.0228 0.0503 0.0262 0.0092 -0.0314 -0.0031 0.0238 0.0023 0.0231 0.1031 0.0147 0.0032 0.0197 -0.0749 0.0452 -0.0060 0.0173 -0.0828 0.0347 0.0330 -0.0970 0.0665 -0.0090 -0.0148 -0.0379 -0.0735 -0.0456 0.0362 -0.0038 -0.0989 0.0229 -0.0710 0.0076 -0.0314 0.0331 0.0470 -0.0968 -0.0182 0.0503 -0.0603 0.0900 0.0617 0.0198 0.0360 0.0885 -0.0665 0.0382 0.0162 -0.0352 -0.0643 0.0298 -0.0647 -0.0815 0.0507 0.0307 -0.0312 -0.0265 -0.0255 -0.0556 0.0302 0.0085 -0.0142 0.0116 0.0497 -0.0091 -0.0327 -0.0533 0.0853 -0.0028 0.0138 0.0235 0.0288 0.0766 -0.0008 0.0410 -0.0574 0.0001 0.0378 0.0842 0.0237 0.0557 -0.0578 -0.0145 -0.0006 -0.1553 -0.0657 0.0826 -0.0335 0.1468 0.0287 -0.0240 -0.0060 0.1243 -0.0685 -0.0024 -0.0419 0.0122 0.0002 -0.1673 -0.1169 -0.0371 -0.0072 -0.0133 -0.0355 0.0781 0.0487 -0.0785 0.1488 0.0351 -0.1184 -0.0185 0.0348 0.0116 -0.0598 -0.0082 0.1296 -0.0158 -0.0234 -0.0796 -0.0322 -0.0004 -0.0170 0.0290 -0.0135 -0.0658 0.0224 0.0262 -0.0747 -0.0174 -0.0673 0.0018 -0.0009 -0.0170 -0.0229 0.0128 0.0414 0.0009 0.0807 -0.0990 0.1185 0.0776 -0.1242 -0.0860 -0.0464 0.0127 -0.0994 0.0284 0.0295 -0.0607 0.0268 0.0738 0.0820 -0.0623 -0.1275 -0.0181 -0.0645 0.0423 -0.0196 0.0610 -0.0459 -0.0614 0.1134 0.0480 -0.0723 -0.0421 -0.0073 -0.0136 -0.0843 -0.0286 -0.0247 0.0456 -0.0090 -0.0546 -0.0464 0.0170 0.0580 -0.0434 0.0340 0.0199 0.0258 -0.0641 0.0110 -0.1129 0.0479 -0.0298 -0.0738 0.0475 -0.0210 0.0199 -0.0134 -0.0297 -0.0400 0.0186 0.0519 0.0505 0.0018 -0.0292 0.0482 0.0071 -0.0222 -0.0302 0.0711 -0.0198 0.0230 -0.0573 0.1053 0.0609 0.0517 0.0693 -0.0668 -0.0047 -0.0557 -0.0430 -0.0130 0.0693 -0.0305 -0.1101 -0.0303 -0.0511 -0.0628 0.0036 0.0101 -0.0206 0.1078 0.0520 -0.0476 0.0408 -0.0027 -0.0753 0.0087 0.0203 0.1821 -0.0566 0.0721 0.0880 -0.0955 -0.1142 -0.0118 -0.0209 0.0230 0.0313 -0.0339 -0.0700 0.0841 -0.0484 -0.0148 -0.0190
Vecteurs de mots alignés
Facebook Research a ensuite publié des vecteurs de mots alignés pour 44 langues. Ils fonctionnent comme une pierre de Rosette et permettent d’organiser les mots de ces langues dans le même espace vectoriel. Pour revenir à trois dimensions, nous pouvons examiner comment red pourrait être représenté en anglais, en français et dans l’espace vectoriel.
Comme nous examinons un mot isolé, sans contexte, la traduction peut être ambiguë dans les langues qui ont des formes féminines ou masculines. En pratique, les vecteurs ne s’alignent pas parfaitement entre eux. Leur représentation peut varier légèrement ; nous devons donc prendre en compte les correspondances approximatives. Puisque nous travaillons dans un espace vectoriel, nous pouvons mesurer la distance euclidienne entre, par exemple, red et une correspondance proche dans une autre langue.
Instant Distance
Les ordinateurs sont rapides et peuvent parcourir par force brute des millions de calculs de distances euclidiennes assez vite, mais pas instantanément. Nous devons construire un index de ces points pour trouver les voisins d’un point dans l’espace. De nombreuses techniques d’apprentissage automatique ou d’intelligence artificielle dépendent d’une navigation efficace dans les espaces vectoriels ; il existe diverses approches et implémentations. Nous voulions une implémentation Rust pure, mais n’en avons trouvé aucune prête pour la production. Nous avons donc créé et publié instant-distance, une implémentation rapide et entièrement en Rust des graphes Hierarchical Navigable Small World, avec des liaisons Python.
Assemblage
Pour créer un outil de traduction simple, nous commençons par télécharger les données de vecteurs de mots publiées par fastText. Nous indexons ensuite ces vecteurs avec Instant Distance. Une fois l’index construit, nous stockons le jeu de données obtenu dans le système de fichiers, avec une correspondance mot-vecteur dans un fichier JSON.
LANGS = ("en", "fr", "it")
LANG_REPLACE = "$$lang"
WORD_MAP_PATH = f"./data/{'_'.join(LANGS)}.json"
BUILT_IDX_PATH = f"./data/{'_'.join(LANGS)}.idx"
DL_TEMPLATE = f"https://dl.fbaipublicfiles.com/fasttext/vectors-aligned/wiki.{LANG_REPLACE}.align.vec"
points = []
values = []
word_map = {}
async with aiohttp.ClientSession() as session:
for lang in LANGS:
# Construct a url for each language
url = DL_TEMPLATE.replace(LANG_REPLACE, lang)
# Ensure the directory and files exist
os.makedirs(os.path.dirname(BUILT_IDX_PATH), exist_ok=True)
lineno = 0
async with session.get(url) as resp:
while True:
lineno += 1
line = await resp.content.readline()
if not line:
# EOF
break
linestr = line.decode("utf-8")
tokens = linestr.split(" ")
# The first token is the word and the rest
# are the embedding
value = tokens[0]
embedding = [float(p) for p in tokens[1:]]
# We only go from english to the other two languages
if lang == "en":
word_map[value] = embedding
else:
# Don't index words that exist in english
# to improve the quality of the results.
if value in word_map:
continue
# We track values here to build the instant-distance index
# Every value is prepended with 2 character language code.
# This allows us to determine language output later.
values.append(lang + value)
points.append(embedding)
# Build the instant-distance index and dump it out to a file with .idx suffix
print("Building index... (this will take a while)")
hnsw = instant_distance.HnswMap.build(points, values, instant_distance.Config())
hnsw.dump(BUILT_IDX_PATH)
# Store the mapping from string to embedding in a .json file
with open(WORD_MAP_PATH, "w") as f:
json.dump(word_map, f)
Enfin, ces outils permettent de convertir une entrée, un mot, en son vecteur et d’utiliser Instant Distance pour trouver ses voisins les plus proches. Comme tous les vecteurs de mots ont été alignés, les vecteurs les plus proches dans les différentes langues devraient être très similaires, voire constituer une traduction directe.
with open(WORD_MAP_PATH, "r") as f:
word_map = json.load(f)
# Get an embedding for the given word
embedding = word_map.get(word)
if not embedding:
print(f"Word not recognized: {word}")
exit(1)
hnsw = instant_distance.HnswMap.load(BUILT_IDX_PATH)
search = instant_distance.Search()
hnsw.search(embedding, search)
# Print the results
for result in list(search)[:10]:
# We know that the first two characters of the value is the language code
# from when we built the index.
print(f"Language: {result.value[:2]}, Translation: {result.value[2:]}")
Voici par exemple les résultats de la traduction du mot anglais « hello » :
Language: fr, Translation: bonjours
Language: fr, Translation: bonsoir
Language: fr, Translation: salutations
Language: it, Translation: buongiorno
Language: it, Translation: buonanotte
Language: fr, Translation: rebonjour
Language: it, Translation: auguri
Language: fr, Translation: bonjour,
Language: it, Translation: buonasera
Language: it, Translation: chiamatemi
Essayez
Vous pouvez consulter l’exemple complet sur Instant Distance sur GitHub. Si vous avez des questions, n’hésitez pas à ouvrir un ticket sur GitHub !