2 points par GN⁺ 2024-05-10 | 2 commentaires | Partager sur WhatsApp
  • Projet de recherche, de cartographie et d’analyse qui collecte plus de 40 millions d’éléments depuis l’API publique de Hacker News, puis ajoute des embeddings, des métadonnées et le texte intégral à plus de 30 millions de commentaires et 4 millions de publications
  • L’approche initiale, qui n’embeddait que les titres, était limitée par les titres ambigus et le biais Ask HN/Show HN ; elle a été remplacée par une méthode utilisant aussi le contenu des pages web liées, les meilleurs commentaires et le contexte des commentaires ancêtres
  • Avec la montée en échelle du traitement, le projet a combiné environ 150 GPU RunPod, un service de file d’attente en Rust, un proxy DB HTTP/2, UMAP, un rendu Canvas et des serveurs edge ; après changement de modèle, le temps d’embedding par entrée est passé d’environ 600 ms à 6 ms
  • Le classement des résultats ne repose pas sur une simple correspondance de chaînes, mais combine similarité cosinus, score HN et pondération temporelle pour refléter la pertinence sémantique, les signaux sociaux et la fraîcheur
  • La démo publique n’inclut que les données jusqu’aux alentours du 10 avril 2024 ; l’ensemble des données et le code sont publiés sur GitHub et peuvent servir à des expériences de recherche, de recommandation, d’analyse utilisateur et de mises à jour en temps réel

Périmètre du projet et données publiques

  • Création d’une carte plaçant toutes les publications de Hacker News dans un espace sémantique, avec des outils de recherche, d’analyse et de visualisation
  • Le point de départ était une expérimentation sur les embeddings de texte ; HN a été choisi comme jeu de données adapté, car il contient beaucoup de contenu sélectionné et expose tout son contenu de façon programmable
  • Les embeddings représentent le texte comme des points dans un espace de grande dimension ; ce qui est utile n’est pas tant la position absolue que la distance relative entre les points
  • Trois usages étaient envisagés
    • Recherche sémantique dans les contenus accumulés de HN
    • Recommandations personnalisées selon les centres d’intérêt
    • Analyse des sentiments, de la popularité et des points de vue opposés par sujet au sein de la communauté
  • Plus de 30 millions de commentaires et 4 millions de publications sont publiés sous forme de release de dataset
    • Métadonnées incluses, comme l’ID, le score et l’auteur
    • Embeddings inclus
    • Texte des commentaires et texte des pages web crawlées inclus
  • Le code est publié dans le dépôt GitHub hackerverse

Collecte des données Hacker News

  • HN fournit une API publique simple, et tous les objets sont récupérés sous forme d’item
  • maxitem.json fournit le plus grand ID ; au moment de l’écriture, l’ID maximal dépasse 40 millions
  • Même avec un temps de réponse moyen de 10 ms, crawler séquentiellement 40 millions d’éléments prendrait plus de 4 jours : le traitement parallèle était donc nécessaire
  • Un service de collecte rapide a été créé en Node.js, mais l’approche avec sémaphores et file de Promises était lente, car la majeure partie du temps CPU était consommée par du code JS en espace utilisateur
  • Ensuite, l’API worker_threads a été utilisée pour distribuer les tâches de fetch sur tous les CPU, améliorant les performances en saturant tous les cœurs
  • Comme la collecte parallèle mélange l’ordre des résultats, les marqueurs d’achèvement sont enregistrés dans l’ordre des ID afin d’éviter les trous en cas d’interruption
  • Certaines caractéristiques de l’API HN ont aussi été observées
    • Le score ne semble pas descendre sous -1
    • Il n’est pas possible de récupérer les downvotes des publications ni le nombre de votes des commentaires
    • Certaines publications et certains commentaires ont un titre, un texte ou une URL vides même s’ils ne sont ni supprimés ni signalés
    • L’ID d’un commentaire peut être inférieur à celui de son ancêtre, possiblement à cause de déplacements dans l’arbre des commentaires
  • Le crawler HN a aussi été séparé dans un projet TypeScript distinct, crawler-toolkit-hn

