Mathis Hammel Profile picture
Jul 17, 2023 33 tweets 9 min read Read on X
🧶THREAD - Un programme de 15 lignes de code Python arrive à rivaliser avec les meilleures intelligences artificielles !

Cette drôle de découverte vient d'être publiée par une équipe de chercheurs canadiens, et risque de bouleverser le monde du Machine Learning.

Explications ⤵️ "Qui gagne ?"  À gauche, un réseau de neurones ultra perfectionné avec 340 millions de paramètres  À droite, 15 lignes de Python
La classification de texte est l'un des domaines de recherche les plus actifs en intelligence artificielle : elle consiste à trier automatiquement des textes courts dans un ensemble de catégories pré-définies. Quelques phrases classées par catégorie :  Le briquet a été inventé 3 ans avant l'allumette (Histoire)  Les crocodiles ne peuvent pas tirer la langue (Nature)  Le miel ne périme jamais (Cuisine)  Les amandiers et les pêchers sont dans la même famille d'arbres (Nature)  (Instant culture inutile : toutes ces phrases sont vraies)
Pour évaluer la performance d'un modèle, on va travailler avec des datasets spécifiques.

L'un des plus connus est basé sur 1.4 millions de questions posées sur le site Yahoo Answers, réparties en 10 catégories : Plusieurs questions triées dans un tableau par catégorie. Voici par exemple les questions de la catégorie "Société" :  Comment ont été inventés les gros mots ? Comment devenir gothique ? SI DIEU NOUS A FAIT QUI A FAIT DIEU !? Est-ce que bisexuel est plus fun ? Croyez-vous en le nouvel an chinois ? Sens de la vie ?  (oui, ces questions existent vraiment dans le dataset)
L'algorithme peut donc utiliser ces données pour apprendre à quoi ressemblent les questions de chaque catégorie.

On va ensuite le mettre à l'épreuve avec 60 000 questions non-étiquetées sur lesquelles il devra prédire la catégorie. Quatre questions dont on ne connaît pas la catégorie :  Quel âge a Homer Simpson ? Quel est le budget militaire des USA ? Où puis-je acheter une quille de bowling ? Quelle est la différence entre HTML et XHTML ?
Il existe plusieurs manières de mesurer la performance d'un modèle de machine learning sur cette tâche.

La plus courante consiste à simplement calculer le taux de bonnes réponses : par exemple, un modèle qui donne 45k catégories correctes sur les 60k textes aura un score de 75%.
Cette mesure est appelée l'accuracy, ou "précision" en français.

Cependant, le mot français est peu utilisé car ambigu avec le terme anglais "precision" : Quatre cibles avec des impacts dessus :  La première a des impacts très étalés partout : low accuracy, low precision La deuxième a des impacts très groupés mais éloignés du centre : low accuracy, high precision La troisième a des impacts peu groupés, mais relativement proches du centre : high accuracy, low precision La dernière a des impacts qui se trouvent tous dans le cercle central : high accuracy, high precision
À l'heure actuelle, parmi les modèles textuels les plus performants (dits "à l'état de l'art") on retrouve notamment BERT, publié en open source par Google en 2018.

C'est un modèle immense qui compte jusqu'à 340 millions de neurones !
Face à ce titan, les chercheurs de l'université de Waterloo ont donc décidé de créer... un script tout simple de 15 lignes. Et ça a marché 😁

Regardons de plus près son fonctionnement.   import gzip   import numpy as np    for (x1, _) in test_set:       Cx1 = len(gzip.compress(x1.encode()))       distance_from_x1 = []       for (x2, _) in training_set:           Cx2 = len(gzip.compress(x2.encode()))           x1x2 = " ".join([x1, x2])           Cx1x2 = len(gzip.compress(x1x2.encode()))           ncd = (Cx1x2 - min(Cx1, Cx2)) / max(Cx1, Cx2)           distance_from_x1.append(ncd)
Dans l'algo présenté, on repère quelques opérations de la forme len(gzip.compress(x)) : c'est ici que se cache son secret.   import gzip   import numpy as np    for (x1, _) in test_set:       Cx1 = len(gzip.compress(x1.encode()))       distance_from_x1 = []       for (x2, _) in training_set:           Cx2 = len(gzip.compress(x2.encode()))           x1x2 = " ".join([x1, x2])           Cx1x2 = len(gzip.compress(x1x2.encode()))           ncd = (Cx1x2 - min(Cx1, Cx2)) / max(Cx1, Cx2)           distance_from_x1.append(ncd)
Gzip est un utilitaire de compression de fichiers basé sur le même algorithme que pour les fichiers .zip : en trouvant des motifs qui se répètent dans les données à compresser, on va pouvoir réduire la taille du fichier sans perdre d'information. Un document de 8,3Mo est compressé avec gzip et ne fait plus que 4,5Mo après compression. La décompression restaure le fichier original de 8,3Mo.
Et ce facteur de compression peut justement être utilisé pour mesurer la redondance d'information dans un texte !

