1 points par GN⁺ 2024-11-30 | 1 commentaires | Partager sur WhatsApp
  • Projet consistant à créer un modèle TensorFlow.js pour résoudre automatiquement les CAPTCHA de 4chan dans le navigateur, avec l’objectif minimal de 80 % de précision et l’objectif préféré de plus de 90 % finalement atteints
  • La collecte des CAPTCHA était difficile à automatiser par simple scraping de masse à cause de ttl, cd, de Cloudflare Turnstile et d’un temps d’attente croissant entre les requêtes
  • Les services commerciaux de résolution par des humains et l’annotation manuelle se heurtaient à des erreurs et au throttling ; l’auteur a donc généré environ 50 000 données synthétiques à partir d’environ 2 500 arrière-plans réels et de 50 à 150 images par caractère pour obtenir une échelle d’entraînement suffisante
  • Le modèle utilise une architecture CNN+LSTM et un encodage CTC ; après entraînement avec Keras/TensorFlow, il a été converti vers TensorFlow.js via Python 3.10, Keras 2 et le format .h5
  • Dans le navigateur réel, le premier chargement prenait environ 1 seconde, puis l’exécution devenait quasi instantanée, avec un taux de réussite supérieur à 90 % sur plusieurs centaines de CAPTCHA réels

Objectif et code publié

  • L’objectif était de créer un modèle capable de résoudre de façon fiable les CAPTCHA de 4chan dans le navigateur, tout en apprenant le machine learning et TensorFlow
  • Le critère visé était une précision minimale de 80 %, avec si possible plus de 90 %, objectif finalement atteint
  • Le code associé est publié sur GitHub dans 4chan-captcha-playground

Fonctionnement du CAPTCHA de 4chan

  • 4chan exige la saisie d’un CAPTCHA avant de publier un message ou une réponse
  • Le CAPTCHA classique est une image contenant 5 à 6 caractères alphanumériques, que l’utilisateur doit tous saisir correctement
  • Le CAPTCHA à curseur fonctionne en alignant une image d’arrière-plan qui ressemble à des fragments de caractères aléatoires avec une image de premier plan comportant un trou transparent, afin de faire apparaître le texte du CAPTCHA

Limitations rencontrées lors de la collecte des CAPTCHA

  • En observant les requêtes de nouveaux CAPTCHA, le navigateur envoie une requête vers https://sys.4chan.org/captcha?framed=1&board={board}
  • En supprimant framed=1, on obtient du JSON brut à la place du postMessage() intégré dans le HTML
    • Le JSON contient notamment challenge, ttl, cd, img, img_width, img_height, bg, bg_width
    • ttl semble être la durée avant expiration du CAPTCHA, environ 2 minutes plus tard
    • cd est interprété comme la valeur de cooldown à attendre avant de pouvoir demander le CAPTCHA suivant
  • Lorsque les requêtes s’enchaînent, cd augmente progressivement
    • Au début, il est possible d’envoyer une requête toutes les 5 secondes
    • Puis cela passe à 8 secondes et continue ensuite à augmenter en doublant à peu près
    • Enfin, la valeur atteint un plafond à 280 secondes
  • Une fois ce minuteur de 280 secondes atteint, les CAPTCHA deviennent plus difficiles
    • Des images apparaissent avec plusieurs lignes horizontales et des éléments elliptiques parasites
    • La qualité des données baisse, mais elles restent exploitables
  • Avant de demander un CAPTCHA, il faut aussi passer Cloudflare Turnstile
    • Une approche reposant sur de nombreux proxys et de simples scripts n’était pas réaliste
    • Le script de collecte copiait les cookies Cloudflare depuis le navigateur et les remplaçait manuellement lorsqu’ils expiraient
  • Cette méthode a permis de collecter plusieurs centaines de CAPTCHA, mais cela restait insuffisant pour l’entraînement et il n’y avait pas de labels de réponse

