1 points par GN⁺ 3 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Ternlight permet d’effectuer des embeddings de texte et des recherches de similarité directement dans le navigateur, sans appel serveur, afin de mettre en place rapidement une petite recherche sémantique côté client
  • Le package de base pèse 7 Mo en combinant moteur et poids, tandis que la variante mini fait 5 Mo, et fonctionne sur CPU sans GPU
  • Après installation de @ternlight/base, il suffit d’importer embed et similar pour créer un flux de recherche sémantique en environ 3 lignes
  • L’exemple d’appel classe les 3 meilleurs résultats dans une liste de recettes, avec environ 5 ms et aucun appel réseau mis en avant
  • La démo de recherche dans la documentation React effectue la recherche dans le navigateur lorsque l’utilisateur saisit une question, et elle est propulsée par @ternlight/mini, le palier à 5 Mo

Des embeddings entièrement dans le navigateur

  • Ternlight met en avant un « modèle d’embeddings de 7 Mo » qui encode du texte en quelques millisecondes, sans appeler de serveur
  • Caractéristiques d’exécution

    • Aucun appel API
    • Moteur + poids : 7 Mo
    • Variante mini : 5 Mo
    • Embeddings rapides : environ 5 ms
    • CPU uniquement, pas de GPU

Installation et exemple d’utilisation

  • Il est fourni sous forme d’un unique package npm et peut être utilisé sans étape séparée de téléchargement de modèle ni serveur
  • La commande d’installation est la suivante
npm install @ternlight/base
  • Importez embed et similar depuis @ternlight/base pour exécuter une recherche sémantique
import { embed, similar } from '@ternlight/base';

similar('easy weeknight dinner ideas', recipes, { topK: 3 });
// → ranked matches · ~5 ms · zero network
  • La démo de recherche dans la documentation React effectue la recherche dans le navigateur lorsque l’utilisateur saisit une question, et fonctionne avec le palier 5 Mo @ternlight/mini

