CBraMod embedder Core ML fp32 (parity 1.3e-5, task-equivalent, Swift-validated)
Browse files
CBraModEmbedder.mlpackage/Data/com.apple.CoreML/model.mlmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:44b7c2fe27d933d926155262b3fff5d23ff844856a8db09324b7c8191b9fc1c2
|
| 3 |
+
size 332412
|
CBraModEmbedder.mlpackage/Data/com.apple.CoreML/weights/weight.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6a738b581cd331c640433008974a71c88871742b8116541713cfa4d3d13bb533
|
| 3 |
+
size 20033984
|
CBraModEmbedder.mlpackage/Manifest.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"fileFormatVersion": "1.0.0",
|
| 3 |
+
"itemInfoEntries": {
|
| 4 |
+
"1DCDC5C2-D434-4197-82B9-2474DBDE3FAC": {
|
| 5 |
+
"author": "com.apple.CoreML",
|
| 6 |
+
"description": "CoreML Model Specification",
|
| 7 |
+
"name": "model.mlmodel",
|
| 8 |
+
"path": "com.apple.CoreML/model.mlmodel"
|
| 9 |
+
},
|
| 10 |
+
"CED5C91C-BA26-4A2C-8D38-2B3C8CF276F9": {
|
| 11 |
+
"author": "com.apple.CoreML",
|
| 12 |
+
"description": "CoreML Model Weights",
|
| 13 |
+
"name": "weights",
|
| 14 |
+
"path": "com.apple.CoreML/weights"
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
"rootModelIdentifier": "1DCDC5C2-D434-4197-82B9-2474DBDE3FAC"
|
| 18 |
+
}
|
README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: bsd-3-clause
|
| 3 |
+
base_model: braindecode/cbramod-pretrained
|
| 4 |
+
tags:
|
| 5 |
+
- coreml
|
| 6 |
+
- eeg
|
| 7 |
+
- bci
|
| 8 |
+
- motor-imagery
|
| 9 |
+
- transformer
|
| 10 |
+
- ios
|
| 11 |
+
- macos
|
| 12 |
+
- visionos
|
| 13 |
+
language:
|
| 14 |
+
- en
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# CBraMod-CoreML-Apple
|
| 18 |
+
|
| 19 |
+
**CBraMod as a native Core ML embedding extractor for Apple platforms (macOS / iOS / visionOS), fp32, validated to rel-L2 1.3e-5 against the PyTorch reference.**
|
| 20 |
+
|
| 21 |
+
This repository packages the pretrained [CBraMod](https://github.com/wjq-learning/CBraMod) EEG foundation model (Wang et al., ICLR 2025) — via the [braindecode](https://braindecode.org) re-hosted checkpoint [`braindecode/cbramod-pretrained`](https://huggingface.co/braindecode/cbramod-pretrained) — as a single `.mlpackage` that maps a 14-channel EEG window to a 14,000-dimensional embedding, entirely on-device via CoreML.framework.
|
| 22 |
+
|
| 23 |
+
It is published as a companion to the [ZUNA Core ML profiles](https://huggingface.co/oraculumai/ZUNA1.1-CoreML-Apple): in our 109-subject motor-imagery evaluation, CBraMod embeddings were the strongest foundation-model feature for sustained motor-imagery decoding, so this artifact is the MI engine of an on-device BCI stack.
|
| 24 |
+
|
| 25 |
+
## What is in the package
|
| 26 |
+
|
| 27 |
+
| Item | Value |
|
| 28 |
+
|---|---|
|
| 29 |
+
| Model | `CBraModEmbedder.mlpackage` (fp32 `mlprogram`) |
|
| 30 |
+
| Backbone | CBraMod criss-cross transformer, pretrained weights, classification head removed (`Identity`) |
|
| 31 |
+
| Input | `eeg` — `float32 [1, 14, 1000]` (14 channels × 5 s @ 200 Hz) |
|
| 32 |
+
| Output | `embedding` — `float32 [1, 14000]` (flattened patch embeddings: 14 ch × 5 patches × 200 dims) |
|
| 33 |
+
| Size | ~20 MB weights |
|
| 34 |
+
| Conversion | coremltools 9.0, `torch.export` frontend (`TorchExport::ATEN` dialect) |
|
| 35 |
+
|
| 36 |
+
The channel count (14) matches the Emotiv EPOC X montage (AF3, F7, F3, FC5, T7, P7, O1, O2, P8, T8, FC6, F4, F8, AF4), but nothing in the backbone is montage-specific beyond the fixed input shape: CBraMod treats channels symmetrically at the patch level, so any 14-channel montage at 200 Hz can use this package. For other channel counts, re-export from source (script linked below).
|
| 37 |
+
|
| 38 |
+
## Expected preprocessing
|
| 39 |
+
|
| 40 |
+
The parity and task-level validation below used this exact chain (matching the upstream evaluation convention of z-scored inputs):
|
| 41 |
+
|
| 42 |
+
1. Window the raw EEG to 5 s.
|
| 43 |
+
2. Average-reference across the available channels.
|
| 44 |
+
3. Global z-score the window (single mean/std over all channels and samples).
|
| 45 |
+
4. Resample to 200 Hz (polyphase), crop/zero-pad to exactly 1000 samples.
|
| 46 |
+
|
| 47 |
+
## Validation
|
| 48 |
+
|
| 49 |
+
All gates were run against the original PyTorch checkpoint on **real EEG** (PhysioNet EEGBCI motor-imagery recordings mapped to the 14-channel montage), not random tensors.
|
| 50 |
+
|
| 51 |
+
| Check | Result |
|
| 52 |
+
|---|---|
|
| 53 |
+
| Numerical parity (worst rel-L2 over 36 real windows, two window regimes, CPU_ONLY) | **1.3e-5** (gate 1e-4) — see `parity.json` |
|
| 54 |
+
| Export fidelity (`torch.export` module vs eager PyTorch) | bit-exact |
|
| 55 |
+
| Task-level equivalence (held-out-run MI accuracy, subjects 1–5, Core ML vs PyTorch embeddings) | **identical** (max accuracy diff 0.000) |
|
| 56 |
+
| Native Swift / CoreML.framework smoke (compile, load, predict, finite outputs) | PASS (0.44 s load, 1.27 s cold first prediction on an M3 Max) |
|
| 57 |
+
|
| 58 |
+
Downstream context (not a property of this artifact, but of the underlying checkpoint): on 109 PhysioNet EEGBCI subjects with held-out-run evaluation, CBraMod embeddings + logistic regression reached **63.7% ± 13.8%** left/right-hand sustained motor-imagery accuracy on cue-offset windows (a control that excludes visual-cue-evoked confounds), significantly above every classical and FM baseline we tested (paired test vs best prior, p ≈ 2e-6).
|
| 59 |
+
|
| 60 |
+
## Conversion notes (for reproducers)
|
| 61 |
+
|
| 62 |
+
Two standard approaches fail on this architecture; both failures are worth knowing:
|
| 63 |
+
|
| 64 |
+
- `torch.jit.trace` is non-deterministic here unless `torch.backends.mha.set_fastpath_enabled(False)` is set (nn.MultiheadAttention's fastpath produces divergent traces), and even then Core ML const-folding fails on ~349 symbolic-int (`aten::Int`) nodes arising from CBraMod's criss-cross reshape arithmetic.
|
| 65 |
+
- `torch.export.export(...).run_decompositions({})` converts cleanly: the modern frontend specializes static shapes to constants, eliminating the symbolic-int nodes. This is the recommended path for reshape-heavy transformers.
|
| 66 |
+
|
| 67 |
+
The export script (including the parity and task-equivalence gates) is open source: [`scripts/port_cbramod_coreml.py`](https://github.com/nschlaepfer/oraculum-gpt-mk1/blob/main/scripts/port_cbramod_coreml.py).
|
| 68 |
+
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
### Python (coremltools)
|
| 72 |
+
|
| 73 |
+
```python
|
| 74 |
+
import numpy as np
|
| 75 |
+
import coremltools as ct
|
| 76 |
+
from huggingface_hub import snapshot_download
|
| 77 |
+
|
| 78 |
+
repo = snapshot_download("oraculumai/CBraMod-CoreML-Apple")
|
| 79 |
+
model = ct.models.MLModel(f"{repo}/CBraModEmbedder.mlpackage")
|
| 80 |
+
|
| 81 |
+
eeg = np.random.randn(1, 14, 1000).astype(np.float32) # preprocessed as above
|
| 82 |
+
embedding = model.predict({"eeg": eeg})["embedding"] # (1, 14000)
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
### Swift (CoreML.framework)
|
| 86 |
+
|
| 87 |
+
```swift
|
| 88 |
+
import CoreML
|
| 89 |
+
|
| 90 |
+
// Compile once: xcrun coremlcompiler compile CBraModEmbedder.mlpackage <outdir>
|
| 91 |
+
let model = try MLModel(contentsOf: compiledURL)
|
| 92 |
+
let input = try MLMultiArray(shape: [1, 14, 1000], dataType: .float32)
|
| 93 |
+
// ... fill input with the preprocessed window ...
|
| 94 |
+
let out = try model.prediction(from: MLDictionaryFeatureProvider(dictionary: ["eeg": input]))
|
| 95 |
+
let embedding = out.featureValue(for: "embedding")!.multiArrayValue! // [1, 14000]
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
A typical decoder is a small linear head (e.g. logistic regression) trained on these embeddings; the 63.7% MI result above is exactly that.
|
| 99 |
+
|
| 100 |
+
## Limitations
|
| 101 |
+
|
| 102 |
+
- Fixed input shape `[1, 14, 1000]`. Other montages/window lengths require re-export.
|
| 103 |
+
- fp32 only. We have not published a compressed variant; palettization/int8 were not validated for this model.
|
| 104 |
+
- Research artifact. Not validated for medical diagnosis, treatment, or clinical decision-making. Use at your own risk and follow the base model's license (BSD-3-Clause).
|
| 105 |
+
|
| 106 |
+
## Provenance & credit
|
| 107 |
+
|
| 108 |
+
- **Original model:** CBraMod — *"CBraMod: A Criss-Cross Brain Foundation Model for EEG Decoding"*, Wang et al., ICLR 2025. Repository: <https://github.com/wjq-learning/CBraMod>
|
| 109 |
+
- **Pretrained weights:** [`braindecode/cbramod-pretrained`](https://huggingface.co/braindecode/cbramod-pretrained) (safetensors, BSD-3-Clause), loaded through the [braindecode](https://braindecode.org) `CBraMod` implementation. The classification head (absent from the pretrained checkpoint) is replaced with `Identity`; all backbone tensors load cleanly.
|
| 110 |
+
- **This conversion:** [oraculumai](https://huggingface.co/oraculumai) — Core ML export, parity/task-level validation, and packaging. Evaluation harness: <https://github.com/nschlaepfer/oraculum-gpt-mk1>
|
| 111 |
+
|
| 112 |
+
If you use this model, please cite the original CBraMod paper and credit braindecode for the checkpoint distribution.
|
parity.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"worst_rel_l2": 1.3118799870426301e-05, "gate": 0.0001, "pass": true, "n_windows": 36, "output_name": "embedding"}
|