Kera et le travail de réduction
Le rapport de bug qui n’en était pas un
L’histoire commence généralement par un nombre presque juste. Pas complètement faux. Pas cassé au point de faire passer le tableau de bord au rouge. Presque juste, mais de la manière coûteuse : le genre d’erreur qui permet à une équipe de livrer, à une autre d’hésiter, et à un auditeur de se demander pourquoi la réponse a changé lorsque le même modèle est passé d’une machine à une autre.
Une compilation s’exécute sur un serveur x86 et produit une valeur. La suivante s’exécute sur un ordinateur portable ARM et produit une valeur suffisamment proche pour qu’une démo survive. Un chemin GPU est plus rapide mais arrondit différemment tout au long du calcul. Un chemin FPGA est attrayant pour le timing, mais soudain l’équipe logicielle se retrouve à discuter matériel. Tout le monde peut expliquer une petite partie de la différence. Personne ne possède l’ensemble du chemin, de la source au résultat.
C’est l’espace pour lequel Kera est conçu. Pas l’idée de modèle, pas la diapositive marketing, pas un article sur un futur compilateur, mais le travail de compilation qui commence lorsqu’une équipe décide que le même calcul doit s’exécuter sur différentes machines et signifier toujours la même chose. Cette obligation a besoin d’un responsable. La promesse du compilateur n’est pas que l’abaissement soit élégant. La promesse est que l’abaissement soit traité comme un travail.
L’abaissement est la partie d’un compilateur où l’intention d’un langage agréable devient des instructions qu’une cible peut exécuter. C’est aussi là que les affirmations vagues deviennent visibles. Si le résultat doit être identique bit pour bit entre CPU, GPU, FPGA et WebAssembly, alors le compilateur ne peut pas hausser les épaules face aux différences de cibles. Il doit porter suffisamment de structure pour décider ce qui peut changer et ce qui ne doit pas changer. Il doit connaître les espaces mémoire, les effets, les opcodes, les mouvements de données, les limites des cibles et les reçus qui prouvent que deux compilations sont le même calcul.
La version tentante de l’histoire est d’appeler cela une couche de portabilité. C’est trop réducteur. La portabilité dit que le programme s’exécute ailleurs. Kera vise une affirmation plus difficile : le programme est représenté sous forme de graphe adressé par contenu, compilé en artefact .keg, abaissé vers plusieurs backends, et produit toujours la même réponse. La cuisine change. La recette, non.
Le milieu que personne ne veut vendre
La première conversation avec un acheteur sérieux commence rarement par la syntaxe. Elle commence par un désordre. Il y a un modèle qui compte. Il y a une simulation qui était de la recherche et qui est devenue opérationnelle. Il y a un calcul de risque dont le résultat n’a plus le droit de varier selon la machine. Il y a un déploiement en périphérie qui ne peut pas embarquer l’intégralité du runtime cloud. Il y a une équipe qui veut un accélérateur mais ne peut pas se permettre de tout réécrire à chaque changement d’accélérateur.
La plupart des outils présentent cela comme un problème de déploiement. Choisissez la cible, exportez le modèle, corrigez le runtime, acceptez une certaine variance, puis rédigez un document expliquant les exceptions. Le document grossit. La matrice de tests grossit. Le nombre de spécialistes grossit. Finalement, l’organisation paie deux fois pour l’hétérogénéité : une fois lorsqu’elle achète le matériel, une autre fois lorsqu’elle tente de prouver que le matériel a fait le même travail.
Kera part de l’extrémité opposée. La page Kera parle d’un langage système statiquement typé avec un IR adressé par contenu et natif aux graphes. Cette expression compte, car le graphe n’est pas un diagramme de compilateur décoratif. C’est l’objet exécutable. Le code source est abaissé en graphes acycliques dirigés d’opérations, stockés sous forme de fichiers .keg. Chaque nœud porte une structure définie. Le travail dupliqué peut être éliminé structurellement. Le même graphe peut être abaissé vers CPU, GPU, FPGA et WASM sans traiter chaque cible comme un petit univers séparé.
C'est pourquoi Kera doit se comporter comme une véritable infrastructure de compilateur plutôt que comme un diagramme. C'est dans cet entre-deux inconfortable que vit le client. La tokenisation doit préserver les positions des octets. L'analyse syntaxique doit alimenter les outils autant que la compilation. La vérification de types doit rejeter les incompatibilités de forme et de bords avant qu'elles ne deviennent des événements d'exécution. La vérification d'emprunt doit comprendre la propriété à travers la mémoire hôte, périphérique, épinglée et unifiée. L'optimisation doit être reproductible. La sérialisation doit fournir à l'organisation un artefact qu'elle peut conserver.
Aucun de ces points ne fait un titre spectaculaire. C'est pourtant bien plus utile qu'un titre. Cela signifie que lorsqu'une charge de travail passe du développement à la production, ou d'une base CPU à un chemin GPU, le compilateur dispose d'un élément stable à comparer : l'empreinte du graphe. Si l'empreinte correspond, le travail est le même travail. C'est un point de contrôle partagé qu'un ingénieur, un acheteur et un auditeur peuvent tous comprendre.
Un graphe est un reçu, pas une image
L'ancienne façon d'expliquer un programme consiste à montrer le code source et à demander au lecteur de faire confiance au compilateur. La page Kera revient sans cesse à un objet différent : le graphe. Chaque opération est un nœud. Les arêtes expriment les dépendances. Le graphe a un contenu. Le contenu a un hachage. Le hachage devient une empreinte qui voyage à travers la construction.
Cela ressemble à de la mécanique interne jusqu'à ce qu'on se tienne à côté d'une équipe de conformité. Une équipe de conformité ne veut pas savoir qu'un fournisseur a une belle architecture de compilateur. Elle veut savoir si le calcul approuvé le mois dernier est le calcul qui s'exécute aujourd'hui. L'empreinte du graphe est le pont entre ces deux mondes. Ce n'est pas une capture d'écran du compilateur. C'est une façon compacte de dire : cet ensemble d'opérations, ces types, ces entrées, ces attributs, cette structure de dépendances.
Le modèle de nœuds est délibérément strict. Un nœud est une version de schéma, un opcode, des descripteurs de sortie, des hachages d'entrée et des cartes d'attributs disposés dans un ordre canonique. Les octets sont hachés avec SHA3-256 sous des préfixes séparés par domaine, de sorte que les hachages de nœuds, de régions et de graphes vivent dans des espaces de noms distincts. Si deux nœuds ont le même opcode, les mêmes entrées et les mêmes attributs, ils ont le même hachage. L'insertion d'un doublon renvoie l'entrée existante. L'élimination des sous-expressions communes devient une conséquence de la représentation, et non une passe héroïque ajoutée plus tard.
C'est ce genre de détail qui transforme un système d'ingénierie en quelque chose sur quoi les gens peuvent compter. Un acheteur n'achète pas un diagramme de compilateur. Un acheteur achète moins de disputes sur la question de savoir si un calcul a changé. Un développeur n'achète pas un slogan sur l'IA déterministe. Un développeur achète un format de graphe où la similarité peut être vérifiée, stockée et utilisée par les outils. Le fichier .keg n'est donc pas une réflexion après coup de l'implémentation. C'est un enregistrement portable du travail.
Les huit petites portes avant l'apparition d'une cible
Quand on imagine un compilateur, on pense souvent directement au backend. On se représente le moment où le code devient AVX, PTX, Verilog ou WASM. Ce moment compte, mais il survient tard dans l’histoire. L’essentiel du travail du compilateur a déjà eu lieu à ce stade, dans des étapes discrètes qui déterminent si le backend peut être digne de confiance.
Kera commence par un analyseur lexical compatible UTF-8 qui convertit le code source en jetons avec un suivi complet des trivia et une récupération d’erreurs. Cela ressemble à de la plomberie d’éditeur, et c’en est. C’est aussi une question de fiabilité de la chaîne d’outils. Si chaque position d’octet est conservée, les diagnostics, le formatage, le re-analyse incrémentale et le comportement du serveur de langage peuvent correspondre à ce que l’utilisateur a réellement écrit. Un compilateur qui perd la forme du code source tôt paie cette perte partout ailleurs.
L’analyseur syntaxique est piloté par événements : la descente récursive avec analyse de précédence de Pratt émet des événements Start, Token, Finish et Error plutôt que de construire un AST unique que tout le monde doit partager. Le flux d’événements alimente indépendamment le constructeur d’arbre, le formateur et le serveur de langage. L’arbre vert est sans perte, préservant jetons et trivia. Le constructeur de graphe parcourt ensuite cet arbre, maintient la résolution de noms et crée un nœud Region par fonction.
Ce n’est qu’ensuite que le code source devient le graphe que le compilateur transporte. Le typage structurel valide la compatibilité entre les arêtes d’opérations et les contraintes de forme des tenseurs. Les types ne correspondent que lorsque leurs hachages canoniques sont identiques. Le vérificateur d’emprunt impose un propriétaire unique par valeur, aucune référence mutable aliasée et des règles de propriété entre espaces mémoire. Les annotations d’effets sont vérifiées pour leur cohérence. Les effets de bord ne sont pas laissés au goût ou à la convention.
Le gestionnaire de passes d’optimisation fait ensuite le travail de compilateur reconnaissable : pliage de constantes, élimination des sous-expressions communes, élimination du code mort, inlining, vectorisation et fusion de boucles dans une boucle à point fixe. La phrase importante n’est pas la liste des passes. C’est ce qui se passe après chaque passe : un validateur d’invariants de graphe vérifie la cohérence des hachages et l’intégrité des dépendances. L’optimisation est autorisée à améliorer le graphe, pas à le rendre mystérieux.
Enfin, des générateurs de code spécifiques à chaque cible émettent du code natif, du PTX, du Verilog ou du WASM, et le graphe optimisé est sérialisé dans un fichier .keg avec une table de sections. Le fichier commence par les octets magiques KEG\0 et contient des sections pour les chaînes, les types, les attributs, les nœuds, les régions et les exports. C’est le chemin qu’une équipe doit maîtriser avant de pouvoir honnêtement parler de cibles.
Les cibles ne sont pas des autocollants sur une diapositive
Une liste de cibles est facile à écrire et difficile à mériter. CPU, GPU, FPGA et WASM tiennent parfaitement dans une fiche produit. C’est dans l’abaissement vers ces cibles que se cache la facture. Chaque cible a ses propres habitudes, forces et modes de défaillance. Un compilateur qui veut une exécution hétérogène déterministe ne peut pas traiter ces habitudes comme le problème de quelqu’un d’autre.
Sur CPU, Kera émet du code machine natif pour x86-64 et ARM64, avec RISC-V Vector dans la fiche technique. Le chemin x86 sélectionne SSE2, AVX2 ou AVX-512 ; le chemin ARM utilise NEON ; l’allocateur de registres et l’ordonnanceur sont partagés. L’affirmation du produit n’est pas simplement qu’un binaire existe. L’affirmation est que des kernels SIMD spécifiques à la cible sont sélectionnés tandis que le graphe reste le même calcul.
Sur GPU, le matériel source nomme la génération PTX pour CUDA et ROCm, avec des tensor cores utilisés lorsque la forme du kernel le permet. Cette dernière clause fait du travail. L’accélération matérielle n’est pas de la poudre de perlimpinpin. Une forme de kernel correspond à un chemin tensor core ou non. Le compilateur doit l’exposer honnêtement, déplacer les données entre l’hôte et le périphérique si nécessaire, et conserver l’empreinte du graphe comme preuve de ce qui est exécuté.
Sur FPGA, le chemin de lowering devient une conversation matérielle : synthèse Verilog, estimation des ressources, analyse temporelle et ordonnancement de pipeline pour un comportement prévisible et exact au cycle près. C’est le genre de cible où les approximations coûtent particulièrement cher. Si l’acheteur a besoin de temps réel strict, la surface du compilateur doit parler en cycles, en ressources et en pipelines, pas seulement en vitesse. L’histoire de Kera fait de FPGA un backend du même graphe plutôt qu’une réécriture par une autre équipe.
Sur WASM, la page nomme le SIMD 128 bits pour le déploiement en périphérie et dans le navigateur. Cela compte parce que la périphérie est l’endroit où la réalité du déploiement entre souvent en collision avec la pureté. Un navigateur, un petit appareil ou un runtime contraint ne peut pas toujours héberger la même pile qu’un serveur. Un chemin de lowering natif au graphe donne à l’équipe un moyen de transporter le même calcul dans cet environnement sans transformer la périphérie en un second produit.
Le déterminisme doit survivre au succès
Le déterminisme est facile à promettre dans une petite pièce. Il devient plus difficile lorsque le produit réussit. Plus d’utilisateurs arrivent. Plus de matériel apparaît. Un modèle passe d’une puce à une autre. Une base de test écrite pour un parc doit en couvrir un autre. Une optimisation qui semble inoffensive change l’ordre d’une réduction. Un chemin rapide apparaît dans un runtime mais pas dans un autre.
The Kera page frames determinism as bit for bit across platforms. That is not a cosmetic claim. It changes product obligations. Primitive arithmetic has defined precision semantics across all targets. Reductions have defined tie-breaking so scheduling and hardware do not change the result. Neural network primitives have deterministic implementations on CPU, GPU, FPGA, and WASM. The graph means the same thing wherever it runs.
This is why undefined behaviour, garbage collector pauses, and implicit side effects are not small language preferences. They are cracks in the execution surface. Kera’s page says no LLVM dependency, no garbage collector, no undefined behaviour. Explicit types, explicit effects, and ownership across memory spaces are product controls. They reduce the number of places a result can change while everyone is looking somewhere else.
There is a human side to this too. When a robotics controller changes behaviour across devices, when a finance workflow rounds one cent differently, when a scientific result cannot be repeated by a reviewer, or when a game simulation diverges between targets, the argument is not really about compiler theory. It is about institutional confidence. Kera’s consumer copy uses simple stories because the underlying problem is simple to feel: same instructions, same answer, on any computer you own.
That confidence must survive acceleration. If performance requires teams to abandon determinism, the product has only moved the risk. Kera tries to keep performance and determinism in the same contract by making the graph the unit of meaning and the target path the unit of execution.
Security is part of lowering
Compiler discussions often isolate security as runtime work. Kera’s source material does not. It talks about capability-based security, a SecurityManager, a default-deny gate, a PolicyBuilder, seccomp BPF, Linux namespaces, and a thread-safe tamper-evident audit log in a fixed-capacity ring buffer. Those words belong in the engineering story because lowering does not end when instructions are emitted. The emitted work still has to run with boundaries.
Capability tokens are granted at startup. Privileged actions require an explicit capability. Access rules are declared up front. A BPF filter restricts syscalls. Namespace isolation separates process, mount, and network views. Security-relevant events land in an audit log. The short sentenceis: nothing is permitted by default.
That matters for heterogeneous execution because targets create surfaces. A CPU process, GPU transfer, FPGA path, browser runtime, and distributed job do not fail in identical ways. A product has to keep policy attached to the work as it moves. If the graph says what the computation is, the runtime controls say what the computation may do.
There is also an operations reason to bring security into the compiler story. Teams do not want one product for compilation, anotherfor policy, another for logging, and another for explanation if the seams between them become the place where incidents hide. Kera’s page does not claim to solve all security. It does something narrower and more useful: it makes permissions explicit and auditedin the execution environment the compiler feeds.
Distributed work is still lowering
The technical sheet names distributed execution, ring allreduce, and checkpoint recovery. In another product, those might be brochure items. In Kera, they belong to the same lowering conversation because parallelism changes the shape of a computation. Data, model, and pipeline parallelism are not just ways to go faster. They are ways to split work without losing the meaning of the original graph.
Si un gros travail s'exécute sur de nombreuses machines et qu'un nœud tombe en panne, la reprise à partir d'un point de contrôle n'est pas un simple confort. Elle fait partie de ce qui rend le calcul opérationnel. Si les résultats sont agrégés de manière fiable, la sémantique de l'agrégation doit être définie. Si un graphe est adressé par contenu, le chemin distribué doit préserver l'identité du graphe plutôt que d'inventer une seconde réalité une fois que le travail quitte une machine.
C'est ici que l'interprétation du produit devient claire. Kera n'est pas une couche de syntaxe avec un module distribué en option. Elle cherche à rendre le calcul portable à la fois dans sa forme et sur le matériel : un programme, un graphe, plusieurs cibles d'exécution et un enregistrement vérifiable. L'exécution distribuée est un lieu de plus où l'abaissement doit porter le contrat d'exécution.
Cela change aussi l'histoire des effectifs. Sans chemin de compilation partagé, un bogue qui n'apparaît que sur une plateforme peut exiger des personnes qui connaissent à la fois la puce, la chaîne d'outils et l'exécution. Avec un graphe unique et un chemin partagé, la question est plus nette : le graphe a-t-il changé, le chemin d'abaissement a-t-il changé, ou la cible a-t-elle violé la sémantique définie ? De meilleures questions ne suppriment pas le travail difficile. Elles empêchent le travail difficile de se répandre au hasard.
Pourquoi quelqu'un doit posséder le chemin
L'abaissement ne peut pas rester sans propriétaire dès lors qu'il porte des résultats sur lesquels les gens comptent. Un graphe qui s'exécute sur CPU, GPU, FPGA et WASM a besoin de plus qu'une représentation astucieuse. Il a besoin de documentation, de diagnostics, de revendications sur les cibles, du comportement de l'éditeur, de la génération de code, des contrôles de sécurité, des conversations de support et d'un moyen de dire à un acheteur exactement ce qui a changé lorsqu'un résultat change.
Cela ne rend pas le travail moins technique. Cela rend le travail technique plus contraignant. Kera est actuellement un produit commercial de Dweve, pas une version open source : tous droits réservés, disponible sous licence commerciale, fabriqué aux Pays-Bas, et destiné aux organisations qui ont besoin que le chemin du graphe soit pris en charge plutôt que simplement publié. Si la page mentionne Rust 2021, IR de graphe, JIT personnalisé, pas de LLVM, CPU/GPU/FPGA/WASM, suivi des effets, propriété entre espaces mémoire, sécurité par capacités, exécution distribuée, intégration C et Python, workflows en ligne de commande, support d'éditeur et outils LSP, ce ne sont pas des détails internes décoratifs. Ce sont des obligations qui doivent survivre à l'évaluation par des charges de travail réelles.
La fiche de capacités est prudente à ce sujet. Elle décrit des cibles de conception et demande de vérifier par rapport à votre charge de travail. Cette retenue compte. Elle est bien plus saine que de prétendre que chaque chiffre de référence se transpose. Le système devrait donner aux équipes un moyen de mesurer, d'inspecter et de comparer dans leur propre environnement, plutôt que de leur demander d'accepter une histoire universelle de vitesse.
Quelqu'un doit posséder ce chemin parce que chaque cible essaie de rendre la source moins universelle. Kera est l'endroit où ces différences de cible deviennent un travail explicite de compilateur au lieu d'un folklore transmis après le rapport de bogue.
Le jour où le graphe devient le contrat
Imaginez à nouveau le rapport de bogue original, mais avec Kera déjà dans le flux de travail. Une équipe financière approuve un calcul de risque. L'empreinte du graphe est enregistrée. Le premier déploiement s'exécute sur CPU. Plus tard, un chemin GPU est introduit pour l'analyse de portefeuille. Plus tard encore, un chemin FPGA est utilisé pour des prix à plus faible latence. La question à chaque étape n'est pas de savoir si le nouveau matériel semble impressionnant. La question est de savoir si le même graphe est abaissé et si la sémantique de la cible maintient le résultat identique.
La conversation change. L'équipe plateforme peut parler d'ordonnancement et de coût. L'équipe compilateur peut parler des backends. L'équipe conformité peut parler de l'empreinte. Le propriétaire métier peut demander si changer de matériel est une décision opérationnelle ou une réécriture. Le produit leur donne à tous un objet unique sur lequel pointer.
Voilà la valeur discrète d’une IR adressée par contenu. Elle transforme l’exécution multiplateforme d’une série d’explications persuasives en un enregistrement. Elle fait du graphe un reçu. Elle permet au même fichier .keg d’alimenter chaque backend. Elle donne à l’organisation une base de référence qui appartient au calcul plutôt qu’à une seule machine.
Aucun compilateur ne peut supprimer la nécessité du jugement d’ingénierie. Les équipes doivent toujours sélectionner les cibles avec soin, tester les charges de travail honnêtement, comprendre les limites des cibles et décider quels domaines exigent une identité bit pour bit. Mais Kera peut rendre ces décisions explicites. Elle peut empêcher qu’une migration de performance ne devienne accidentellement une migration sémantique.
La leçon de l’abaissement
Kera importe parce que la difficulté ne réside pas dans le fait d’avoir une idée ingénieuse d’abaissement. La difficulté consiste à porter cette idée à travers tous les endroits ternes où l’ingénierie devient digne de confiance ou se transforme en folklore : diagnostics, arbres verts, hachages de types, vérification d’emprunt, optimisation à point fixe, validation d’invariants, sérialisation .keg, émission de backend, politique de sécurité, journaux d’audit, support éditeur et exécution spécifique à la cible.
L’abaissement est un travail parce que chaque cible tente de rendre la source moins universelle. L’ingénierie de compilateur déterministe est la discipline qui consiste à refuser que cela se produise en silence. Le CPU veut des vecteurs. Le GPU veut des kernels. Le FPGA veut des cycles. WASM veut des contraintes. L’organisation veut une seule réponse. Le rôle de Kera est de préserver le sens du calcul tout en laissant chaque cible faire ce qu’elle fait de mieux.
C’est une forme d’ingénierie, pas une abstraction théorique. Elle a un acheteur, un mode de défaillance, un format de fichier, un chemin de compilation et des conséquences opérationnelles. La promesse n’est pas que le matériel devienne simple. La promesse est que la complexité est représentée, abaissée, vérifiée et maîtrisée.
Lorsque le prochain nombre presque correct arrive, l’équipe ne devrait pas devoir commencer par du folklore sur quelle machine a exécuté quoi. Elle devrait commencer par le graphe. L’empreinte correspondait-elle ? Quel backend a émis le code ? Quelles capacités ont été accordées ? Quelle sémantique de cible a été appliquée ? Quel artefact a été stocké ? Ce sont des questions de produit. Kera existe parce que ce sont aussi des questions de compilateur.