1 commentaires

 
GN⁺ 3 시간 전
Avis sur Hacker News
  • Pour un projet perso, je voulais faire tourner un modèle utile dans le navigateur ; j’ai donc distillé un petit encodeur de phrases à partir de MiniLM, puis appliqué un entraînement avec quantification ternaire consciente
    J’ai aussi écrit moi-même le moteur d’inférence et je le déploie en Rust → WASM SIMD
    Ce n’est pas un LLM, mais un modèle d’embeddings : quand on lui donne du texte, il produit un vecteur à 384 dimensions, et on juge la pertinence entre deux textes via la similarité cosinus de deux vecteurs. Par exemple, « reset my password » et « I forgot my password » peuvent donner 0,88
    Il peut servir à la recherche sémantique, au matching FAQ/intention et au clustering ; comme il s’exécute sur l’appareil, il permet une recherche sémantique rapide dès la saisie, sans dépendre d’une API
    La démo recherche dans 2 000 documents React entièrement sur l’appareil : https://ternlight-demo.vercel.app
    Sur npm, il y a deux niveaux : @ternlight/base (7 Mo, environ 5 ms par embedding, embeddings plus performants) et @ternlight/mini (5 Mo transférés, environ 2,5 ms par embedding), empaquetés pour Node et le navigateur
    Le dépôt contient les détails techniques, la licence MIT et le pipeline d’entraînement : https://github.com/soycaporal/ternlight
    Je me demande si les embeddings sur l’appareil sont réellement utiles, et pour quels cas d’usage

    • J’ai un dictionnaire qui mappe des mots vers des tags OpenStreetMap, comme ici : https://codeberg.org/cartes/web/src/branch/master/components...
      Je me demande si cela pourrait aider à trouver crêpe quand l’utilisateur saisit « pancake », sans devoir ajouter explicitement une entrée de dictionnaire « pancake = crêpe »
      Si j’ai bien compris, la bibliothèque télécharge 5 Mo une première fois, puis on l’utilise ensuite un peu comme j’utilise Fuse.js aujourd’hui ?
      J’aimerais aussi savoir dans quelle mesure elle gère les langues autres que l’anglais, et si on peut l’entraîner avec le wiki des tags OpenStreetMap
    • Je suis vraiment intéressé par l’ajout d’une simple recherche sémantique dans une application desktop native
      Je me demande s’il existe une comparaison avec d’autres modèles d’embeddings ultralégers. Difficile de savoir si le choix de partir de MiniLM-L6 vient du fait que c’est un modèle particulièrement bon dans cette catégorie, puisque la seule métrique fournie est « Retrieval (SciFact NDCG@10) »
      Cela dit, je suis assez loin des performances annoncées : dans Firefox sur un i5-4570, je n’obtiens que 35 embeddings par seconde, pas 400. Je soupçonne un basculement vers un chemin sans SIMD, et je compte aussi essayer le binaire Rust natif
    • Je viens d’embedder toute la documentation de django ainsi que notre base de connaissances interne, et je peux maintenant rechercher instantanément dans les deux sources
  • C’est cool, mais ce serait bien d’avoir un bouton pour lancer la démo sur la landing page. J’ai été assez surpris d’entendre les ventilateurs s’emballer dès l’ouverture de la page

    • D’accord. En même temps, ça m’a rappelé avec plaisir l’époque où l’on pouvait savoir assez intimement ce qui se passait juste au bruit de l’ordinateur
    • J’ai été surpris quand les ventilateurs ont démarré. Cela dit, mon grille-pain aussi me surprend parfois
    • Utilisation extrême des cycles CPU : qui a dit que seuls les GPU avaient droit à un traitement spécial ?
  • Ce serait bien d’en faire un plugin Astro ou de méta-framework générique, qui parserait automatiquement tous les fichiers HTML générés et créerait une petite base de données d’embeddings
    Côté frontend, on pourrait la charger paresseusement, et peut-être stocker aussi HNSW par chunks pour ne charger que les parties nécessaires à la requête
    Par exemple, quelque chose de proche de https://pagefind.app/, mais avec une recherche vectorielle entièrement statique

    • Pour notre générateur de site statique, je voulais utiliser sqlite-vec, mais la dernière fois que j’ai vérifié, HNSW n’était pas implémenté ou le support de la recherche vectorielle dans le navigateur n’était pas bon. Il me semble qu’il faisait encore un scan complet de table
      Plusieurs mois, voire années, ont passé, et si c’est toujours le cas, c’est assez décevant : cela ressemble à un signe que le projet n’a pas les moyens de vraiment aboutir. En plus, je l’avais recommandé comme bon candidat dans une subvention à laquelle j’ai postulé ; eux ont été retenus et moi non
      Si quelqu’un connaît une bonne solution dans ce domaine, ou si je me trompe au sujet de SQLite-vec, j’aimerais le savoir. Pour notre SSG, on a plus ou moins décidé de travailler quelques mois sur une autre infrastructure, puis de le construire nous-mêmes si ce n’est toujours pas prêt
  • Ça pourrait être un ajout vraiment sympa au projet de recherche HNSW avec DuckDB que j’avais vu ici auparavant : https://github.com/jasonjmcghee/portable-hnsw
    Le fait que la recherche s’effectue sur des fichiers Parquet hébergés statiquement en utilisant des requêtes HTTP Range est vraiment intéressant
    Je pense que ce genre de choses pourrait devenir un écosystème de recherche relativement ouvert et distribué, non contrôlé par les grandes entreprises

    • Dans un esprit similaire, utiliser une base SQLite sur un hébergeur statique avec des requêtes HTTP Range et WASM pourrait aussi être intéressant
      https://news.ycombinator.com/item?id=27016630
    • Excellente idée. J’aime beaucoup les requêtes Range et les formats explorables côté client avec de l’hébergement statique
  • C’est vraiment cool, et ça pourrait être la pièce manquante d’une chose que je voulais construire depuis un moment
    Avec https://github.com/npiesco/absurder-sql, on peut persister tout le corpus source dans IndexedDB/SQLite à l’intérieur du navigateur
    Ensuite, comme dans https://weaviate.io/blog/chunking-strategies-for-rag, au lieu de tout indexer à l’avance, on peut utiliser Ternlight pour générer et mettre en cache les embeddings à la demande
    Cela permettrait aussi une recherche hybride via Reciprocal Rank Fusion, en combinant FTS5/BM25 de SQLite natif avec la recherche sémantique de Ternlight

  • Beau travail
    C’est présenté comme faisant 7 Mo, mais il existe aussi une version mini à 5 Mo
    Il semble que mini utilise en interne des vecteurs de 256 éléments, et non 384, pour réduire l’espace, puis les projette à la fin en 384 pour des raisons de compatibilité
    La taille baisse d’un tiers, mais la perte n’est pas linéaire ; même avec un chemin de données plus petit, la perte d’information semble inférieure à un tiers

  • Super projet
    J’avais essayé quelque chose de similaire auparavant : http://sol.quipu-strands.com/
    Je voulais charger un modèle d’embeddings dans le navigateur pour ordonner sémantiquement du texte
    J’ai récupéré des poids ONNX (MPNet, MiniLM) depuis HuggingFace, généré les embeddings avec Transformers.js, puis utilisé un algorithme de clustering de scikit-learn exécuté dans la page via pyodide. Tout tournait côté client, et j’ai été surpris que ça fonctionne parfaitement

  • La démo se comporte de façon assez étrange. Par exemple, si l’on cherche « how to use typescript with createContext », les meilleurs résultats ne sont que des entrées typescript, ce qui donne l’impression que la recherche par similarité échoue

  • Merci. Les modèles locaux apporteront un jour la confidentialité, et je connais déjà un excellent cas d’usage qui convient parfaitement à ce genre de petits modèles d’embeddings : la recherche bon marché et rapide dans une base de données produits
    Dans mon cas, le fait de s’appuyer sur le CPU est aussi un avantage

    • Bien. S’il y a une façon de contribuer, ou des cas d’usage précis à traiter dans la roadmap, ce serait utile de me le dire
  • Peut-on précalculer la génération des embeddings qui prend 30 secondes et les envoyer au navigateur ?
    Ensuite, l’inférence est rapide et agréable

    • Oui. Il suffit de lancer l’indexation une seule fois côté serveur, puis d’envoyer uniquement les embeddings au frontend