BLOG

Handwired : Écrire le code JS de manière manuelle, comme s’il s’agissait d’une réseau de neurones

Yongliang
AItech
广告 · Advertisement

Le 15 octobre, le membre du groupe React, chenglou, a publié handwired sur GitHub. La première phrase du README est : « Transformez votre code JavaScript ordinaire en un réseau neuronal ; pas besoin de entraînement, le résultat est précis et entièrement différentiable ». Le 20 octobre, le repository avait reçu 1804★ de popularité, principalement grâce aux articles trending sur GitHub et aux médias sociaux. Le projet a été écrit en TypeScript et suit le protocole MIT. L’outil de construction est bun, et la démo en ligne se trouve sur chenglou.me/handwired. Sur le plan local, il suffit de bun install && bun start pour l’exécuter. Cet article analyse le projet en six parties.

Ce qui rend ce projet particulier, c’est qu’il ne suit pas la voie traditionnelle de « simuler un programme avec un réseau neuronal entraîné », mais au contraire : on écrit d’abord le programme, puis on le compile pour qu’il puisse fonctionner comme un réseau neuronal. Cette méthode inverse transforme le réseau neuronal d’un « apprenant » en un « exécutant ».

I. Qui est-ce ?

L’auteur, chenglou, est un développeur connu sur GitHub et membre du groupe React. Il a publié handwired sous forme de projet personnel. D’après les archives des expériences dans le dossier lab, il y avait des logs quotidiens d’expérimentation depuis le début septembre, ainsi que des discussions de conception en juin et juillet, ce qui indique une longue période de préparation avant la publication. Les nombreux contributions réalisés peu après la publication doivent être interprétés comme une « publication définitive après une longue préparation avec organisation continue », et non comme une construction complète en une seule fois. Ce rythme de publication n’est pas rare dans le monde open source : on travaille d’abord en secret, puis on publie tout en même temps, utilisant les médias sociaux pour augmenter l’attention initiale.

En termes de taille du projet, le répertoire src/ contient des modules tels que runtime, handwiredos, json-search. Les fichiers clés mesurent environ : src/runtime/numeric-ui-core.ts 152 KB, src/runtime/cells.ts 22 KB, src/runtime/host-timing.ts 21 KB. Le repository est principalement composé de TypeScript, à 90,5 %, ce qui le rend un projet complet avec documents, tests et démo en ligne, et non une simple démonstration conceptuelle au niveau de gist. Son objectif n’est pas de devenir un autre framework front-end, mais de fournir une implémentation référentielle exécutable pour le principe « le programme est un réseau ». Pour les développeurs souhaitant comprendre rapidement le differentiable programming, ce repository offre un point de départ direct pour du clone, de l’exécution et des modifications.

II. Analyse du mécanisme

Le point de départ de handwired : tout programme se résume à des conditions if-else, des boucles et des états, et il faut transformer ces trois éléments en « multiplication matricielle + ReLU » pour l’exécution sur des nombres flottants.

L’exemple donné dans le README est le plus intuitif. Une branche comme (a > 4) ? 10 : 12 peut être réécrite en calcul pure :

above4 = max(0, a - 4) - max(0, a - 5)   // 1 si a > 4, sinon 0
result = above4 * 10 + (1 - above4) * 12 // Calculer les deux branches, puis choisir avec above4

Où max(0, x) est le ReLU. Ces primitives de contrôle de flux, comparaison et sélection, sont donc codées en addition, soustraction, multiplication et ReLU. Les boucles et les états fonctionnent de la même manière : les états sont stockés dans une table source de type Float32Array, et à chaque itération, on lit la table, calcule et réécrit.

Pour lier tout le processus de compilation, handwired exécute une JavaScript normale lors de la construction, déployant des macros comme emitMultiply et emitCompare en instructions de longueur fixe ; pendant l’exécution, il n’y a pas de branches ou de boucles, seule une évaluation séquentielle de cette table de nombres flottants est effectuée. Cela signifie également que, une fois le programme compilé, son chemin d’exécution est déterminé, permettant à la GPU de scheduler un grand nombre de threads isomorphes en une seule fois, sans avoir à gérer des branches dynamiques pendant l’exécution.