Premier embedding et infrastructure

  • Au départ, l’hypothèse était que le seul titre des publications suffirait à produire une représentation sémantique
  • La comparaison des modèles s’est appuyée sur le Massive Text Embedding Benchmark, et le premier modèle choisi a été BGE-M3
  • BGE-M3 peut générer, en plus des embeddings denses classiques, des lexical weights, utilisables pour une recherche hybride combinée à des approches comme BM25
  • L’infrastructure de génération d’embeddings n’était pas simple
    • Les bons modèles peuvent compter des centaines de millions à des milliards de paramètres
    • Ils sont bien plus efficaces sur GPU, mais les clusters de GPU coûtent cher
    • Si l’inférence prend plusieurs centaines de ms par entrée, traiter 40 millions d’entrées sur un seul GPU se chiffre presque en une année
    • Comme les données, les serveurs et les GPU sont éloignés, il faut maintenir le pipeline pour éviter que les GPU restent inactifs
  • RunPod a été utilisé pour déployer sous forme de conteneurs des machines GPU exécutées en datacenter, en exploitant des GPU relativement bon marché comme les RTX 4090
  • Comme les GPU étaient dispersés dans le monde entier et que la latence de connexion à la DB ainsi que le coût de connexion posaient problème, db-rpc a été créé
    • Proxy de requêtes SQL vers une DB locale via HTTP/2
    • Utilisation d’un grand pool de connexions partagé
    • Traitement de plusieurs requêtes sur une seule connexion grâce au multiplexage HTTP/2
  • AWS SQS imposait des limites de débit faibles et un coût par message pénalisant pour des millions de petits messages de tâche ; un service de file d’attente en Rust basé sur RocksDB, queued, a donc été créé
    • Traite plus de 100K op/s sur un seul nœud
    • Réduit les contraintes de batching, de taille des messages, de limites de débit et de coûts
  • Après une montée en charge jusqu’à environ 150 GPU, les embeddings des 40 millions de publications et commentaires ont été générés en quelques heures
  • À l’époque, le coût d’embedding par entrée était d’environ 600 ms, et le taux d’utilisation des GPU est resté élevé pendant toute la durée du traitement

Enrichissement du contexte par crawl de pages web

  • L’approche consistant à embedder uniquement les titres n’était pas suffisante
    • Beaucoup de publications ont des titres étranges, créatifs ou ambigus
    • Les libellés Ask HN et Show HN occupaient une grande part du titre complet et avaient tendance à être clusterisés ensemble indépendamment du sujet
  • Pour les publications textuelles et les commentaires, leur propre texte pouvait être utilisé, mais la plupart des publications avec lien nécessitaient de crawler la page web liée
  • Un service Rust récupérait les URL et parsait dans le HTML les métadonnées comme le titre, l’image, l’auteur et le texte du corps
  • La première version en Node.js était 10 fois plus lente que la version Rust sur les tâches intensives en CPU ; la réécriture en Rust a amélioré les performances
  • L’extraction de texte se faisait en parsant le HTML avec scraper, en supprimant les éléments HTML5 qui ne correspondent pas au contenu principal sur le plan sémantique, puis en parcourant l’arbre restant
  • La dégradation des liens était également importante
    • Environ 200 000 URL ont échoué pour cause de 404, d’échec de résolution DNS ou de timeout de connexion
    • Cela représente moins de 5 % des 4 millions de pages
  • Pour réduire les manques, une partie des anciens articles a été récupérée via la Wayback API de l’Internet Archive
    • La limite de débit de l’Internet Archive était très faible, autour de 5 requêtes par minute

Deuxième stratégie d’embedding

  • Les pages web sont longues, mais BGE-M3 prend en charge une fenêtre de contexte de 8192 tokens
  • Cependant, BGE-M3 était lent et a été remplacé par jina-embeddings-v2-small-en
    • Nombre de paramètres bien plus faible
    • Performances également correctes selon MTEB
    • Temps d’inférence réduit à environ 6 ms, soit 100 fois plus rapide
  • Avec les entrées longues, augmenter la taille des batches provoquait des OOM, si bien que les GPU ne pouvaient pas être totalement saturés
  • Pour compléter les pages avec peu de texte ou impossibles à récupérer, les meilleurs commentaires HN de la publication ont été ajoutés après le corps du texte
    • Les commentaires de premier niveau ont été utilisés en considérant que item.kids était déjà classé
    • Les commentaires supprimés, dead ou à score négatif ont été exclus
    • L’entrée est limitée à 64 KiB au maximum
  • Comme les commentaires peuvent manquer de sens isolément, un contexte plus long a été construit en remontant jusqu’aux commentaires ancêtres et au titre de la publication
  • Les grandes valeurs comme les embeddings et le texte sont stockées dans une table kv séparée
    • Les stocker avec la ligne rendrait celle-ci trop volumineuse
    • Les mises à jour de petites colonnes deviendraient également coûteuses
    • Les changements de schéma deviendraient aussi coûteux

Créer une carte sémantique 2D avec UMAP

  • UMAP est une technique de réduction de dimension qui cherche à préserver les relations sémantiques tout en ramenant des embeddings de grande dimension vers un espace de plus faible dimension
  • Les vecteurs d’embedding à 1024 dimensions ont été réduits à des points 2D pour servir à un nuage de points et à une visualisation cartographique
  • UMAP a reçu en entrée le graphe PyNNDescent et les embeddings d’origine, avec metric="cosine" et n_components=2
  • L’entraînement sur des millions d’entrées de grande dimension prenant longtemps, une VM EC2 c7i.metal-48xl a été utilisée
    • Les 96 cœurs du processeur ont été utilisés au maximum
    • Après environ 1 h 30, une matrice 2D a été générée
  • Les embeddings 2D générés et le modèle UMAP entraîné ont été enregistrés, afin de pouvoir ensuite transformer de nouveaux embeddings sans réentraînement
  • Le premier nuage de points contenait trop de points ; la densité a été réduite en ne sélectionnant, pour chaque cellule de grille, que la publication au score le plus élevé afin d’afficher son titre
  • Dans le second embedding, qui incluait davantage de contexte, les publications difficiles à positionner avec le seul titre ont été placées plus précisément près de contenus liés

