Run transformer inference 4.76x faster on Apple Silicon Neural Engine
Espresso compiles transformer inference straight to Apple's Neural Engine via private APIs, running 4.76x faster than CoreML on Apple Silicon.
Why it matters
Accelerate transformer model inference on Apple Silicon by compiling MIL programs directly to the Neural Engine through reverse-engineered private APIs, bypassing CoreML overhead for production-grade speed improvements in on-device AI applications.
Outcomes
What it gets done
Compile transformer models directly to ANE silicon with zero-copy IOSurface buffers
Fuse multi-layer transformer kernels into 2 ANE dispatches instead of 6
Generate tokens at 1.08 ms/token with verified two-token decode steps
Train models on ANE with forward and backward passes plus gradient accumulation
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/christopherkarani-espresso | bash Overview
Espresso
Espresso compiles MIL programs directly to Apple's Neural Engine via reverse-engineered private APIs, bypassing CoreML for a 4.76x faster decode (1.08ms/token vs 5.09ms/token) using fused multi-layer kernels and zero-copy IOSurface I/O. It also supports full ANE training. Use it on Apple Silicon (M1+, macOS 15+) for high-throughput on-device inference or training in internal tools, research, or enterprise apps; it relies on private APIs so it cannot ship on the App Store.
What it does
Espresso compiles MIL (Model Intermediate Language) programs straight to Apple Neural Engine (ANE) silicon through reverse-engineered private APIs (_ANEClient, _ANEInMemoryModel), bypassing CoreML entirely. There is no per-token recompilation: the decode loop compiles once and reuses the program across all steps, with the KV cache living directly in IOSurface buffers instead of being marshaled through CoreML, and each step producing two exact tokens with verified parity. Fused triplet kernels process 3 transformer layers per ANE dispatch, so a 6-layer model runs in 2 dispatches instead of 6.
On a 6-layer reference model (dim=768, 12 heads, 32k vocab, seqLen=256, M3 Max, macOS 15), Espresso decodes at 1.08 ms/token (926 tok/s) versus CoreML's .cpuAndNeuralEngine path at 5.09 ms/token (196 tok/s) - a 4.76x speedup - and roughly 11x faster than llama.cpp's Metal GPU path, which has no ANE backend at all. Beyond inference, Espresso supports full training on the ANE: forward and backward passes with gradient accumulation and Adam. The whole project is pure Swift 6.2 with ~Copyable move-only tensors, strict concurrency, typed throws, and zero external dependencies - only Apple system frameworks.
Espresso also ships an ESP model platform around portable .esp bundles: .esp is the canonical portable model bundle, .espc is a derived compiled-cache layer, espc packs native model directories into .esp, and esprun inspects, resolves, and runs bundle artifacts.
When to use - and when NOT to
Use Espresso when you're building on Apple Silicon (M1 or later, macOS 15+) and want transformer inference or training to run directly on the Neural Engine at meaningfully higher throughput than CoreML's standard ANE path, or when you're researching or building internal tools, sideloaded apps, or enterprise-distributed software that can rely on private Apple APIs. It's a fit for anyone who wants zero-copy IOSurface I/O, fused multi-layer kernel dispatch, and a Swift Package Manager-integrable ANE runtime.
Do not use it in anything destined for the App Store: apps using the private _ANEClient and _ANEInMemoryModel APIs will be rejected. It also has no support for Intel Macs (no Neural Engine) and only conditional, entitlement-gated support on iOS/tvOS (not App Store safe there either). The published benchmarks are run on a local artifact family built by this repo, not a pretrained production model, and results are explicitly hardware- and OS-dependent since the whole approach relies on undocumented, reverse-engineered private APIs.
Inputs and outputs
Quick start clones the repo and runs a bootstrap script that builds, downloads demo weights, and launches a TUI:
git clone https://github.com/christopherkarani/Espresso.git
cd Espresso
./espresso
Other CLI entry points include ./espresso "Hello" (generate text), ./espresso doctor (check host readiness), ./espresso compare --no-power "Hello" (side-by-side vs CoreML), ./espresso install (install to ~/.local/bin), swift run espresso-bench --ane-only --inference --layers 6 (benchmarking), and the espc/esprun tools for packing and running .esp model bundles.
For library integration, add the package via Swift Package Manager and compile a kernel directly:
import ANERuntime
let kernel = try ANEKernel(milText: myMIL, weights: blobs, inputSizes: [input], outputSizes: [output])
try kernel.eval()
let result = kernel.outputSurface(at: 0)
Output is a zero-copy IOSurface-backed result read directly off the Neural Engine, plus, for benchmarking, machine-readable results written to artifacts/benchmarks/.
Integrations
Espresso integrates as a Swift Package Manager dependency, exposing the ANERuntime and ANETypes products for direct use in a Swift project. Internally it's layered as ANEInterop (a dlopen bridge to the private ANE APIs with NEON-vectorized I/O), ANETypes (~Copyable tensors and IOSurface I/O), MILGenerator (28+ kernel variants for forward, backward, decode, and fused kernels), CPUOps (RMSNorm, RoPE, embedding, softmax, and Adam via Accelerate/vDSP), and ANERuntime (MIL-to-ANE-E5-binary compilation and IOSurface buffer management), with Espresso itself providing transformer layers, generation, and the training loop, plus EspressoTrain and EspressoBench CLIs. Testing integrates swift test for unit tests plus opt-in hardware and cross-validation test suites gated by ANE_HARDWARE_TESTS=1 and OBJC_CROSS_VALIDATION=1.
Who it's for
Swift developers and ML engineers building on-device transformer inference or training for Apple Silicon who need throughput beyond CoreML's standard ANE path and are comfortable relying on private, reverse-engineered Apple APIs outside the App Store - internal tools, research, sideloaded apps, or enterprise distribution. It is licensed under MIT.
Source README
Direct Neural Engine inference for transformers on Apple Silicon.
Espresso compiles MIL programs straight to ANE silicon through reverse-engineered private APIs (_ANEClient, _ANEInMemoryModel). No CoreML in the hot path. No per-token recompilation. IOSurface buffers and fused multi-layer kernels for Apple Silicon.
- Direct ANE path - private-API compile once, reuse across decode steps
- Fused multi-layer kernels - fewer ANE dispatches per token
- Zero-copy I/O - NEON-vectorized surface reads, vDSP/Metal where useful
- Pure Swift 6.2 core -
~Copyablemove-only tensors, strict concurrency, typed throws - Zero required third-party packages - clean clone resolves and builds on macOS 15+
Product journeys
Pick one path. Everything else is optional or research.
1. Try it (demo)
git clone https://github.com/christopherkarani/Espresso.git
cd Espresso
./espresso # builds, downloads demo weights, launches TUI
./espresso doctor # host readiness check
2. Serve a model (.esp bundles)
Portable model bundles are the retained serving path:
# Pack a prepared native model directory into a portable bundle
swift run espc pack-native /path/to/model /tmp/model.esp --overwrite
# Inspect / run
swift run esprun inspect /tmp/model.esp
swift run esprun generate /tmp/model.esp "Hello" 32
# Same bundle boundary via the generate CLI
swift run espresso-generate generate --bundle /tmp/model.esp --max-tokens 32 "Hello"
| Artifact | Role |
|---|---|
.esp |
Canonical portable model bundle |
.espc |
Derived compiled-cache layer (host-local) |
espc |
Pack native model dirs into .esp |
esprun |
Inspect, resolve, generate from bundles |
espresso-generate --bundle |
Full generate/benchmark CLI on the same boundary |
3. Embed the library (ANEKernel)
// Package.swift
.package(url: "https://github.com/christopherkarani/Espresso.git", from: "1.0.0")
import ANERuntime
let kernel = try ANEKernel(
milText: myMIL,
weights: blobs,
inputSizes: [input],
outputSizes: [output]
)
try kernel.eval() // runs on Neural Engine
let result = kernel.outputSurface(at: 0) // zero-copy read
For end-to-end text generation from prepared weights, use RealModelInference or a .esp bundle rather than hand-writing MIL.
Optional tooling (bench, install, training)
./espresso install # shim → ~/.local/bin
./espresso compare --no-power "Hello" # side-by-side vs CoreML (demo weights)
swift run espresso-bench --ane-only --inference --layers 6
swift run espresso-train # experimental ANE training loop
Rejected experiment configs and distillation scripts live under research/ and are not product entry points.
Benchmark
Numbers below match the checked-in machine-readable results inbenchmarks/results/latest.json
(M3 Max, macOS 15.0, Espresso 1.1.0).
Espresso vs CoreML (local 6-layer Stories artifact)
| Backend | ms/token | tok/s | Notes |
|---|---|---|---|
| Espresso ANE (recurrent fused, 6-layer) | 1.93 | 519 | Fused 3-layer recurrent decode + ANE classifier |
| Espresso ANE (direct transformer, 6-layer) | 6.56 | 153 | Same model without recurrent fusion |
CoreML .cpuAndNeuralEngine |
6.58 | 152 | Apple's standard ANE path |
| Espresso speedup vs CoreML | 3.41× | fused recurrent path |
All Espresso / CoreML numbers: 6-layer local artifact · dim=768 · 12 heads · 32k vocab · seqLen=256 · M3 Max · macOS 15.
This is a research / demo artifact family, not a pretrained production model.
What these numbers are not
- Not a claim about full GPT-2 117M or llama.cpp Metal on the same workload
- Not every serving path: retained exact hybrid
.espStories runs can land lower in wall-clock tok/s after compile and full decode accounting - Not trunk-only or partial-pipeline peaks from blog posts - only figures backed by
latest.json(or a PR artifact from the reproduce script) are project claims
Reproduce Espresso benchmarks
RESULTS_DIR=results/$(date +%Y%m%d-%H%M%S) \
REPEATS=5 WARMUP=3 ITERATIONS=20 \
./scripts/reproduce_local_real_artifact_claim.sh
Machine-readable output lands in artifacts/benchmarks/ and is kept out of git.
Update benchmarks/results/latest.json only when you intentionally refresh the public table.
CI fails if the README table drifts from latest.json.
Platform Compatibility
| SoC | Neural Engine | Tested | Notes |
|---|---|---|---|
| M1 / M1 Pro / M1 Max / M1 Ultra | 16-core ANE | ✅ | Full feature set |
| M2 / M2 Pro / M2 Max / M2 Ultra | 16-core ANE | ✅ | Full feature set |
| M3 / M3 Pro / M3 Max | 18-core ANE | ✅ | Reference hardware (M3 Max) |
| M4 / M4 Pro / M4 Max | 38-core ANE | ✅ | Faster compile cache warm-up |
| Intel Mac | - | ❌ | No Neural Engine |
| Apple A-series (iOS) | ✅ | ⚠️ | Requires entitlement; not App Store safe |
macOS 15+ required. iOS / tvOS not supported out of the box (private API entitlements differ per platform).
How It Works
┌─────────────────────┐
│ MIL Program Text │ Generated per-kernel
└──────────┬──────────┘
▼
┌─────────────────────┐
│ _ANEClient compile │ Private API (dlopen)
└──────────┬──────────┘
▼
┌─────────────────────┐
│ ANE E5 Binary │ Cached by system
└──────────┬──────────┘
▼
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ IOSurface │ │ IOSurface │ │ IOSurface │
│ (input) │ │ (weights) │ │ (output) │
└──────┬───────┘ └──────────────┘ └──────┬───────┘
│ ANE Hardware │
└──────────────eval───────────────┘
The decode loop compiles once and reuses the program across all steps. KV cache lives in IOSurface buffers - not marshaled through CoreML.
Architecture
ANEInterop (ObjC/C — private API bridge)
└── ANETypes (~Copyable value types, IOSurface I/O)
├── MILGenerator (kernel variants)
│ └── ANERuntime (compile, eval, surface management)
│ └── Espresso / RealModelInference (serving, decode)
│ ├── espresso-generate / esprun (CLI)
│ └── ESPBundle (portable .esp)
└── CPUOps (Accelerate/vDSP kernels)
| Module | What it does |
|---|---|
| ANEInterop | dlopen bridge to _ANEClient and _ANEInMemoryModel. NEON-vectorized I/O. |
| ANETypes | ~Copyable tensors, SurfaceIO, weight serialization, model config. |
| MILGenerator | Generates MIL text for forward, backward, decode, and fused kernels. |
| CPUOps | RMSNorm, RoPE, embedding, softmax, Adam via Accelerate/vDSP. |
| ANERuntime | Compiles MIL to ANE E5 binaries. Manages IOSurface buffers and compile budget. |
| Espresso | Generation harnesses, decode, training experiments. |
| RealModelInference | Hybrid serving path used by espresso-generate / .esp runtime. |
| ESPBundle / ESPRuntime | Portable .esp bundles and runtime resolution. |
SPM Integration
// Package.swift
dependencies: [
.package(url: "https://github.com/christopherkarani/Espresso.git", from: "1.0.0")
],
targets: [
.target(name: "MyApp", dependencies: [
.product(name: "ANERuntime", package: "Espresso"),
.product(name: "ANETypes", package: "Espresso"),
])
]
import ANERuntime
import ANETypes
let kernel = try ANEKernel(
milText: milText,
weights: weightBlobs,
inputSizes: [inputByteSize],
outputSizes: [outputByteSize]
)
try kernel.eval()
let output = try kernel.outputSurface(at: 0)
Dependencies
Zero third-party Swift packages. The package graph depends only on Apple system frameworks (Foundation, Accelerate, IOSurface, Metal, CoreML). A clean clone of this repo alone must resolve and build.
Requirements
| Minimum | |
|---|---|
| Hardware | Apple Silicon (M1+) with Neural Engine |
| macOS | 15.0+ |
| Swift | 6.0+ (6.2 recommended) |
| Dependencies | None required - Apple system frameworks only |
Testing
swift test # unit tests (no ANE needed)
ANE_HARDWARE_TESTS=1 swift test --filter "ANERuntimeTests|EspressoTests" # hardware tests
OBJC_CROSS_VALIDATION=1 ANE_HARDWARE_TESTS=1 swift test --filter CrossValidationTests # parity
CI runs non-hardware unit tests including ESP bundle/runtime and RealModelInference unit suites, asserts a zero-dependency default graph, and checks README claim numbers against latest.json. Hardware ANE tests run on self-hosted matrix jobs.
Research vs product
| Path | Location |
|---|---|
| Retained product surface | Sources/, ./espresso, espc / esprun / espresso-generate, public docs |
| Quarantined experiments | research/ - rejected draft/student/future-head configs and tooling |
Do not treat research/ numbers or flags as supported product behavior.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.