Les limites de l’annotation humaine

  • L’alignement des CAPTCHA à curseur obtenait un taux de réussite de 100 % grâce à un script heuristique dans trainer/captcha_aligner.py
  • L’auteur a écrit trainer/labeler.py pour envoyer les CAPTCHA à un service commercial de résolution, où de vraies personnes saisissaient les réponses
  • Sur les premières dizaines de CAPTCHA envoyés, la plupart étaient résolus avec au moins un caractère erroné
  • La fonctionnalité « 100% Recognition » du service a été utilisée pour ne recevoir un résultat que lorsque plusieurs travailleurs donnaient la même réponse
    • Les paramètres étaient n = 2, x = 2, y = 3
    • Le CAPTCHA était d’abord envoyé à 2 personnes ; si leurs réponses ne correspondaient pas, il pouvait être envoyé jusqu’à 3 personnes supplémentaires jusqu’à ce que deux réponses coïncident
  • Avec ce réglage, environ 80 % des CAPTCHA étaient résolus, et parmi eux environ 90 % étaient corrects, mais environ 10 % contenaient encore des erreurs
    • Il arrivait que plusieurs travailleurs commettent la même erreur
  • Un script utilisateur a aussi été utilisé pour résoudre les CAPTCHA manuellement, seul ou avec l’aide de proches, puis enregistrer l’image et la bonne réponse
    • Cela a permis d’ajouter plusieurs centaines d’images supplémentaires au jeu d’entraînement
    • Cette approche a été abandonnée à cause du throttling des requêtes répétées et de la hausse de difficulté des CAPTCHA

Génération de données synthétiques

  • 4chan et le code de son CAPTCHA n’étant pas open source, il n’était pas possible d’exécuter exactement le même code en local
  • À la place, l’auteur a généré des CAPTCHA synthétiques qui reproduisaient approximativement la structure des vrais
  • Le CAPTCHA a été traité comme deux éléments distincts : l’arrière-plan et les caractères
    • L’arrière-plan a été obtenu en trouvant de grands contour dans les images réelles pour supprimer la zone des caractères
    • Une fois les caractères retirés, il ne restait qu’un fond bruité
  • Les caractères individuels ont été obtenus par annotation manuelle
    • Les caractères ont été tagués avec VoTT
    • Un script simple a ensuite servi à les extraire et à les post-traiter
    • Entre 50 et 150 images isolées ont été obtenues pour chaque caractère
  • Les CAPTCHA de 4chan ne contiennent que 0, 2, 4, A, D, G, H, J, K, M, N, P, R, S, T, W, X, Y
    • Il s’agit probablement d’un choix destiné à éviter les ambiguïtés
  • Les caractères extraits et les arrière-plans ont ensuite été combinés pour produire des images synthétiques correspondant aux motifs de placement observés
  • Comme les caractères d’entrée étaient déjà annotés, les réponses correctes des CAPTCHA synthétiques pouvaient elles aussi être générées automatiquement

Architecture du modèle et prétraitement

  • Les données d’entraînement mélangeaient des CAPTCHA à curseur préalablement alignés, des CAPTCHA classiques et des CAPTCHA synthétiques
  • Le script d’entraînement redimensionnait toutes les images en 300x80 pixels et les convertissait en noir et blanc pur
  • Le modèle suivait une architecture de type LSTM CNN, construite en s’inspirant de plusieurs articles sur la résolution de CAPTCHA
    • 3 couches convolution/max-pooling étaient utilisées
    • 2 couches LSTM étaient utilisées
    • Une 4e couche convolution avait aussi été testée, sans amélioration des performances
  • Comme la sortie pouvait faire 5 ou 6 caractères, un encodage CTC a été utilisé
  • L’implémentation reposait sur Keras et TensorFlow

Problème d’ordre des arguments de tf.image.resize()

  • Certains anciens CAPTCHA à curseur alignés ne correspondaient ni à la résolution 300x80 ni au bon ratio
  • Le script d’entraînement utilisait tf.image.resize() pour gérer ces entrées variées
  • Au départ, l’auteur avait supposé que les dimensions devaient être passées sous forme de tuple (width, height), alors que tf.image.resize() attend en réalité (height, width)
  • Cette erreur étirait les images verticalement en 80x300, les rendant illisibles
    • Même après plus de 32 epochs d’entraînement, les performances restaient très faibles sur les images observées
    • Sur les nouveaux CAPTCHA, les prédictions étaient proches du hasard
  • Le problème a été identifié en visualisant les images traitées en entrée, puis corrigé, ce qui a nettement amélioré les performances d’entraînement

