ANE/training
Andy Huang dcacf8a3ae Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
..
.gitignore Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
Makefile Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
PR-01.md Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
README.md Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
ane_mil_gen.h Initial release 2026-02-28 00:22:06 -08:00
ane_runtime.h Initial release 2026-02-28 00:22:06 -08:00
backward.h Initial release 2026-02-28 00:22:06 -08:00
benchmark_ane.m Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
dashboard.gif stories110M: 12-layer ANE training with dashboard, 107ms/step 2026-03-01 03:14:39 -08:00
dashboard.py stories110M: 12-layer ANE training with dashboard, 107ms/step 2026-03-01 03:14:39 -08:00
encode_bpe.py Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
forward.h Initial release 2026-02-28 00:22:06 -08:00
m5result.md Add M5 probe results: weight reload fails, all QoS work, chaining API found 2026-03-01 23:16:38 -08:00
model.h Initial release 2026-02-28 00:22:06 -08:00
sample.py Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
stories_config.h Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
stories_cpu_ops.h stories110M: 12-layer ANE training with dashboard, 107ms/step 2026-03-01 03:14:39 -08:00
stories_io.h Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
stories_mil.h Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
test_ane_advanced.m Add M5 probe results: weight reload fails, all QoS work, chaining API found 2026-03-01 23:16:38 -08:00
test_ane_causal_attn.m Initial release 2026-02-28 00:22:06 -08:00
test_ane_sdpa5.m Initial release 2026-02-28 00:22:06 -08:00
test_conv_attn3.m Initial release 2026-02-28 00:22:06 -08:00
test_full_fused.m Initial release 2026-02-28 00:22:06 -08:00
test_fused_bwd.m Initial release 2026-02-28 00:22:06 -08:00
test_fused_qkv.m Initial release 2026-02-28 00:22:06 -08:00
test_perf_stats.m Add M5 probe results: weight reload fails, all QoS work, chaining API found 2026-03-01 23:16:38 -08:00
test_qos_sweep.m Add M5 probe results: weight reload fails, all QoS work, chaining API found 2026-03-01 23:16:38 -08:00
test_weight_reload.m Add M5 probe results: weight reload fails, all QoS work, chaining API found 2026-03-01 23:16:38 -08:00
tiny_train.m Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
tiny_train_old.m Initial release 2026-02-28 00:22:06 -08:00
tokenize.py Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
tokenize_text.py Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
tokenizer.py Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
train.m Initial release 2026-02-28 00:22:06 -08:00
train_bpe.py Refactor hardcoded absolute paths to script-relative paths 2026-03-03 14:32:43 +11:00
train_large.m Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00
vocab.json Optimize ANE training with weights-as-tensors, add inference and benchmarking tools 2026-03-03 14:10:44 +11:00

README.md

ANE Training — Stories110M on Apple Neural Engine

Training a 109M-parameter Llama2-architecture transformer (Stories110M) directly on Apple's Neural Engine using private ANE APIs. This implementation uses a "Weights-as-Tensors" optimization to bypass compilation limits and achieve high throughput.

Dashboard

Architecture

  • Model: Stories110M — dim=768, hidden=2048, heads=12, layers=12, vocab=5000, seq=256
  • Optimization: Weights-as-Tensors. All model weights are passed as dynamic input tensors via IOSurfaces. Kernels are compiled exactly once at startup.
  • 72 ANE kernels total (60 weight-bearing, 12 weight-free sdpaBwd2).
  • 6 kernel types per layer: fwdAttn, fwdFFN, ffnBwd, sdpaBwd1, sdpaBwd2, qkvBwd.

Performance (Optimized)

Metric Value
Training Latency ~79.6 ms/step
Inference Latency (SEQ=256) 0.60 ms
Sustained ANE Throughput ~94.4 TFLOPS
Theoretical Inference TPS ~429,000 Tokens/sec
Weight Sync ~3.4 ms per layer (NEON-accelerated)
Compile Budget 0 restarts (Dynamic weight updates)

Configuration Variables

Most configuration is handled in stories_config.h and train_large.m.

Model Hyperparameters (stories_config.h)

  • DIM: Model dimension (default: 768)
  • HIDDEN: FFN hidden dimension (default: 2048)
  • NLAYERS: Number of transformer layers (default: 12)
  • VOCAB: Vocabulary size (default: 5000)
  • SEQ: Sequence length / context window (default: 256)

Training Paths (train_large.m)

  • DATA_PATH: Path to the tokenized binary dataset (default: tinystories_data00.bin)
  • MODEL_PATH: Path to the initial pretrained weights in llama2.c format.
  • CKPT_PATH: Output path for training checkpoints.

Compiling & Running

1. Prerequisites

Ensure you have a modern Mac with Apple Silicon (M1/M2/M3/M4). You will need xcrun (Xcode Command Line Tools) and various Python dependencies for data prep and monitoring.

2. Prepare Data

The trainer expects a flat binary file of uint16_t token IDs.

# Tokenize raw text into the expected format
python3 tokenize.py

3. Build and Train

# Compile the training binary
make train_large

# Start training (fresh start or default steps)
./train_large

# Resume with custom steps and learning rate
./train_large --resume --steps 1000 --lr 1e-4

Dataset Adaptation

To adapt this trainer to any custom text dataset:

  1. Tokenize: Use a tokenizer to convert your text corpus into a sequence of IDs.
  2. Export: Save the IDs as a raw binary file of uint16_t values.
  3. Configure: Update VOCAB, SEQ, and DATA_PATH in the config files to match your dataset.
  4. Compile: Re-run make train_large. The ANE kernels will automatically adjust to your new shapes.

Monitoring with Dashboard

The TUI dashboard provides real-time telemetry on loss, power usage, and model generation.

pip install blessed psutil numpy
# Dashboard may require sudo for powermetrics access
python3 dashboard.py --resume

Testing the Model

You can test the trained model using the standalone inference script. It uses standard vanilla NumPy to perform the forward pass on the CPU, making it easy to inspect.

Generate Text

# Test with a custom prompt and checkpoint
python3 sample.py --prompt "Once upon a time" --ckpt ane_stories110M_ckpt.bin --steps 100

Parameters

  • --prompt: The starting text for generation.
  • --ckpt: Path to the training checkpoint (.bin).
  • --vocab: Path to the BPE vocabulary (vocab.json).
  • --steps: Maximum number of tokens to generate.
  • --temp: Sampling temperature (default 0.8).

ANE Hardware Benchmark

To measure raw hardware throughput and verify the Weights-as-Tensors optimization on the actual ANE silicon, use the C-based benchmark utility:

# Build the benchmark
make benchmark_ane

# Run 100 iterations of full-model forward pass
./benchmark_ane

This utility measure tokens per second and TFLOPS directly on the ANE by running 24 kernels (Attn+FFN) in a continuous loop.


Key Optimization: Weights as Tensors

Previously, ANE training required recompiling kernels every time weights changed, hitting an OS-enforced 119-compile limit.

The current implementation defines weights as formal function parameters (tensor<fp16, [dim, dim]>) in the MIL program. This allows us to:

  1. Compile the kernel logic once.
  2. Update weights between batches by writing directly to IOSurfaces via NEON-accelerated loops (io_write_fp16_t).
  3. Maintain resident memory for the model, eliminating the need for exec() restarts.