Kera och arbetet med att sänka

Deterministisk sänkning, målansvar och bevis som håller en beräkning identisk över hårdvara.

Kera och arbetet med att sänka

Buggrapporten som inte var en bugg

Historien börjar oftast med en siffra som är nästan rätt. Inte vilt fel. Inte trasig på ett sätt som gör instrumentpanelen röd. Nästan rätt på det dyra sättet: den typen av fel som gör att ett team kan leverera, ett annat team tvekar och en revisor frågar varför svaret ändrades när samma modell flyttades från en maskin till en annan.

En build körs på en x86-server och producerar ett värde. Nästa build körs på en ARM-bärbar dator och producerar ett värde som är tillräckligt nära för att en demo ska fungera. En GPU-sökväg är snabbare men avrundar genom beräkningen på ett annat sätt. En FPGA-sökväg är attraktiv för tajming men plötsligt har mjukvaruteamet ett hårdvarusamtal. Alla kan förklara en liten del av skillnaden. Ingen äger hela vägen från källa till resultat.

Det är utrymmet Kera är byggd för. Inte modellidén, inte marknadsföringssladden, inte en artikel om en framtida kompilator, utan kompilatorarbetet som börjar när ett team säger att samma beräkning måste köras på olika maskiner och fortfarande betyda samma sak. Den skyldigheten behöver en ägare. Kompilatorlöftet är inte att lowering är elegant. Löftet är att lowering behandlas som arbete.

Lowering är den del av en kompilator där trevlig språkavsikt blir instruktioner som en målenhet kan exekvera. Det är också där vaga påståenden blir synliga. Om resultatet ska vara bit för bit identiskt över CPU, GPU, FPGA och WebAssembly, då kan kompilatorn inte rycka på axlarna åt målskillnader. Den måste bära tillräckligt med struktur för att avgöra vad som får ändras och vad som inte får ändras. Den måste känna till minnesutrymmen, effekter, opcodes, dataförflyttning, målbegränsningar och kvittona som bevisar att två builds är samma beräkning.

Den lockande versionen av historien är att kalla detta ett portabilitetslager. Det är för litet. Portabilitet säger att programmet körs någon annanstans. Kera siktar på det svårare påståendet: programmet representeras som en content-adresserad graf, kompileras till en .keg-artefakt, loweras till flera backends och producerar fortfarande samma svar. Köket ändras. Receptet gör det inte.

Mitten ingen vill sälja

Det första samtalet med en seriös köpare börjar sällan med syntax. Det börjar med en röra. Det finns en modell som spelar roll. Det finns en simulering som brukade vara forskning och har blivit operativ. Det finns en riskberäkning vars resultat inte längre får variera mellan maskiner. Det finns en edge-distribution som inte kan bära hela molnkörningsmiljön. Det finns ett team som vill ha en accelerator men inte har råd med en omskrivning varje gång acceleratorn ändras.

De flesta verktyg får detta att se ut som ett distributionsproblem. Välj målet, exportera modellen, patcha körningsmiljön, acceptera viss variation, skriv sedan ett dokument som förklarar undantagen. Dokumentet växer. Testmatrisen växer. Antalet specialister växer. Till slut betalar organisationen för heterogenitet två gånger: en gång när den köper hårdvaran, en gång när den försöker bevisa att hårdvaran gjorde samma arbete.

Kera börjar från den motsatta änden. Keras sida kallar det ett statiskt typat systemprogrammeringsspråk med en graf-nativ, content-adresserad IR. Den frasen spelar roll eftersom grafen inte är ett dekorativt kompilatordiagram. Det är det exekverbara objektet. Källkod loweras till riktade acykliska grafer av operationer, lagrade som .keg-filer. Varje nod bär definierad struktur. Dubbelt arbete kan elimineras strukturellt. Samma graf kan loweras till CPU, GPU, FPGA och WASM utan att behandla varje mål som ett separat litet universum.

Det är därför Kera måste uppföra sig som seriös kompilatorinfrastruktur snarare än ett diagram. Det obekväma mellantinget är där kunden lever. Tokenisering måste bevara bytepositioner. Parsning måste mata både verktyg och kompilering. Typpkontroll måste avvisa form- och kantfel innan de blir körtidsfel. Lånekontroll måste förstå ägande över värd-, enhets-, pinnad och enhetligt minne. Optimering måste vara repeterbar. Serialisering måste ge organisationen en artefakt den kan behålla.

Inget av det ger en dramatisk rubrik. Det är mycket mer användbart än en rubrik. Det innebär att när en arbetsbelastning flyttas från utveckling till produktion, eller från en CPU-baslinje till en GPU-sökväg, har kompilatorn något stabilt att jämföra med: graffingeravtrycket. Om fingeravtrycket matchar är arbetet samma arbete. Det är en gemensam kontrollpunkt som en ingenjör, köpare och revisor alla kan förstå.