J'ai compressé 1000 caractères de la page Wikipédia "réseaux de neurones artificiels" et 1000 caractères aléatoires, voici les résultats respectifs : L'article Wikipédia se compresse en 536 octets, alors que le texte aléatoire occupe 882 octets après compression.
On peut donc constater qu'un texte en français contient davantage de redondance (= moins d'entropie) qui permet de le compresser plus efficacement.

De même, la concaténation de deux textes se compressera plus facilement si les deux textes sont similaires : La concaténation de l'article Pizza et Tomate se compresse en 950 octets, alors que la concaténation des articles Pizza+Clown occupe 1030 octets.
En se basant sur cette observation, on peut donc mettre en place un système capable de calculer une sorte de "distance sémantique" entre deux textes !

La formule ci-dessous est celle qui est utilisée par les chercheurs dans leur article : NCD(x,y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
Cette formule provient de concepts théoriques comme la distance de Kolmogorov conditionnelle et l'information algorithmique mutuelle.

Sûrement des concepts inventés par les chercheurs pour se la péter en soirée, mais je vais vous montrer qu'on peut la comprendre facilement. De la notation compliquée sur un papier de recherche en anglais
Considérons que l'on veut comparer la similarité de deux textes x1 et x2. On note C(x) la taille d'un texte x après compression.

Pour simplifier les choses, on va dire que la distance est comprise entre 0 et 1, et que C(x1)≥C(x2).
Penchons-nous sur deux cas extrêmes :
Cas 1 - x1 et x2 sont extrêmement similaires : les infos de x2 sont entièrement contenues dans x1.
Ajouter x2 après x1 ne change pas la taille du fichier compressé.

Les deux textes sont très proches, on souhaite donc que leur distance soit 0. Information parfaitement redondante : C(x1+x2) = C(x1)
Cas 2 - x1 et x2 sont radicalement différents : compresser x1+x2 ensemble ne permettra pas de gagner de place par rapport à la compression des deux textes séparément.

Ici, on veut donner une distance élevée (donc 1) à cette paire de textes. Information parfaitement exclusive : C(x1+x2) = C(x1)+C(x2)
Bien sûr, ces deux cas sont extrêmes et ne se produisent pas en pratique, mais à l'aide de ces deux points de référence il est maintenant possible de mettre en place une fonction affine qui donne la distance en fonction de C(x1+x2) : Une droite dont l'équation affine est la suivante : dist(x1, x2) = (C(x1+x2)-C(x1))/C(x2)
L'équation de la droite ci-dessus correspond en fait exactement à celle utilisée par les chercheurs de l'université de Waterloo !

La seule différence est l'utilisation des fonctions min et max, qui permettent d'échanger potentiellement x1 et x2 pour s'assurer que C(x1)≥C(x2). NCD(x,y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
Avec cette formule, on peut maintenant créer un puissant classificateur : pour trouver la catégorie d'un texte x1 inconnu, on va chercher le texte x2 parmi le dataset d'entraînement qui s'en approche le plus.

Il est probable que la catégorie de x1 soit la même que x2. Plusieurs textes sont comparés avec le texte "Quelle est la meilleure équipe de basketball ?" : le texte avec la distance la plus proche est "Où a été inventé le basket ?" dans la catégorie Sport. Il est donc probable que le texte que l'on cherche à classifier fasse partie de la catégorie Sport.
En pratique, les résultats sont impressionnants : sur un benchmark comprenant 13 modèles récents, cet algorithme parvient à se classer sur le podium à plusieurs reprises, et même en première place sur de nombreux datasets non-anglais !
Et même si BERT semble tout de même plus efficace que notre technique magique à base de gzip, cette dernière présente 3 avantages majeurs :

- Sa simplicité de mise en œuvre
- Aucun pré-entraînement nécessaire
- Une bonne performance dans toutes les langues
Avant de terminer ce thread, je vous propose deux petites curiosités de code liées à ce papier.

La première est une erreur algorithmique que j'ai trouvée dans le code publié : un calcul pourrait être optimisé, voyez-vous lequel ? (indice : c'est dans les 3 dernières lignes) Les dernières lignes du script sont :  sorted_idx = np.argsort(np.array(distance_from_x1)) top_k_class = training_set[sorted_idx[:k], 1] predict_class = max(set(top_k_class), key=top_k_class.count)
On peut constater ici que le code cherche les k textes les plus proches de chaque x1 dans le jeu d'entraînement, puis trouve la catégorie majoritaire parmi ceux-ci.
On appelle ça une recherche kNN (k Nearest Neighbors). Dans ce papier en particulier, les chercheurs prennent k=2.
Pour calculer les k plus proches voisins, l'implémentation du papier de recherche va faire quelque chose comme ça (via numpy.argsort) : distances = [] for x2 in training_set:     distances.append(dist(x1, x2)) k_lowest = sorted(distances)[:k]
Cette opération est en réalité très inefficace : on appelle une fonction de tri sur un tableau gigantesque (jusqu'à 1,4 millions d'éléments pour le dataset Yahoo Answers), pour n'utiliser que les 2 premiers résultats...
En utilisant un tas binaire, structure de données spécialisée, on peut grandement améliorer la performance du calcul en ne gardant que les k meilleurs résultats au fil de l'exécution : la complexité temporelle de l'extraction passe de O(N·log(N)) à O(N·log(k)). import heapq heap=[-1]*K for x2 in training_set: 	heapq.heappushpop(h, dist(x1, x2)) return sorted(heapq)
Et en pratique ?