Taille de l’entraînement et résultats

  • Le jeu de données final comprenait environ 500 images résolues manuellement et environ 50 000 images synthétiques
  • Les images synthétiques étaient générées par échantillonnage aléatoire à partir d’environ 2 500 images de fond et de 50 à 150 images pour chaque caractère
  • Le jeu de données était mélangé aléatoirement puis séparé en ensembles d’entraînement et d’évaluation selon un ratio 90/10
  • Sur un NVIDIA RTX A4000 Laptop GPU, le temps d’entraînement par epoch était d’environ 45 secondes
  • À la fin du premier epoch, la loss tournait autour de 19 et les prédictions étaient presque toutes fausses
  • À la fin du 4e epoch, la loss était tombée à 0,55, et 5 prédictions sur 5 lors d’un test aléatoire étaient correctes
  • La plage de 8 à 16 epochs représentait un bon compromis entre temps passé et performances finales
    • Vers le 8e epoch, la loss se stabilisait
    • Au-delà de 16 epochs, les gains devenaient très limités
  • L’inférence a été testée en Python avec trainer/infer.py, avec des résultats prometteurs même sur des images jamais vues

Conversion vers TensorFlow.js et exécution dans le navigateur

  • Le script utilisateur a été écrit avec TensorFlow.js et TypeScript
  • L’algorithme d’alignement des CAPTCHA et le code de prétraitement d’image du script Python ont été réimplémentés
  • Le code correspondant se trouve dans le répertoire user-scripts/ du dépôt
  • Le format de modèle Python TensorFlow/Keras n’est pas compatible avec celui attendu par TensorFlow.js
  • Il a donc fallu utiliser le script de conversion officiel, mais deux problèmes se sont posés
    • Le convertisseur officiel TensorFlow-vers-TFJS ne fonctionnait pas avec Python 3.12, sans message d’erreur vraiment explicite
    • En utilisant Python 3.10 avec PyEnv, la conversion a réussi
  • Le script de conversion pouvait convertir les modèles Keras 3 au format TensorFlow.js, mais TensorFlow.js était ensuite incapable de réellement les lire
    • Ce problème a été confirmé via ce forum post
  • La solution a été d’utiliser Keras 2
    • Le paquet legacy tf_keras a été installé
    • La variable d’environnement TF_USE_LEGACY_KERAS=1 a été définie pour l’entraînement
    • Le modèle a été exporté dans l’ancien format .h5, puis ce format d’entrée a été indiqué au script de conversion
    • Le changement dans le code s’est limité à une simple modification d’une ligne

Performances sur les vrais CAPTCHA de 4chan

  • Le modèle fonctionnait bien aussi sur les vrais CAPTCHA de 4chan
  • Le premier chargement du modèle prenait environ 1 seconde
  • Les exécutions suivantes étaient perçues comme quasi instantanées
  • D’après l’expérience accumulée sur plusieurs centaines de CAPTCHA réels dans le navigateur, le taux de réussite dépassait 90 %
  • Les erreurs de reconnaissance de caractères étaient rares ; lorsque le modèle se trompait, il omettait généralement un caractère entier
  • Il y aurait encore une marge d’amélioration en ajoutant davantage de données réelles à l’entraînement ou en ajustant la disposition des CAPTCHA dans le générateur synthétique
  • La précision du modèle était bien supérieure à celle des services commerciaux de résolution humaine de CAPTCHA

CAPTCHA à 4 caractères et conclusion

  • Après la fin du projet, pendant la rédaction et l’édition de l’article, 4chan a commencé à proposer parfois des CAPTCHA à 4 caractères
  • Le modèle n’avait été entraîné que sur des CAPTCHA à 5 et 6 caractères, mais il montrait un niveau de performance similaire aussi sur les CAPTCHA à 4 caractères
  • Le projet a permis d’apprendre beaucoup sur le machine learning et la vision par ordinateur, tout en atteignant l’objectif initial : créer un modèle de résolution de CAPTCHA dans le navigateur

