JohnP1 commited on
Commit
e9f8aad
·
verified ·
1 Parent(s): e747474

D1A-E4B v0.6 Core ML: text trunk, 7 int8 chunks, L=512 (#224)

Browse files
Files changed (33) hide show
  1. .gitattributes +1 -0
  2. README.md +49 -0
  3. config.json +171 -0
  4. coreml/L512_00-06.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  5. coreml/L512_00-06.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  6. coreml/L512_00-06.mlpackage/Manifest.json +18 -0
  7. coreml/L512_06-12.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  8. coreml/L512_06-12.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  9. coreml/L512_06-12.mlpackage/Manifest.json +18 -0
  10. coreml/L512_12-18.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  11. coreml/L512_12-18.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  12. coreml/L512_12-18.mlpackage/Manifest.json +18 -0
  13. coreml/L512_18-24.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  14. coreml/L512_18-24.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  15. coreml/L512_18-24.mlpackage/Manifest.json +18 -0
  16. coreml/L512_24-30.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  17. coreml/L512_24-30.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  18. coreml/L512_24-30.mlpackage/Manifest.json +18 -0
  19. coreml/L512_30-36.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  20. coreml/L512_30-36.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  21. coreml/L512_30-36.mlpackage/Manifest.json +18 -0
  22. coreml/L512_36-42.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
  23. coreml/L512_36-42.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
  24. coreml/L512_36-42.mlpackage/Manifest.json +18 -0
  25. d1a_config.json +38 -0
  26. embeddings.safetensors +3 -0
  27. head.safetensors +3 -0
  28. io.json +1 -0
  29. reference/d1a_coreml.py +183 -0
  30. reference/pipeline.py +79 -0
  31. reference/workers.py +99 -0
  32. tokenizer.json +3 -0
  33. tokenizer_config.json +55 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: google/gemma-4-E4B
4
+ tags: [coreml, apple-neural-engine, decision-model, d1a]
5
+ ---
6
+ # D1A-E4B v0.6 · Core ML (text, ≤ 512 tokens)
7
+
8
+ A Core ML conversion of D1A-E4B v0.6 (`JohnP1/d1a-e4b-mlx-q8@v0.6`, the model the Mac mini serves). It is the text path
9
+ only, for the Apple Neural Engine. The details are in jonpol01/d1a#224.
10
+
11
+ ## Status
12
+
13
+ It is **correct at ≤ 512 tokens**. On 28 real requests (42 questions), 0 clear-cut answers changed against the
14
+ fp32 torch rebuild, on an M1 Max and an M4 Neural Engine.
15
+
16
+ **Speed (median):**
17
+ - M4: 1.8 s per request, against 0.63 s for MLX on the GPU.
18
+ - M1 Max: 2.9 s, against 0.8 s.
19
+
20
+ Use it where the GPU should stay free or power matters, not for speed.
21
+
22
+ **Not included yet:**
23
+ - Photo, voice and video (the vision and audio encoders are separate models, still to convert).
24
+ - Inputs longer than 512 tokens: 2,048-token programs give wrong answers on the M4 Neural Engine.
25
+
26
+ ## Files
27
+
28
+ | Path | What |
29
+ |---|---|
30
+ | `coreml/L512_<a>-<b>.mlpackage` | 7 int8 chunks (per-block 64), layers a..b of the 42-layer trunk. Chunk 18-24 outputs the shared keys/values that chunks 24-42 read. |
31
+ | `io.json` | each chunk's input names |
32
+ | `embeddings.safetensors` | the token and per-layer embedding tables (MLX affine-quantized), looked up on the host, not in Core ML |
33
+ | `head.safetensors`, `d1a_config.json` | pointer head (q, k), temperature 1.954, pad and delimiter ids |
34
+ | `tokenizer.json` | Gemma 4 tokenizer |
35
+ | `reference/` | Python reference: host lookups, masks, the chunk chain (one process per chunk), the pointer head |
36
+
37
+ ## How a request runs
38
+
39
+ 1. Encode with D1A's layout (`d1a.core.encoding.encode`) and right-pad to 512 with the pad token.
40
+ 2. Look up the embeddings (`emb` scaled by √2560) and the per-layer embeddings (`ple_tok` scaled by √256).
41
+ 3. Build the block-causal masks (full and sliding-512), clamped to -1e4.
42
+ 4. Run the 7 chunks in order, each in its own process.
43
+ 5. Read the hidden states at each question's `<decide>` and `</opt>` positions.
44
+ 6. Score them with the head, divide by the temperature, and take the softmax.
45
+
46
+ ## Requirements
47
+
48
+ macOS 15 / iOS 18 or later. Loading 7 large Neural Engine programs in one process can crash the runtime, so the
49
+ reference runs one process per chunk.
config.json ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Gemma4ForConditionalGeneration"
4
+ ],
5
+ "audio_config": {
6
+ "_name_or_path": "",
7
+ "architectures": null,
8
+ "attention_chunk_size": 12,
9
+ "attention_context_left": 13,
10
+ "attention_context_right": 0,
11
+ "attention_invalid_logits_value": -1000000000.0,
12
+ "attention_logit_cap": 50.0,
13
+ "chunk_size_feed_forward": 0,
14
+ "conv_kernel_size": 5,
15
+ "dtype": "bfloat16",
16
+ "gradient_clipping": 10000000000.0,
17
+ "hidden_act": "silu",
18
+ "hidden_size": 1024,
19
+ "id2label": {
20
+ "0": "LABEL_0",
21
+ "1": "LABEL_1"
22
+ },
23
+ "initializer_range": 0.02,
24
+ "is_encoder_decoder": false,
25
+ "label2id": {
26
+ "LABEL_0": 0,
27
+ "LABEL_1": 1
28
+ },
29
+ "model_type": "gemma4_audio",
30
+ "num_attention_heads": 8,
31
+ "num_hidden_layers": 12,
32
+ "output_attentions": false,
33
+ "output_hidden_states": false,
34
+ "output_proj_dims": 1536,
35
+ "problem_type": null,
36
+ "residual_weight": 0.5,
37
+ "return_dict": true,
38
+ "rms_norm_eps": 1e-06,
39
+ "subsampling_conv_channels": [
40
+ 128,
41
+ 32
42
+ ],
43
+ "use_clipped_linears": true
44
+ },
45
+ "audio_token_id": 258881,
46
+ "boa_token_id": 256000,
47
+ "boi_token_id": 255999,
48
+ "dtype": "bfloat16",
49
+ "eoa_token_id": 258883,
50
+ "eoa_token_index": 258883,
51
+ "eoi_token_id": 258882,
52
+ "eos_token_id": 1,
53
+ "image_token_id": 258880,
54
+ "initializer_range": 0.02,
55
+ "model_type": "gemma4",
56
+ "quantization": {
57
+ "group_size": 64,
58
+ "bits": 8,
59
+ "mode": "affine",
60
+ "language_model.model.embed_tokens_per_layer": {
61
+ "group_size": 64,
62
+ "bits": 4,
63
+ "mode": "affine"
64
+ }
65
+ },
66
+ "quantization_config": {
67
+ "group_size": 64,
68
+ "bits": 8,
69
+ "mode": "affine",
70
+ "language_model.model.embed_tokens_per_layer": {
71
+ "group_size": 64,
72
+ "bits": 4,
73
+ "mode": "affine"
74
+ }
75
+ },
76
+ "text_config": {
77
+ "attention_bias": false,
78
+ "attention_dropout": 0.0,
79
+ "attention_k_eq_v": false,
80
+ "bos_token_id": 2,
81
+ "dtype": "bfloat16",
82
+ "enable_moe_block": false,
83
+ "eos_token_id": 1,
84
+ "expert_intermediate_size": null,
85
+ "final_logit_softcapping": 30.0,
86
+ "global_head_dim": 512,
87
+ "head_dim": 256,
88
+ "hidden_activation": "gelu_pytorch_tanh",
89
+ "hidden_size": 2560,
90
+ "hidden_size_per_layer_input": 256,
91
+ "initializer_range": 0.02,
92
+ "intermediate_size": 10240,
93
+ "layer_types": [
94
+ "sliding_attention",
95
+ "sliding_attention",
96
+ "sliding_attention",
97
+ "sliding_attention",
98
+ "sliding_attention",
99
+ "full_attention",
100
+ "sliding_attention",
101
+ "sliding_attention",
102
+ "sliding_attention",
103
+ "sliding_attention",
104
+ "sliding_attention",
105
+ "full_attention",
106
+ "sliding_attention",
107
+ "sliding_attention",
108
+ "sliding_attention",
109
+ "sliding_attention",
110
+ "sliding_attention",
111
+ "full_attention",
112
+ "sliding_attention",
113
+ "sliding_attention",
114
+ "sliding_attention",
115
+ "sliding_attention",
116
+ "sliding_attention",
117
+ "full_attention",
118
+ "sliding_attention",
119
+ "sliding_attention",
120
+ "sliding_attention",
121
+ "sliding_attention",
122
+ "sliding_attention",
123
+ "full_attention",
124
+ "sliding_attention",
125
+ "sliding_attention",
126
+ "sliding_attention",
127
+ "sliding_attention",
128
+ "sliding_attention",
129
+ "full_attention",
130
+ "sliding_attention",
131
+ "sliding_attention",
132
+ "sliding_attention",
133
+ "sliding_attention",
134
+ "sliding_attention",
135
+ "full_attention"
136
+ ],
137
+ "max_position_embeddings": 131072,
138
+ "model_type": "gemma4_text",
139
+ "num_attention_heads": 8,
140
+ "num_experts": null,
141
+ "num_global_key_value_heads": null,
142
+ "num_hidden_layers": 42,
143
+ "num_key_value_heads": 2,
144
+ "num_kv_shared_layers": 18,
145
+ "pad_token_id": 0,
146
+ "rms_norm_eps": 1e-06,
147
+ "rope_parameters": {
148
+ "full_attention": {
149
+ "partial_rotary_factor": 0.25,
150
+ "rope_theta": 1000000.0,
151
+ "rope_type": "proportional"
152
+ },
153
+ "sliding_attention": {
154
+ "rope_theta": 10000.0,
155
+ "rope_type": "default"
156
+ }
157
+ },
158
+ "sliding_window": 512,
159
+ "tie_word_embeddings": true,
160
+ "top_k_experts": null,
161
+ "use_bidirectional_attention": null,
162
+ "use_cache": true,
163
+ "use_double_wide_mlp": false,
164
+ "vocab_size": 262144,
165
+ "vocab_size_per_layer_input": 262144
166
+ },
167
+ "tie_word_embeddings": true,
168
+ "transformers_version": "5.5.0.dev0",
169
+ "video_token_id": 258884,
170
+ "vision_soft_tokens_per_image": 280
171
+ }
coreml/L512_00-06.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:89c72aadc6f5a401047a07736e43abedc4cccd5355e605f3be79a63347407902
3
+ size 219716
coreml/L512_00-06.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:62874262b7021dfc7990bac95cdf9ff69fd1472cc59d58ecd4cc4f639d4d227d
3
+ size 627316160
coreml/L512_00-06.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "3C09B49F-607E-44C3-8A4A-BE61559AAC82": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Weights",
7
+ "name": "weights",
8
+ "path": "com.apple.CoreML/weights"
9
+ },
10
+ "E68B5681-3E21-4324-A4E2-C98CC1AFAF15": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Specification",
13
+ "name": "model.mlmodel",
14
+ "path": "com.apple.CoreML/model.mlmodel"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "E68B5681-3E21-4324-A4E2-C98CC1AFAF15"
18
+ }
coreml/L512_06-12.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddb926861da7e4ddaf2641a4751dc36fdc80dcc1b28585834fc12022918d817d
3
+ size 215418
coreml/L512_06-12.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:7e2f722f173caca828bc4fa528aaadd56edb09c1fbfbfe76cb7b371e019fe8af
3
+ size 598477312
coreml/L512_06-12.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "1E669D90-60B5-4734-AC55-7740F8D01BA4": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Weights",
7
+ "name": "weights",
8
+ "path": "com.apple.CoreML/weights"
9
+ },
10
+ "B0AFD2A8-B841-4662-B82D-D2CCB4B83093": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Specification",
13
+ "name": "model.mlmodel",
14
+ "path": "com.apple.CoreML/model.mlmodel"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "B0AFD2A8-B841-4662-B82D-D2CCB4B83093"
18
+ }
coreml/L512_12-18.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:191fe3f0cb649b9f41948030f7dabe7750f6347e93f094bfa2145e17e30a118a
3
+ size 216034
coreml/L512_12-18.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:a914b189bde1d07d7ff980d152745914bc0b065ff98e497b424a37bd8c09b320
3
+ size 598478464
coreml/L512_12-18.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "2C8B7345-8589-4596-85E7-BEDDD4493047": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Weights",
7
+ "name": "weights",
8
+ "path": "com.apple.CoreML/weights"
9
+ },
10
+ "82121673-49E3-483C-995A-8FA0699BF674": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Specification",
13
+ "name": "model.mlmodel",
14
+ "path": "com.apple.CoreML/model.mlmodel"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "82121673-49E3-483C-995A-8FA0699BF674"
18
+ }
coreml/L512_18-24.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1b060d669ac0ffb4f691139088576f98273799882510faaca9bf86b06d3185ad
3
+ size 215866
coreml/L512_18-24.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:07e4f3649600aa202e31441b0c5b1141de8f25b60aea087b220c03cd4b0e1b50
3
+ size 598477888
coreml/L512_18-24.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "07C10B3B-C0D2-493A-98F2-873F1FA95521": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Specification",
7
+ "name": "model.mlmodel",
8
+ "path": "com.apple.CoreML/model.mlmodel"
9
+ },
10
+ "703DA848-64F6-498C-BCAC-B4990539ACC0": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Weights",
13
+ "name": "weights",
14
+ "path": "com.apple.CoreML/weights"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "07C10B3B-C0D2-493A-98F2-873F1FA95521"
18
+ }
coreml/L512_24-30.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff93f6c33d5434f8946bb15cd96c59845d4c8a5967ee8f7e313ff9f79644ca99
3
+ size 158180
coreml/L512_24-30.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:66233324553f3ee4bed95d8302d8bc5ec46b91b4951614893ec323c51c6bcdb7
3
+ size 579256448
coreml/L512_24-30.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "481F0249-E92D-463B-9B6B-6F8606E597ED": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Weights",
7
+ "name": "weights",
8
+ "path": "com.apple.CoreML/weights"
9
+ },
10
+ "F73B99D0-DC7C-4319-9AB4-2A3E3EFB7838": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Specification",
13
+ "name": "model.mlmodel",
14
+ "path": "com.apple.CoreML/model.mlmodel"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "F73B99D0-DC7C-4319-9AB4-2A3E3EFB7838"
18
+ }
coreml/L512_30-36.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bbf8c3217c7c3dcf4ab93bd5478570c2bb450efc72428632fbff3eae2b72a75e
3
+ size 158180
coreml/L512_30-36.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:8de285048aa14b9074e01eec3d214d8b812d698a7abf44f4af04e44b23228b8c
3
+ size 579256448
coreml/L512_30-36.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "92E60EB2-8586-46A5-AAFB-175CFD413BA4": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Specification",
7
+ "name": "model.mlmodel",
8
+ "path": "com.apple.CoreML/model.mlmodel"
9
+ },
10
+ "F9C38AD8-3C08-487B-930C-0E61ED5BD177": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Weights",
13
+ "name": "weights",
14
+ "path": "com.apple.CoreML/weights"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "92E60EB2-8586-46A5-AAFB-175CFD413BA4"
18
+ }
coreml/L512_36-42.mlpackage/Data/com.apple.CoreML/model.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:14838a7962789a75a743d3da40fbfe99c90c10fa5fe821aa29f364303a5d7358
3
+ size 163824
coreml/L512_36-42.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:eb254c977f42c0f100a771ec3e74f5d255c94fb78fad9bb1e3721e07e26715e1
3
+ size 579261632
coreml/L512_36-42.mlpackage/Manifest.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "fileFormatVersion": "1.0.0",
3
+ "itemInfoEntries": {
4
+ "2E3E8772-B27F-4A92-98C4-57320668E2BE": {
5
+ "author": "com.apple.CoreML",
6
+ "description": "CoreML Model Specification",
7
+ "name": "model.mlmodel",
8
+ "path": "com.apple.CoreML/model.mlmodel"
9
+ },
10
+ "D218135C-CC81-4D22-A335-A01164CC36C5": {
11
+ "author": "com.apple.CoreML",
12
+ "description": "CoreML Model Weights",
13
+ "name": "weights",
14
+ "path": "com.apple.CoreML/weights"
15
+ }
16
+ },
17
+ "rootModelIdentifier": "2E3E8772-B27F-4A92-98C4-57320668E2BE"
18
+ }
d1a_config.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "d1a-mlx",
3
+ "format_version": 1,
4
+ "base": "google/gemma-4-E4B",
5
+ "base_revision": "411aa17b749aa952df1359d2dcea73917a544d9a",
6
+ "source": "JohnP1/d1a-e4b",
7
+ "source_revision": "3ca01b824280cacf027826b0ded8632f242a7e8b",
8
+ "adapter_sha256": "739ce962c3ae630243ee53b212a822e8b2feee41080b68d5b460fd0ebb19e4ea",
9
+ "lora": 16,
10
+ "head_dim": 256,
11
+ "hidden_size": 2560,
12
+ "temperature": 1.9543199368684914,
13
+ "leading_ids": [
14
+ 2
15
+ ],
16
+ "bos_id": 2,
17
+ "delimiter_ids": [
18
+ 6,
19
+ 7,
20
+ 8,
21
+ 9,
22
+ 10
23
+ ],
24
+ "pad_id": 0,
25
+ "dtype": "bfloat16",
26
+ "quantization": {
27
+ "group_size": 64,
28
+ "bits": 8,
29
+ "mode": "affine",
30
+ "language_model.model.embed_tokens_per_layer": {
31
+ "group_size": 64,
32
+ "bits": 4,
33
+ "mode": "affine"
34
+ },
35
+ "embeddings": true
36
+ },
37
+ "head": "head.safetensors"
38
+ }
embeddings.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c42f972c8aa60a0036de48a32985f9077f19e2ee18b845279b563a306c69f8e3
3
+ size 2298479528
head.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:05b9d0c49f5df117ea43cf6c55159ffd2e7aab876e67cd69bd13911ff7fb627a
3
+ size 5245232
io.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"chunks": ["00-06", "06-12", "12-18", "18-24", "24-30", "30-36", "36-42"], "inputs": {"00-06": ["emb", "ple_tok", "pos", "mask_full", "mask_slide"], "06-12": ["h_in", "ple", "pos", "mask_full", "mask_slide"], "12-18": ["h_in", "ple", "pos", "mask_full", "mask_slide"], "18-24": ["h_in", "ple", "pos", "mask_full", "mask_slide"], "24-30": ["h_in", "ple", "pos", "mask_full", "mask_slide", "k_full_attention", "v_full_attention", "k_sliding_attention", "v_sliding_attention"], "30-36": ["h_in", "ple", "pos", "mask_full", "mask_slide", "k_full_attention", "v_full_attention", "k_sliding_attention", "v_sliding_attention"], "36-42": ["h_in", "ple", "pos", "mask_full", "mask_slide", "k_full_attention", "v_full_attention", "k_sliding_attention", "v_sliding_attention", "picks"]}}
reference/d1a_coreml.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """D1A (Gemma 4 text) -> Core ML pilot (jonpol01/d1a#224): rebuild a D1A MLX export as a torch module, split into
2
+ - host side: the two embedding tables (token embedding, per-layer embedding: 2.75B of E2B's 4.6B parameters) read
3
+ row by row from the export's safetensors (dequantized per request, never held whole), and
4
+ - Core: everything that computes (per-layer projection, 35 decoder layers, final norm, pointer head), which is what
5
+ gets converted to Core ML.
6
+ Inputs follow D1A's packed encoding (d1a.core.encoding.encode): one record, block-causal mask, positions restarting per
7
+ question after the state, readout at each question's <decide> and </opt> tokens."""
8
+ import json
9
+ import math
10
+ from pathlib import Path
11
+
12
+ import numpy as np
13
+ import torch
14
+ from safetensors import safe_open
15
+ from torch import nn
16
+ from transformers import AutoConfig
17
+ from transformers.models.gemma4 import modeling_gemma4 as G
18
+
19
+ PREFIX = "language_model.model."
20
+
21
+
22
+ def dequant(packed, scales, biases, bits, group=64):
23
+ """MLX affine dequantization: packed uint32 [out, in*bits/32] (lowest bits first) -> float32 [out, in]."""
24
+ p = packed.view(torch.int32).to(torch.int64) & 0xFFFFFFFF
25
+ per = 32 // bits
26
+ shifts = torch.arange(per, dtype=torch.int64) * bits
27
+ q = ((p[..., None] >> shifts) & ((1 << bits) - 1)).reshape(p.shape[0], -1).to(torch.float32)
28
+ s, b = scales.to(torch.float32), biases.to(torch.float32)
29
+ return (q.view(q.shape[0], -1, group) * s[..., None] + b[..., None]).reshape(q.shape[0], -1)
30
+
31
+
32
+ class _Shards:
33
+ """model.safetensors or model-0000N-of-0000M.safetensors (via model.safetensors.index.json), read like one safe_open."""
34
+
35
+ def __init__(self, path):
36
+ idx = Path(path) / "model.safetensors.index.json"
37
+ if idx.exists():
38
+ wm = json.loads(idx.read_text())["weight_map"]
39
+ files = {f: safe_open(str(Path(path) / f), "pt") for f in sorted(set(wm.values()))}
40
+ self.where = {k: files[f] for k, f in wm.items()}
41
+ else:
42
+ f = safe_open(str(Path(path) / "model.safetensors"), "pt")
43
+ self.where = {k: f for k in f.keys()}
44
+
45
+ def keys(self):
46
+ return self.where.keys()
47
+
48
+ def get_tensor(self, k):
49
+ return self.where[k].get_tensor(k)
50
+
51
+ def get_slice(self, k):
52
+ return self.where[k].get_slice(k)
53
+
54
+
55
+ class Export:
56
+ """A D1A MLX export directory (config.json, d1a_config.json, model.safetensors, head.safetensors)."""
57
+
58
+ def __init__(self, path):
59
+ self.path = Path(path)
60
+ self.cfg = AutoConfig.from_pretrained(self.path)
61
+ self.tc = self.cfg.text_config
62
+ self.tc._attn_implementation = "eager"
63
+ self.d1a = json.loads((self.path / "d1a_config.json").read_text())
64
+ q = self.d1a["quantization"]
65
+ self.bits = {"default": (q["bits"], q["group_size"]), "embed_tokens_per_layer": (q[PREFIX.replace("model.", "") + "model.embed_tokens_per_layer"]["bits"] if False else q["language_model.model.embed_tokens_per_layer"]["bits"], q["language_model.model.embed_tokens_per_layer"]["group_size"])}
66
+ self.f = _Shards(self.path)
67
+
68
+ def bits_of(self, name):
69
+ return self.bits["embed_tokens_per_layer"] if name.endswith("embed_tokens_per_layer") else self.bits["default"]
70
+
71
+ def tensor(self, name):
72
+ """A float32 tensor for `name` (without PREFIX), dequantized if it is stored quantized."""
73
+ full = PREFIX + name
74
+ keys = set(self.f.keys())
75
+ if full + ".weight" in keys and full + ".scales" in keys:
76
+ bits, group = self.bits_of(name)
77
+ return dequant(self.f.get_tensor(full + ".weight"), self.f.get_tensor(full + ".scales"), self.f.get_tensor(full + ".biases"), bits, group)
78
+ return self.f.get_tensor(full).to(torch.float32)
79
+
80
+ def text_model(self, dtype=torch.float32):
81
+ """The Gemma 4 text trunk with every non-embedding weight loaded (embedding tables stay empty: host side)."""
82
+ with torch.device("meta"):
83
+ m = G.Gemma4TextModel(self.tc)
84
+ m = m.to_empty(device="cpu")
85
+ state = {}
86
+ keys = set(self.f.keys())
87
+ for name, p in m.named_parameters():
88
+ if name.startswith("embed_tokens"):
89
+ continue
90
+ base = name[: -len(".weight")] if name.endswith(".weight") else name
91
+ if PREFIX + base + ".scales" in keys:
92
+ state[name] = self.tensor(base)
93
+ else:
94
+ state[name] = self.f.get_tensor(PREFIX + name).to(torch.float32)
95
+ assert state[name].shape == p.shape, (name, state[name].shape, p.shape)
96
+ for name, b in m.named_buffers():
97
+ if PREFIX + name in keys:
98
+ state[name] = self.f.get_tensor(PREFIX + name).to(torch.float32)
99
+ missing, unexpected = m.load_state_dict(state, strict=False)
100
+ missing = [k for k in missing if not k.startswith("embed_tokens")]
101
+ assert not missing and not unexpected, (missing, unexpected)
102
+ # buffers transformers computes itself (rotary inv_freq, embed_scale): re-run their init on CPU
103
+ m.rotary_emb = G.Gemma4TextRotaryEmbedding(self.tc)
104
+ return m.to(dtype).eval()
105
+
106
+ def head(self):
107
+ h = safe_open(str(self.path / "head.safetensors"), "pt")
108
+ dp, d = h.get_tensor("q.weight").shape # pointer width, hidden size (E2B 1536, E4B 2560)
109
+ q, k = nn.Linear(d, dp), nn.Linear(d, dp)
110
+ q.weight.data, q.bias.data = h.get_tensor("q.weight").float(), h.get_tensor("q.bias").float()
111
+ k.weight.data, k.bias.data = h.get_tensor("k.weight").float(), h.get_tensor("k.bias").float()
112
+ return q, k
113
+
114
+
115
+ class HostEmbed:
116
+ """Row lookups of the two embedding tables, dequantized per request: emb = E[ids] * sqrt(hidden) and
117
+ ple = E_pl[ids] * sqrt(ple_dim), reshaped [L, layers, ple_dim] (transformers' get_per_layer_inputs)."""
118
+
119
+ def __init__(self, ex):
120
+ self.ex, self.tc = ex, ex.tc
121
+ self.f = ex.f
122
+
123
+ def _rows(self, name, ids):
124
+ full = PREFIX + name
125
+ bits, group = self.ex.bits_of(name)
126
+ w, s, b = (self.f.get_slice(full + suf) for suf in (".weight", ".scales", ".biases"))
127
+ uniq, inv = np.unique(np.asarray(ids), return_inverse=True)
128
+ rows = [dequant(w[int(i): int(i) + 1], s[int(i): int(i) + 1], b[int(i): int(i) + 1], bits, group) for i in uniq]
129
+ return torch.cat(rows)[torch.as_tensor(inv)]
130
+
131
+ def __call__(self, ids):
132
+ emb = self._rows("embed_tokens", ids) * (self.tc.hidden_size ** 0.5)
133
+ ple = self._rows("embed_tokens_per_layer", ids) * (self.tc.hidden_size_per_layer_input ** 0.5)
134
+ return emb[None], ple.view(1, len(ids), self.tc.num_hidden_layers, self.tc.hidden_size_per_layer_input)
135
+
136
+
137
+ def masks_for(enc, window, L=None, dtype=torch.float32):
138
+ """D1A's packed masks (d1a.backends.torch.branch_masks) for one record, padded to L: additive [1, 1, L, L]."""
139
+ seg, pos = enc["seg"], enc["pos"]
140
+ n = len(seg)
141
+ L = L or n
142
+ s = torch.full((L,), -1)
143
+ s[:n] = torch.tensor(seg)
144
+ p = torch.zeros(L, dtype=torch.long)
145
+ p[:n] = torch.tensor(pos)
146
+ causal = torch.tril(torch.ones(L, L, dtype=torch.bool))
147
+ same = (s[None, :] == s[:, None]) | (s[None, :] == 0)
148
+ allow = (causal & same & (s != -1)[None, :]) | torch.eye(L, dtype=torch.bool)
149
+ neg = torch.finfo(dtype).min
150
+ full = torch.zeros(L, L, dtype=dtype).masked_fill(~allow, neg)
151
+ far = (p[:, None] - p[None, :] >= window) & ~torch.eye(L, dtype=torch.bool)
152
+ slide = full.masked_fill(far, neg)
153
+ return full[None, None], slide[None, None], p[None]
154
+
155
+
156
+ class Core(nn.Module):
157
+ """Everything that computes: per-layer projection, decoder layers, final norm, pointer head.
158
+ forward(emb [1,L,d], ple_tok [1,L,layers,256], pos [1,L] int, mask_full, mask_slide [1,1,L,L],
159
+ decide [Q] int, opts [Q,K] int, opt_valid [Q,K] float (1 used, 0 padding)) -> logits [Q,K]
160
+ (raw, temperature not applied; padded options get a large negative)."""
161
+
162
+ def __init__(self, text, head_q, head_k, silu_tanh=True):
163
+ super().__init__()
164
+ self.text, self.hq, self.hk = text, head_q, head_k
165
+ self.types = text.config.layer_types
166
+ self.scale = 1 / math.sqrt(head_q.out_features)
167
+
168
+ def forward(self, emb, ple_tok, pos, mask_full, mask_slide, decide, opts, opt_valid):
169
+ t = self.text
170
+ ple = t.project_per_layer_inputs(emb, ple_tok)
171
+ rope = {lt: t.rotary_emb(emb, pos, lt) for lt in t.unique_layer_types}
172
+ masks = {"full_attention": mask_full, "sliding_attention": mask_slide}
173
+ from collections import UserDict
174
+ kv = UserDict()
175
+ h = emb
176
+ for i, layer in enumerate(t.layers):
177
+ h = layer(h, ple[:, :, i, :], shared_kv_states=kv, position_embeddings=rope[self.types[i]],
178
+ attention_mask=masks[self.types[i]], position_ids=pos)
179
+ h = t.norm(h)[0] # [L, d]
180
+ q = self.hq(h[decide]) # [Q, dp]
181
+ k = self.hk(h[opts.reshape(-1)]).view(*opts.shape, -1) # [Q, K, dp]
182
+ z = (k * q[:, None, :]).sum(-1) * self.scale
183
+ return z + (opt_valid - 1.0) * 1e4
reference/pipeline.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Run a chunked D1A Core ML trunk end to end: host embeddings -> chunk 0 .. chunk N (h, per-layer inputs and the shared
2
+ keys/values passed along) -> hidden states at the picks -> pointer head on the host.
3
+ Usage as a library: Pipeline(export_dir, chunk_dir, L, units).probs(enc) -> [per-question probabilities]."""
4
+ import glob
5
+ import re
6
+ import sys
7
+ import time
8
+
9
+ import coremltools as ct
10
+ import numpy as np
11
+ import torch
12
+
13
+ sys.path.insert(0, "/Users/john/d1a-runs/coreml")
14
+ from d1a_coreml import Export, HostEmbed, masks_for # noqa: E402
15
+
16
+ P_PICKS = 128
17
+
18
+
19
+ class Pipeline:
20
+ def __init__(self, export_dir, chunk_dir, L, units="CPU_AND_NE"):
21
+ self.ex = Export(export_dir)
22
+ self.host = HostEmbed(self.ex)
23
+ self.hq, self.hk = self.ex.head()
24
+ self.T = self.ex.d1a["temperature"]
25
+ self.L = L
26
+ cu = getattr(ct.ComputeUnit, units)
27
+ self.chunks = []
28
+ if chunk_dir.endswith(".mlpackage"): # one multifunction package: functions c00_07, c07_15, ...
29
+ names = ["c00_07", "c07_15", "c15_22", "c22_29", "c29_35"]
30
+ for name in names:
31
+ a, b = map(int, name[1:].split("_"))
32
+ m = ct.models.MLModel(chunk_dir, compute_units=cu, function_name=name)
33
+ fn = next(f for f in m.get_spec().description.functions if f.name == name)
34
+ self.chunks.append((a, b, m, [i.name for i in fn.input], [o.name for o in fn.output]))
35
+ return
36
+ files = sorted(glob.glob(f"{chunk_dir}/L{L}_*.mlpackage"))
37
+ for f in files:
38
+ a, b = map(int, re.search(r"_(\d+)-(\d+)\.mlpackage$", f).groups())
39
+ m = ct.models.MLModel(f, compute_units=cu)
40
+ spec = m.get_spec()
41
+ self.chunks.append((a, b, m, [i.name for i in spec.description.input], [o.name for o in spec.description.output]))
42
+
43
+ def hidden(self, enc):
44
+ L, n = self.L, len(enc["ids"])
45
+ # right-pad with the pad token's own embeddings (as d1a's torch backend pads ids), never zero rows: an all-zero row
46
+ # makes every RMSNorm compute 0 / sqrt(eps), and eps (1e-6) is subnormal in fp16, which the Neural Engine flushes
47
+ ids = list(enc["ids"]) + [self.ex.d1a.get("pad_id", 0)] * (L - n)
48
+ emb, ple = self.host(ids)
49
+ e = emb.numpy().astype(np.float16)
50
+ p = ple.numpy().astype(np.float16)
51
+ mf, ms, pos = masks_for(enc, self.ex.tc.sliding_window, L=L)
52
+ picks = list(enc["decide_idx"]) + [o for oo in enc["opt_idx"] for o in oo]
53
+ pk = np.zeros(P_PICKS, np.int32); pk[: len(picks)] = picks
54
+ common = {"pos": pos.numpy().astype(np.int32), "mask_full": mf.clamp(min=-1e4).numpy().astype(np.float16),
55
+ "mask_slide": ms.clamp(min=-1e4).numpy().astype(np.float16)}
56
+ state = {"emb": e, "ple_tok": p, "picks": pk}
57
+ for a, b, m, ins, outs in self.chunks:
58
+ feed = {k: np.ascontiguousarray(common[k] if k in common else state[k]) for k in ins}
59
+ feed = {k: (v.astype(np.float16) if v.dtype == np.float32 else v) for k, v in feed.items()} # chunk outputs come back fp32
60
+ out = {k: np.array(v, copy=True) for k, v in m.predict(feed).items()} # Core ML may reuse its output buffers on the next call
61
+ if "hidden" in out:
62
+ return torch.tensor(out["hidden"][: len(picks)], dtype=torch.float32)
63
+ state["h_in"] = out["h"]
64
+ if "ple_out" in out:
65
+ state["ple"] = out["ple_out"]
66
+ for k, v in out.items():
67
+ if k.endswith("_out") and k != "ple_out":
68
+ state[k[: -len("_out")]] = v
69
+ raise RuntimeError("no chunk returned hidden")
70
+
71
+ def probs(self, enc):
72
+ h = self.hidden(enc)
73
+ Q = len(enc["decide_idx"])
74
+ out, j = [], Q
75
+ with torch.no_grad():
76
+ for qi, oo in enumerate(enc["opt_idx"]):
77
+ z = (self.hk(h[j: j + len(oo)]) @ self.hq(h[qi])) / (self.hq.out_features ** 0.5)
78
+ out.append(torch.softmax(z / self.T, -1).numpy()); j += len(oo)
79
+ return out
reference/workers.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """One process per Core ML chunk (workaround: several long-context chunks in one process crash the Neural Engine runtime
2
+ on the second request on this Mac, while each chunk alone, or all on the GPU, runs fine). The parent runs the host side
3
+ (embeddings, masks, pointer head) and passes tensors along the chain through pipes.
4
+ WorkerPipeline(export_dir, chunk_dir, L, units).probs(enc)"""
5
+ import glob
6
+ import multiprocessing as mp
7
+ import re
8
+ import sys
9
+
10
+ import numpy as np
11
+ import torch
12
+
13
+ sys.path.insert(0, "/Users/john/d1a-runs/coreml")
14
+
15
+
16
+ import os
17
+ BUCKETS = tuple(int(x) for x in os.environ.get("D1A_COREML_BUCKETS", "512,2048").split(",")) # each length is its own ANE program; fewer keeps the ANE within its memory
18
+
19
+
20
+ def _worker(path, units, conn):
21
+ import coremltools as ct
22
+ cu = getattr(ct.ComputeUnit, units)
23
+ # a precompiled .mlmodelc (compiled once by coremltools.models.utils.compile_model): loading each length function
24
+ # from it never recompiles, where MLModel(.mlpackage) compiles the whole package again for every function
25
+ models = {L: ct.models.CompiledMLModel(path, compute_units=cu, function_name=f"L{L}") for L in BUCKETS}
26
+ spec = ct.utils.load_spec(path.replace("compiled/", "buckets/").replace(".mlmodelc", ".mlpackage"))
27
+ fn = next(f for f in spec.description.functions if f.name == f"L{BUCKETS[0]}")
28
+ conn.send(([i.name for i in fn.input], [o.name for o in fn.output]))
29
+ while True:
30
+ msg = conn.recv()
31
+ if msg is None:
32
+ break
33
+ L, feed = msg
34
+ import time as _t
35
+ t0 = _t.perf_counter()
36
+ out = models[L].predict(feed)
37
+ t1 = _t.perf_counter()
38
+ res = {k: np.array(v, dtype=np.float16 if v.dtype == np.float32 else v.dtype, copy=True) for k, v in out.items()}
39
+ res["_predict_ms"] = np.array((t1 - t0) * 1000)
40
+ conn.send(res)
41
+
42
+
43
+ class WorkerPipeline:
44
+ def __init__(self, export_dir, chunk_dir, L=None, units="CPU_AND_NE"):
45
+ from d1a_coreml import Export, HostEmbed
46
+ self.ex = Export(export_dir)
47
+ self.host = HostEmbed(self.ex)
48
+ self.hq, self.hk = self.ex.head()
49
+ self.T, self.L = self.ex.d1a["temperature"], L
50
+ ctx = mp.get_context("spawn")
51
+ self.chunks = []
52
+ for f in sorted(glob.glob(f"{chunk_dir}/*.mlmodelc")):
53
+ a, b = map(int, re.search(r"(\d+)-(\d+)\.mlmodelc$", f).groups())
54
+ parent, child = ctx.Pipe()
55
+ p = ctx.Process(target=_worker, args=(f, units, child), daemon=True)
56
+ p.start()
57
+ self.chunks.append((a, b, p, parent))
58
+ self.io = getattr(self, "io", []) + [parent.recv()] # one at a time: concurrent first loads race in Core ML's compiler
59
+
60
+ def close(self):
61
+ for _, _, p, conn in self.chunks:
62
+ conn.send(None); p.join(5)
63
+
64
+ def hidden(self, enc):
65
+ from d1a_coreml import masks_for
66
+ self.last_predict_ms = []
67
+ n = len(enc["ids"])
68
+ L = next(b for b in BUCKETS if b >= n) # the smallest compiled length that fits
69
+ ids = list(enc["ids"]) + [self.ex.d1a.get("pad_id", 0)] * (L - n)
70
+ emb, ple = self.host(ids)
71
+ mf, ms, pos = masks_for(enc, self.ex.tc.sliding_window, L=L)
72
+ picks = list(enc["decide_idx"]) + [o for oo in enc["opt_idx"] for o in oo]
73
+ pk = np.zeros(128, np.int32); pk[: len(picks)] = picks
74
+ common = {"pos": pos.numpy().astype(np.int32), "mask_full": mf.clamp(min=-1e4).numpy().astype(np.float16),
75
+ "mask_slide": ms.clamp(min=-1e4).numpy().astype(np.float16)}
76
+ state = {"emb": emb.numpy().astype(np.float16), "ple_tok": ple.numpy().astype(np.float16), "picks": pk}
77
+ for (a, b, p, conn), (ins, outs) in zip(self.chunks, self.io):
78
+ conn.send((L, {k: (common[k] if k in common else state[k]) for k in ins}))
79
+ out = conn.recv()
80
+ self.last_predict_ms = getattr(self, "last_predict_ms", []) + [float(out.pop("_predict_ms"))]
81
+ if "hidden" in out:
82
+ return torch.tensor(out["hidden"][: len(picks)].astype(np.float32))
83
+ state["h_in"] = out["h"]
84
+ if "ple_out" in out:
85
+ state["ple"] = out["ple_out"]
86
+ for k, v in out.items():
87
+ if k.endswith("_out") and k != "ple_out":
88
+ state[k[: -len("_out")]] = v
89
+ raise RuntimeError("no chunk returned hidden")
90
+
91
+ def probs(self, enc):
92
+ h = self.hidden(enc)
93
+ Q = len(enc["decide_idx"])
94
+ out, j = [], Q
95
+ with torch.no_grad():
96
+ for qi, oo in enumerate(enc["opt_idx"]):
97
+ z = (self.hk(h[j: j + len(oo)]) @ self.hq(h[qi])) / (self.hq.out_features ** 0.5)
98
+ out.append(torch.softmax(z / self.T, -1).numpy()); j += len(oo)
99
+ return out
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:12bac982b793c44b03d52a250a9f0d0b666813da566b910c24a6da0695fd11e6
3
+ size 32170070
tokenizer_config.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "audio_token": "<|audio|>",
3
+ "backend": "tokenizers",
4
+ "boa_token": "<|audio>",
5
+ "boi_token": "<|image>",
6
+ "bos_token": "<bos>",
7
+ "eoa_token": "<audio|>",
8
+ "eoc_token": "<channel|>",
9
+ "eoi_token": "<image|>",
10
+ "eos_token": "<eos>",
11
+ "eot_token": "<turn|>",
12
+ "escape_token": "<|\"|>",
13
+ "etc_token": "<tool_call|>",
14
+ "etd_token": "<tool|>",
15
+ "etr_token": "<tool_response|>",
16
+ "extra_special_tokens": [
17
+ "<|video|>"
18
+ ],
19
+ "image_token": "<|image|>",
20
+ "is_local": false,
21
+ "local_files_only": false,
22
+ "mask_token": "<mask>",
23
+ "model_max_length": 1000000000000000019884624838656,
24
+ "model_specific_special_tokens": {
25
+ "audio_token": "<|audio|>",
26
+ "boa_token": "<|audio>",
27
+ "boi_token": "<|image>",
28
+ "eoa_token": "<audio|>",
29
+ "eoc_token": "<channel|>",
30
+ "eoi_token": "<image|>",
31
+ "eot_token": "<turn|>",
32
+ "escape_token": "<|\"|>",
33
+ "etc_token": "<tool_call|>",
34
+ "etd_token": "<tool|>",
35
+ "etr_token": "<tool_response|>",
36
+ "image_token": "<|image|>",
37
+ "soc_token": "<|channel>",
38
+ "sot_token": "<|turn>",
39
+ "stc_token": "<|tool_call>",
40
+ "std_token": "<|tool>",
41
+ "str_token": "<|tool_response>",
42
+ "think_token": "<|think|>"
43
+ },
44
+ "pad_token": "<pad>",
45
+ "padding_side": "left",
46
+ "processor_class": "Gemma4Processor",
47
+ "soc_token": "<|channel>",
48
+ "sot_token": "<|turn>",
49
+ "stc_token": "<|tool_call>",
50
+ "std_token": "<|tool>",
51
+ "str_token": "<|tool_response>",
52
+ "think_token": "<|think|>",
53
+ "tokenizer_class": "GemmaTokenizer",
54
+ "unk_token": "<unk>"
55
+ }