La prochaine étape est la collecte : toutes les additions, multiplications et ReLU du programme sont intégrées dans une grande opération matmul, qui est exécutée en JS ou avec WebGPU. Comme seuls ces deux primitives sont utilisées, le README propose trois propriétés : tout le programme reste dérivable ; les poids sont écrits manuellement, sans nécessité de entraînement ; les technologies d’optimisation matures de la GPU sont particulièrement efficaces pour ces primitives minimalistes.

L’innovation centrale du projet réside dans le fait qu’il ne s’agit pas d’entraîner un réseau pour approximer le programme, mais de compiler précisément un programme écrit manuellement en une structure de réseau neuronal. Les poids ne sont pas le produit de l’entraînement, ils font partie du programme lui-même. Ce triple objectif de « sans entraînement, précision, dérivabilité » est atteint grâce à la sélection de la direction de la compilation. En d’autres termes, le réseau neuronal ici ressemble davantage à un format d’exécution de programme qu’à une fonction approximative apprise des données.

L’intérêt de cette approche réside dans le fait qu’elle déplace la « dérivabilité » du processus d’entraînement vers le processus de compilation. Les réseaux neuronaux traditionnels nécessitent de grandes quantités de données et une propagation rétroactive pour ajuster les poids ; handwired vous permet d’écrire d’abord un comportement déterministe avec une logique de programme familière, puis conserve sa structure de gradient pour l’intégrer à l’optimiseur lorsque nécessaire. Il ne s’agit pas de remplacer l’entraînement, mais de repousser la frontière entre « entraînement » et « programme » d’un pas en arrière.

3. Qualité ingénieuse

D’après la structure des répertoires, src/ est le noyau du runtime, lab/ sont les projets expérimentaux, template/ sont les modèles, et docs/ sont les documents. La partie runtime comprend principalement des fichiers comme cells, host-timing, numeric-ui-core. Le fichier numeric-ui-core.ts mesure environ 152 KB et constitue le noyau du runtime numérique/Ui.

La proportion de TypeScript dans le repository atteint 90,5 %, ce qui indique qu’il ne s’agit pas d’une implémentation légère, mais plutôt d’un projet où les calculs numériques, la synchronisation des animations et les interactions avec l’hôte sont intégrés. Les documents dans le répertoire docs couvrent les modèles d’exécution, les tutoriels, les modes et les choix de comportement, ce qui est très avantageux pour ceux qui souhaitent comprendre la programmation dérivable. Cette densité de développement montre également que handwired n’est pas le fruit d’une idée surgie du jour au lendemain, mais un système qui a été développé à travers plusieurs itérations.

En termes de relations de dépendance, handwired ne prend pas en charge des runtime lourds. Le package.json contient uniquement TypeScript, les outils de test et de lint, et le logiciel central est entièrement auto-contained. Cette sélection permet au repository de rester légère, mais cela signifie également qu’il ne peut actuellement couvrir que les fragments de code qui peuvent être exprimés via l’API builder. Pour les grands systèmes commerciaux existants, une migration directe n’est pas réaliste ; la voie plus réaliste consiste à extraire et réécrire les fragments de calcul intensif. Du point de vue de la structure du code source, le répertoire tests est coordonné avec le répertoire template, ce qui indique que l’auteur souhaite que les utilisateurs partent des modèles pour transformer progressivement le JS ordinaire en style handwired.

La démo en ligne et les exemples dans le répertoire template constituent l’entrée la plus intuitive : un composant UI écrit en JS ordinaire, après avoir été transformé par le code builder de handwired, devient une table de valeurs qui peut être exécutée sur GPU. Pendant la phase de construction, un JavaScript ordinaire est exécuté une fois, et les macros comme emitMultiply et emitCompare sont transformées en instructions de longueur fixe ; pendant l’exécution, il n’y a pas de branches ni de boucles.

Cette approche est naturellement attrayante pour les ingénieurs front-end : vous n’avez pas besoin d’écrire du CUDA ou du WGSL, vous只需 utiliser l’API builder de JavaScript pour décrire les calculs numériques, et le reste – la transformation, la collecte et l’exécution – est géré par handwired. Pour ceux qui sont habitués aux composants déclaratifs de React, cela équivaut à remplacer « l’arbre des composants » par « un diagramme de programmation numérique », mais la interface reste écrite en JavaScript. Cela signifie également que les ingénieurs front-end peuvent utiliser leur langage le plus familier pour explorer la parallélisation GPU et la programmation dérivable, avec un seuil d’entrée beaucoup plus bas que l’apprentissage d’un nouveau langage.