Similarité cosinus et classement de recherche

  • Le cœur de l’utilisation des embeddings consiste à trouver la similarité entre deux embeddings
  • Pour les embeddings de texte, on utilise souvent la distance ou la similarité cosinus plutôt que la distance euclidienne classique
  • La distance cosinus est utile lorsque la direction compte davantage que la magnitude
    • Une longue discussion sur X doit être plus proche de X qu’une longue discussion sur Y
    • Prendre en compte la magnitude peut fausser ce type de relation
  • Le calcul central utilisé est le produit scalaire entre la matrice d’embeddings et l’embedding de la requête
  • Si les vecteurs sont unitaires, aucune division supplémentaire par la magnitude n’est nécessaire
  • Les résultats de recherche ne sont pas triés uniquement par similarité pure
    • La similarité cosinus est un facteur important, mais pas le seul
    • Le score HN est utilisé comme preuve sociale
    • La pondération temporelle est intégrée comme un facteur négatif proportionnel à log(age), afin que le contenu ancien recule rapidement pour les requêtes où la fraîcheur est importante

Application de carte dans le navigateur

  • L’objectif était de transformer l’espace d’embeddings HN en carte interactive explorable comme Google Maps
  • Les comportements attendus étaient clairs
    • En zoomant par pincement ou à la molette de la souris, davantage de points s’affichent
    • L’espacement entre les points augmente aussi
    • Certains points ont une étiquette, mais pas tous
    • Cliquer sur un point affiche les détails de la publication
    • Le tactile et la souris sont pris en charge sur mobile comme sur desktop
  • Avec des millions de points, les envoyer tous d’un coup au client n’était pas adapté
  • La solution consiste à découper l’espace de la carte en tuiles de grille, et à ne faire récupérer par le client que les tuiles nécessaires
    • Les tuiles peuvent être identifiées par des coordonnées (x, y)
    • Elles peuvent être stockées dans un magasin clé-valeur comme S3
    • Le déploiement est facile sans logique côté serveur
  • Les niveaux de zoom sont gérés avec une approche LOD
    • À chaque niveau, la carte est divisée en deux fois plus de cellules de grille sur chaque axe
    • Les points sélectionnés au niveau précédent sont aussi copiés au niveau suivant, afin qu’ils ne disparaissent pas lors du zoom
  • La taille visée des tuiles était inférieure à 20 Kio après compression
    • Elles sont limitées à environ 1 500 points
    • Chaque point utilise 8 octets pour (x, y), 4 octets pour l’ID et 2 octets pour le score
  • Pour le rendu de l’application web, l’approche avec des milliers d’éléments DOM dégradait fortement les performances
  • L’implémentation finale utilise Canvas et redessine à chaque mise à jour du viewport
    • Même en redessinant des milliers de points à chaque frame, le fonctionnement reste fluide et simple
  • L’étiquetage sélectionne à répétition les publications au score le plus élevé, mais exclut celles qui chevauchent des étiquettes existantes
    • La détection de collisions utilise l’implémentation d’arbre R RBush
    • La longueur des étiquettes est approximée avec un tableau d’octets de la longueur du titre et une formule ajustée, plutôt qu’avec measureText() du navigateur
  • Les boîtes d’étiquettes initiales et le calcul des collisions étant intensifs côté CPU, ils ont été déplacés vers des Web Workers
  • OffscreenCanvas a aussi été testé, mais comme la logique de rendu était déjà efficace, l’effet n’a pas été significatif