Sur le dataset Yahoo Answers, j'ai atteint un gain de performance de +16% avec cette optimisation, ce qui est loin d'être négligeable sur un benchmark qui demande 6 jours de calcul !
(La technique gzip est très lente car on doit calculer toutes les paires)
La seconde curiosité que je voulais vous montrer concerne la taille du code : c'est rare d'avoir un papier de recherche complet qui tient en 15 lignes de code, mais peut-on aller encore plus loin ?
En utilisant quelques techniques assez sales, j'ai réussi à faire passer le script de 538 à 214 caractères (en ajoutant au passage mon optimisation algorithmique 😇)

Je vous présente le meilleur classifieur de texte au monde qui tient en un tweet :
# state-of-the-art gzip text classifier in a tweet

import gzip,heapq
g=lambda x:len(gzip.compress(x))
def classify(t):
A=g(t)
h=[(-1,)]*K
for(a,b)in train:heapq.heappushpop(h,((min(A,g(a))-g(t+b' '+a))/max(A,g(a)),b))
s=[x[1]for x in h]
return max(set(s),key=s.count)
Fin du thread, merci d'avoir tenu jusqu'au bout !
Il aurait pu être 2 fois plus court si je voulais aller droit au but, mais y'avait plein de petites digressions que je trouvais trop intéressantes. N'hésitez pas à partager ☺️
Et pour aller lire le papier de recherche complet, c'est par ici :

Merci à @Guardia_School pour son soutien sur mes activités de vulgarisation :)aclanthology.org/2023.findings-…

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Mathis Hammel

Mathis Hammel Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @MathisHammel

Oct 21
THREAD - Une immense avancée pour l'humanité : on a réussi à afficher Bad Apple et jouer à Doom sur une croix de pharmacie.

Petit complément technique à la vidéo de @Sylvqin pour vous montrer les coulisses du reverse-engineering de cet objet mystique. Image
Le socle de la croix de pharmacie est occupé par une carte de contrôle électronique relativement simple, entourée de composants d'électronique de puissance (mine de rien, 2560 LED ça consomme pas mal de watts) Image
Les composants ont résisté au temps et aux éléments, mais les gravures des puces ont quasiment disparu.