Cependant, la convivialité de l’API builder présente également des limites : tous les calculs doivent pouvoir être exprimés via les primitives fournies par le projet, et toute opération dépassant ce cadre doit être traitée dans le JavaScript ordinaire. handwired ressemble davantage à un langage spécifique intégré dans JS qu’à une traduction indifférenciée de la syntaxe JS.

Quatrième partie : Effets et vérification

L’effet de la description du repository se divise en trois niveaux. Le premier niveau est le proof of concept : les conditions if-else, les boucles et les mappages d’états sont transformés en multiplications matricielles et en ReLU, et le programme fonctionne toujours de manière précise et différentiable. Le deuxième niveau est la démonstration : la démo en ligne montre un système d’interface utilisateur complet, HandwiredOS, où les interactions telles que le déplacement des fenêtres, l’agrandissement, le clic pour sélectionner, le changement de paragraphe du texte, le défilement virtuel des listes sont intégrées dans le programme numérique. Le hôte se charge simplement d’enregistrer les événements du navigateur dans la table source, de l’exécuter une fois pour effectuer la valeur, et de récupérer l’output dans le DOM. Le troisième niveau est la démonstration des performances : la démo de recherche JSON prétend pouvoir effectuer des recherches sur 100 000 documents en quelques millisecondes, grâce à la parallélisation isomorphe, c’est-à-dire que chaque document subit les mêmes opérations sans interférence. En d’autres termes, la valeur de la démonstration de handwired réside dans la preuve que « un programme peut fonctionner sur une table de nombres à virgule flottante » est possible, et non seulement théoriquement. Elle transforme le concept abstrait en une démo visible dans le navigateur, ce qui est l’une des raisons principales de ses nombreux éloges.

Cependant, les auteurs qualifient cela de projet expérimental. Le style du README « what does that even do? Let’s find out! » ainsi que les questions telles que « En connectant un programme spécifique au formatage pour une formation end-to-end avec un réseau neuronal général, nanoGPT peut apprendre à la fois Shakespeare et votre interface utilisateur ? » indiquent qu’il s’agit plus d’un projet exploratoire qu’une outil mature.

V. Limites et controverses

Tout d’abord, il y a les limites de la description. Le passage du README « Transformez votre code JavaScript ordinaire en réseau neuronal » peut prêter à confusion, car on pourrait croire qu’il est possible de compiler automatiquement n’importe quel JS en réseau ; mais en réalité, il exige que le programme soit réécris manuellement avec les langages fournis par le projet et les contrats numériques, et non un compilateur JS général.

Ensuite, il y a les limites numériques. Le codage des entiers en ReLU dépend de la position des opérandes dans la grille et la plage annoncées ; dans le monde des nombres à virgule flottante, les entrées hors plage ne sont pas traitées de manière magique ; l’lecture des index est également limitée. Les développeurs doivent maintenir ces contrats numériques activement.

Le troisième niveau est la limite de la taille. Lorsque les opérations se déroulent des deux côtés d’une branche, les opérandes augmentent avec la complexité du programme. handwired est adapté pour vérifier l’idée que « le programme est un réseau », mais si tout le flux de contrôle d’un système commercial réel était transformé en opérations matricielles, la taille et les coûts de débogage augmenteraient rapidement. Cela signifie également que handwired est actuellement plus adapté pour des scénarios de calcul intensif locaux tels que les contrôles, les recherches et les animations, plutôt que pour tout le système logique du business.

Enfin, il y a la limite de l’écosystème. En tant que projet expérimental récemment lancé, handwired n’a pas encore formé une communauté stable ni un chaîne d’outils. Les bibliothèques tierces, les plugins d’éditeur et les outils de débogage ne sont pas encore matures. Si une entreprise souhaite l’intégrer, elle doit assumer à la fois les coûts de maintenance et les coûts cognitifs.