Relief, frontières et étiquettes de villes

  • Une carte uniquement composée de points manquait de repères et d’intérêt visuel ; les notions de relief et de villes ont donc été ajoutées
  • Comme il n’existe pas de géographie réelle ni de frontières politiques, le relief est utilisé comme une métaphore de la densité des points
  • La densité des points sert de signal pour repérer rapidement les zones avec beaucoup d’activité, d’intérêt, de contenus, de participation, de popularité et de discussions
  • Au départ, l’estimation de densité par noyau (Kernel Density Estimation) a été envisagée, mais les essais avec les bibliothèques standard prenaient beaucoup trop longtemps
  • À la place, chaque point a été projeté dans une grande cellule de grille, les comptages par cellule ont été calculés, puis un flou gaussien a été appliqué
  • Les valeurs de densité linéaires donnaient une carte peu satisfaisante, la plupart paraissant proches de 0
  • L’application de log(density + 1) a produit une hiérarchie bien plus naturelle, et les zones de rencontre entre différents niveaux de densité ressemblent à des frontières implicites
  • Plutôt qu’une immense image, des chemins SVG ont été générés pour que le client les dessine sous forme de polygones
    • C’est efficace car il n’y a que 4 couleurs
    • Les frontières restent nettes même en zoomant
    • Les contours fermés de chaque niveau sont calculés avec la fonction de contour d’OpenCV
  • Les étiquettes de villes représentent un thème commun dans un rayon donné
  • Les noms de villes sont transformés en embeddings, puis leur position (x, y) est obtenue avec le modèle UMAP enregistré
  • La génération automatique a aussi été testée
    • L’idée était de créer des noms de villes avec un LLM, mais il était difficile d’obtenir de manière fiable la sortie voulue par prompt
    • K-means n’a pas trouvé beaucoup de clusters sémantiques pertinents tels qu’un humain les regrouperait
  • Au final, quelques villes ont été saisies manuellement en explorant directement la carte, ce qui a pris environ une heure

Déploiement en périphérie et réactivité

  • L’exploration de la carte devait être rapide et réactive ; il était donc important de réduire la latence des fetchs de données
  • Au début, toutes les données de la carte étaient placées dans la région ENAM de Cloudflare R2, mais la latence allait de 600 ms à plusieurs secondes
  • Même avec une latence physique d’environ 200 ms, ce n’était pas assez bon, car 100 ms est le seuil à partir duquel une réponse est perçue comme instantanée
  • Pour réduire la latence, les données ont été rapprochées des utilisateurs
  • De petits serveurs ont été installés en Virginie, à San Jose, à Londres et à Sydney, avec un serveur Rust pour fournir les données
  • Le client appelle plusieurs fois /healthz sur plusieurs nœuds edge et sélectionne le serveur qui répond en premier
  • Des approches comme Anycast ou un CDN auraient aussi été possibles, mais elles n’ont pas été utilisées en raison du coût et d’une complexité excessive
  • L’utilisation mémoire des processus des serveurs edge était 2 à 4 fois supérieure aux données brutes, ce qui restait une interrogation
    • Possibilité d’utilisation de types inadaptés
    • Padding des structures
    • Surallocation des Vec et HashMap
    • Possibilité de fragmentation ou d’inefficacité de l’allocateur mémoire

Résultats de recherche sémantique et limites

  • Pour une requête simple comme “entering the tech industry”, des résultats avec beaucoup d’upvotes et d’autres moins remarqués apparaissaient ensemble, avec une pertinence et une utilité apparemment bonnes
  • Par rapport au service de recherche existant de HN, la recherche par embeddings sémantiques trouve des résultats même sans correspondance littérale
  • Une requête formulée comme une question, telle que “what happened to wework”, affiche aussi des résultats couvrant plusieurs années, comme les licenciements, la chute du cours de l’action et la faillite de WeWork
  • Les résultats correspondent même s’ils ne contiennent pas réellement les mots “what happened” ou ne sont pas formulés comme une question
  • Un problème est que les résultats pas assez similaires ne sont pas filtrés, ce qui laisse entrer des résultats de bas de liste totalement hors sujet
    • C’est considéré comme un problème facile à corriger
  • La recherche “career growth” fait apparaître des essais créatifs et variés qui ne contiennent pas les mots exacts
  • La qualité de curation et les scores de HN contribuent à la qualité de la recherche
  • L’application contient des suggestions de requêtes codées en dur, comme “linus rants”, “self bootstrapping” et “cool things with css”

Analyse des communautés virtuelles et des commentaires

  • Les embeddings permettent de créer une fonctionnalité de sous-communautés virtuelles
  • Lorsqu’un utilisateur saisit un nom ou une description de communauté, les publications dépassant un certain seuil de similarité sont regroupées à la volée
  • Comme HN ne propose pas de fonction pour segmenter davantage les publications, c’est une manière de créer instantanément une curation centrée sur des centres d’intérêt précis
  • Les extraits et les images des cartes de résultats proviennent des métadonnées de page enregistrées par un crawler web
  • Pour les icônes de site, l’approche a été simplifiée : plutôt que de parser des métadonnées complexes, le client récupère le /favicon.ico du domaine
  • Les fils de commentaires peuvent aussi être affichés de la même façon
  • Les scores des commentaires n’étant pas fournis par l’API HN, seul le tri chronologique est possible
  • Sans score de commentaire, il semble possible d’établir un classement en s’appuyant sur l’historique des commentaires de l’utilisateur, l’engagement autour du commentaire, la publication, le sujet, le contenu, etc.
  • Il est aussi possible de trouver les utilisateurs influents ou actifs sur un sujet donné
    • Pour la requête « cloudflare », jgrahamc et eastdakota apparaissent en tête
    • Ces deux utilisateurs sont respectivement le CTO et le CEO de Cloudflare
  • Ce traitement est effectué par opérations matricielles, sans classification séparée des commentaires ni recherche par mots-clés
  • Le post-filtrage est généralement plus rapide et suffisant que le préfiltrage
    • Le préfiltrage oblige à retirer les lignes correspondantes de la matrice d’embeddings, ce qui peut nécessiter une énorme copie mémoire ou des calculs de vectorisation partielle plus lents
    • Il semble préférable de trouver d’abord les lignes similaires, puis de filtrer les résultats
  • Le seuil minimal est important
    • Même des éléments non pertinents peuvent avoir une similarité autour de 0,6
    • Sans seuil, les utilisateurs ayant un très grand nombre de commentaires peuvent dominer le classement uniquement par effet de volume

