JevLite for Apple Silicon — typed decisions on the Neural Engine

Apple Silicon Core ML Neural Engine Params License

English | 日本語

Ready-to-run Core ML packages of a 149M ModernBERT typed-decision engine, built for Apple Silicon. Hand it a state plus any set of typed questions (noul / choice / score) and it answers all of them in one forward pass with a confidence each — fully on-device, no server, no API cost.

  • 🍎 Core ML .mlpackage, fp16, runs on the Apple Neural Engine (compute_units="cpu_and_ne")
  • ⚡ 13 ms per call at 256 tokens on an M2 Max — 5.4× faster than PyTorch-CPU, with the GPU left free
  • 🎯 No accuracy loss vs PyTorch: 99.65% decision agreement on the full test split, accuracy −0.15 pp
  • 🧩 Schema stays dynamic: questions and labels are data, not baked into the graph — new questions need no re-export
  • 🔁 fp32 packages (exact parity) and the PyTorch weights included for verification and non-Apple platforms

Apple Neural Engine performance

Measured on Mac14,6 — Apple M2 Max (32 GB), macOS 26.6.2, coremltools 9.0, batch 1, median of 100 runs after 20 warmup, real encoded inputs.

seq len PyTorch CPU PyTorch MPS Core ML cpu_only Core ML cpu_and_ne
256 71.5 ms 13.4 ms 32.8 ms 13.2 ms
512 123.8 ms 22.9 ms 64.2 ms 37.1 ms
1024 253.7 ms 47.4 ms 169.0 ms 111.1 ms
  • cpu_and_ne beats Core ML cpu_only by 2.5× / 1.7× / 1.5× and PyTorch-CPU by 5.4× / 3.3× / 2.3×.
  • It matches the GPU (MPS) at 256 tokens while keeping the GPU idle — the low-power, GPU-freeing path. At 512/1024 tokens MPS is still faster.
  • ANE participation is inferred from cpu_and_ne being consistently faster than cpu_only with identical math; a per-op placement trace from Xcode was not produced.

Parity vs PyTorch (full test split, 400 cases / 2,000 decisions, cpu_and_ne)

metric value
decision agreement 0.9965
accuracy (Core ML / PyTorch) 0.6445 / 0.6430
confidence MAE 0.0024

The fp32 packages are exact (max |Δlogit| 0.0000) but run on CPU/GPU only — the ANE is fp16-only.

Requirements

package set OS hardware
coreml/ (fp16, ANE) macOS 26+ Apple Silicon
coreml-fp32/ (exact) macOS 15+ Apple Silicon
jevlite.pt / model.safetensors any CPU / CUDA / MPS

Python: torch, transformers>=4.48, numpy, coremltools>=9.0,<10. The tokenizer is fetched from answerdotai/ModernBERT-base.

Quick start (Mac)

hf download j-llm/jevlite --local-dir jevlite
cd jevlite
pip install torch "transformers>=4.48" numpy "coremltools>=9.0,<10"

python decide.py --backend coreml --pkg-dir coreml   # interactive console on the Neural Engine
from engine import DecisionEngine
from typed_schema import Question

eng = DecisionEngine(backend="coreml", ckpt="jevlite.pt", pkg_dir="coreml",
                     compute_units="cpu_and_ne")   # Neural Engine; backend="torch" elsewhere
print(eng.decide({"user": "I was charged twice this month"}, {
    "category": Question.choice("What kind of support request is this?", {
        "billing": "Charges, invoices, refunds or payment methods.",
        "bug": "Something in the product is broken.",
        "other": "Anything else."}),
    "urgent": Question.noul("This request is urgent."),
}))
eng.close()

Run from the repo root (engine.py loads 05_serve.py by relative path). The default coreml_mode="worker" isolates the Core ML runtime in a subprocess — use it behind any server.

Files

path what
coreml/jevlite-{256,512,1024}.mlpackage Core ML fp16, Neural Engine. Smallest bucket covering the input is used. ~300 MB each.
coreml-fp32/jevlite-{256,512,1024}.mlpackage Core ML fp32, exact parity reference.
jevlite.pt PyTorch checkpoint (state_dict, encoder, max_len=1024, temperatures). Source of all exports.
model.safetensors Same weights as jevlite.pt (fp32, 149M params); metadata holds encoder, max_len, temperatures.
*.py, requirements.txt Minimal inference code from the source repo (unchanged).

How the Core ML graph is split

The .mlpackage computes token_logits [1, S] — ModernBERT encoder + score head at every position, inputs input_ids / attention_mask (int32). Tokenizing the questions, gathering the label-marker positions, per-type temperature and per-question softmax run in numpy on the CPU (coreml_backend.py, a few µs per call). That is why the schema stays fully dynamic.

Model

ModernBERT-base + Linear(d, 1) token head, trained 20 epochs on LocalLLaMA/typed-decisions. Test accuracy 0.6430, ECE 0.0536 (official 400-case split). Source: eightman999/open-jev-typed-decision-engine (fork of intikhab49/open-jev-typed-decision-engine) — see ANE_REPORT.md and BENCHMARK.md there for full measurements and limitations.


日本語

English | 日本語

