Instructions to use pmarquees/succinct-router with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use pmarquees/succinct-router with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir succinct-router pmarquees/succinct-router
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Upload 11 files
Browse files- README.md +48 -0
- calibration.json +40 -0
- config.json +16 -0
- example_inputs.jsonl +8 -0
- labels.json +7 -0
- manifest.json +391 -0
- mlx_model.py +132 -0
- model.safetensors +3 -0
- route_mlx.py +94 -0
- tokenizer.json +0 -0
- tokenizer_config.json +12 -0
README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
library_name: mlx
|
| 3 |
+
tags:
|
| 4 |
+
- mlx
|
| 5 |
+
- model-routing
|
| 6 |
+
- synthetic-data
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# Succinct Router 14M
|
| 10 |
+
|
| 11 |
+
A 14M-parameter decoder-only routing model trained from random initialization. It predicts an
|
| 12 |
+
independent pass probability for each of these candidate configurations:
|
| 13 |
+
|
| 14 |
+
- `gpt-5.6-luna-none`
|
| 15 |
+
- `gpt-5.6-terra-low`
|
| 16 |
+
- `gpt-5.6-sol-medium`
|
| 17 |
+
|
| 18 |
+
This model does **not** answer prompts. It selects the cheapest candidate configuration expected to
|
| 19 |
+
pass a calibrated quality threshold.
|
| 20 |
+
|
| 21 |
+
## Evaluation
|
| 22 |
+
|
| 23 |
+
```json
|
| 24 |
+
{
|
| 25 |
+
"exact_route_accuracy": 0.9508599508599509,
|
| 26 |
+
"unsafe_downroute_rate": 0.005528255528255528,
|
| 27 |
+
"selected_model_pass_rate": 0.9944717444717445,
|
| 28 |
+
"abstention_rate": 0.0,
|
| 29 |
+
"savings_vs_always_large": 0.8486732186732187
|
| 30 |
+
}
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
## Run with MLX
|
| 34 |
+
|
| 35 |
+
```bash
|
| 36 |
+
pip install "mlx>=0.32,<0.33" tokenizers
|
| 37 |
+
python route_mlx.py --model-dir . --prompt "Extract the invoice number from INV-4821."
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
The result contains calibrated pass probabilities and the selected candidate configuration. If no
|
| 41 |
+
candidate clears the threshold, `abstained_to_largest` is true and the route falls back to the
|
| 42 |
+
largest configuration.
|
| 43 |
+
|
| 44 |
+
## Limitations
|
| 45 |
+
|
| 46 |
+
Training and evaluation data are synthetic and mechanically graded. The artifact is a learning
|
| 47 |
+
prototype, not a production-ready router. Validate it on anonymized real traffic before making
|
| 48 |
+
product or cost claims. MLX runtime parity and latency must be measured on Apple Silicon.
|
calibration.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": "1",
|
| 3 |
+
"model_ids": [
|
| 4 |
+
"gpt-5.6-luna-none",
|
| 5 |
+
"gpt-5.6-terra-low",
|
| 6 |
+
"gpt-5.6-sol-medium"
|
| 7 |
+
],
|
| 8 |
+
"temperatures": [
|
| 9 |
+
1.0598043203353882,
|
| 10 |
+
1.106358528137207,
|
| 11 |
+
0.3136223554611206
|
| 12 |
+
],
|
| 13 |
+
"selection_threshold": 0.58,
|
| 14 |
+
"constraints": {
|
| 15 |
+
"max_unsafe_downroute_rate": 0.005,
|
| 16 |
+
"min_selected_model_pass_rate": 0.99,
|
| 17 |
+
"satisfied": true
|
| 18 |
+
},
|
| 19 |
+
"validation_route_metrics": {
|
| 20 |
+
"exact_route_accuracy": 0.9509283819628647,
|
| 21 |
+
"unsafe_downroute_rate": 0.004641909814323607,
|
| 22 |
+
"selected_model_pass_rate": 0.9953580901856764,
|
| 23 |
+
"abstention_rate": 0.0,
|
| 24 |
+
"savings_vs_always_large": 0.8416445623342175
|
| 25 |
+
},
|
| 26 |
+
"uncalibrated": {
|
| 27 |
+
"pass_vector_accuracy": 0.9244031830238727,
|
| 28 |
+
"pass_bit_accuracy": 0.9748010610079576,
|
| 29 |
+
"macro_f1": 0.985090243264452,
|
| 30 |
+
"brier_score": 0.01777769201095797,
|
| 31 |
+
"expected_calibration_error": 0.018437407725585803
|
| 32 |
+
},
|
| 33 |
+
"calibrated": {
|
| 34 |
+
"pass_vector_accuracy": 0.9244031830238727,
|
| 35 |
+
"pass_bit_accuracy": 0.9748010610079576,
|
| 36 |
+
"macro_f1": 0.985090243264452,
|
| 37 |
+
"brier_score": 0.017453370615839958,
|
| 38 |
+
"expected_calibration_error": 0.01830040662266169
|
| 39 |
+
}
|
| 40 |
+
}
|
config.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": "1",
|
| 3 |
+
"architecture": "succinct-router-decoder-v1",
|
| 4 |
+
"model": {
|
| 5 |
+
"vocab_size": 8192,
|
| 6 |
+
"max_sequence_length": 1024,
|
| 7 |
+
"layers": 6,
|
| 8 |
+
"model_width": 384,
|
| 9 |
+
"attention_heads": 6,
|
| 10 |
+
"ffn_width": 1024,
|
| 11 |
+
"dropout": 0.1,
|
| 12 |
+
"candidate_count": 3
|
| 13 |
+
},
|
| 14 |
+
"route_state": "final_<ROUTE>_token",
|
| 15 |
+
"tied_lm_head": true
|
| 16 |
+
}
|
example_inputs.jsonl
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"example_id": "sha256:5db7b3e355519960ac61e93ac9f7cd537f5010bb5142e8d2f0b85d9e801162e5", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 492, 352, 11, 351, 11, 133, 612, 159, 141, 13, 94, 94, 560, 11, 859, 530, 605, 13, 332, 700, 526, 13, 1036, 238, 540, 664, 13, 686, 608, 702, 99, 973, 59, 974, 29, 4], "reference_pass_logits": [7.015040397644043, 6.347684383392334, 6.796907901763916], "reference_scores": [0.989065408706665, 0.9848109483718872, 0.990003764629364]}
|
| 2 |
+
{"example_id": "sha256:780d0b0600848b763ea1d247395a6abc9295344d2a44d8cd7ba33641927bec67", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 492, 352, 11, 351, 11, 133, 612, 159, 141, 13, 94, 94, 560, 11, 859, 530, 605, 13, 332, 700, 526, 13, 1036, 238, 540, 664, 13, 686, 608, 702, 99, 973, 59, 974, 29, 4], "reference_pass_logits": [7.015040397644043, 6.347684383392334, 6.796907901763916], "reference_scores": [0.989065408706665, 0.9848109483718872, 0.990003764629364]}
|
| 3 |
+
{"example_id": "sha256:2f773ba7a80b8d601866a7d93b6ea025b2fe8dfc9140365dac1e8e60ab9e26d1", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 814, 180, 617, 133, 240, 158, 148, 595, 651, 345, 704, 683, 537, 59, 270, 11, 639, 644, 267, 158, 110, 571, 6, 348, 116, 483, 629, 238, 13, 712, 24, 349, 234, 107, 110, 678, 59, 270, 181, 110, 345, 107, 148, 270, 59, 144, 107, 110, 340, 641, 148, 234, 107, 110, 445, 59, 270, 181, 110, 345, 107, 148, 270, 59, 144, 107, 110, 340, 181, 110, 618, 107, 110, 340, 642, 94, 94, 558, 434, 12, 1216, 820, 25, 295, 682, 491, 541, 13, 4], "reference_pass_logits": [6.926111698150635, 6.366804122924805, 6.842347621917725], "reference_scores": [0.99000084400177, 0.9857044219970703, 0.9898501634597778]}
|
| 4 |
+
{"example_id": "sha256:2c7baa36710166560457211f804dd37cf02b40470e395dda9a0c64c72b528a91", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 814, 180, 617, 133, 240, 158, 148, 595, 651, 345, 704, 683, 537, 59, 270, 11, 639, 644, 267, 158, 110, 571, 6, 348, 116, 483, 629, 238, 13, 712, 24, 349, 234, 107, 110, 678, 59, 270, 181, 110, 345, 107, 148, 270, 59, 144, 107, 110, 340, 641, 148, 234, 107, 110, 445, 59, 270, 181, 110, 345, 107, 148, 270, 59, 144, 107, 110, 340, 181, 110, 618, 107, 110, 340, 642, 94, 94, 558, 434, 12, 1216, 820, 25, 295, 682, 491, 541, 13, 4], "reference_pass_logits": [6.926111698150635, 6.366804122924805, 6.842347621917725], "reference_scores": [0.99000084400177, 0.9857044219970703, 0.9898501634597778]}
|
| 5 |
+
{"example_id": "sha256:1746c9cf5738c6f562730b79c8a48454e0457b259ee27e32fb1ac9b0b8eba4f9", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 166, 125, 464, 459, 699, 548, 677, 717, 706, 159, 148, 436, 107, 481, 456, 671, 684, 819, 11, 551, 99, 554, 7, 654, 11, 755, 551, 333, 7, 834, 548, 125, 991, 992, 13, 670, 24, 349, 284, 107, 1114, 13, 1062, 11, 110, 286, 107, 335, 285, 148, 284, 107, 1095, 13, 17, 11, 110, 286, 107, 288, 285, 148, 284, 107, 1150, 13, 1049, 11, 110, 286, 107, 288, 285, 148, 284, 107, 1156, 13, 1009, 11, 110, 286, 107, 230, 457, 4], "reference_pass_logits": [-7.627079963684082, 2.626823663711548, 4.990095615386963], "reference_scores": [0.018578819930553436, 0.9573246240615845, 0.9830689430236816]}
|
| 6 |
+
{"example_id": "sha256:40396bbb4a9130ac5fdeb93980af7a9f98f12406d55c20b9c48a05ad6e65ece7", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 833, 506, 464, 459, 699, 548, 677, 717, 706, 159, 148, 436, 107, 481, 456, 671, 684, 819, 11, 551, 99, 554, 7, 654, 11, 755, 551, 333, 7, 834, 548, 506, 991, 992, 13, 670, 24, 349, 284, 107, 1114, 13, 1062, 11, 110, 286, 107, 335, 285, 148, 284, 107, 1095, 13, 17, 11, 110, 286, 107, 288, 285, 148, 284, 107, 1150, 13, 1049, 11, 110, 286, 107, 288, 285, 148, 284, 107, 1156, 13, 1009, 11, 110, 286, 107, 230, 457, 4], "reference_pass_logits": [-7.622464656829834, 2.636568307876587, 4.985684394836426], "reference_scores": [0.018651440739631653, 0.9573564529418945, 0.9829824566841125]}
|
| 7 |
+
{"example_id": "sha256:62fafb8ee1842978bd6c2b7a324561b09a2b546db5c40264b20d33c6fa2de220", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 817, 125, 715, 315, 342, 59, 144, 133, 714, 459, 59, 633, 13, 177, 141, 271, 13, 94, 94, 132, 568, 107, 148, 144, 107, 110, 691, 12, 1221, 865, 273, 110, 688, 107, 110, 695, 181, 110, 436, 59, 574, 107, 1120, 13, 1067, 87, 4], "reference_pass_logits": [6.730648040771484, 6.451633453369141, 6.800724506378174], "reference_scores": [0.9886912107467651, 0.9871037602424622, 0.9892838597297668]}
|
| 8 |
+
{"example_id": "sha256:3c9e6ec5cf888091fd117958d1f87455b125ac6985f38d2adfa72fcd66815b50", "input_ids": [2, 26, 200, 28, 94, 219, 125, 222, 158, 13, 177, 180, 220, 141, 221, 133, 188, 215, 11, 217, 11, 115, 168, 223, 13, 214, 198, 115, 218, 224, 159, 201, 199, 13, 94, 94, 26, 211, 28, 94, 817, 506, 715, 315, 342, 59, 144, 133, 714, 459, 59, 633, 13, 240, 141, 271, 13, 94, 94, 132, 568, 107, 148, 144, 107, 110, 691, 12, 1221, 865, 273, 110, 688, 107, 110, 695, 181, 110, 436, 59, 574, 107, 1120, 13, 1067, 87, 4], "reference_pass_logits": [6.713947296142578, 6.455345153808594, 6.808040618896484], "reference_scores": [0.9886158108711243, 0.9869857430458069, 0.9892330169677734]}
|
labels.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"candidate_model_config_ids": [
|
| 3 |
+
"gpt-5.6-luna-none",
|
| 4 |
+
"gpt-5.6-terra-low",
|
| 5 |
+
"gpt-5.6-sol-medium"
|
| 6 |
+
]
|
| 7 |
+
}
|
manifest.json
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": "1",
|
| 3 |
+
"format": "succinct-router-mlx-v1",
|
| 4 |
+
"linux_validation": {
|
| 5 |
+
"tensor_names_shapes_dtypes": "passed",
|
| 6 |
+
"tokenizer_round_trip": "passed",
|
| 7 |
+
"reference_pytorch_logits": 8
|
| 8 |
+
},
|
| 9 |
+
"mlx_runtime_validation": {
|
| 10 |
+
"status": "passed",
|
| 11 |
+
"device": "Device(cpu, 0)",
|
| 12 |
+
"examples": 8,
|
| 13 |
+
"max_abs_pass_logit_error": 3.814697265625e-06,
|
| 14 |
+
"max_abs_score_error": 5.960464477539063e-08,
|
| 15 |
+
"tolerance": 0.0001
|
| 16 |
+
},
|
| 17 |
+
"apple_silicon_metal_latency_validation": "required",
|
| 18 |
+
"weights": {
|
| 19 |
+
"tensor_count": 48,
|
| 20 |
+
"sha256": "35e54bfcffe5ade95e32bee903c708ca30554170acb9c7b82dc7db6e3d4eebe4",
|
| 21 |
+
"bytes": 55084128,
|
| 22 |
+
"tied_weight": {
|
| 23 |
+
"lm_head.weight": "embedding.weight"
|
| 24 |
+
},
|
| 25 |
+
"tensors": {
|
| 26 |
+
"blocks.0.attention.output.weight": {
|
| 27 |
+
"shape": [
|
| 28 |
+
384,
|
| 29 |
+
384
|
| 30 |
+
],
|
| 31 |
+
"dtype": "float32"
|
| 32 |
+
},
|
| 33 |
+
"blocks.0.attention.qkv.weight": {
|
| 34 |
+
"shape": [
|
| 35 |
+
1152,
|
| 36 |
+
384
|
| 37 |
+
],
|
| 38 |
+
"dtype": "float32"
|
| 39 |
+
},
|
| 40 |
+
"blocks.0.attention_norm.weight": {
|
| 41 |
+
"shape": [
|
| 42 |
+
384
|
| 43 |
+
],
|
| 44 |
+
"dtype": "float32"
|
| 45 |
+
},
|
| 46 |
+
"blocks.0.ffn.down.weight": {
|
| 47 |
+
"shape": [
|
| 48 |
+
384,
|
| 49 |
+
1024
|
| 50 |
+
],
|
| 51 |
+
"dtype": "float32"
|
| 52 |
+
},
|
| 53 |
+
"blocks.0.ffn.gate.weight": {
|
| 54 |
+
"shape": [
|
| 55 |
+
1024,
|
| 56 |
+
384
|
| 57 |
+
],
|
| 58 |
+
"dtype": "float32"
|
| 59 |
+
},
|
| 60 |
+
"blocks.0.ffn.up.weight": {
|
| 61 |
+
"shape": [
|
| 62 |
+
1024,
|
| 63 |
+
384
|
| 64 |
+
],
|
| 65 |
+
"dtype": "float32"
|
| 66 |
+
},
|
| 67 |
+
"blocks.0.ffn_norm.weight": {
|
| 68 |
+
"shape": [
|
| 69 |
+
384
|
| 70 |
+
],
|
| 71 |
+
"dtype": "float32"
|
| 72 |
+
},
|
| 73 |
+
"blocks.1.attention.output.weight": {
|
| 74 |
+
"shape": [
|
| 75 |
+
384,
|
| 76 |
+
384
|
| 77 |
+
],
|
| 78 |
+
"dtype": "float32"
|
| 79 |
+
},
|
| 80 |
+
"blocks.1.attention.qkv.weight": {
|
| 81 |
+
"shape": [
|
| 82 |
+
1152,
|
| 83 |
+
384
|
| 84 |
+
],
|
| 85 |
+
"dtype": "float32"
|
| 86 |
+
},
|
| 87 |
+
"blocks.1.attention_norm.weight": {
|
| 88 |
+
"shape": [
|
| 89 |
+
384
|
| 90 |
+
],
|
| 91 |
+
"dtype": "float32"
|
| 92 |
+
},
|
| 93 |
+
"blocks.1.ffn.down.weight": {
|
| 94 |
+
"shape": [
|
| 95 |
+
384,
|
| 96 |
+
1024
|
| 97 |
+
],
|
| 98 |
+
"dtype": "float32"
|
| 99 |
+
},
|
| 100 |
+
"blocks.1.ffn.gate.weight": {
|
| 101 |
+
"shape": [
|
| 102 |
+
1024,
|
| 103 |
+
384
|
| 104 |
+
],
|
| 105 |
+
"dtype": "float32"
|
| 106 |
+
},
|
| 107 |
+
"blocks.1.ffn.up.weight": {
|
| 108 |
+
"shape": [
|
| 109 |
+
1024,
|
| 110 |
+
384
|
| 111 |
+
],
|
| 112 |
+
"dtype": "float32"
|
| 113 |
+
},
|
| 114 |
+
"blocks.1.ffn_norm.weight": {
|
| 115 |
+
"shape": [
|
| 116 |
+
384
|
| 117 |
+
],
|
| 118 |
+
"dtype": "float32"
|
| 119 |
+
},
|
| 120 |
+
"blocks.2.attention.output.weight": {
|
| 121 |
+
"shape": [
|
| 122 |
+
384,
|
| 123 |
+
384
|
| 124 |
+
],
|
| 125 |
+
"dtype": "float32"
|
| 126 |
+
},
|
| 127 |
+
"blocks.2.attention.qkv.weight": {
|
| 128 |
+
"shape": [
|
| 129 |
+
1152,
|
| 130 |
+
384
|
| 131 |
+
],
|
| 132 |
+
"dtype": "float32"
|
| 133 |
+
},
|
| 134 |
+
"blocks.2.attention_norm.weight": {
|
| 135 |
+
"shape": [
|
| 136 |
+
384
|
| 137 |
+
],
|
| 138 |
+
"dtype": "float32"
|
| 139 |
+
},
|
| 140 |
+
"blocks.2.ffn.down.weight": {
|
| 141 |
+
"shape": [
|
| 142 |
+
384,
|
| 143 |
+
1024
|
| 144 |
+
],
|
| 145 |
+
"dtype": "float32"
|
| 146 |
+
},
|
| 147 |
+
"blocks.2.ffn.gate.weight": {
|
| 148 |
+
"shape": [
|
| 149 |
+
1024,
|
| 150 |
+
384
|
| 151 |
+
],
|
| 152 |
+
"dtype": "float32"
|
| 153 |
+
},
|
| 154 |
+
"blocks.2.ffn.up.weight": {
|
| 155 |
+
"shape": [
|
| 156 |
+
1024,
|
| 157 |
+
384
|
| 158 |
+
],
|
| 159 |
+
"dtype": "float32"
|
| 160 |
+
},
|
| 161 |
+
"blocks.2.ffn_norm.weight": {
|
| 162 |
+
"shape": [
|
| 163 |
+
384
|
| 164 |
+
],
|
| 165 |
+
"dtype": "float32"
|
| 166 |
+
},
|
| 167 |
+
"blocks.3.attention.output.weight": {
|
| 168 |
+
"shape": [
|
| 169 |
+
384,
|
| 170 |
+
384
|
| 171 |
+
],
|
| 172 |
+
"dtype": "float32"
|
| 173 |
+
},
|
| 174 |
+
"blocks.3.attention.qkv.weight": {
|
| 175 |
+
"shape": [
|
| 176 |
+
1152,
|
| 177 |
+
384
|
| 178 |
+
],
|
| 179 |
+
"dtype": "float32"
|
| 180 |
+
},
|
| 181 |
+
"blocks.3.attention_norm.weight": {
|
| 182 |
+
"shape": [
|
| 183 |
+
384
|
| 184 |
+
],
|
| 185 |
+
"dtype": "float32"
|
| 186 |
+
},
|
| 187 |
+
"blocks.3.ffn.down.weight": {
|
| 188 |
+
"shape": [
|
| 189 |
+
384,
|
| 190 |
+
1024
|
| 191 |
+
],
|
| 192 |
+
"dtype": "float32"
|
| 193 |
+
},
|
| 194 |
+
"blocks.3.ffn.gate.weight": {
|
| 195 |
+
"shape": [
|
| 196 |
+
1024,
|
| 197 |
+
384
|
| 198 |
+
],
|
| 199 |
+
"dtype": "float32"
|
| 200 |
+
},
|
| 201 |
+
"blocks.3.ffn.up.weight": {
|
| 202 |
+
"shape": [
|
| 203 |
+
1024,
|
| 204 |
+
384
|
| 205 |
+
],
|
| 206 |
+
"dtype": "float32"
|
| 207 |
+
},
|
| 208 |
+
"blocks.3.ffn_norm.weight": {
|
| 209 |
+
"shape": [
|
| 210 |
+
384
|
| 211 |
+
],
|
| 212 |
+
"dtype": "float32"
|
| 213 |
+
},
|
| 214 |
+
"blocks.4.attention.output.weight": {
|
| 215 |
+
"shape": [
|
| 216 |
+
384,
|
| 217 |
+
384
|
| 218 |
+
],
|
| 219 |
+
"dtype": "float32"
|
| 220 |
+
},
|
| 221 |
+
"blocks.4.attention.qkv.weight": {
|
| 222 |
+
"shape": [
|
| 223 |
+
1152,
|
| 224 |
+
384
|
| 225 |
+
],
|
| 226 |
+
"dtype": "float32"
|
| 227 |
+
},
|
| 228 |
+
"blocks.4.attention_norm.weight": {
|
| 229 |
+
"shape": [
|
| 230 |
+
384
|
| 231 |
+
],
|
| 232 |
+
"dtype": "float32"
|
| 233 |
+
},
|
| 234 |
+
"blocks.4.ffn.down.weight": {
|
| 235 |
+
"shape": [
|
| 236 |
+
384,
|
| 237 |
+
1024
|
| 238 |
+
],
|
| 239 |
+
"dtype": "float32"
|
| 240 |
+
},
|
| 241 |
+
"blocks.4.ffn.gate.weight": {
|
| 242 |
+
"shape": [
|
| 243 |
+
1024,
|
| 244 |
+
384
|
| 245 |
+
],
|
| 246 |
+
"dtype": "float32"
|
| 247 |
+
},
|
| 248 |
+
"blocks.4.ffn.up.weight": {
|
| 249 |
+
"shape": [
|
| 250 |
+
1024,
|
| 251 |
+
384
|
| 252 |
+
],
|
| 253 |
+
"dtype": "float32"
|
| 254 |
+
},
|
| 255 |
+
"blocks.4.ffn_norm.weight": {
|
| 256 |
+
"shape": [
|
| 257 |
+
384
|
| 258 |
+
],
|
| 259 |
+
"dtype": "float32"
|
| 260 |
+
},
|
| 261 |
+
"blocks.5.attention.output.weight": {
|
| 262 |
+
"shape": [
|
| 263 |
+
384,
|
| 264 |
+
384
|
| 265 |
+
],
|
| 266 |
+
"dtype": "float32"
|
| 267 |
+
},
|
| 268 |
+
"blocks.5.attention.qkv.weight": {
|
| 269 |
+
"shape": [
|
| 270 |
+
1152,
|
| 271 |
+
384
|
| 272 |
+
],
|
| 273 |
+
"dtype": "float32"
|
| 274 |
+
},
|
| 275 |
+
"blocks.5.attention_norm.weight": {
|
| 276 |
+
"shape": [
|
| 277 |
+
384
|
| 278 |
+
],
|
| 279 |
+
"dtype": "float32"
|
| 280 |
+
},
|
| 281 |
+
"blocks.5.ffn.down.weight": {
|
| 282 |
+
"shape": [
|
| 283 |
+
384,
|
| 284 |
+
1024
|
| 285 |
+
],
|
| 286 |
+
"dtype": "float32"
|
| 287 |
+
},
|
| 288 |
+
"blocks.5.ffn.gate.weight": {
|
| 289 |
+
"shape": [
|
| 290 |
+
1024,
|
| 291 |
+
384
|
| 292 |
+
],
|
| 293 |
+
"dtype": "float32"
|
| 294 |
+
},
|
| 295 |
+
"blocks.5.ffn.up.weight": {
|
| 296 |
+
"shape": [
|
| 297 |
+
1024,
|
| 298 |
+
384
|
| 299 |
+
],
|
| 300 |
+
"dtype": "float32"
|
| 301 |
+
},
|
| 302 |
+
"blocks.5.ffn_norm.weight": {
|
| 303 |
+
"shape": [
|
| 304 |
+
384
|
| 305 |
+
],
|
| 306 |
+
"dtype": "float32"
|
| 307 |
+
},
|
| 308 |
+
"embedding.weight": {
|
| 309 |
+
"shape": [
|
| 310 |
+
8192,
|
| 311 |
+
384
|
| 312 |
+
],
|
| 313 |
+
"dtype": "float32"
|
| 314 |
+
},
|
| 315 |
+
"norm.weight": {
|
| 316 |
+
"shape": [
|
| 317 |
+
384
|
| 318 |
+
],
|
| 319 |
+
"dtype": "float32"
|
| 320 |
+
},
|
| 321 |
+
"pass_head.bias": {
|
| 322 |
+
"shape": [
|
| 323 |
+
3
|
| 324 |
+
],
|
| 325 |
+
"dtype": "float32"
|
| 326 |
+
},
|
| 327 |
+
"pass_head.weight": {
|
| 328 |
+
"shape": [
|
| 329 |
+
3,
|
| 330 |
+
384
|
| 331 |
+
],
|
| 332 |
+
"dtype": "float32"
|
| 333 |
+
},
|
| 334 |
+
"score_head.bias": {
|
| 335 |
+
"shape": [
|
| 336 |
+
3
|
| 337 |
+
],
|
| 338 |
+
"dtype": "float32"
|
| 339 |
+
},
|
| 340 |
+
"score_head.weight": {
|
| 341 |
+
"shape": [
|
| 342 |
+
3,
|
| 343 |
+
384
|
| 344 |
+
],
|
| 345 |
+
"dtype": "float32"
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
},
|
| 349 |
+
"files": {
|
| 350 |
+
"README.md": {
|
| 351 |
+
"bytes": 1397,
|
| 352 |
+
"sha256": "a1c485e0e037508e1ea8b7fe6c6422d24ed1ddaa8c60579ba552eeae4a673c29"
|
| 353 |
+
},
|
| 354 |
+
"calibration.json": {
|
| 355 |
+
"bytes": 1139,
|
| 356 |
+
"sha256": "416b2d6d5d609608c405a615646cab6e7ee9022d24586b9245053a75e78daf74"
|
| 357 |
+
},
|
| 358 |
+
"config.json": {
|
| 359 |
+
"bytes": 350,
|
| 360 |
+
"sha256": "68c3fd9f8ae9c8376cfdbba58acb642c76645c145705f6bb7e68e86c3de4367a"
|
| 361 |
+
},
|
| 362 |
+
"example_inputs.jsonl": {
|
| 363 |
+
"bytes": 6124,
|
| 364 |
+
"sha256": "223879c190c301466279ddd177fd46af91e448b6b8e1be44a4aa89c2ccc43ca0"
|
| 365 |
+
},
|
| 366 |
+
"labels.json": {
|
| 367 |
+
"bytes": 117,
|
| 368 |
+
"sha256": "c4ea84d5fcde04d423647df6843a07c21ee680ec95983ac485370f07697d495a"
|
| 369 |
+
},
|
| 370 |
+
"mlx_model.py": {
|
| 371 |
+
"bytes": 5486,
|
| 372 |
+
"sha256": "5fbb97e004f7c9e613ae94144f3d04966d64d1a2a0bbf152664296876fd28901"
|
| 373 |
+
},
|
| 374 |
+
"model.safetensors": {
|
| 375 |
+
"bytes": 55084128,
|
| 376 |
+
"sha256": "35e54bfcffe5ade95e32bee903c708ca30554170acb9c7b82dc7db6e3d4eebe4"
|
| 377 |
+
},
|
| 378 |
+
"route_mlx.py": {
|
| 379 |
+
"bytes": 3265,
|
| 380 |
+
"sha256": "20b7520c89c876d9ae2e964bf49679294a1f50e67567538f719c8107db9a4d6c"
|
| 381 |
+
},
|
| 382 |
+
"tokenizer.json": {
|
| 383 |
+
"bytes": 532269,
|
| 384 |
+
"sha256": "f417f5abf0de1c4a475620c4b16b487834115555688d379b29202c4edc5d7481"
|
| 385 |
+
},
|
| 386 |
+
"tokenizer_config.json": {
|
| 387 |
+
"bytes": 183,
|
| 388 |
+
"sha256": "568172f0cc44b6d1d080d53807dce5537a0e58cdbe7fb9d7e6678f97c1f3641c"
|
| 389 |
+
}
|
| 390 |
+
}
|
| 391 |
+
}
|
mlx_model.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Any
|
| 6 |
+
|
| 7 |
+
try:
|
| 8 |
+
import mlx.core as mx
|
| 9 |
+
import mlx.nn as nn
|
| 10 |
+
except ImportError: # Linux export validation intentionally has no MLX runtime.
|
| 11 |
+
mx = None
|
| 12 |
+
nn = None
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
if nn is not None and mx is not None:
|
| 16 |
+
|
| 17 |
+
class RMSNorm(nn.Module):
|
| 18 |
+
def __init__(self, dimension: int, epsilon: float = 1e-6) -> None:
|
| 19 |
+
super().__init__()
|
| 20 |
+
self.weight = mx.ones((dimension,))
|
| 21 |
+
self.epsilon = epsilon
|
| 22 |
+
|
| 23 |
+
def __call__(self, values: Any) -> Any:
|
| 24 |
+
normalized = values * mx.rsqrt(
|
| 25 |
+
mx.mean(mx.square(values), axis=-1, keepdims=True) + self.epsilon
|
| 26 |
+
)
|
| 27 |
+
return normalized * self.weight
|
| 28 |
+
|
| 29 |
+
def _rotate_half(values: Any) -> Any:
|
| 30 |
+
first, second = mx.split(values, 2, axis=-1)
|
| 31 |
+
return mx.concatenate((-second, first), axis=-1)
|
| 32 |
+
|
| 33 |
+
def apply_rope(query: Any, key: Any) -> tuple[Any, Any]:
|
| 34 |
+
sequence_length = query.shape[-2]
|
| 35 |
+
dimension = query.shape[-1]
|
| 36 |
+
positions = mx.arange(sequence_length, dtype=mx.float32)
|
| 37 |
+
frequencies = 1.0 / (10000 ** (mx.arange(0, dimension, 2, dtype=mx.float32) / dimension))
|
| 38 |
+
angles = positions[:, None] * frequencies[None, :]
|
| 39 |
+
angles = mx.concatenate((angles, angles), axis=-1)[None, None, :, :]
|
| 40 |
+
cosine = mx.cos(angles)
|
| 41 |
+
sine = mx.sin(angles)
|
| 42 |
+
return query * cosine + _rotate_half(query) * sine, key * cosine + _rotate_half(key) * sine
|
| 43 |
+
|
| 44 |
+
class CausalSelfAttention(nn.Module):
|
| 45 |
+
def __init__(self, config: dict[str, Any]) -> None:
|
| 46 |
+
super().__init__()
|
| 47 |
+
self.heads = int(config["attention_heads"])
|
| 48 |
+
self.head_dimension = int(config["model_width"]) // self.heads
|
| 49 |
+
width = int(config["model_width"])
|
| 50 |
+
self.qkv = nn.Linear(width, 3 * width, bias=False)
|
| 51 |
+
self.output = nn.Linear(width, width, bias=False)
|
| 52 |
+
|
| 53 |
+
def __call__(self, values: Any) -> Any:
|
| 54 |
+
batch, sequence, width = values.shape
|
| 55 |
+
qkv = self.qkv(values).reshape(batch, sequence, 3, self.heads, self.head_dimension)
|
| 56 |
+
qkv = qkv.transpose(2, 0, 3, 1, 4)
|
| 57 |
+
query, key, value = qkv[0], qkv[1], qkv[2]
|
| 58 |
+
query, key = apply_rope(query, key)
|
| 59 |
+
mask = nn.MultiHeadAttention.create_additive_causal_mask(sequence)
|
| 60 |
+
attended = mx.fast.scaled_dot_product_attention(
|
| 61 |
+
query,
|
| 62 |
+
key,
|
| 63 |
+
value,
|
| 64 |
+
scale=self.head_dimension**-0.5,
|
| 65 |
+
mask=mask,
|
| 66 |
+
)
|
| 67 |
+
return self.output(attended.transpose(0, 2, 1, 3).reshape(batch, sequence, width))
|
| 68 |
+
|
| 69 |
+
class SwiGLU(nn.Module):
|
| 70 |
+
def __init__(self, config: dict[str, Any]) -> None:
|
| 71 |
+
super().__init__()
|
| 72 |
+
width = int(config["model_width"])
|
| 73 |
+
ffn_width = int(config["ffn_width"])
|
| 74 |
+
self.gate = nn.Linear(width, ffn_width, bias=False)
|
| 75 |
+
self.up = nn.Linear(width, ffn_width, bias=False)
|
| 76 |
+
self.down = nn.Linear(ffn_width, width, bias=False)
|
| 77 |
+
|
| 78 |
+
def __call__(self, values: Any) -> Any:
|
| 79 |
+
return self.down(nn.silu(self.gate(values)) * self.up(values))
|
| 80 |
+
|
| 81 |
+
class TransformerBlock(nn.Module):
|
| 82 |
+
def __init__(self, config: dict[str, Any]) -> None:
|
| 83 |
+
super().__init__()
|
| 84 |
+
width = int(config["model_width"])
|
| 85 |
+
self.attention_norm = RMSNorm(width)
|
| 86 |
+
self.attention = CausalSelfAttention(config)
|
| 87 |
+
self.ffn_norm = RMSNorm(width)
|
| 88 |
+
self.ffn = SwiGLU(config)
|
| 89 |
+
|
| 90 |
+
def __call__(self, values: Any) -> Any:
|
| 91 |
+
values = values + self.attention(self.attention_norm(values))
|
| 92 |
+
return values + self.ffn(self.ffn_norm(values))
|
| 93 |
+
|
| 94 |
+
class TransformerRouterMLX(nn.Module):
|
| 95 |
+
def __init__(self, config: dict[str, Any]) -> None:
|
| 96 |
+
super().__init__()
|
| 97 |
+
width = int(config["model_width"])
|
| 98 |
+
self.config = config
|
| 99 |
+
self.embedding = nn.Embedding(int(config["vocab_size"]), width)
|
| 100 |
+
self.blocks = [TransformerBlock(config) for _ in range(int(config["layers"]))]
|
| 101 |
+
self.norm = RMSNorm(width)
|
| 102 |
+
self.pass_head = nn.Linear(width, int(config["candidate_count"]))
|
| 103 |
+
self.score_head = nn.Linear(width, int(config["candidate_count"]))
|
| 104 |
+
|
| 105 |
+
def __call__(self, input_ids: Any) -> dict[str, Any]:
|
| 106 |
+
hidden = self.embedding(input_ids)
|
| 107 |
+
for block in self.blocks:
|
| 108 |
+
hidden = block(hidden)
|
| 109 |
+
hidden = self.norm(hidden)
|
| 110 |
+
route_state = hidden[:, -1]
|
| 111 |
+
return {
|
| 112 |
+
"pass_logits": self.pass_head(route_state),
|
| 113 |
+
"scores": mx.sigmoid(self.score_head(route_state)),
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
def load_mlx_router(directory: str | Path) -> Any:
|
| 117 |
+
root = Path(directory)
|
| 118 |
+
config = json.loads((root / "config.json").read_text(encoding="utf-8"))["model"]
|
| 119 |
+
model = TransformerRouterMLX(config)
|
| 120 |
+
weights = mx.load(str(root / "model.safetensors"))
|
| 121 |
+
model.load_weights(list(weights.items()), strict=True)
|
| 122 |
+
mx.eval(model.parameters())
|
| 123 |
+
return model
|
| 124 |
+
|
| 125 |
+
else:
|
| 126 |
+
|
| 127 |
+
class TransformerRouterMLX: # type: ignore[no-redef]
|
| 128 |
+
def __init__(self, config: dict[str, Any]) -> None:
|
| 129 |
+
raise RuntimeError("MLX requires macOS on Apple Silicon")
|
| 130 |
+
|
| 131 |
+
def load_mlx_router(directory: str | Path) -> Any:
|
| 132 |
+
raise RuntimeError("MLX requires macOS on Apple Silicon")
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:35e54bfcffe5ade95e32bee903c708ca30554170acb9c7b82dc7db6e3d4eebe4
|
| 3 |
+
size 55084128
|
route_mlx.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from typing import Any
|
| 7 |
+
|
| 8 |
+
import mlx.core as mx
|
| 9 |
+
from mlx_model import load_mlx_router
|
| 10 |
+
from tokenizers import Tokenizer
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def _encode_prompt(
|
| 14 |
+
tokenizer: Tokenizer,
|
| 15 |
+
prompt: str,
|
| 16 |
+
*,
|
| 17 |
+
system: str | None,
|
| 18 |
+
max_length: int,
|
| 19 |
+
) -> list[int]:
|
| 20 |
+
text = f"<user>\n{prompt}" if system is None else f"<system>\n{system}\n\n<user>\n{prompt}"
|
| 21 |
+
bos_id = tokenizer.token_to_id("<BOS>")
|
| 22 |
+
route_id = tokenizer.token_to_id("<ROUTE>")
|
| 23 |
+
head_tail_id = tokenizer.token_to_id("<HEAD_TAIL>")
|
| 24 |
+
if bos_id is None or route_id is None or head_tail_id is None:
|
| 25 |
+
raise ValueError("Tokenizer is missing required routing tokens")
|
| 26 |
+
body = tokenizer.encode(text, add_special_tokens=False).ids
|
| 27 |
+
available = max_length - 2
|
| 28 |
+
if len(body) > available:
|
| 29 |
+
head_length = (available - 1 + 1) // 2
|
| 30 |
+
tail_length = available - 1 - head_length
|
| 31 |
+
body = body[:head_length] + [head_tail_id] + (body[-tail_length:] if tail_length else [])
|
| 32 |
+
return [bos_id, *body, route_id]
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def route_prompt(
|
| 36 |
+
model_dir: str | Path,
|
| 37 |
+
prompt: str,
|
| 38 |
+
*,
|
| 39 |
+
system: str | None = None,
|
| 40 |
+
) -> dict[str, Any]:
|
| 41 |
+
root = Path(model_dir)
|
| 42 |
+
config = json.loads((root / "config.json").read_text(encoding="utf-8"))
|
| 43 |
+
calibration = json.loads((root / "calibration.json").read_text(encoding="utf-8"))
|
| 44 |
+
labels = json.loads((root / "labels.json").read_text(encoding="utf-8"))[
|
| 45 |
+
"candidate_model_config_ids"
|
| 46 |
+
]
|
| 47 |
+
tokenizer = Tokenizer.from_file(str(root / "tokenizer.json"))
|
| 48 |
+
input_ids = _encode_prompt(
|
| 49 |
+
tokenizer,
|
| 50 |
+
prompt,
|
| 51 |
+
system=system,
|
| 52 |
+
max_length=int(config["model"]["max_sequence_length"]),
|
| 53 |
+
)
|
| 54 |
+
model = load_mlx_router(root)
|
| 55 |
+
prediction = model(mx.array([input_ids]))
|
| 56 |
+
temperatures = mx.array(calibration["temperatures"])
|
| 57 |
+
probabilities = mx.sigmoid(prediction["pass_logits"][0] / temperatures)
|
| 58 |
+
mx.eval(probabilities, prediction["scores"])
|
| 59 |
+
pass_probabilities = probabilities.tolist()
|
| 60 |
+
threshold = float(calibration["selection_threshold"])
|
| 61 |
+
selected_index = next(
|
| 62 |
+
(index for index, probability in enumerate(pass_probabilities) if probability >= threshold),
|
| 63 |
+
None,
|
| 64 |
+
)
|
| 65 |
+
abstained = selected_index is None
|
| 66 |
+
fallback_index = len(labels) - 1
|
| 67 |
+
route_index = fallback_index if abstained else selected_index
|
| 68 |
+
return {
|
| 69 |
+
"route_config_id": labels[route_index],
|
| 70 |
+
"abstained_to_largest": abstained,
|
| 71 |
+
"selection_threshold": threshold,
|
| 72 |
+
"pass_probabilities": dict(zip(labels, pass_probabilities, strict=True)),
|
| 73 |
+
"predicted_scores": dict(zip(labels, prediction["scores"][0].tolist(), strict=True)),
|
| 74 |
+
"input_tokens": len(input_ids),
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def main() -> None:
|
| 79 |
+
parser = argparse.ArgumentParser(description="Route one prompt with the exported MLX model")
|
| 80 |
+
parser.add_argument("--model-dir", default=".")
|
| 81 |
+
parser.add_argument("--prompt", required=True)
|
| 82 |
+
parser.add_argument("--system")
|
| 83 |
+
args = parser.parse_args()
|
| 84 |
+
print(
|
| 85 |
+
json.dumps(
|
| 86 |
+
route_prompt(args.model_dir, args.prompt, system=args.system),
|
| 87 |
+
indent=2,
|
| 88 |
+
sort_keys=True,
|
| 89 |
+
)
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
if __name__ == "__main__":
|
| 94 |
+
main()
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"vocab_size": 8192,
|
| 3 |
+
"model_vocab_size": 8192,
|
| 4 |
+
"special_tokens": {
|
| 5 |
+
"<PAD>": 0,
|
| 6 |
+
"<UNK>": 1,
|
| 7 |
+
"<BOS>": 2,
|
| 8 |
+
"<EOS>": 3,
|
| 9 |
+
"<ROUTE>": 4,
|
| 10 |
+
"<HEAD_TAIL>": 5
|
| 11 |
+
}
|
| 12 |
+
}
|