D1A-E4B v0.6 Core ML: text trunk, 7 int8 chunks, L=512 (#224)
Browse files- .gitattributes +1 -0
- README.md +49 -0
- config.json +171 -0
- coreml/L512_00-06.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_00-06.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_00-06.mlpackage/Manifest.json +18 -0
- coreml/L512_06-12.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_06-12.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_06-12.mlpackage/Manifest.json +18 -0
- coreml/L512_12-18.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_12-18.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_12-18.mlpackage/Manifest.json +18 -0
- coreml/L512_18-24.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_18-24.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_18-24.mlpackage/Manifest.json +18 -0
- coreml/L512_24-30.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_24-30.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_24-30.mlpackage/Manifest.json +18 -0
- coreml/L512_30-36.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_30-36.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_30-36.mlpackage/Manifest.json +18 -0
- coreml/L512_36-42.mlpackage/Data/com.apple.CoreML/model.mlmodel +3 -0
- coreml/L512_36-42.mlpackage/Data/com.apple.CoreML/weights/weight.bin +3 -0
- coreml/L512_36-42.mlpackage/Manifest.json +18 -0
- d1a_config.json +38 -0
- embeddings.safetensors +3 -0
- head.safetensors +3 -0
- io.json +1 -0
- reference/d1a_coreml.py +183 -0
- reference/pipeline.py +79 -0
- reference/workers.py +99 -0
- tokenizer.json +3 -0
- 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 |
+
}
|