BLOG
Handwired: Verwandelt normale JS-Code in ein neuronales Netzwerk, in 4 Tagen 1730 Sterne.
Am 15. Oktober hat der Entwickler chenglou einen Repository namens handwired auf GitHub erstellt. Die erste Zeile des README-Textes lautet: „Verwandeln Sie Ihren normalen JavaScript-Code in ein neuronales Netzwerk; ohne Training, präzise und dennoch vollständig differenzierbar.“ Bis zum 19. Oktober hatte das Repository einen Rang von 1730★, 143 Fork-Vorgänger und 9 offene Probleme. In nur 4 Tagen erreichte es 1000 Sterne. Der einzige Beitragsträger, chenglou, hat 825 Commits vorgenommen. Das Projekt ist unter der MIT-Lizenz veröffentlicht, mit TypeScript und bun als Build-Tool. Die Online-Demo befindet sich unter chenglou.me/handwired. Um es lokal auszuführen, muss man bun install && bun start ausführen. Interessant ist der Verbreitungspfad: In derselben Zeit gab es nur 5▲ und 4▲ Commits auf HN, wobei fast die gesamte Popularität von GitHub kam. Dieser Artikel wird wie gewohnt in sechs Abschnitten dargestellt.
1. Wer ist der Entwickler?
Der Autor ist chenglou mit einem Karma-Wert von 1295. In der persönlichen Präsentation werden nur die GitHub- und Twitter-Links angegeben. Die Communityinformationen zeigen, dass er ein bekannter Entwickler in der React-Ökologie ist (Autor von React Motion, Verbreiter von ReasonML, früher bei Meta tätig). Dieser Hintergrund wurde in diesem Artikel nicht separat überprüft; der Text wird einfach als „Entwickler chenglou“ behandelt.
Es gibt eine zeitliche Differenz bezüglich des Projekts: Das Repository wurde am 15. Oktober erstellt, aber die Experimente im Lab-Verzeichnis wurden bereits Anfang September geschrieben und beziehen sich auf Diskussionen über Design im Juni und Juli. Mitte September gab es tägliche Updates zu den Experimenten, was darauf hindeutet, dass die Entwicklung viel früher stattfand als die Öffentlichkeit. Die 4 Tage mit 825 Commits entsprechen dem Commit-Rhythmus des offenen Repositories, nicht der gesamten Entwicklungszeit des Projekts. Es ist besser, dies als „langfristige Vorbereitung mit einmaliger Veröffentlichung und kontinuierlicher Organisation“ zu verstehen.
Lokale Testung (leichter Clone, 10-19): Insgesamt gibt es 1542 Dateien im Repository, davon 1101 ts-Dateien, was etwa 275.000 Zeilen entspricht; das src-Kernverzeichnis umfasst etwa 18.000 Zeilen, das Lab-Experimenteverzeichnis etwa 235.000 Zeilen und das Testsverzeichnis etwa 22.000 Zeilen. Die sechs Dokumente imdocs-Verzeichnis haben insgesamt 1.296 Zeilen. Die Verteilung der Dateitypen ist: ts-Dateien 1101, json-Dateien 151, md-Dateien 141, txt-Dateien 49, html-Dateien 38 und css-Dateien 22. Dies ist keine einfache Ideendemonstration auf Gist-Ebene, sondern ein vollständiges Projekt mit Dokumenten, Tests, Tutorials und einer Online-Seite.
2. Mechanismusanalyse
Der Ansatz von handwired: Programme bestehen aus if-else-Regeln, Schleifen und Zuständen. Das Projekt verwandelt diese drei Elemente in „Matrixmultiplikationen mit Reglu“ zur Ausführung auf Fließkommazahlen.
Das README gibt ein sehr intuitives Beispiel. Eine Abzweigung wie a > 4 ? 10 : 12 kann in reines Arithmetik umgewandelt werden: Zuerst wird above4 = max(0, a-4) - max(0, a-5) berechnet, wobei max(0, x) ReLU ist. Für die ganze Zahl a gilt: above4 ist 1, wenn a>4, sonst 0. Anschließend wird result = above4*10 + (1-above4)*12 berechnet. Beide Abzweigungen werden berechnet, und above4 wählt einen aus. Der Vergleich und die Auswahl dieser Kontrollstrategien werden so in Addition, Multiplikation und ReLU umgewandelt. Für Schleifen und Zustände gilt dasselbe: Der Zustand wird in einem Float32Array-Template gespeichert, und bei jeder Iteration wird das Template gelesen, berechnet und zurückgesetzt.
Das nächste Schritt ist die Sammlung: Alle Additionen, Multiplikationen und ReLU-Aufgaben werden in eine große matmul-Matrix eingefügt, die auf JS oder WebGPU ausgeführt wird. Da nur diese beiden Grundoperationen verwendet werden, gibt das README drei Eigenschaften an: Das gesamte Programm bleibt differenzierbar; die Gewichte sind handschriftlich und erfordern keinen Trainingsprozess; die bewährte Optimierungstechnik der GPU (fusion, sparsität, reordnung) ist besonders effektiv bei dieser reduzierten Struktur.
Die Definitionen in docs/execution-model.md sind viel strenger als im README. Das Programm besteht aus einer Reihe von festlängeren Anweisungen, wobei es nur vier Arten gibt: affine (affine Gewichtung), reglu (left * max(0, gate), wenn gate konstant 1 ist, wird zu ReLU), boolean (die Werte zwischen 0 und 1 zu einem präzisen 0 oder 1 festlegen) und index (Tabelle-Leseoperation, also die Auswahl aus der Kandidatentabelle nach floor(Index)). Alle numerischen Semantiken werden auf dem Rundungsniveau von FP32 gespeichert, und affine Elemente werden einzeln froundiert. Der Dokumentation zufolge muss jede Plattform bitweise mit dem Referenz-Evaluiergerät übereinstimmen.
Der Vergleich wird nicht nur durch ReLU-Encoding realisiert. emitCompare erzeugt direkt präzise Bits auf der Anzahl der ganzen Zahlen: Auf einer 1/64-Matrix benötigt a>=b nur 2 Operationen und 2 Schichten; ohne Anzahlangabe erfolgt eine symbolische Kaskade, wobei a>=b im Bereich von 0..16.384 15 Operationen und 14 Schichten erfordern. Die Index-Leseoperation verfügt über eine spezielle lowering-Funktion, die bei beliebigem Tabellengröße in einer Operation abgeschlossen wird, wobei der Indexbereich auf ±2^24 beschränkt ist. Was Sie schreiben, ist nicht ein Befehlsplan, sondern „Builder-Code“: Normaler JavaScript wird während des Build-Prozesses einmal ausgeführt, um emitMultiply und emitCompare in Befehle zu wandeln. Während der Ausführung gibt es keine Schleifen oder Iterationen.
Differenzierbarkeit ist ebenfalls strukturiert, nicht nur durch Patches. Der Gradient kann entlang dieser vier Anweisungen zurückgeführt werden: Der Gradient von affine ist die Koeffizienten, der Gradient von reglu enthält ReLU-Tore, und solche festgelegten Operationen wie boolean werden im Dokument als „rounding point“ bezeichnet. Die Plattform kann andere Summen frei umordnen und fusionieren, aber diese Punkte müssen semantisch konsistent sein. Bei der Berechnung des Gradienten für Indizes muss der Aufrufer explizit eine von zwei Strategien wählen: zero oder backward-difference, sonst wird ein Fehler ausgelöst. Das Design zwingt dazu, einen Fehler zu melden, anstatt heimlich einen undefinierten Gradienten zu geben. Diese Vereinbarungen machen die Aussage „Das gesamte Programm ist differenzierbar“ zu einem begrenzten Vertrag.
Noch einen Schritt weiter sind Zeit und Animationen. host-timing.ts zerlegt die Spring-Animation in 4ms-Schritte auf und berechnet eine 2×2-Schrittmatrix basierend auf Haltbarkeit und Dämpfung. Jede Frame des Hosts schreibt die Matrix in 4 Eingabezellen ein, und das Programm verwendet emitApplySpringMatrix, um sie anzuwenden. Das bedeutet, dass sogar UI-Animationen, die am wenigsten wie ein neuronales Netzwerk erscheinen, in dieselbe numerische Tabelle kompiliert wurden.
III. Engineering-Qualität
Die Datei src ist in vier Teile unterteilt: runtime ist der Kern des Laufzeitbetriebs, die Dateien cells, host-timing, numeric-ui-core und prefix-networks; handwiredos ist eine vollständige Desktop-Demonstration, bei der das Fenstermanager, Photos, Notes und Files alle als numerische Programme kompiliert wurden, etwa 5500 Zeilen umfassend; json-search hat etwa 6200 Zeilen und stellt eine Such-Demonstration dar; learned-gallery ist eine Lern-Demonstration. Im Verzeichnis tests befinden sich 42 Testdateien, die verschiedene Semantiken, Gathering Lowering, numerische Semantik und Spring-Matrix-Operationen abdecken, und json-search enthält mit einem Modul 184 Tests, die etwa 45 Sekunden dauern. Im Verzeichnis template befindet sich ein Lehrbeispiel für Schalterknöpfe, in docs/tutorial.md wird jede Zeile erklärt, begleitet von einer Referenzimplementierung in normalem JS, wobei getestet wird, dass die Ausgaben beider gleich sind. In docs befinden sich außerdem patterns.md (484 Zeilen), behavior-choices.md und execution-model.md sowie sechs weitere Dokumente, was zeigt, dass die Engineering-Vorgehensweise sehr ordentlich ist.
HandwiredOS ist eine Demonstration, die weitere Erwähnung verdient. Es ist die überzeugendste Darstellung im gesamten Repository. Fensterziehen, Maximierung, Auswahl von Bildern per Klick, Zeilenumbrüchten von Texten und virtuelles Scrollen durch Listen finden keine Erwähnung im Host-JS, sondern werden in die numerischen Programme kompiliert: Die Fensterprüfung wird mit emitCompare auf einer 1/64-Pixel-Grid berechnet, die Zeigerkoordinaten werden zuerst auf die Grids gerundet und dann in das Programm eingefügt, sodass jede Vergleichung exakt ganzzahlige Positionen hat. Die virtuelle Liste im Files-Fenster ist einfach der Wertliste des Programms selbst, wobei 64 DOM-Slots von dem Programm besetzt werden. Der Host ist nur dafür verantwortlich, Browser-Ereignisse in die Quelldaten zu schreiben, einmal zu berechnen und die Ausgabe wieder ins DOM zu schreiben. Mit anderen Worten: Ein funktionierendes Desktop-System hat beim Laufzeitbetrieb eine Matrixoperation auf einer Fließkomma-Tabelle.
Die Leistungsdaten sind in lab/status.md auf Mikrosekunden genau aufgezeichnet. HandwiredOS als ganzes Desktop-System wurde in 20,381 aktive Operationen, 230 Schichten und 45,436 Speichergewicht kompiliert, die einzelne Berechnung dauert etwa 133µs, die leeren Frames etwa 141µs und das Tippen etwa 282µs. Im README von json-search wird selbst zugegeben, dass eine einzige GPU-Rück- und Vorbeifahrt mehr als 0.6ms dauert, was keinen Nutzen für einzelne Dokumente bringt. Der Nutzen liegt nur in der Parallelisierung von 100.000 identischen Dokumenten vor: Jedes Dokument durchläuft dieselben Operationen, ohne die Werte anderer zu lesen, und überprüft alles einmal.
README: Es gibt drei Beispiele für die Anwendung des Projekts (in der Autorensprache): Direktes Training mit aufgebrochenen Gewichten – wie der Autor sagt: „Was wird passieren? Man muss es ausprobieren, um es zu erfahren.“ End-to-end-Training einer festgelegten Funktion mit einem universellen neuronalen Netzwerk – „Kann nanoGPT gleichzeitig Shakespeare und deine UI lernen?“ Und die traditionelle JS-Programmierung in einem Thread erhält eine GPU-basierte Parallelisierung, wodurch die JSON-Suche auf 100.000 Dokumenten in Millisekunden abgeschlossen wird. Alle drei Beispiele enden mit einem Fragezeichen, und die Art des Experiments ist offensichtlich.
Die Rate der Commitmenten ist ein interessanter Punkt: Einzelne Benutzer haben 4 Tage lang 825 Commitmente vorgenommen. Der Autor hat keine spezifische Generierungstechnik beschrieben, aber in den Notizen vom 3. September im Labor steht, dass der Autor „die Claude-Dialoge im Juni und Juli“ sowie „die Diskussionen zum Design von Codex im Juni“ durchgesehen hat. Die Überprüfung wurde von drei unabhängigen Auditoren durchgeführt. Die Informationen liegen hier, die Beurteilung bleibt dem Leser überlassen.
Ein weiterer Beweis für Ehrlichkeit: In den Notizen vom September steht: „Das besorgendste Ergebnis war auch konkret: Einige Korrektionsprüfungen haben dieselben Fehler in vergleichbaren Implementierungen festgestellt.“ Das Projekt hat die Schwachstellen seines Testsystems selbst dokumentiert, anstatt darauf zu warten, dass andere sie entdecken – das ist in den „Star-Repositories“ nicht üblich.
4. Vergleich mit ähnlichen Projekten
Konzeptionell gehört Handwired zur alten Richtung der „differenzierbaren Programmierung“: Es ermöglicht es gewöhnlichen Programmen, ihren Kontrollfluss in differenzierbare Werte umzuwandeln, was mit den Ideen des neuronalen Symbolismus verbunden ist. Doch seine Methode hat ihre eigene Position: Es geht nicht darum, ein Netzwerk zu trainieren, das das Programm nachahmt, sondern es geht darum, handschriftliche Programme exakt in die Form eines neuronalen Netzwerks zu kompilieren. Die Gewichte sind nicht Produkte des Trainings, sie sind Teil des Programms selbst. Differenzierbare Interpreter arbeiten normalerweise mit Verlusten an Präzision, indem sie Verzweigungen durch Bereichsbeschreibungen, Integer-Grids und symbolische Kaskaden ersetzen. Handwired geht hingegen von Präzision aus, indem es Bereichsbeschreibungen, Integer-Grids und symbolische Kaskaden verwendet, um Präzision zu gewährleisten, und nutzt diese Möglichkeiten zur Differenzierbarkeit. Die drei Wörter „ohne Training, präzise, differenzierbar“ sind gleichzeitig erfüllt, und dies hängt genau von der Wahl dieser Kompilierungsmethode ab. Dieser Vergleich dient nur einer konzeptionellen Orientierung und bezieht sich nicht auf die Qualität des Projekts.
5. Beschränkungen
Drei Punkte. Erstens, die numerischen Grenzen: Die Verwendung von ReLU zur Kodierung von Integern hängt davon ab, ob der Operand innerhalb der angegebenen Bereichsbeschreibungen und -grenzen liegt. Der Repo verwendet Bereichsbeschreibungen und präzise Bit-Informationen, um diese Probleme zu lösen, aber das bedeutet, dass die Programmierer selbst die numerischen Kontraktionsregeln pflegen müssen. In der Fließkomma-Welt gibt es keine Magie für Eingaben, die die Grenzen von ±2^24 überschreiten, und Index-Erkennungen, die diese Grenzen überschreiten, werden direkt abgelehnt. Zweitens, die Skalierbarkeit: Beide Seiten der Verzweigungen werden berücksichtigt, und die Operanden steigen mit der Komplexität des Programms. In status.md gibt es bereits Beispiele dafür, dass nach dem Übertritt von Notes auf HandwiredOS die Anzahl der aktiven Operationen von 14.019 auf 20.381 gestiegen ist, und die Speichergewichte von 31.359 auf 45.436 gewachsen sind. Eine einzelne Berechnung hat von etwa 75µs auf etwa 133µs angestiegen. Ein Spielzeugprojekt hat bereits 20.000 Operationen durchgeführt, so dass man sich eine Vorstellung davon machen kann, wie groß die tatsächliche Anwendung sein muss. Drittens, die Praktikabilität: Der Autor selbst hat das Projekt als Experiment eingestuft, und im README steht: „Was macht das eigentlich? Lassen wir es herausfinden!“ Das ist direct evidence, die nicht übertrieben werden muss.
6. Beurteilung und Eignung für die Nutzer
Schauen wir uns zunächst die Popularitätsstruktur an: HN hat insgesamt 9 Likes, GitHub 4 Tage 1730★. Die Aufmerksamkeit kam hauptsächlich durch „Trending“-Beiträge und soziale Medien, während technische Foren kaum Beachtung fanden. Diese Widersprüche zeigen, dass die meisten Menschen von der Idee „Code als Netzwerk“ angezogen wurden – der Aufwand für das Erhalten von Stars ist viel geringer als der für das Lesen des Execution-model.md. Die Anzahl der Stars misst hier die Themenwirksamkeit, nicht die Nutzung.
Beurteilen wir das nach dem Publikumsverhalten. Fürjenige, die über mikroprogrammierte Systeme verfügen, ist dies eine Einführung auf Lehrstufe: Sechs Dokumente lesen, Beispiele für das Ausführen von Templates ausprobieren, mit einer einzigen Befehlsanweisung eine lokale Demo erstellen – der Aufwand beträgt nur eine halbe Stunde, was intuitiver ist als das Lesen von Forschungsarbeiten. Fürjenige, die GPU-basierte numerische Berechnungen oder Compiler entwickeln, kann man das Macro-Design übernehmen: Wie werden emitCompare und index read während des Entwurfs zu minimalistischen Befehlen umgewandelt und wie wird rounding point verwendet, um die Freiheit der Anordnung zu bewahren – das sind Methoden, die direkt übernommen werden können. Fürjenige, die Produktionswerkzeuge suchen, sollten sie jetzt nicht kommen: 9 offene Probleme, die APIs können jederzeit ändern – der Autor ist dabei nur ein Experimentator.
Ob es sich um Forschungstools oder Paradigmen signalisiert, lässt sich nach 4 Tagen nicht entscheiden. Doch eines ist sicher: Das Ziel der Kompilierung „Programm als Netzwerk“ wurde von einer Person mit 270.000 Zeilen TypeScript erreicht – das Programm kann auf Desktop-Systemen laufen und in Millisekunden 100.000 Dokumente durchsuchen. Die Vollständigkeit der Dokumentation und Tests entspricht der Anzahl der Stars. Diese Sache allein ist bereits einen Aufschluss wert.
Quellen
- Repository: github.com/chenglou/handwired (README, docs/execution-model.md, docs/tutorial.md, docs/patterns.md, template/, src/json-search/README.md, lab/status.md, lab/reassessment-2026-09-03.md, 19.10. Lokale Clone-Abfrage; Anzahl der Zeilen und Dateien berechnet mit local find/wc)
- Stars, Fork, Erstellungszeit, Mitwirkende und Anzahl der Änderungen: GitHub API (Snapshot vom 19.10., die Anzahl der Stars ändert sich weiterhin)
- HN-Austellungen: id=50105849 (5▲), id=50105735 (4▲), Snapshot vom 19.10.
- Teile des Autorenhintergrunds, die noch nicht überprüft wurden, sind im Text mit „Community-Daten angegeben“ markiert.