Enfin, il y a la différence entre la diffusion et la popularité. Sur GitHub, le score de 1804 est très élevé, et HN est également apparu plusieurs fois en première page ; mais les nombreux éloges mesurent davantage la pertinence du sujet que la production d’une adoption. Les interfaces peuvent changer à tout moment, et les issues ouvertes augmentent, donc il n’est pas approprié de s’appuyer directement sur ces outils actuellement.

VI. Conclusion

La valeur de handwired réside dans le fait qu’il transforme l’idée que « une routine ordinaire peut être compilée en un réseau neuronal dérivable » d’un slogan vers une échelle de démonstration. Il remet en question la perception établie selon laquelle les réseaux neuronaux doivent être entraînés, et montre que la dérivabilité peut naître à partir de la structure de compilation, plutôt que d’être imposée par la propagation rétroactive. Cette approche complète les pratiques actuelles de développement d’IA qui dépendent massivement des données d’entraînement : dans certains contextes, la structure même de la routine peut garantir la dérivabilité, sans avoir besoin de modéliser l’ensemble du problème comme une question d’optimisation.

Le fait que le projet ait atteint le rang 1804 en seulement 4 jours montre que ce sujet a touché la curiosité de la communauté ; cependant, pour déterminer s’il s’agit d’un jouet de recherche ou d’un signal de paradigme, il faudra voir si quelqu’un développera des applications réelles à partir de lui et si quelqu’un pourra étendre cette méthode à des flux de contrôle plus complexes. À ce stade, il convient davantage de le considérer comme une entrée de niveau pédagogique pour comprendre la programmation dérivable et la compilation numérique, plutôt que comme un nouveau framework front-end immédiatement utilisable. Pour les développeurs du domaine des frontends et des compilateurs, handwired offre une manière intéressante de représenter les routines ; pour les équipes souhaitant l’appliquer directement, il nécessite encore plus de验证 et de développement d’un écosystème.

Un objet de comparaison intéressant est le réseau neuronal traditionnel. Les réseaux traditionnels utilisent l’entraînement pour trouver les poids, avec l’avantage d’une grande généralité, mais la conséquence est que leur comportement est inexplicable et qu’ils nécessitent de grandes quantités de données. handwired utilise les routines pour spécifier directement les poids, avec l’avantage d’un comportement déterminé et explicable, mais le désavantage est que sa capacité de représentation est limitée par la complexité des programmes que peuvent écrire les programmeurs. Les deux ne sont pas une substitution, mais une complémentarité. Dans certains contextes où l’explicabilité et la détermination sont essentielles, comme les animations UI, le calcul financier ou la simulation physique, l’approche de handwired pourrait être plus fiable que celle des réseaux entraînés.

Il ne changera pas nécessairement votre manière de programmer demain, mais il creuse effectivement une brèche dans le mur entre les routines et les réseaux. Les questions à suivre à l’avenir incluent : peut-il supporter des flux de contrôle plus dynamiques ? Peut-il réduire la taille et la croissance tout en conservant sa dérivabilité ? Peut-il se compléter avec les frameworks front-end existants plutôt que de les remplacer ? Ces questions n’ont pas de réponses prêtes, mais c’est précisément elles qui permettent à handwired de rester un sujet de discussion intéressant.

Sources d’information

  • Répertoire GitHub : chenglou/handwired (README, docs/, src/, lab/)
  • Packages de faits : /Users/kael/xhs-content/drafts/2026-10-20-facts-packages.json (taille du répertoire, auteur, mécanisme central, adresse Demo, capacité de propagation)
  • Démo en ligne : https://chenglou.me/handwired/
广告 · Advertisement

Questions fréquentes

Qu’est-ce que Handwired ?

Handwired est un outil qui convertit du code JavaScript en réseaux neuronaux différenciables, permettant leur exécution sans entraînement.

Qui est l’auteur de Handwired ?

L’auteur de Handwired est chenglou, un développeur connu sur GitHub et membre du groupe React.

Comment fonctionne Handwired ?

Handwired écrit d’abord le programme, puis le compile pour qu’il puisse fonctionner comme un réseau neuronal, inversant ainsi la méthode traditionnelle de simulation d’un programme avec un réseau neuronal entraîné.