En graf är ett kvitto, inte en bild

Det gamla sättet att förklara ett program är att visa källkoden och be läsaren lita på kompilatorn. Keras sida återkommer ständigt till ett annat objekt: grafen. Varje operation är en nod. Kanter uttrycker beroenden. Grafen har innehåll. Innehållet har en hash. Hashen blir ett fingeravtryck som färdas genom bygget.

Grafen är det beständiga objektet: källkod, typer, regioner, hashvärden och den artefakt som färdas vidare.

Det här låter som intern mekanik tills du står bredvid ett regelefterlevnadsteam. Ett regelefterlevnadsteam vill inte veta att en leverantör har en snygg kompilatorarkitektur. Det vill veta om beräkningen som godkändes förra månaden är den beräkning som körs idag. Graffingeravtrycket är bron mellan dessa världar. Det är inte en skärmdump av kompilatorn. Det är ett kompakt sätt att säga: denna operationsuppsättning, dessa typer, dessa indata, dessa attribut, denna beroendestruktur.

Nodmodellen är medvetet strikt. En nod är en schemaversion, en opcode, utdatadeskriptorer, indatahashar och attributkartor ordnade i kanonisk ordning. Byten hashas med SHA3-256 under domänseparerade prefix, så att nod-, region- och grafhashar lever i separata namnområden. Om två noder har samma opcode, indata och attribut har de samma hash. Att infoga en dubblett returnerar den befintliga posten. Eliminering av gemensamma deluttryck blir en följd av representationen, inte en heroisk pass som läggs till senare.

Det är den typen av detalj som förvandlar ett tekniskt system till något människor kan lita på. En köpare köper inte ett kompilatordiagram. En köpare köper färre argument om huruvida en beräkning har ändrats. En utvecklare köper inte en slogan om deterministisk AI. En utvecklare köper ett grafformat där likhet kan kontrolleras, lagras och användas av verktyg. .keg-filen är därför inte en eftertanke i implementeringen. Den är en bärbar registrering av arbetet.

De åtta små dörrarna innan ett mål visas

När människor föreställer sig en kompilator hoppar de ofta direkt till backenddelen. De ser framför sig ögonblicket då kod blir AVX, PTX, Verilog eller WASM. Det ögonblicket spelar roll, men det kommer sent i berättelsen. Det mesta av kompilatorarbetet har redan skett då, i tysta steg som avgör om backenddelen går att lita på.

Backenddelarna kommer sent. Det mesta av förtroendet förtjänas tidigare, i de små kompilatorsteg som bevarar innebörden.

Kera börjar med en UTF-8-medveten lexer som omvandlar källkod till token med fullständig trivia-spårning och felåterställning. Det låter som editorplumbing, och det är det. Det är också verktygskedjans tillförlitlighet. Om varje byteposition bevaras kan diagnostik, formatering, inkrementell omtolkning och språkserverns beteende stämma överens med vad användaren faktiskt skrev. En kompilator som förlorar källkodens form tidigt betalar för den förlusten överallt annars.

Parsern är händelsebaserad: rekursiv descent med Pratt-uttrycksparsning avger Start-, Token-, Finish- och Error-händelser i stället för att bygga ett enda AST som alla måste dela. Händelseströmmen matar trädbyggaren, formateraren och språkservern oberoende av varandra. Det gröna trädet är förlustfritt och bevarar token och trivia. Grafbyggaren går sedan igenom trädet, upprätthåller namnupplösning och skapar en Region-nod per funktion.

Först efter det blir källkoden den graf kompilatorn bär med sig. Strukturell typkontroll validerar kompatibilitet över operationskanter och begränsningar för tensorformer. Typer matchar bara när deras kanoniska hashvärden är identiska. Lånekontrollen upprätthåller en ägare per värde, inga aliaserade muterbara referenser och ägarskapsregler över minnesutrymmen. Effektannotationer kontrolleras för konsistens. Sidoeffekter lämnas inte åt smak eller konvention.

Optimeringspasshanteraren gör sedan det igenkännbara kompilatorarbetet: konstantvikning, eliminering av gemensamma deluttryck, eliminering av död kod, inlining, vektorisering och slingfusion i en fixpunktsloop. Den viktiga frasen är inte listan över pass. Det är vad som händer efter varje pass: en grafinvariantvaliderare kontrollerar hashkonsistens och beroendeintegritet. Optimering får förbättra grafen, inte göra den gåtfull.