Analyse du sentiment et de la popularité sur l’ensemble des commentaires

  • L’analyse à grande échelle que l’auteur voulait tenter sur 30 millions de commentaires portait sur la popularité et le sentiment
  • L’objectif était de voir comment HN perçoit certains sujets au fil du temps, comment les grands événements influencent le sentiment, et comment les centres d’intérêt croissent ou déclinent
  • Comme il n’y avait pas de données de sentiment, un modèle open source de classification du sentiment de Hugging Face a été utilisé
  • Le modèle choisi est TweetEval, entraîné sur du contenu de réseaux sociaux
  • TweetEval étant conçu pour de courts tweets, seul le commentaire lui-même est fourni en entrée, sans ajouter le contexte des ancêtres comme pour les embeddings
  • Les commentaires sont placés dans une file, traités sur un cluster de GPU, puis les résultats sont enregistrés
  • Le modèle étant petit, la taille de batch a été augmentée pour améliorer l’efficacité GPU
  • Augmenter la taille de batch consomme davantage de VRAM, mais peut réduire les transferts mémoire hôte-GPU et accroître le parallélisme
  • Dans les modèles Transformer, les entrées d’un batch doivent être rectangulaires, elles sont donc complétées par padding jusqu’à la longueur de l’entrée la plus longue
    • Si une entrée longue est mélangée à quelques entrées courtes, la taille totale de l’entrée et l’état interne peuvent beaucoup augmenter
    • Cela peut provoquer des pics mémoire et des OOM
  • Dans l’exemple d’analyse de sentiment sur Rust, le sentiment positif envers Rust était globalement majoritaire
    • Un pic positif est apparu autour de l’annonce de Rust 1.0
    • Les publications plus négatives étaient corrélées, selon le modèle, à de nombreux commentaires négatifs
  • La popularité par langage est aussi estimée en pondérant scores et similarité
    • HN ne fournissant pas les scores des commentaires, ceux-ci ne peuvent pas être utilisés
    • Rust se porte bien, mais ne semblait pas aussi populaire que d’autres langages
    • Le seuil de similarité pouvant nécessiter des ajustements, les résultats peuvent être erronés

Accélérer les calculs numériques à grande échelle avec le GPU

  • Les requêtes d’analyse prenaient 10 à 30 secondes même sur une machine à 32 cœurs, ce qui était trop lent pour des expérimentations interactives
  • Après avoir envisagé des index ou du prétraitement, l’auteur est passé à l’utilisation du GPU pour les calculs numériques vectorisés
  • CuPy et cuDF fournissent respectivement des API similaires à NumPy et pandas, tout en s’exécutant sur GPU
  • Le portage a été relativement simple, et le temps de requête est descendu à quelques centaines de ms
  • La vitesse étant suffisante, aucun graphe ANN n’a été utilisé
  • La partie difficile a été de charger la grande matrice d’embeddings sur le GPU
    • La matrice d’embeddings des commentaires fait 30M x 512
    • Il était difficile de conserver plus d’une copie de la matrice en mémoire système ou en mémoire vidéo
  • Une méthode de chargement naïve peut créer plusieurs copies
    • Lecture des octets depuis le disque
    • Chargement dans un tableau NumPy
    • Conversion en tableau CuPy
    • Copie vers le GPU
    • Ce processus peut créer au total 4 copies, dont 3 en mémoire
  • La méthode finale consiste à mapper en mémoire la matrice sur disque, à préallouer sur le GPU une matrice non initialisée de même taille, puis à copier par chunks
  • Cette approche évite de lire d’abord les données dans la mémoire Python et n’utilise exactement qu’une seule copie en RAM système et une seule en VRAM

Démo et prochaines étapes

  • L’application de démonstration est disponible sur hn.wilsonl.in
  • La page principale contient la carte et la recherche, et les boutons en haut à droite donnent accès aux outils de communautés et d’analyse
  • Les URL des communautés ou des résultats d’analyse stockent la requête dans l’URL, ce qui permet de les partager avec d’autres personnes
  • Le jeu de données de démonstration s’arrête autour du 10 avril 2024 et n’inclut pas les publications ni commentaires live les plus récents
  • Plusieurs idées restent à explorer
    • Des données live maintenues en permanence à jour
    • Un système de recommandation basé sur le deep learning, opérant sur le web sélectionné par HN
    • L’amélioration des résultats de recherche par entraînement d’un reranker
    • Des parcours et itinéraires intéressants sur la carte
    • L’analyse des relations de similarité et d’opposition entre utilisateurs
    • L’analyse des utilisateurs les plus experts dans des niches spécifiques
  • L’ensemble des données et du code est disponible sur GitHub

