Traditionally, bringing a complex AI model to new AI acceleration hardware is complex. Most companies do not offer any low level programming layer, they provide a model zoo and and a black box compiler. If you need something new, you need to wait for months until the compiler supports it. Some companies offer programmability but performance is simply not there, only their engineers are equipped with the tools to extract the performance out of the hardware.
We built AxeleraScript (AxScript for short) to break that cycle and offer both programmability and performance. And to prove how much the game has changed, I decided to test it myself.
As a result, GR00T N1.7, a 3-billion-parameter vision-language-action model (VLA), now runs on a single Axelera AI Europa card with no accuracy loss versus the PyTorch reference, driving a simulated Panda arm through LIBERO tasks. I ported it and brought it to about 200 ms per decision (5 Hz), with every transformer in the model on the card. I am a product person, not an ML engineer: I did it by steering AI coding agents against AxScript, in about a week of part-time work (prompting the agent every 4-5 hours, between meetings or before going to bed) and around $500 in tokens, the same week Europa started shipping to customers. Then one of our engineers spent a day on it and took it to 66 ms (15 Hz), with the whole network, action head included, on the card.
This post is an account of how that went, what closed the gap between 200 and 66 ms, and what it says about AxScript and Europa for Physical AI.
Why GR00T, and why it is hard
GR00T N1.7 is two models glued together. A Qwen3-VL vision-language backbone (a 24-block vision transformer plus 16 decoder layers) reads two camera images and the instruction. A 32-block diffusion transformer (the "action head") then denoises a chunk of 16 future robot actions in four flow-matching steps, attending to the backbone's output at every block. It is exactly the shape of model that generative AI at the edge is converging on: billions of weights, a transformer that runs many times per decision, and a hard real-time budget, because a robot that thinks for a second drops the bowl.
On the desktop CPU of the test host (an Intel Core i5-13500E), one decision took 19.2 seconds. The first port to Metis took it below 1s. Then I set out to bring it below 200 ms. When I was done, I asked for help and it went down to 66ms. Here is the full account.


The Metis-based Axelera 130p (top) and the Europa-based Axelera 232p (bottom) cards used to run the VLA. Both are HHHL (Half-length, half-height) x4 PCIe cards.
Step 1: port it to Metis (one day, steering the AI agent in between meetings)
I did not write kernels. I wrote a plan, and I ran AI coding agents against our Voyager SDK with one rule: build the numerical oracle first. The AI agent used AxScript, our newly released DSL for programming Axelera AI hardware, to port the model. Every stage of the port got a recorded reference from the real checkpoint before a single line of device code existed, and every kernel had to reproduce it before the next one was written.
That discipline is what AxScript makes practical. AxScript lets a model's blocks be written as Python kernels that compile to the in-memory-compute cores, with the SDK's quantization toolkit calibrating the same torch reference the kernel is scored against. The agents used the SDK's own Qwen3-VL pipeline for the backbone, which came out as a compiled graph, and wrote the diffusion head themselves: two block kernels (self-attention over the 41 action tokens, cross-attention into the vision-language context), compiled once and instantiated 32 times in one graph, plus the small self-attention pre-pass in front of it.
Result: backbone and action head both on the card, feature cosine 0.9995 against PyTorch, end-to-end action cosine 0.9992, 870 ms per call.
|
Stage |
All on the host CPU |
Both halves on Metis |
|---|---|---|
|
Backbone (vision + language) |
7,941 ms |
331 ms |
|
Action head |
1,320 ms (fp32) |
536 ms |
|
Policy call |
19,200 ms |
870 ms |
|
Episode wall time |
137 s |
30 s |
What AxScript gave me in this step
- A transformer with no existing pipeline was brought up on the device in a day, from PyTorch.
- Quantization calibrates against the same reference the kernel is tested against, which is why 0.999 cosine held at every stage.
- Two kernels, compiled once, became a 32-block graph.
- The SDK's existing Qwen3-VL pipeline covered the backbone, so the agents only had to write what was new.
Step 2: optimize it on Metis (half a day)
The second phase felt most like product management: provide the documentation (the AxScript performance guidelines), set a metric, insist on an A/B judge, refuse changes that cannot be measured.
AxScript exposes two levels of control in Python, and the agents used both. Schedule-level knobs on the SDK's matmul op: pipelining each tile's weights under the previous tile's compute, prefetching the first tile under the attention, sharding the big feed-forward across the four cores. And graph-level structure: the cross-attention blocks' keys and values are projections of the vision-language context, which does not change across the four denoising steps, so a "prime" graph projects them once per call into device state and the denoising graph reads them.
The head went from 86.8 to 64.0 ms per step, a 26% gain from documented knobs with no compiler changes. The call went from 870 to 644 ms, without impact to task success rates. But Metis was just my starting point, my end goal was always Europa and now I had a board. For context, Metis has 30 GB/s of LPDDR4X memory bandwidth; Europa has 200 GB/s.

