Par Arthur Dekeyser
En résumé
Perplexity réutilise ses noyaux prefill et decode pour les embeddings.
Ivy, Tulip et ROSE séparent réseau, ordonnancement et inférence GPU.
Les graphes CUDA et LazyTensor réduisent les attentes entre CPU et GPU.
Le signal : Perplexity réutilise ses noyaux LLM prefill et decode pour servir pplx-embed.
Vous appréciez ce genre d'analyse ?
Chaque mardi et vendredi, l'essentiel en business & IA décryptées en 5 minutes. Gratuit, sans engagement.
+11 000 fondateurs abonnés
Perplexity décrit son infrastructure de production pour pplx-embed dans un article publié par son équipe d’ingénierie. Cette pile sert les modèles de classement utilisés dans Perplexity Search, Computer et l’API Platform. L’entreprise distingue l’inférence par lots, utilisée lors de la construction ou de la réindexation d’une base vectorielle, et l’inférence en ligne, appliquée aux requêtes. Le scoring intervient après la recherche vectorielle, avec de grands lots de documents à classer. Perplexity indique que l’inférence d’embeddings converge largement sur les GPU Hopper et Blackwell. Les gains recherchés se situent donc dans l’environnement d’exécution. L’article technique est disponible sur le blog de Perplexity.
Un moteur unique remplace chez Perplexity un service distinct pour chaque mode d’embedding. L’équipe réutilise les noyaux prefill et decode de sa pile de grands modèles de langage. Les lots d’embeddings ressemblent au prefill, car ils mobilisent fortement le calcul. Les requêtes courtes ressemblent au decode, davantage limité par les accès mémoire. Cette architecture couvre donc les lots, les requêtes en ligne et le scoring. Perplexity rapporte que la latence suit surtout le nombre de tokens, plutôt que le nombre de séquences. Sur un modèle inférieur au milliard de paramètres, environ 512 tokens saturent le GPU. Ajouter des séquences au-delà de ce seuil n’améliore plus l’efficacité selon la mesure présentée.
Trois services répartissent le traitement d’une requête. Ivy est une passerelle HTTP écrite en Rust. Elle analyse le JSON, effectue la tokenisation, prépare les entrées et découpe les grands lots. Elle convertit ensuite les demandes vers un protocole gRPC personnalisé. Ivy répartit aussi les fragments entre plusieurs répliques afin de corriger les déséquilibres liés aux tailles variables des charges. Tulip fournit l’interface du serveur d’inférence. Ce serveur gRPC utilise Rust, tokio et tonic pour gérer l’ordonnancement et la constitution des lots. ROSE, ou Runtime-Optimized Serving Engine, exécute l’inférence. Principalement écrit en Python, il fournit les noyaux, les couches et les définitions des modèles.
Un ordonnancement simple choisit les séquences selon leur ordre d’arrivée pendant l’accumulation des requêtes. Tulip conserve ainsi une politique premier arrivé, premier servi. Perplexity justifie ce choix par le poids des couches denses sur les petits modèles d’embeddings. Selon l’article, leur coût linéaire domine le coût quadratique de l’attention aux longueurs servies. ROSE gère plusieurs moteurs d’attention pour les entrées irrégulières. Il prend en charge FlashInfer 2, FlashInfer 3 et FlashAttention 4. Perplexity rapporte que FlashAttention 4 est généralement plus rapide. FlashInfer 3 dépasse toutefois ce résultat sur des modèles fondés sur Qwen et de très longues séquences. Le choix du moteur dépend donc du modèle et de la longueur.
Les graphes CUDA regroupent les lancements d’un modèle entier en un seul appel au pilote. Cette optimisation cible les petits lots, pour lesquels le lancement côté processeur peut coûter davantage que le calcul GPU. Perplexity capture un graphe pour chaque configuration d’embedding. Les tailles de tokens sont complétées vers des seuils multiples de 64 ou 256. Cette méthode produit des milliers de graphes et peut demander plusieurs minutes de capture par modèle. Le mécanisme de capture différée réduit ce coût initial. Chaque configuration commence par une exécution préparatoire. La capture et la relecture se déclenchent lors de la deuxième utilisation. La latence p99 augmente au démarrage, tandis que le travail est réparti sur plusieurs heures.
LazyTensor coordonne le processeur et le GPU pendant l’exécution. Cet objet suit un tampon hôte verrouillé, une copie cudaMemcpyAsync et un événement CUDA. La fonction step() de ROSE renvoie ce résultat sans attendre la fin du calcul sur le dispositif. Une tâche asynchrone Rust peut alors attendre le lot N pendant que le processeur prépare et envoie le lot N+1. ROSE n’instancie pas de cache KV pour les modèles d’embeddings. Il utilise plutôt des variantes d’attention irrégulières afin d’éviter le remplissage artificiel des séquences. Perplexity a également contribué des modifications à FlashInfer pour permettre la capture de graphes complets malgré certaines entrées dynamiques côté hôte.
Les tests comparent ROSE à vLLM v0.22.0 en BF16, avec des poids réels et des entrées issues de l’évaluation. Des exécutions préparatoires vérifient une divergence de similarité cosinus inférieure ou égale à 0,1 %. Quatre séries mesurent les embeddings à faible latence, le scoring à faible latence, les embeddings à haut débit et les embeddings à forte concurrence. La première utilise une taille de lot de 1 et 128, 512 ou 4 096 tokens. La deuxième teste des lots de 5, 25 et 50 à 512 tokens. La troisième emploie un lot de 100 avec quatre processus simultanés. La dernière varie la concurrence de 1 à 16 requêtes et inclut la tokenisation d’Ivy ainsi que les échanges réseau. Les détails sont publiés dans l’article technique de Perplexity.
Gardez un coup d'avance en IA et tech.
Chaque mardi et vendredi, l'essentiel en business & IA décryptées en 5 minutes. Zéro spam.
+11 000 fondateurs abonnés