1 commentaires

 
GN⁺ 2024-11-30
Réactions sur Hacker News
  • L’intégration entre Keras et TensorFlow.js est bancale, ce qui est très typique de TensorFlow
    Quand on utilise TensorFlow, on a toujours eu l’impression non pas d’un produit intégré et fluide, mais d’un ensemble d’outils vaguement liés rassemblés sous une même bannière
    On pourrait même dire que c’est l’impression que donnent tous les bibliothèques open source et outils de Google

    • À ce propos, il y avait un contexte similaire dans un billet d’il y a 15 jours annonçant que François Chollet quittait Google : https://news.ycombinator.com/item?id=42130881
      À la question « Pourquoi avoir décidé en 2019 de fusionner Keras avec TensorFlow ? », la réponse était : « Ce n’est pas moi qui ai pris cette décision. C’était une décision prise en 2018 par les responsables de TF, et à l’époque j’étais contributeur individuel L5, tandis que c’était une décision de niveau L8 »
    • Ça fait penser à la loi de Conway
  • J’avais besoin d’un CAPTCHA pour empêcher le spam sur le formulaire de commentaires de mon site[0], et j’ai réutilisé une méthode amusante que j’avais vue auparavant
    Ce n’est absolument ni parfait ni difficile, mais j’ai vraiment adoré le processus de création
    [0] https://www.hybridlogic.co.uk/contact

  • Il y a une raison pour laquelle les gens se sont éloignés des CAPTCHA à texte déformé
    On est presque arrivé au point où les ordinateurs les résolvent mieux que les humains
    https://www.usenix.org/system/files/conference/woot14/woot14... est un article sur le sujet, que je trouve assez intéressant
    Malgré tout, un nombre surprenant de CAPTCHA textuels peuvent être résolus avec quelques lignes de shell script qui convertissent l’image en niveaux de gris avec ImageMagick, appliquent des opérations de dilatation et d’érosion, puis l’envoient à Tesseract
    Mais il existe aussi des sites comme https://2captcha.net, donc au final un CAPTCHA ressemble surtout à un mécanisme qui exige un minimum de petit effort

    • Le fait qu’on puisse techniquement le contourner ne le rend pas inutile
      La solution présentée dans cet article a demandé beaucoup de temps, de compétences et d’efforts, et le résultat se généralise mal : pour un autre type de CAPTCHA, il faudrait tout recommencer depuis le début
      La plupart des spammeurs ne pourront pas le reproduire, et ceux qui le peuvent ont de bonnes chances de gagner de l’argent légalement ou de viser des cibles plus rentables
      Ce type de CAPTCHA fonctionne donc encore très bien pour faire monter le coût d’un spam réussi au-dessus du revenu attendu
    • Je me demande ce qui viendra ensuite
      Pourrait-on créer un forum où tous les membres doivent passer un entretien vidéo de 15 minutes avec l’administrateur ? Je sais que « ce n’est pas scalable », mais comme dispositif de plaisanterie absurde, ça semble possible
    • À mon avis, un CAPTCHA n’est qu’une ligne de défense supplémentaire qui augmente la difficulté pour les acteurs abusifs
      Ce n’est pas une solution, juste une petite forteresse qui se dégrade peu à peu
    • Je ne dirais pas que c’est petit
      D’après le lien, reCAPTCHA v3 prend 10 à 15 secondes et coûte 1,3 dollar pour 1 000 CAPTCHA
      Pour beaucoup de tâches qui cherchent à contourner des CAPTCHA, comme le scraping massif de gros sites, ce coût devient réellement important et difficile à absorber
    • À ce niveau-là, les CAPTCHA par preuve de travail sont peut-être la meilleure option
      mCaptcha.org en est un exemple, et il existe d’autres implémentations
      Les CAPTCHA traditionnels, dès qu’ils deviennent un tant soit peu efficaces, tournent facilement au cauchemar du point de vue de l’accessibilité
  • Si ce sujet vous intéresse, j’ai aussi une analyse du CAPTCHA de Silk Road que j’avais rédigée en 2014 : https://github.com/mieko/sr-captcha

  • La réponse de 4chan semble appropriée
    Puisque les réseaux neuronaux les résolvent de toute façon facilement, autant simplifier la tâche donnée aux humains
    Désormais, même si l’on conçoit des CAPTCHA très difficiles, il est peu probable qu’ils deviennent plus durs pour les machines ; en revanche, ils risquent surtout d’agacer davantage les humains

    • Dans ce cas, ils pourraient aussi simplement bloquer complètement la publication pour les utilisateurs gratuits, et obliger tout le monde à acheter un 4chan Pass à 20 dollars par an pour pouvoir poster
      https://4chan.org/pass
      C’est déjà proposé comme option pour poster sans CAPTCHA
      Si les CAPTCHA sont totalement devenus inefficaces, la conclusion logique serait de supprimer les CAPTCHA et la publication gratuite, et d’exiger de tous ceux qui veulent poster qu’ils achètent un 4chan Pass
    • J’ai l’impression qu’ils sont coincés à ce stade depuis au moins 5 ans, voire 10 ans
    • La prochaine étape, ce sera simplement un scan rétinien Worldcoin
    • 4chan se soucie assez peu de l’agacement des humains
      Ils ont récemment introduit un délai de publication de 15 minutes, et c’est vraiment exaspérant
      J’ai dû mettre 4chan sur la liste blanche dans Cookie AutoDelete
  • Je me demande s’il ne vaudrait pas mieux faire semblant d’avoir un CAPTCHA tout en analysant en réalité le timing et le comportement de l’utilisateur
    Honnêtement, j’ai l’impression que c’est probablement déjà le cas
    En poussant l’idée jusqu’au bout, on pourrait même entraîner une IA à déterminer si l’acteur en face est un humain ou non
    Autrement dit, ce serait l’invention d’un test de Turing inversé : si l’IA n’arrive pas à distinguer la réponse d’une personne de celle d’un humain « normal », on considère que c’est un humain
    La différence, c’est qu’il ne s’agirait pas de distinguer des réponses humaines destinées au marketing
    Rien que d’y penser, ça me donne un peu la nausée, je vais m’allonger

    • Les grands fournisseurs de CAPTCHA font déjà en grande partie ça
      Avant même d’afficher un CAPTCHA, ils identifient d’abord l’empreinte TLS, l’IP, HTTP/2, les requêtes, l’environnement JavaScript, la capacité de rendu des polices et des images, ainsi que le navigateur lui-même
      Avec ces informations, ils calculent un score de confiance et décident s’ils doivent montrer un CAPTCHA dès le départ
      Ce n’est qu’ensuite qu’analyser la saisie du CAPTCHA a du sens, mais à ce stade, 90 % des bots sont déjà arrêtés
      La quantité d’informations qu’un navigateur peut transmettre au serveur sans aucune interaction est hallucinante, au point que notre empreinte numérique est probablement plus unique que notre vraie empreinte digitale
    • C’est exactement ce que fait reCAPTCHA
  • À mon avis, le cas fondateur du contournement du CAPTCHA de 4chan reste celui où Yannick Kilcher a affiné GPT-J sur le dataset « Raiders of the Lost Kek »
    C’est peut-être l’un des usages de grand modèle de langage les plus impressionnants montrés en vidéo : https://youtu.be/efPrtcLdcdM?si=errY0PrEhnX9ylDw

    • Rien que les avertissements et clauses de non-responsabilité sur 4chan durent presque une minute
      C’est un record
  • À cause de choses comme « le convertisseur officiel de modèles TensorFlow vers TFJS ne fonctionne pas sous Python 3.12 et n’est pas correctement documenté » ou « TensorFlow.js ne prend pas en charge Keras 3 », j’ai failli abandonner il y a quelques années en essayant simplement de toucher un peu au machine learning
    Trop de tutoriels récents étaient déjà obsolètes, il y avait trop de pièges aléatoires, et il était frappant de voir à quel point les guides « getting started » supposaient déjà qu’on était un expert

    • En tant que personne qui fait du machine learning depuis quelques années, je conseillerais d’éviter les modes du moment
      Mieux vaut apprendre les bases avec un vieux manuel de statistiques bayésiennes, puis passer à un framework majeur comme PyTorch
      Au début, il vaut mieux écrire soi-même toutes les parties des architectures CNN, RNN et Transformer ainsi que du pipeline d’entraînement
      Y compris le data loader, mais sans aller jusqu’aux noyaux matriciels CUDA
      Mieux vaut rester loin des wrappers qui re-encapsulent les wrappers de quelqu’un d’autre, comme LangChain
      La documentation est souvent plus qu’ancienne : elle peut être carrément fausse sur les bases
      Hugging Face est excellent si on maîtrise les fondamentaux et qu’on sait réparer un wrapper standard quand il casse
  • C’est un peu comme passer des heures à apprendre comment ouvrir le couvercle d’une fosse septique

    • Étrangement, la majeure partie de 4chan donne moins l’impression de ramollir le cerveau que Twitter avant Musk
    • Il ne faut pas sous-estimer ce qu’on peut apprendre en étudiant les systèmes de fosses septiques
  • Si on suit les liens vers les services de résolution de CAPTCHA, on peut lire le profil des gens qui font ce travail
    C’est présenté comme étant plus éthique que de travailler dans une usine dangereuse