Heureusement, on peut les identifier grâce au circuit imprimé sur lequel figurent les références, et comprendre le layout de la carte : Image
Read 33 tweets
Jun 20
J'en ai trop marre de voir des smicards pleurer pour qu'on augmente pas les impôts des millionnaires.

J'ai gagné un peu plus de 7000€/mois pendant plusieurs années, si tu te considères pas riche à ce niveau c'est du déni ou de la malhonnêteté. Thread ⤵️
J'aime pas trop parler d'argent ici parce que ça peut passer pour de l'orgueil, mais on voit tellement de conneries se propager en ce moment que je me suis senti obligé de partager mon expérience (je supprimerai probablement le thread d'ici quelques jours)
Commençons par "tu t'offres un ou deux resto par mois" : je mange au resto quasiment chaque midi en semaine.

Le soir j'aime bien cuisiner, jamais aucune hésitation avant de prendre des produits bio ou premium.
Read 10 tweets
Mar 29
THREAD - les manipulations illicites du classement lors de la compétition la plus chère d'Europe.

Cette semaine, l'équipe de l'European Cyber Cup a trafiqué arbitrairement son scoreboard pour favoriser certaines équipes qui lui faisaient pression. 1/14 Image
Je suis coach de 10 étudiant·es de @Guardia_School qui ont participé cette semaine aux épreuves de l'European Cyber Cup.

Cette compétition est organisée par le forum InCyber (anciennement FIC, qui a discrètement changé de nom à cause de quelques casseroles).
Le prix d'inscription n'est pas rendu public, mais en 2021 je me souviens que mon entreprise avait dû payer 10.000€ pour nous inscrire, sachant que le cash prize pour l'équipe gagnante est de 5.000€ 🙃 Image
Read 16 tweets
Feb 8
J'ai besoin de votre aide pour m'aider à entraîner l'équipe de France de cybersécurité !

Quelques détails ci-dessous, merci de partager au maximum 🙏
En janvier, j'ai eu l'honneur d'être nommé entraîneur des compétiteurs français en cybersécurité, pour la prestigieuse compétition WorldSkills qui opposera 65 pays cette année.
Contrairement aux excellentes compétitions FCSC/ECSC qui sont très orientées CTF, le challenge WorldSkills va plutôt demander des compétences métier, appliquées à des environnements réalistes.
Read 6 tweets
Nov 8, 2023
THREAD

Je me suis intéressé à la cybersécurité de Crush, l'appli de rencontres pour 10-21 ans qui fait beaucoup de bruit.

J'y ai découvert un réseau de sociétés fictives qui récolte activement les données de dizaines de milliers de mineur·es. Explications ⤵️ Capture de l'appli "Crush, trouve ton crush secret" sur le store iOS.
PARTIE 1. Le fonctionnement de l'appli

Crush est une appli dont le but est de découvrir ses admirateurs secrets au collège/lycée.

Elle a été renommée "Friendzy, sondages entre amis" depuis son bad buzz.
Le principe est simple : après avoir ajouté vos amis sur l'appli, vous répondez à des questions sur vos liens d'amitié.

Dans un autre onglet, vous pouvez savoir ce que les gens ont répondu sur vous, sans voir leur nom. Sondage "La discrétion est son superpouvoir" avec 4 choix parmi mes amis sur l'appli (j'ai masqué deux noms qui appartiennent potentiellement à des vraies personnes)
Read 24 tweets
Aug 1, 2023
Droite au Coeur est toujours en maintenance, mais j'ai réussi à contourner la fermeture de l'authentification donc j'ai toujours accès au site.

La vulnérabilité initiale a été corrigée, je peux donc légalement vous expliquer la pire faille de sécurité du monde. 🧵1/9
L'interface de Droite au Coeur, comme beaucoup de sites web depuis ~2010, est dynamique.

Cela signifie que votre navigateur va d'abord télécharger le code qui gère l'affichage de la page, mais sans télécharger le contenu.

Pendant qq secondes, la page ressemble en gros à ça : Image
C'est ce squelette de page qui va ensuite faire d'autres requêtes pour récupérer le contenu, ici les profils de dating.

Pour ça, l'interface va utiliser une API : c'est un programme hébergé côté serveur, qui va récupérer et formater les données qu'on lui demande. Image
Read 10 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(