Step 3: port it to Europa (two more days, mostly steering AI agents)
Europa is the part this was all for: eight in-memory-compute cores, 200 GB/s of memory BW and 32 GiB on one card. The port took a morning, on the early-access SDK release, with the same code all our customers get.
The reason it took a morning is the AxScript workflow itself. Every tool in the repo already took the hardware generation from one environment variable. The only real work was that the Europa early-access compiler did not yet support one of the schedule options used on Metis (weight pipelining), so the build scripts now check which options the installed SDK offers and fall back to the plain schedule when one is missing. Same checkpoint, same calibration frames, same checks: feature cosine 0.99952, action cosine 0.9996, LIBERO task success and 391 ms per call. That is 1.6x faster than optimized Metis before any Europa-specific work, on an early compiler, with zero tuning.
First optimization step. Using a newer, soon-to-be-released compiler, the decoder was compiled for the context length the task actually uses, each block's weights were split across the card's two memory regions so both stream at once, and the two cameras went through the vision tower in one dispatch instead of two. The call came to 274 ms, at the same accuracy.
Second optimization step. The remaining time was in the plumbing between kernels, and AxScript's graph descriptor already had the tools to remove it. The diffusion head went from 33 kernel dispatches per step to four by binding eight blocks to one call, a configuration change rather than new code. Folding the vision-language self-attention into the diffusion head's priming kernel removed one loaded model and one model switch per call. And trimming graph inputs (a denoise step went from fifty inputs to eight, and each block's eighteen small scale tables became three buffers) cut the runtime's per-run overhead. The head went from 114 to 67 ms for four steps.


|
Per policy call |
Metis, optimized |
Europa, first port |
Europa, first optimization step |
Europa, second optimization step |
|---|---|---|---|---|
|
Vision tower, both cameras |
137 ms |
82 ms |
84 ms |
56 ms |
|
Decoder prefill |
193 ms |
90 ms |
44 ms |
33 ms |
|
VL self-attention + K/V priming |
25 ms |
24 ms |
24 ms |
19.5 ms |
|
Diffusion head, four steps |
256 ms |
184 ms |
114 ms |
67 ms |
|
Policy call, steady state |
644 ms |
391 ms |
274 ms |
199 ms |
|
LIBERO Task success |
20/20 |
20/20 |
20/20 |
20/20 |
|
Action cosine vs PyTorch |
0.9996 |
0.9996 |
0.9996 |
0.9965 |
Against optimized Metis, Europa's final numbers are close to 6x on decoder prefill (193 to 33 ms), almost 4x on the diffusion head (256 to 67 ms), and 3.2x on the full call. Against the host CPU we started from, the policy call is 96x faster. The small drop in action cosine in the last column (0.9996 to 0.9965) comes from the shorter compiled context and had no effect on the closed loop, which stayed at 20 of 20.
Hide the latency that is left. Even at 200 ms a call, a synchronous loop is visible: the arm executes eight steps, then holds while the next chunk is inferred. The fix was not in the model's speed but in the loop, and the model already carried it. GR00T N1.7's action head implements real-time chunking: given the chunk that is still executing, it denoises the next one so that the steps that will have run by the time it arrives are kept, the next few ramp over, and the rest are free. So the simulator now asks for chunk n+1 eight steps into chunk n, from a worker thread, keeps executing chunk n meanwhile, and splices the new chunk in at the index that corresponds to "now" when it lands, two to four steps later. Because the model was told which steps would already have run, the splice causes no jump in the motion. The animation at the top of this post shows this asynchronous loop
A second pair of hands: from 199 ms to 66.4 ms
Under 200 ms was the goal, and the agents had reached it. With the documented knobs exhausted, their own estimate of the floor was around 170 ms. But I had a feeling Europa could do better. So I shared the port with Fabian, from our engineering team, to see how far he could push it, with the same model, the same two cameras, the same four denoising steps, and the same checks.
Less than a day later, one policy call went down to 66.4 ms (15Hz), 3 times faster than where I had left it.

Every stage moved. The vision tower and the text prefill were re-cut so that all eight cores stay busy and every weight is already on its way before the matmul that needs it; the diffusion head streams its weights the same way and runs eight blocks per dispatch; the small action encoder and decoder, which had been the host's job, moved onto the card, so a call is four graph runs instead of seven; and the whole policy became one runtime model. The host's share fell from 33 ms to 5. None of it changed the model or the sampler: the actions are bit-identical between runs, within a hair of the previous configuration on a held-out set of observations from every task in the suite, and the closed-loop success rate is the same.
Three things in his work are worth naming for what they say about our roadmap:
- He used a profiler. The per-core timeline that told him where each core was waiting, and on what, comes from an internal profiling tool for the Europa datapath. That tool is not yet part of the public SDK, and it will take some time before it is. When it ships, this kind of analysis becomes a one-command step, and agents will be able to optimize AxScript kernels against it in a closed loop.
- He used tricks the compiler supports but the documentation does not yet explain. Streaming a kernel's weights ahead of its ops on the DMA channel the ops leave idle, laying out the attention for a core's heads in one pass, keeping intermediates where the next op can read them without a round trip through memory. These are AxScript idioms, and we will make them available as part of the AxScript documentation, with the examples from this port.
- Some of the gain is in the runtime, not the kernels. A few small changes to the host runtime library remove per-call setup work that grew with the size of the model. They are on their way into a release.
All three are on their way into the SDK. When they land, anyone, including a product person steering an AI agent, will be able to reach this level of optimization.
A single Domain Specific Language (DSL) to dominate all Axelera chips
The beauty of AxScript compatibility across Axelera chips is that optimization work is not stranded on the part it was done on. Fabian's pass on Europa, which took a GR00T N1.7 policy call from 199 to 66.4 ms, was written as AxScript kernels and host code against one SDK release, and the same branch was pulled onto a Metis host the next day.
One merged runtime model, the two-camera vision tower, eight DiT blocks a dispatch with the VL self-attention folded into the prime, the device action head, the cached front end and the three runtime patches all compiled and ran on Metis as they were. The only changes were a generation-aware choice of memory region, a per-matmul decision on weight pipelining, a Metis variant of the text-prefill kernel's data movement, and dropping three schedule options that rely on Europa-only hardware features, which the Metis compiler refused at build time rather than running wrong. The result was a Metis call that went from 644 ms to 476 ms, with the same four denoising steps (411 ms with three, which this task tolerates). The work done to make Europa fast moved back to Metis in a day, with the compiler telling us exactly where the two chips differ.
What AxScript, Metis & Europa mean for Physical AI
Unlocking More Intelligence per Watt
Both Europa and Metis run every transformer in the policy: the vision tower, the language model and the diffusion head. The host runs the simulator plus some light glue logic. On a robot, that means a low-power host CPU is enough to drive the full system. What is the accelerator power?
- On Metis, I measured power consumption on the Axelera Edge 130p rev2.0 (a PCIe card) which has two embedded power probes (on the main and aux rails) and the power consumption was 4.87W average

- On Europa, unfortunately the power probes on the PCIe card are not exposed yet in the SDK, so I could not take measurements. When it becomes available, I will update this post, until then I assume 30W which I expect to be above the actual draw
Compared with NVIDIA's published GR00T N1.7 numbers on Jetson Thor and Orin AGX, both Metis and Europa provide significantly more performance per watt. If we think about thermally and battery-constrained robots, vehicles or other physical AI devices, this can break or make an application. Not to mention that both chips cost a fraction of what GPUs do.

Unlocking any workload, now and in the future
We know the models change fast. GR00T has swapped its vision-language backbone between releases, and N1.7 now builds on Cosmos-Reason2-2B, a Qwen3-VL model. Action heads range from flow matching with four denoising steps (GR00T) or ten (π0.5) to autoregressive action tokens, and research groups are already testing one-step heads. Hardware for this market has to run the next two years of architectures, not only the one it was benchmarked on.
This port shows what that looks like in practice. A non-developer, steering AI agents with no help from Axelera engineering, wrote a new transformer head as AxScript kernels, optimized it from the performance guidelines, moved it across two hardware generations with one environment variable and a few compiler-feature checks, and reached the 200 ms target in days of very spare part-time work. One engineer then found the next 3x in a day, and the tools behind that are on their way into the SDK. When the next VLA ships with a different head, we expect the port to take days, using the same workflow.
Physical AI has advanced remarkably in the past few years. Vision-language models gave robots an understanding of scenes and instructions, and VLAs now turn that understanding directly into motion. What has been missing is hardware that runs these models where robots actually operate, within the power and cost budgets of a real product. With Metis and Europa today, and the generations that follow, we aim to close that gap: bringing the performance, efficiency, affordability and flexibility physical intelligence needs to the edge, and putting it within reach of every robotics team, not only the best-funded labs.