Slutligen genererar målspecifika kodgeneratorer nativ kod, PTX, Verilog eller WASM, och den optimerade grafen serialiseras till en .keg-fil med en sektionstabell. Filen börjar med magibytarna KEG\0 och innehåller sektioner för strängar, typer, attribut, noder, regioner och exporter. Det är den väg ett team måste äga innan det ärligt kan tala om mål.

Mål är inte klistermärken på en bild

En mållista är lätt att skriva och svår att förtjäna. CPU, GPU, FPGA och WASM passar snyggt i en produktkort. Att sänka till dem är där fakturan gömmer sig. Varje mål har sina egna vanor, styrkor och felsätt. En kompilator som vill ha deterministisk heterogen exekvering kan inte behandla dessa vanor som någon annans problem.

CPU, GPU, FPGA och WASM är inte etiketter. De är målvärldar som samma graf måste överleva i.

På CPU:er genererar Kera inbyggd maskinkod för x86-64 och ARM64, med RISC-V Vector i den tekniska specifikationen. x86-sökvägen väljer SSE2, AVX2 eller AVX-512; ARM-sökvägen använder NEON; registerallokeraren och schemaläggaren är delade. Produktpåståendet är inte bara att en binär finns. Påståendet är att målspecifika SIMD-kärnor väljs medan grafen förblir samma beräkning.

På GPU:er nämner källmaterialet PTX-generering för CUDA och ROCm, med tensor-kärnor som används när kärnformen tillåter. Den sista klausulen gör jobb. Hårdvaruacceleration är inte magiskt stoft. En kärnform passar antingen en tensor-kärnsökväg eller inte. Kompilatorn måste visa det ärligt, flytta data mellan värd och enhet när det behövs, och fortfarande behålla graffingeravtrycket som bevis på vad som exekveras.

På FPGA blir sänkningssökvägen ett hårdvarusamtal: Verilog-syntes, resursuppskattning, timinganalys och pipelineschemaläggning för förutsägbart, cykelexakt beteende. Det här är den typ av mål där handviftande är särskilt dyrt. Om köparen behöver hård realtid måste kompilatorytan tala i cykler, resurser och pipelines, inte bara hastighet. Keras berättelse gör FPGA till en backend för samma graf i stället för en omskrivning av ett annat team.

På WASM nämner sidan 128-bitars SIMD för edge- och webbläsardistribution. Det spelar roll eftersom edge är där distributionsverkligheten ofta kolliderar med renhet. En webbläsare, en liten enhet eller en begränsad runtime kan inte alltid vara värd för samma stack som en server. En grafnativ sänkningssökväg ger teamet ett sätt att bära samma beräkning in i den miljön utan att göra edge till en andra produkt.

Determinism måste överleva framgång

Determinism är lätt att lova i ett litet rum. Det blir svårare när produkten lyckas. Fler användare kommer. Mer hårdvara dyker upp. En modell flyttas från ett chip till ett annat. En testbaslinje skriven för en miljö måste täcka en annan. En optimering som ser ofarlig ut ändrar ordningen på en reduktion. En snabb sökväg dyker upp i en runtime men inte i en annan.

Determinism är en loop, inte en slogan: bygg, kör, jämför, fixa och håll grafen stabil.

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.

Om ett stort jobb körs över många maskiner och en nod fallerar, är återställning från en kontrollpunkt ingen bekvämlighet. Det är en del av att göra beräkningen operativ. Om resultat aggregeras tillförlitligt måste aggregeringssemantiken definieras. Om en graf är innehållsadresserad måste den distribuerade sökvägen bevara grafens identitet snarare än att uppfinna en andra verklighet när jobbet lämnar en maskin.

Det är här produktens tolkning blir tydlig. Kera är inte ett syntaxlager med en distribuerad tilläggsmodul. Den försöker göra beräkningen portabel över både form och hårdvara: ett program, en graf, flera exekveringsmål och en post som kan kontrolleras. Distribuerad exekvering är ytterligare en plats där lowering måste bära exekveringskontraktet.

Det förändrar också bemanningsbilden. Utan en gemensam kompileringsväg kan en bugg som bara uppträder på en plattform kräva personer som kan chipet, verktygskedjan och runtime samtidigt. Med en graf och en gemensam väg blir frågan skarpare: ändrades grafen, ändrades lowering-vägen, eller bröt målet mot den definierade semantiken? Bättre frågor tar inte bort det hårda arbetet. De hindrar det hårda arbetet från att sprida sig slumpmässigt.

Varför någon måste äga vägen

Lowering kan inte förbli ägarlös när den bär resultat som människor förlitar sig på. En graf som körs på CPU, GPU, FPGA och WASM behöver mer än en smart representation. Den behöver dokumentation, diagnostik, målpåståenden, editorbeteende, kodgenerering, säkerhetskontroller, supportkonversationer och ett sätt att berätta för en köpare exakt vad som ändrades när ett resultat ändras.