Apple Silicon 向けにそのまま動かせる、149M パラメータの ModernBERT 型付き判定エンジン(Core ML 版)です。 状態(JSON やテキスト)と、型付きの質問(noul = 真偽 / choice = 選択 / score = 段階評価)を任意の数だけ渡すと、 1回の推論ですべてに答え、それぞれの確信度を返します。端末内で完結し、サーバーも API 料金も不要です。

  • 🍎 Core ML .mlpackage(fp16)で Apple Neural Engine 上で動作(compute_units="cpu_and_ne")
  • ⚡ M2 Max で 256 トークンなら 1回 13 ms。PyTorch(CPU)の 5.4 倍速く、GPU は空いたまま
  • 🎯 PyTorch と比べて精度は落ちない:テストデータ全件で判定一致率 99.65%、精度差 −0.15 ポイント
  • 🧩 質問は自由に変えられる:質問やラベルはデータとして渡すので、グラフに焼き込まれていない。新しい質問でも再変換は不要
  • 🔁 完全一致の検証用 fp32 版と、Apple 以外でも使える PyTorch の重みも同梱

Apple Neural Engine での性能

計測環境:Mac14,6 — Apple M2 Max(32 GB)、macOS 26.6.2、coremltools 9.0、バッチ 1、 ウォームアップ 20 回のあと 100 回計測した中央値、実際にエンコードした入力を使用。

入力長 PyTorch CPU PyTorch MPS Core ML cpu_only Core ML cpu_and_ne
256 71.5 ms 13.4 ms 32.8 ms 13.2 ms
512 123.8 ms 22.9 ms 64.2 ms 37.1 ms
1024 253.7 ms 47.4 ms 169.0 ms 111.1 ms
  • cpu_and_ne は Core ML cpu_only より 2.5 / 1.7 / 1.5 倍、PyTorch(CPU)より 5.4 / 3.3 / 2.3 倍速い。
  • 256 トークンでは GPU(MPS)と同等の速さで、GPU を使わずに済む。省電力で GPU を空けておける構成。 512・1024 トークンでは MPS のほうが速い。
  • Neural Engine を使っていることは、同じ計算で cpu_and_ne が cpu_only より常に速いことから推測している。 Xcode での演算ごとの割り当ては確認していない。

PyTorch との一致(テストデータ全件:400 件 / 2,000 判定、cpu_and_ne)

指標 値
判定一致率 0.9965
精度(Core ML / PyTorch) 0.6445 / 0.6430
確信度の平均絶対誤差 0.0024

fp32 版は完全一致(logit 差の最大 0.0000)ですが、Neural Engine は fp16 専用のため CPU/GPU で動きます。

動作要件

ファイル OS ハードウェア
coreml/(fp16、Neural Engine) macOS 26 以上 Apple Silicon
coreml-fp32/(完全一致) macOS 15 以上 Apple Silicon
jevlite.pt / model.safetensors 問わない CPU / CUDA / MPS

Python パッケージ:torch、transformers>=4.48、numpy、coremltools>=9.0,<10。 トークナイザーは answerdotai/ModernBERT-base から取得します。

使い方(Mac)

hf download j-llm/jevlite --local-dir jevlite
cd jevlite
pip install torch "transformers>=4.48" numpy "coremltools>=9.0,<10"

python decide.py --backend coreml --pkg-dir coreml   # Neural Engine で対話コンソールを起動

Python から使う場合は、上の英語版にあるコード例をそのまま使えます(backend="coreml"、pkg_dir="coreml")。 engine.py は 05_serve.py を相対パスで読むので、ダウンロードしたフォルダで実行してください。 既定の coreml_mode="worker" は Core ML の実行をサブプロセスに分けるので、サーバーに組み込むときはこちらを使ってください。

ファイル

パス 内容
coreml/jevlite-{256,512,1024}.mlpackage Core ML fp16(Neural Engine 用)。入力長をカバーする最小のものが使われる。各約 300 MB。
coreml-fp32/jevlite-{256,512,1024}.mlpackage Core ML fp32。PyTorch と完全一致する検証用。
jevlite.pt PyTorch チェックポイント(state_dict、エンコーダ名、max_len=1024、温度)。すべての変換の元。
model.safetensors jevlite.pt と同じ重み(fp32、149M)。メタデータにエンコーダ名・max_len・温度を格納。
*.py、requirements.txt 元リポジトリの推論コード(変更なし)。

Core ML 側と Python 側の分担

.mlpackage が計算するのは token_logits [1, S](ModernBERT エンコーダ+スコアヘッドを全位置で評価した値)だけです。 入力は input_ids / attention_mask(int32)。質問のトークン化、ラベル位置の取り出し、型ごとの温度、 質問ごとの softmax は CPU 上の numpy で行います(coreml_backend.py、1回数マイクロ秒)。 そのため質問の形は自由に変えられます。

モデル

ModernBERT-base に Linear(d, 1) のトークンヘッドを付け、 LocalLLaMA/typed-decisions で 20 エポック学習しました。 テスト精度 0.6430、ECE 0.0536(公式の 400 件テストセット)。 元リポジトリ:eightman999/open-jev-typed-decision-engine (intikhab49/open-jev-typed-decision-engine のフォーク)。 詳しい計測結果と制約は、そちらの ANE_REPORT.md と BENCHMARK.md を参照してください。

Downloads last month
-
Safetensors
Model size
0.1B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for j-llm/jevlite

Finetuned
(1556)
this model

Dataset used to train j-llm/jevlite

Collection including j-llm/jevlite