2 commentaires

 
GN⁺ 2024-05-10
Avis de Hacker News
  • Travail particulièrement impressionnant pour un projet mené par une seule personne
    Le graphe d’analyse de sentiment au fil du temps m’a marqué, et c’était intéressant, car c’est la première fois que je voyais Rust présenté de cette façon. Je me demande quels ont été les sujets les plus positifs au fil du temps, et s’il y en a eu qui ont soudainement fortement chuté
    La phrase selon laquelle « il semble y avoir beaucoup de sentiment négatif sur HN dans son ensemble » sonne aussi juste, intuitivement, à propos des réseaux sociaux. Ce serait aussi amusant de comparer les sentiments selon les plateformes sociales et les périodes

    • J’aimerais creuser davantage la partie sentiment. Comme tu le dis, ce serait intéressant d’avoir une vue d’ensemble plutôt que seulement des requêtes spécifiques
      Si le sentiment négatif m’a sauté aux yeux, c’est parce que je m’attendais à l’origine à un graphe de sentiment plus net. Je m’attendais à quelque chose de globalement neutre à positif, avec des pics positifs autour des articles positifs et des pics négatifs autour des articles négatifs, mais, pour presque toutes les requêtes, le sentiment était presque toujours négatif. Même les articles positifs semblaient attirer beaucoup de négativité selon le modèle et l’approche, et comme les deux pourraient être erronés, j’aimerais approfondir cela dans un prochain billet de blog
    • En plus du sentiment par plateforme sociale et par période, ce serait bien d’examiner aussi les heures de la journée ainsi que les jours de semaine/week-ends
    • Il y a quelques mois, j’ai écrit un billet de blog analysant le sentiment des commentaires HN à propos de l’IA, de la blockchain, du télétravail et de Rust. Le graphe final tout à la fin de l’article est lié à ce sujet
      https://openpipe.ai/blog/hn-ai-crypto
    • C’est vraiment dommage que l’API HN ne fournisse pas le nombre de votes des commentaires. Je me demande comment l’analyse de sentiment changerait si elle était pondérée par les votes positifs/négatifs
      Sans preuve à l’appui, j’ai l’impression que les ingénieurs sont globalement critiques et que, pour les retours positifs, ils ont plutôt tendance à cliquer sur +1 qu’à les écrire à répétition. Les critiques, elles, sont plus souvent rédigées directement :)
    • Crypto entrerait probablement aussi dans cette catégorie
  • C’est un bon exemple pour quelqu’un qui n’est pas familier avec l’ingénierie des données/MLOps
    Je suggérerais de créer des clusters hiérarchiques sur les points avec HDBSCAN, puis de générer les noms des clusters internes avec un modèle. Cela faciliterait l’exploration des sujets jusqu’aux feuilles, en faisant apparaître les sous-éléments selon leur connexion avec le nœud actuel
    Les couleurs des groupes devraient être plus distinctes, et l’existence de clusters aiderait probablement. La taille du texte des articles individuels devrait varier selon leur importance ou leur pertinence, soit globalement, soit par rapport à la recherche en cours. Avec davantage de résumés de clusters internes, on pourrait remplacer plusieurs articles par un résumé de groupe jusqu’au zoom, ce qui réduirait aussi l’encombrement du texte

  • La portée du projet est étonnamment vaste
    Cela dit, qu’il s’agisse de jina ou de bge-3/flag, les embeddings et le tokenizer ne semblent pas très adaptés aux sujets techniques. Les mots en langage naturel passent bien, mais quand on recherche des concepts techniques comme « xaml » ou « simd », cela tend à tokeniser l’entrée puis à chercher des mots qui sonnent de façon similaire
    Comme retour constructif, ce serait bien d’avoir un moyen de ne pas afficher à répétition les mêmes résultats de type « classement HN » lorsqu’un sujet est trop de niche et ne renvoie aucun résultat. Quand on recherche un mot que l’embedding ne connaît pas, « Stephen Hawking has died » apparaît souvent
    Je ne suis pas non plus certain que l’analyse de sentiment fonctionne si bien. Il semblait y avoir beaucoup trop de sentiment négatif par rapport à la réalité, et même en cherchant quelque chose que HN verrait très majoritairement de façon positive, comme « Mr Rogers », on obtient un fort pic négatif. En recherchant « Carter », il y a un énorme pic négatif lié au décès de Rosalynn Carter, alors que l’article en question parlait des grandes choses accomplies par le couple Carter
    La « popularité au fil du temps » devrait probablement être corrigée par le nombre médian de votes des articles du mois/de l’année concernés. Si l’on trace simplement le nombre d’articles, la courbe de tendance continue de monter. En regardant la popularité de « diesel », on voit ce que je veux dire : ce terme a atteint son pic il y a 10 ans. Ou alors il faudrait peut-être utiliser le taux d’occurrence du mot-clé plutôt que le score des articles, ou le nombre d’éléments dont l’indice de similarité cosinus avec la requête est inférieur à x
    La fonctionnalité dynamique qui permet de cliquer sur des articles pour les retirer et de recalculer le seuil de similarité est excellente

    • Comment pourrait-on déterminer programmatiquement qu’un modèle d’embedding ne reconnaît pas un terme ou un mot donné ?
  • Il existe un excellent outil qui fait presque la même chose pour n’importe quel jeu de données : https://github.com/enjalot/latent-scope
    Bien sûr, l’échelle du projet original ajoute beaucoup de complexité intéressante, et cet outil ne peut pas gérer une telle échelle, mais il est bien pour les jeux de données de taille moyenne

  • J’aimerais analyser si l’autopromotion a augmenté sur HN
    Ici, je définis l’autopromotion non pas comme les posts du type « Show HN: Something ... », mais comme ceux au format « Show HN: I ... »
    Parmi les 100 premiers actuellement, par exemple, « Show HN: Exploring HN by mapping and analyzing 40M posts and comments for fun » et « Show HN: Browser-based knitting (pattern) software » ne sont pas des titres d’autopromotion. Dans chaque cas, le sujet est respectivement l’exploration et le logiciel
    En revanche, « Show HN: I built a non-linear UI for ChatGPT » et « Show HN: I created 3,800+ Open Source React Icons » sont des titres d’autopromotion. Dans chaque cas, le sujet est « I »
    J’ai simplement vérifié, dans les résultats de recherche Algolia, les titres commençant par « Show HN: I » pour chaque année à partir du 1er avril, puis je les ai divisés par le nombre total de résultats de l’année correspondante et tracés en graphique, ce qui donnait ceci
    2023 ****************************************
    2022 ***********************************
    2021 ***************************
    2020 **************************************
    2019 *************************
    2018 *************
    2017 *******
    2016 **********
    2015 ********
    2014 ************
    2013 *********************
    2012 *****************
    2011 *********
    2010 ***
    À l’époque où j’ai grandi, il me semble que l’autopromotion était généralement considérée comme un mauvais trait de caractère. On m’a appris que ce sont les actes qui doivent vous promouvoir, pas le fait d’attirer l’attention dessus, mais j’ai l’impression que cette culture change
    Si l’autopromotion a réellement augmenté, je me demande si c’est sous l’influence des réseaux sociaux, etc. Je ressens une hausse similaire sur YouTube, mais je n’ai que l’impression de voir beaucoup de vidéos recommandées commençant par « I..... », sans données à l’appui

    • Ta définition de l’autopromotion diffère un peu de celle que j’ai habituellement en tête. En général, lorsqu’une personne promeut quelque chose qu’elle a créé, on considère cela comme de l’autopromotion. Donc les deux exemples que tu cites comme n’étant pas de l’autopromotion en sont aussi selon ma définition
      Autrement dit, ce que tu as séparé entre autopromotion et non-autopromotion correspond, selon mes critères, aux cas où le titre indique très clairement qu’il s’agit d’autopromotion et à ceux où il l’indique moins clairement. Cela dit, l’expression « Show HN » elle-même semble être réservée à l’autopromotion, donc même sans « I », quelqu’un qui connaît l’usage sait qu’il s’agit d’autopromotion
    • Tous les Show HN doivent être des choses créées par l’auteur, donc je ne vois pas bien en quoi rendre explicite ce qui est implicite rendrait quelque chose plus autopromotionnel
      Ils signifient tous : « regarde, j’ai fait un truc cool, qu’en penses-tu ? »
    • C’est aussi un thème largement abordé dans la biographie d’Einstein par Walter Isaacson, donc les gens observent cette tendance depuis longtemps
      Par exemple, les Allemands accusaient Einstein de faire de l’autopromotion, tandis qu’à l’inverse les États-Unis avaient une culture de la célébrité. C’est peut-être un phénomène cyclique
  • C’est de loin l’article le plus cool que j’aie vu sur HN cette année

  • Ce n’était pas évident au premier abord, mais l’app réelle est ici : https://hn.wilsonl.in/

    • Je me demande si le lien vers la landing page a été placé presque tout à la fin intentionnellement. En pratique, seuls ceux qui ont vraiment lu l’article arrivent sur le site
      Je ne dis pas ça ironiquement, je pense que c’est une bonne idée
    • Le lien de recherche ne semble pas partageable, ou alors il ne semble pas inclure la requête
      Je me demande aussi si la phrase de recherche est embarquée mot par mot, et si le même modèle que celui utilisé pour les documents est employé. J’ai cherché « lead generation », mais j’ai obtenu des résultats sur l’intoxication au plomb, alors qu’une vraie embedding non unigramme devrait comprendre cette expression
    • Je m’y suis trouvé, moi et mes posts ! Sympa
  • Une recommandation moderne pour UMAP est Parametric UMAP : https://umap-learn.readthedocs.io/en/latest/parametric_umap....
    Il entraîne un petit MLP Keras pour effectuer une réduction de dimension en 2D tout en minimisant la perte UMAP. L’avantage est que ce modèle est petit, donc on peut l’enregistrer et le réutiliser pour prédire sur de nouvelles données inconnues. Un modèle UMAP entraîné de manière traditionnelle est volumineux. De plus, comme il utilise le GPU, l’entraînement devrait théoriquement être beaucoup plus rapide
    L’inconvénient est que l’implémentation du package Python UMAP n’est pas très bonne, et qu’elle construit puis envoie sur le GPU l’ensemble du dataset étendu de nœuds/arêtes. Elle ne peut donc s’entraîner que sur environ 100 000 embeddings avant de manquer de mémoire
    Le pipeline entièrement non supervisé UMAP → HDBSCAN → étiquetage des clusters par IA est tellement utile que cela me donne envie de créer une implémentation plus scalable de Parametric UMAP

    • Il existe une implémentation GPU rapide dans cuML. Je ne sais pas très bien pourquoi cuML est si peu connu
    • À première vue, cela semble venir du fait que l’implémentation envoie tout le graphe, c’est-à-dire toutes les arêtes, sur le GPU. Faire un échantillonnage des arêtes pendant l’entraînement pourrait atténuer le problème
  • Pour ce qui ressemble à un projet exploratoire mené par passion, c’est un travail étonnamment massif. Je ne cherche pas à minimiser le résultat, qui est vraiment impressionnant, mais l’ampleur des moyens engagés m’a surpris
    Ils ont utilisé 150 GPU rien que pour calculer les embeddings, et développé deux systèmes maison, db-rpc et queued, pour la communication entre serveurs. Il y a aussi eu beaucoup de travail périphérique et de calculs
    Je suis curieux du contexte du projet. Je me demande aussi comment ils ont trouvé le financement et le temps nécessaires pour ce type de recherche
    Ayant pas mal travaillé professionnellement sur des sujets similaires, notamment la cartographie du paysage des articles scientifiques et des brevets, je ne suis pas certain que 150 GPU aient vraiment été nécessaires. Si, au final, il s’agit d’une projection en 2D et d’un clustering, des approches traditionnelles de sac de mots ou de modélisation de sujets seraient bien plus simples et moins coûteuses, avec probablement une différence de qualité à peine perceptible. On pourrait obtenir des résultats similaires en utilisant le graphe des auteurs et des fils de commentaires

    • Le coût n’a pas été mentionné dans l’article, mais il était de l’ordre de quelques centaines de dollars, donc assez accessible même pour un projet personnel
      Les GPU étaient étonnamment bon marché, et j’ai surtout augmenté l’échelle parce que je manquais de patience :) L’ensemble du cluster n’a tourné que quelques heures
      Si tu as un lien vers les travaux que tu as faits, j’aimerais bien les voir. Ça a l’air intéressant et j’aimerais en lire davantage
    • L’auteur est clairement très compétent. C’est aussi intéressant qu’il publie sur HN mais n’ait plus commenté depuis 2018, puis qu’il ait lancé ce projet
      Côté financement et temps, il est possible qu’il soit entre deux projets ou deux emplois, et qu’il ait suffisamment bien réussi financièrement dans sa carrière ou une activité précédente pour le mener sur ses fonds propres. L’utilisation des GPU semble aussi très efficace, donc le coût n’a probablement pas été si élevé
    • On peut obtenir d’assez bons résultats avec des embeddings moins coûteux
      En appliquant à ce type d’embeddings de l’apprentissage automatique classique, comme des SVM avec calibration probabiliste, on obtient de bons résultats en classification et en clustering, avec une vitesse plus de 100 fois supérieure à celle du fine-tuning de LLM
  • En général, on ne fait pas comme dans cette démo : on normalise les vecteurs
    Avec des vecteurs normalisés, la distance euclidienne mesure la distance entre les extrémités des deux vecteurs. En revanche, la distance cosinus mesure la longueur de la projection d’un vecteur sur l’autre

    • Le problème de la normalisation, c’est qu’on perd un degré de liberté. Pour la visualisation, cela revient en pratique à perdre une dimension
      Un vecteur 2D normalisé n’est en réalité qu’un vecteur 1D. Si l’on veut montrer des relations en 2D, il faut utiliser des vecteurs 3D afin de retrouver deux degrés de liberté
 
ggg213 2024-05-10

Le titre manque, apparemment.