Det gör inte arbetet mindre tekniskt. Det gör det tekniska arbetet mer bindande. Kera är för närvarande en kommersiell Dweve-produkt, inte en öppen källkodsrelease: alla rättigheter förbehållna, tillgänglig under kommersiell licens, tillverkad i Nederländerna och avsedd för organisationer som behöver grafvägen stödd snarare än bara publicerad. Om sidan säger Rust 2021, graf-IR, anpassad JIT, ingen LLVM, CPU/GPU/FPGA/WASM, effektspårning, ägande över minnesutrymmen, kapabilitetssäkerhet, distribuerad exekvering, C- och Python-inbäddning, CLI-arbetsflöden, editorstöd och LSP-verktyg, är det inte dekorativa interna detaljer. Det är åtaganden som måste överleva utvärdering av verkliga arbetsbelastningar.

Kapabilitetsbladet är noggrant här. Det beskriver designmål och säger att man ska verifiera mot sin egen arbetsbelastning. Den återhållsamheten betyder något. Det är mycket sundare än att låtsas att varje benchmark-siffra färdas. Systemet bör ge team ett sätt att mäta, inspektera och jämföra i sin egen miljö, inte be dem acceptera en universell hastighetsberättelse.

Någon måste äga den vägen eftersom varje mål försöker göra källan mindre universell. Kera är platsen där dessa måls skillnader blir explicit kompilatorarbete i stället för folklore som förs vidare efter buggrapporten.

Dagen då grafen blir kontraktet

Tänk dig den ursprungliga buggrapporten igen, men med Kera redan i arbetsflödet. Ett finansteam godkänner en riskberäkning. Grafens fingeravtryck registreras. Den första driftsättningen körs på CPU. Senare introduceras en GPU-väg för portföljanalys. Ännu senare används en FPGA-väg för prissättning med lägre latens. Frågan vid varje steg är inte om den nya hårdvaran låter imponerande. Frågan är om samma graf lowering-behandlas och om målsemantiken håller resultatet identiskt.

Konversationen förändras. Plattformsteamet kan prata om schemaläggning och kostnad. Kompilatorteamet kan prata om backends. Efterlevnadsteamet kan prata om fingeravtrycket. Verksamhetsägaren kan fråga om att byta hårdvara är ett operativt beslut eller en omskrivning. Produkten ger dem alla ett objekt att peka på.

Det är det tysta värdet med en innehållsadresserad IR. Den förvandlar plattformsoberoende exekvering från en rad övertalande förklaringar till ett register. Den gör grafen till ett kvitto. Den låter samma .keg mata varje backend. Den ger organisationen en baslinje som tillhör beräkningen snarare än en enskild maskin.

Ingen kompilator kan ta bort behovet av ingenjörsmässigt omdöme. Team måste fortfarande välja mål noggrant, testa arbetsbelastningar ärligt, förstå målets begränsningar och besluta vilka domäner som kräver bit-för-bit-identitet. Men Kera kan göra dessa beslut tydliga. Den kan förhindra att en prestandamigrering av misstag blir en semantisk migrering.

Läxan om lowering

Kera är viktig eftersom det svåra inte är att ha en smart idé om lowering. Det svåra är att bära den idén genom alla de tråkiga ställen där ingenjörskonst antingen blir pålitlig eller blir folklore: diagnostik, gröna träd, typ-hashar, borrow checking, fixpunktsoptimering, invariantvalidering, .keg-serialisering, backend-emission, säkerhetspolicy, revisionsloggar, editorstöd och målspecifik exekvering.

Lowering är arbete eftersom varje mål försöker göra källan mindre universell. Deterministisk kompilatorteknik är disciplinen att vägra låta det ske tyst. CPU vill ha vektorer. GPU vill ha kernels. FPGA vill ha cykler. WASM vill ha begränsningar. Organisationen vill ha ett svar. Keras jobb är att bevara beräkningens innebörd samtidigt som varje mål får göra det det är bra på.

Det är en ingenjörsmässig form, inte en abstraktion på papper. Den har en köpare, ett felscenario, ett filformat, en kompilatorväg och operativa konsekvenser. Löftet är inte att hårdvara blir enkel. Löftet är att komplexiteten representeras, loweras, kontrolleras och ägs.

När nästa nästan-rätt nummer dyker upp ska teamet inte behöva börja med folklore om vilken maskin som körde vad. Det ska börja med grafen. Stämde fingeravtrycket? Vilken backend genererade koden? Vilka förmågor beviljades? Vilken målsemantik tillämpades? Vilken artefakt lagrades? Det är produktfrågor. Kera finns för att de också är kompilatorfrågor.