maderix / ANE
- четверг, 30 июля 2026 г. в 00:00:06
Training neural networks on Apple Neural Engine via reverse-engineered private APIs
Training neural networks directly on Apple's Neural Engine (ANE) via reverse-engineered private APIs. No CoreML training APIs, no Metal, no GPU — pure ANE compute.
I'm genuinely grateful for all the attention this project has received — I never expected a weekend research hack to blow up like this. Thank you to everyone who starred, forked, ran benchmarks on their own hardware, and shared the work. It means a lot.
That said, I want to set clear expectations about what this project is and isn't.
This is a research project, not a production framework.
The goal was to demonstrate that training on the Apple Neural Engine — and potentially other NPUs — is possible, and that the barrier has always been software support, not hardware capability. The ANE is a remarkably capable piece of silicon that Apple restricts to inference-only use through CoreML. This project bypasses that restriction using reverse-engineered private APIs to show what's possible when you give the hardware a chance.
_ANEClient and _ANECompiler private APIsSome coverage of this project has overstated its implications. To be clear:
The honest results — including all limitations — are documented in the accompanying articles:
I don't intend to grow this into a large community project. My focus is on original research (compiler infrastructure for edge AI optimization), and maintaining an open-source framework takes time away from that.
That said:
This is MIT licensed for a reason. Everyone now has access to AI-assisted development tools that can adapt and extend code in hours. If this project is useful to you — take it, modify it, build something better. If you do something cool with it, I'd love to hear about it.If in future, community decides to maintain one source of truth repo, I'm in full support of that.
A from-scratch implementation of transformer training (forward + backward pass) running on the ANE in Apple Silicon. The ANE is a 15.8 TFLOPS FP16 (M4) inference accelerator that Apple does not expose for training. This project reverse-engineers the _ANEClient / _ANECompiler private APIs and the MIL (Model Intermediate Language) format to run custom compute graphs — including backpropagation — directly on ANE hardware.
Current results:
| Model | Params | ms/step | Pipeline |
|---|---|---|---|
| Stories110M (12L, dim=768, MHA 12/12) | 109M | 91 ms | Dynamic (no recompile) |
| Qwen3-0.6B (28L, dim=1024, GQA 16/8) | 596M | 412 ms | Dynamic (no recompile) |
INT8 W8A8 quantization — 1.88x throughput (M4, H16G):
| Config | FP16 | INT8 W8A8 | Speedup |
|---|---|---|---|
| 128x conv 512ch 64x64 | 18.6 TOPS, 14.8ms | 35.1 TOPS, 7.8ms | 1.88x |
| 64x conv 512ch 64x64 | 18.4 TOPS, 7.5ms | 34.1 TOPS, 4.0ms | 1.85x |
INT8 activations halve L2 SRAM bandwidth between tiles via MIL quantize/dequantize ops. Weights use constexpr_affine_dequantize (int8 stored, fp16 at compile time).
The dynamic pipeline uses shared ANE kernels with weights packed into spatial dimensions (no recompilation when weights change):
MHA models (Stories110M) — 6 kernels per layer:
| Kernel | Function |
|---|---|
sdpaFwd |
QKV projection + SDPA + output projection |
ffnFused |
SwiGLU FFN (W1, W3, SiLU, W2) |
ffnBwdW2t / ffnBwdW13t |
FFN backward (split for memory) |
sdpaBwd1 / sdpaBwd2 |
SDPA backward |
GQA models (Qwen3-0.6B) — 10 kernels per layer:
Adds separate woFwd, qBwd, kvBwd kernels for grouped-query attention (Q_DIM ≠ DIM).
CPU handles: RMSNorm forward/backward, residual connections (DeepNet α scaling), loss computation, dW gradient accumulation (cblas_sgemm), Adam optimizer updates.
Key optimizations:
[1,C,1,S] format, eliminates all transpose overhead├── api_exploration.m # Initial ANE API discovery
├── inmem_basic.m # In-memory MIL compilation proof-of-concept
├── inmem_bench.m # ANE dispatch latency benchmarks
├── inmem_peak.m # Peak TFLOPS measurement (2048x2048 matmul)
├── ane_int8_bench.m # INT8 W8A8 vs FP16 throughput benchmark
├── sram_bench.m # ANE SRAM bandwidth probing
├── sram_probe.m # SRAM size/layout exploration
├── gpu_ane_share.m # GPU↔ANE zero-copy IOSurface demo
├── gpu_prefill_ane_decode.m # GPU prefill → ANE decode pipeline
├── bridge/
│ ├── ane_bridge.h # C-callable ANE API (compile, eval, I/O)
│ ├── ane_bridge.m # Bridge implementation (int8 + fp16 weight blobs)
│ └── Makefile
└── training/
├── ane_runtime.h # ANE private API wrapper (compile, eval, IOSurface)
├── ane_classifier.h # Classifier fwd (32K conv), softmax, rmsnorm on ANE
├── train_large.m # Static pipeline (weights as constants, recompiles)
├── training_dynamic/
│ ├── train.m # Dynamic training loop (model-agnostic)
│ ├── config.h # Derived sizes, structs, alloc helpers
│ ├── mil_dynamic.h # MIL generators for dynamic weight kernels (GQA-aware)
│ ├── io.h # IOSurface I/O, weight staging, GQA tile/reduce
│ ├── models/
│ │ ├── stories110m.h # Stories110M config (12L, MHA)
│ │ └── qwen3_06b.h # Qwen3-0.6B config (28L, GQA)
│ └── Makefile
├── dashboard.py # Live training dashboard (blessed TUI)
└── Makefile
Training requires pretokenized TinyStories data. To download:
cd training && bash download_data.shSee training/README.md for detailed training instructions.
Requires macOS 15+ on Apple Silicon (tested on M4).
# Dynamic pipeline (recommended) — model selected at build time
cd training/training_dynamic
make MODEL=stories110m # Stories110M (12L, MHA, 109M params)
make MODEL=qwen3_06b # Qwen3-0.6B (28L, GQA, 596M params)
./train --scratch # train from random init
./train --resume # resume from checkpoint
# Static pipeline (legacy — recompiles weights each step)
cd training && make train_large
./train_large ane_stories110M_ckpt.bin 256 100 1e-4
# INT8 benchmark
xcrun clang -O2 -fobjc-arc -framework Foundation -framework IOSurface -ldl \
-o ane_int8_bench ane_int8_bench.m
./ane_int8_bench
# Bridge library (C-callable ANE API)
cd bridge && makeNo external dependencies. Uses only system frameworks + private ANE APIs resolved at runtime via objc_msgSend.
_ANEInMemoryModelDescriptor compiles MIL text + weight blobs directly to ANE programs, no disk mlmodelc needed[1, channels, 1, spatial] format (fp16 or fp32; fp16 direct I/O is ~37% faster)constexpr_affine_dequantize for int8 weights, quantize/dequantize between layers for int8 activation caching in L2 SRAM (1.88x throughput)attn_mask in SDPA ops; causal attention is decomposed into separate Q@K^T (ANE) → mask+softmax (CPU) → scores@V (ANE)exec() restart with checkpoint256 * NLAYERS)Training throughput (M4):
| Model | Params | ms/step | Layers | Kernels/layer |
|---|---|---|---|---|
| Stories110M | 109M | 91 ms | 12 | 6 (MHA) |
| Qwen3-0.6B | 596M | 412 ms | 28 | 10 (GQA) |
ANE peak throughput (M4, H16G):
| Precision | Peak TOPS | Config |
|---|---|---|
| FP16 | 18.6 | 128x conv 512ch 64x64 |
| INT8 W8A8 | 35.1 | 128x conv 512ch 64x64 |
GPU↔ANE inference pipeline (M4, seq=256):
| Model | GPU Prefill | ANE Decode | Total |
|---|---|---|---|
| Stories110M | 6.7ms | 1.9ms | 8.8ms |
| Qwen3-0.6B | 9.7ms | 2.3ms | 12.0ms |
This project uses Apple's private, undocumented APIs (_ANEClient, _ANECompiler, _ANEInMemoryModelDescriptor). These APIs are not covered by any public stability guarantee and may change or break with any macOS update. This is independent research into Apple Neural Engine architecture, using APIs discovered through runtime introspection for research and educational purposes under fair use and interoperability provisions (see Sega v. Accolade, 1992; DMCA §1201(f)). No Apple proprietary code or binaries are included in this repository. This project is not affiliated with or endorsed by Apple Inc. Use at your own risk.
MIT — see LICENSE
Built by a human + Claude, one weekend at a time.