alessandrobologna commited on
Commit
74983fc
·
verified ·
1 Parent(s): 96008bb

Add files using upload-large-folder tool

Browse files
.gitattributes CHANGED
@@ -1,35 +1 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz 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
 
1
+ *.gguf filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ .venv/
2
+ sources/
3
+ upstream-metadata/
4
+ *.partial-*
5
+ .*.repeat-check
6
+ __pycache__/
7
+ *.pyc
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.14.6
DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33
3
+ size 10897110272
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 DeepSeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
LICENSE.code ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alessandro Bologna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: gguf
4
+ base_model: deepseek-ai/DeepSeek-V4-Flash-0731
5
+ base_model_relation: quantized
6
+ tags:
7
+ - gguf
8
+ - deepseek-v4
9
+ - dspark
10
+ - speculative-decoding
11
+ - draft-model
12
+ - auxiliary-model
13
+ ---
14
+
15
+ # DeepSeek V4 Flash 0731 DSpark Drafter GGUF
16
+
17
+ This repository contains only the **DSpark auxiliary drafter** extracted from
18
+ DeepSeek V4 Flash 0731. It is not a standalone language model and does not
19
+ contain the target model weights.
20
+
21
+ The GGUF is built from the official
22
+ [`deepseek-ai/DeepSeek-V4-Flash-0731`](https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731)
23
+ checkpoint using the standalone Python scripts included here. The complete
24
+ source manifest, build recipe, structural parser, numeric verifier, dependency
25
+ pin, and build results are published alongside the artifact.
26
+
27
+ ## Artifact
28
+
29
+ | File | Bytes | SHA-256 |
30
+ |---|---:|---|
31
+ | `DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf` | 10,897,110,272 | `5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33` |
32
+
33
+ The artifact uses GGUF v3 with the custom architecture
34
+ `deepseek_v4_flash_dspark_draft` and contains 81 tensors:
35
+
36
+ | Output type | Tensors | Transformation |
37
+ |---|---:|---|
38
+ | F32 | 45 | BF16 expanded exactly to F32, or source F32 bytes preserved |
39
+ | F16 | 2 | BF16 Markov heads rounded to F16 |
40
+ | Q8_0 | 25 | FP8 E4M3 weights with E8M0 block scales dequantized, then quantized to Q8_0 |
41
+ | MXFP4 | 9 | Routed-expert FP4 nibbles and E8M0 scales repacked without requantization |
42
+
43
+ The MXFP4 transformation is bit-preserving. Q8_0 and F16 transformations are
44
+ lossy and are checked against explicit numeric error bounds. This repository
45
+ does not claim that the complete conversion is lossless.
46
+
47
+ ## Pinned source
48
+
49
+ - Repository: `deepseek-ai/DeepSeek-V4-Flash-0731`
50
+ - Revision: `9e165c30e2704aec5d9d593cce3eebd58bbef1cb`
51
+ - Input: only safetensors shards 46, 47, and 48
52
+ - Total source size: 10,863,342,388 bytes
53
+
54
+ Exact file sizes and SHA-256 values are in
55
+ [`manifest/source.json`](manifest/source.json). The downloader and converter
56
+ refuse any source that does not match them.
57
+
58
+ ## Reproduce
59
+
60
+ The reference build used Linux aarch64, Python 3.14.6, NumPy 2.5.1, uv 0.11.29,
61
+ and Hugging Face CLI 1.24.0. The NumPy wheel is pinned by hash in
62
+ `requirements-linux-aarch64-py314.lock`. The upstream checkpoint is public, so
63
+ a Hugging Face token is not required for source download.
64
+
65
+ ```bash
66
+ uv venv --python 3.14.6 .venv
67
+ uv pip install --python .venv/bin/python \
68
+ --require-hashes --only-binary=:all: \
69
+ -r requirements-linux-aarch64-py314.lock
70
+
71
+ .venv/bin/python scripts/download_sources.py --destination sources
72
+ .venv/bin/python -m unittest discover -s tests -v
73
+ .venv/bin/python scripts/reproduce.py \
74
+ --sources sources \
75
+ --recipe mxfp4-q8_0 \
76
+ --manifest-dir manifest \
77
+ --repeat-check
78
+ sha256sum -c SHA256SUMS
79
+ ```
80
+
81
+ `--repeat-check` performs a second clean conversion and requires its complete
82
+ GGUF SHA-256 to match the verified first build byte for byte. The converter
83
+ memory-maps the source shards and processes FP8 tensors in bounded bands. It
84
+ does not require PyTorch, CUDA, safetensors, a GGUF package, or a GPU.
85
+
86
+ ## Verification
87
+
88
+ The included verifier checks pinned source hashes and tensor inventories, GGUF
89
+ structure and metadata, exact F32/F16 bytes, exact MXFP4 repacking, and Q8_0
90
+ encoding plus reconstruction error against a fresh FP8 source decode.
91
+
92
+ Reference-build results:
93
+
94
+ | Check | Result |
95
+ |---|---:|
96
+ | Tensor count | 81 |
97
+ | Exact F32/F16 tensors | 47 |
98
+ | Exact MXFP4 tensors | 9 |
99
+ | Maximum Q8_0 block-relative error | 0.00396728515625 |
100
+ | Q8_0 limit | 0.01 |
101
+ | Repeat build | byte-identical |
102
+
103
+ Machine-readable observations are in
104
+ [`manifest/validation.json`](manifest/validation.json) and
105
+ [`manifest/build.json`](manifest/build.json).
106
+
107
+ ## Compatibility and limitations
108
+
109
+ - This is an auxiliary drafter, not a complete checkpoint.
110
+ - A consumer must explicitly support the
111
+ `deepseek_v4_flash_dspark_draft` GGUF architecture and `dspark.*` tensor
112
+ namespace defined by the checked-in recipe.
113
+ - Generic GGUF support alone is insufficient. No compatibility with llama.cpp,
114
+ Ollama, LM Studio, vLLM, or other runtimes is implied.
115
+ - The drafter must be paired with a compatible DeepSeek V4 Flash 0731 target
116
+ model. No universal quality, acceptance-rate, or speed claim is made across
117
+ target quantizations or runtimes.
118
+ - This is a community conversion, not an official DeepSeek release or
119
+ endorsement.
120
+
121
+ ## DSpark configuration
122
+
123
+ The pinned source configuration defines block size 5, target layers 40, 41,
124
+ and 42, Markov rank 256, hidden size 4096, and vocabulary size 129,280. These
125
+ values are embedded in the GGUF metadata and validated during the build.
126
+
127
+ ## License and references
128
+
129
+ The source-derived weights remain under DeepSeek's MIT terms in
130
+ [`LICENSE`](LICENSE). The newly authored conversion and verification scripts
131
+ are under [`LICENSE.code`](LICENSE.code). The pinned checkpoint's
132
+ [upstream license](https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731/blob/9e165c30e2704aec5d9d593cce3eebd58bbef1cb/LICENSE)
133
+ and the DS4/GGML attribution in
134
+ [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) provide the applicable notices.
135
+
136
+ - [Official DeepSeek V4 Flash 0731 checkpoint](https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731)
137
+ - [DeepSeek V4 technical report](https://arxiv.org/abs/2606.19348)
138
+ - [DeepSpec](https://github.com/deepseek-ai/DeepSpec)
SHA256SUMS ADDED
@@ -0,0 +1 @@
 
 
1
+ 5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33 DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf
THIRD_PARTY_NOTICES.md ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Third-party notices
2
+
3
+ This repository contains a transformed subset of the weights published in
4
+ [`deepseek-ai/DeepSeek-V4-Flash-0731`](https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731)
5
+ at commit `9e165c30e2704aec5d9d593cce3eebd58bbef1cb`.
6
+
7
+ DeepSeek publishes that repository under the MIT License. Its copyright and
8
+ permission notice are available in the pinned checkpoint's
9
+ [upstream license](https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731/blob/9e165c30e2704aec5d9d593cce3eebd58bbef1cb/LICENSE).
10
+
11
+ The standalone conversion and verification scripts are newly authored for
12
+ this repository and published under the repository's declared MIT license.
13
+
14
+ The conversion scripts implement publicly documented numeric and file formats.
15
+ The Q2_K encoder in `scripts/convert.py` is a Python port of the unweighted
16
+ `ds4q_write_q2_k_block_ref` path and its numeric helpers from
17
+ [`antirez/ds4` at commit `453a5faa899759d0edf7729d595c4c39cddfcfca`](https://github.com/antirez/ds4/blob/453a5faa899759d0edf7729d595c4c39cddfcfca/gguf-tools/quants.c).
18
+ That source identifies its block layout and search procedure as derived from
19
+ the MIT-licensed GGML/llama.cpp quantizers.
20
+
21
+ The applicable DS4/GGML MIT notice is:
22
+
23
+ > Copyright (c) 2026 The ds4.c authors
24
+ > Copyright (c) 2023-2026 The ggml authors
25
+ >
26
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
27
+ > of this software and associated documentation files (the "Software"), to deal
28
+ > in the Software without restriction, including without limitation the rights
29
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30
+ > copies of the Software, and to permit persons to whom the Software is
31
+ > furnished to do so, subject to the following conditions:
32
+ >
33
+ > The above copyright notice and this permission notice shall be included in
34
+ > all copies or substantial portions of the Software.
35
+ >
36
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42
+ > SOFTWARE.
43
+
44
+ No PyTorch, llama.cpp, or GGUF Python package is required at build time.
45
+
46
+ Format references:
47
+
48
+ - [DeepSeek-V3 FP8 block scaling implementation](https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/kernel.py)
49
+ - [OCP Microscaling Formats specification](https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf)
50
+ - [GGUF format documentation](https://github.com/ggml-org/ggml/blob/master/docs/gguf.md)
51
+ - [DS4 reference quantizer](https://github.com/antirez/ds4/blob/453a5faa899759d0edf7729d595c4c39cddfcfca/gguf-tools/quants.c)
52
+ - [DeepSpec](https://github.com/deepseek-ai/DeepSpec)
manifest/build.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifact": {
3
+ "filename": "DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf",
4
+ "sha256": "5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33",
5
+ "size": 10897110272
6
+ },
7
+ "build_inputs": {
8
+ "manifest/source.json": "bd7744f0efffd71d45e6233bfd8008e02acf422e01d701f82277d8821938b9c5",
9
+ "requirements-linux-aarch64-py314.lock": "f66db1728c9a0702b511a12bfe8cffbfab0fba4fbbf56f10d0e1d96ee70ee66d",
10
+ "scripts/convert.py": "319dc5083a5dc1b0a3cbce16702ae2378594b415ecf3f4198b2b84662fe31c43",
11
+ "scripts/download_sources.py": "2c39fff99a0c91b3ad099a5d685c394563e7b7a963b0a88cd1f668ee6bee51d1",
12
+ "scripts/formats.py": "4963ff62387bdbdbf0276b9db98e53da04ae621cb2cad231330cfff9f1533149",
13
+ "scripts/recipe.py": "661bf7b14ee5f2fc46770b5494cf6641407b5268c83ef5de6fc2d3e77e25b937",
14
+ "scripts/reproduce.py": "05956fbff7c6e32c9eeab6a959fc3d4dcd29d04a097296ea66cd000c64bfaa45",
15
+ "scripts/verify.py": "9073c95f157bee37c0fdea5d26b029b9495ef63f1c46e1d2022afdceb5cc9cc0"
16
+ },
17
+ "environment": {
18
+ "machine": "aarch64",
19
+ "numpy": "2.5.1",
20
+ "platform": "Linux-6.17.0-1026-nvidia-aarch64-with-glibc2.39",
21
+ "python": "3.14.6"
22
+ },
23
+ "format": {
24
+ "architecture": "deepseek_v4_flash_dspark_draft",
25
+ "gguf_version": 3,
26
+ "recipe": "mxfp4-q8_0",
27
+ "recipe_version": 1
28
+ },
29
+ "repeat_build": {
30
+ "performed": true,
31
+ "sha256": "5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33",
32
+ "status": "byte-identical"
33
+ },
34
+ "source": {
35
+ "repository": "deepseek-ai/DeepSeek-V4-Flash-0731",
36
+ "revision": "9e165c30e2704aec5d9d593cce3eebd58bbef1cb"
37
+ }
38
+ }
manifest/source.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": {
3
+ "model-00046-of-00048.safetensors": {
4
+ "sha256": "5db924ca907e0d93acd975bd5079c3662717f9ac709f23d079bd8f816d29d9dd",
5
+ "size": 3610455184
6
+ },
7
+ "model-00047-of-00048.safetensors": {
8
+ "sha256": "62816173f9f6e136b20b48e3b6f16613ac9ea02b5603f636928b253244a548bd",
9
+ "size": 3560111960
10
+ },
11
+ "model-00048-of-00048.safetensors": {
12
+ "sha256": "cc43742bd24ae6bcdea343a91442f6f66aed2cfebcc6b235470204851ce2f8a9",
13
+ "size": 3692775244
14
+ }
15
+ },
16
+ "repository": "deepseek-ai/DeepSeek-V4-Flash-0731",
17
+ "revision": "9e165c30e2704aec5d9d593cce3eebd58bbef1cb",
18
+ "total_size": 10863342388
19
+ }
manifest/validation.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifact": {
3
+ "filename": "DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf",
4
+ "sha256": "5c8a1ce75e4797c170e22ac65080281a1b694c77f2e4fa7a703fbf09c5de0e33",
5
+ "size": 10897110272
6
+ },
7
+ "gguf": {
8
+ "alignment": 32,
9
+ "data_start": 5824,
10
+ "tensor_count": 81,
11
+ "types": {
12
+ "F16": 2,
13
+ "F32": 45,
14
+ "MXFP4": 9,
15
+ "Q8_0": 25
16
+ },
17
+ "version": 3
18
+ },
19
+ "recipe": "mxfp4-q8_0",
20
+ "source": {
21
+ "files": {
22
+ "model-00046-of-00048.safetensors": {
23
+ "sha256": "5db924ca907e0d93acd975bd5079c3662717f9ac709f23d079bd8f816d29d9dd",
24
+ "size": 3610455184
25
+ },
26
+ "model-00047-of-00048.safetensors": {
27
+ "sha256": "62816173f9f6e136b20b48e3b6f16613ac9ea02b5603f636928b253244a548bd",
28
+ "size": 3560111960
29
+ },
30
+ "model-00048-of-00048.safetensors": {
31
+ "sha256": "cc43742bd24ae6bcdea343a91442f6f66aed2cfebcc6b235470204851ce2f8a9",
32
+ "size": 3692775244
33
+ }
34
+ },
35
+ "repository": "deepseek-ai/DeepSeek-V4-Flash-0731",
36
+ "revision": "9e165c30e2704aec5d9d593cce3eebd58bbef1cb"
37
+ },
38
+ "validation": {
39
+ "f16_exact_tensors": 2,
40
+ "f32_exact_tensors": 45,
41
+ "mxfp4_exact_tensors": 9,
42
+ "q8_0_limit": 0.01,
43
+ "q8_0_max_block_relative_error": 0.00396728515625,
44
+ "status": "pass"
45
+ }
46
+ }
requirements-linux-aarch64-py314.lock ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # CPython 3.14 / Linux aarch64 reference-build dependency.
2
+ # Wheel: numpy-2.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
3
+ numpy==2.5.1 \
4
+ --hash=sha256:caf3e317d33d60c37986b452613f4ab51246d0691350c03d0cb4a898627f4a95
scripts/convert.py ADDED
@@ -0,0 +1,653 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Deterministically convert the pinned DSpark tensors into one GGUF v3 file."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import math
8
+ import os
9
+ from concurrent.futures import ThreadPoolExecutor
10
+ from pathlib import Path
11
+ from typing import BinaryIO
12
+
13
+ import numpy as np
14
+
15
+ from formats import SafeTensorSet, sha256_path, verify_source_files, write_gguf
16
+ from recipe import (
17
+ DEFAULT_RECIPE,
18
+ KIND_FP8_TO_Q8_0,
19
+ KIND_FUSED_EXPERTS_MXFP4,
20
+ KIND_FUSED_EXPERTS_Q2_K,
21
+ KIND_MARKOV_F16,
22
+ KIND_PLAIN_F32,
23
+ KIND_RELABEL_F32,
24
+ N_EXPERTS,
25
+ RECIPES,
26
+ ArtifactRecipe,
27
+ TensorRecipe,
28
+ build_plan,
29
+ resolve_recipe,
30
+ source_paths,
31
+ )
32
+
33
+
34
+ def _e4m3_value(byte: int) -> np.float32:
35
+ sign = -1.0 if byte & 0x80 else 1.0
36
+ exponent = (byte >> 3) & 0x0F
37
+ mantissa = byte & 0x07
38
+ if exponent == 0x0F and mantissa == 0x07:
39
+ return np.float32(np.nan)
40
+ if exponent == 0:
41
+ return np.float32(sign * (mantissa / 8.0) * math.ldexp(1.0, 1 - 7))
42
+ return np.float32(sign * (1.0 + mantissa / 8.0) * math.ldexp(1.0, exponent - 7))
43
+
44
+
45
+ E4M3_TABLE = np.array([_e4m3_value(byte) for byte in range(256)], dtype=np.float32)
46
+ E8M0_TABLE = np.array(
47
+ [
48
+ np.float32(np.nan) if byte == 0xFF else np.float32(math.ldexp(1.0, byte - 127))
49
+ for byte in range(256)
50
+ ],
51
+ dtype=np.float32,
52
+ )
53
+ FP4_TABLE = np.array(
54
+ [
55
+ 0.0,
56
+ 0.5,
57
+ 1.0,
58
+ 1.5,
59
+ 2.0,
60
+ 3.0,
61
+ 4.0,
62
+ 6.0,
63
+ 0.0,
64
+ -0.5,
65
+ -1.0,
66
+ -1.5,
67
+ -2.0,
68
+ -3.0,
69
+ -4.0,
70
+ -6.0,
71
+ ],
72
+ dtype=np.float32,
73
+ )
74
+
75
+ Q2_K_BLOCK_SIZE = 256
76
+ Q2_K_BLOCK_BYTES = 84
77
+ # Both routed shapes contain at most 4,096 rows. Each task keeps one decoded
78
+ # expert resident at a time; the bounded worker count limits the larger set of
79
+ # NumPy fitting temporaries while avoiding tiny-band dispatch overhead across
80
+ # the 2,304 experts in the full artifact.
81
+ EXPERT_ROW_BATCH = 4096
82
+ Q2_K_EXPERT_WORKERS = max(1, min(8, os.cpu_count() or 1))
83
+
84
+
85
+ def bf16_bits_to_f32(bits: np.ndarray) -> np.ndarray:
86
+ """Convert little-endian BF16 payloads exactly by placing them in F32 high bits."""
87
+
88
+ wide = np.asarray(bits, dtype="<u2").astype("<u4")
89
+ wide <<= np.uint32(16)
90
+ return wide.view("<f4")
91
+
92
+
93
+ def round_away_from_zero(values: np.ndarray) -> np.ndarray:
94
+ values = np.asarray(values, dtype=np.float32)
95
+ truncated = np.trunc(values).astype(np.float32, copy=False)
96
+ fraction = np.abs(values - truncated)
97
+ return np.where(
98
+ fraction >= np.float32(0.5),
99
+ truncated + np.copysign(np.float32(1.0), values),
100
+ truncated,
101
+ ).astype(np.float32, copy=False)
102
+
103
+
104
+ def nearest_int_f32(values: np.ndarray) -> np.ndarray:
105
+ """Port ds4q_nearest_int's binary32 round-to-nearest-even bit trick."""
106
+
107
+ f32 = np.asarray(values, dtype=np.float32)
108
+ if not np.isfinite(f32).all() or np.any(np.abs(f32) > np.float32(4_194_303.0)):
109
+ raise ValueError("nearest-int input is outside the DS4 reference range")
110
+ shifted = np.add(f32, np.float32(12_582_912.0), dtype=np.float32)
111
+ bits = shifted.view(np.int32)
112
+ return ((bits & np.int32(0x007F_FFFF)) - np.int32(0x0040_0000)).astype(
113
+ np.int32, copy=False
114
+ )
115
+
116
+
117
+ def _make_qkx2_quants(
118
+ groups: np.ndarray,
119
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
120
+ """Vectorized binary32 port of DS4's unweighted 16-value Q2_K fit."""
121
+
122
+ x = np.asarray(groups, dtype=np.float32)
123
+ if x.ndim != 2 or x.shape[1] != 16:
124
+ raise ValueError("Q2_K fitting groups must have shape (n, 16)")
125
+ weights = np.abs(x).astype(np.float32, copy=False)
126
+ minimum = x[:, 0].copy()
127
+ maximum = x[:, 0].copy()
128
+ for index in range(1, 16):
129
+ minimum = np.minimum(minimum, x[:, index])
130
+ maximum = np.maximum(maximum, x[:, index])
131
+ minimum = np.where(minimum > 0, np.float32(0.0), minimum).astype(
132
+ np.float32, copy=False
133
+ )
134
+ constant = maximum == minimum
135
+ value_range = np.subtract(maximum, minimum, dtype=np.float32)
136
+ safe_range = np.where(constant, np.float32(1.0), value_range).astype(
137
+ np.float32, copy=False
138
+ )
139
+ inverse_scale = np.divide(np.float32(3.0), safe_range, dtype=np.float32)
140
+ scale = np.divide(np.float32(1.0), inverse_scale, dtype=np.float32)
141
+ normalized = np.multiply(
142
+ np.subtract(x, minimum[:, None], dtype=np.float32),
143
+ inverse_scale[:, None],
144
+ dtype=np.float32,
145
+ )
146
+ labels = np.clip(nearest_int_f32(normalized), 0, 3).astype(np.uint8)
147
+ scale[constant] = np.float32(0.0)
148
+ labels[constant] = np.uint8(0)
149
+
150
+ sum_w = weights[:, 0].copy()
151
+ sum_x = np.multiply(weights[:, 0], x[:, 0], dtype=np.float32)
152
+ for index in range(1, 16):
153
+ sum_w = np.add(sum_w, weights[:, index], dtype=np.float32)
154
+ sum_x = np.add(
155
+ sum_x,
156
+ np.multiply(weights[:, index], x[:, index], dtype=np.float32),
157
+ dtype=np.float32,
158
+ )
159
+
160
+ best_error = np.zeros(x.shape[0], dtype=np.float32)
161
+ for index in range(16):
162
+ reconstructed = np.add(
163
+ np.multiply(scale, labels[:, index], dtype=np.float32),
164
+ minimum,
165
+ dtype=np.float32,
166
+ )
167
+ difference = np.abs(
168
+ np.subtract(reconstructed, x[:, index], dtype=np.float32)
169
+ ).astype(np.float32, copy=False)
170
+ best_error = np.add(
171
+ best_error,
172
+ np.multiply(weights[:, index], difference, dtype=np.float32),
173
+ dtype=np.float32,
174
+ )
175
+
176
+ for step in range(16):
177
+ candidate_numerator = np.add(
178
+ np.add(
179
+ np.float32(-0.5),
180
+ np.multiply(np.float32(0.1), np.float32(step), dtype=np.float32),
181
+ dtype=np.float32,
182
+ ),
183
+ np.float32(3.0),
184
+ dtype=np.float32,
185
+ )
186
+ candidate_range = np.subtract(maximum, minimum, dtype=np.float32)
187
+ safe_candidate_range = np.where(
188
+ constant, np.float32(1.0), candidate_range
189
+ ).astype(np.float32, copy=False)
190
+ candidate_inverse = np.divide(
191
+ candidate_numerator, safe_candidate_range, dtype=np.float32
192
+ )
193
+ candidate_labels = np.clip(
194
+ nearest_int_f32(
195
+ np.multiply(
196
+ np.subtract(x, minimum[:, None], dtype=np.float32),
197
+ candidate_inverse[:, None],
198
+ dtype=np.float32,
199
+ )
200
+ ),
201
+ 0,
202
+ 3,
203
+ ).astype(np.uint8)
204
+
205
+ sum_l = np.zeros(x.shape[0], dtype=np.float32)
206
+ sum_l2 = np.zeros(x.shape[0], dtype=np.float32)
207
+ sum_xl = np.zeros(x.shape[0], dtype=np.float32)
208
+ for index in range(16):
209
+ weighted_label = np.multiply(
210
+ weights[:, index], candidate_labels[:, index], dtype=np.float32
211
+ )
212
+ sum_l = np.add(sum_l, weighted_label, dtype=np.float32)
213
+ sum_l2 = np.add(
214
+ sum_l2,
215
+ np.multiply(
216
+ weighted_label, candidate_labels[:, index], dtype=np.float32
217
+ ),
218
+ dtype=np.float32,
219
+ )
220
+ sum_xl = np.add(
221
+ sum_xl,
222
+ np.multiply(weighted_label, x[:, index], dtype=np.float32),
223
+ dtype=np.float32,
224
+ )
225
+
226
+ determinant = np.subtract(
227
+ np.multiply(sum_w, sum_l2, dtype=np.float32),
228
+ np.multiply(sum_l, sum_l, dtype=np.float32),
229
+ dtype=np.float32,
230
+ )
231
+ valid = np.logical_and(~constant, determinant > 0)
232
+ safe_determinant = np.where(valid, determinant, np.float32(1.0)).astype(
233
+ np.float32, copy=False
234
+ )
235
+ candidate_scale = np.divide(
236
+ np.subtract(
237
+ np.multiply(sum_w, sum_xl, dtype=np.float32),
238
+ np.multiply(sum_x, sum_l, dtype=np.float32),
239
+ dtype=np.float32,
240
+ ),
241
+ safe_determinant,
242
+ dtype=np.float32,
243
+ )
244
+ candidate_minimum = np.divide(
245
+ np.subtract(
246
+ np.multiply(sum_l2, sum_x, dtype=np.float32),
247
+ np.multiply(sum_l, sum_xl, dtype=np.float32),
248
+ dtype=np.float32,
249
+ ),
250
+ safe_determinant,
251
+ dtype=np.float32,
252
+ )
253
+ positive_minimum = np.logical_and(valid, candidate_minimum > 0)
254
+ safe_sum_l2 = np.where(positive_minimum, sum_l2, np.float32(1.0)).astype(
255
+ np.float32, copy=False
256
+ )
257
+ zero_minimum_scale = np.divide(sum_xl, safe_sum_l2, dtype=np.float32)
258
+ candidate_scale = np.where(
259
+ positive_minimum, zero_minimum_scale, candidate_scale
260
+ ).astype(np.float32, copy=False)
261
+ candidate_minimum = np.where(
262
+ positive_minimum, np.float32(0.0), candidate_minimum
263
+ ).astype(np.float32, copy=False)
264
+
265
+ current_error = np.zeros(x.shape[0], dtype=np.float32)
266
+ for index in range(16):
267
+ reconstructed = np.add(
268
+ np.multiply(
269
+ candidate_scale, candidate_labels[:, index], dtype=np.float32
270
+ ),
271
+ candidate_minimum,
272
+ dtype=np.float32,
273
+ )
274
+ difference = np.abs(
275
+ np.subtract(reconstructed, x[:, index], dtype=np.float32)
276
+ ).astype(np.float32, copy=False)
277
+ current_error = np.add(
278
+ current_error,
279
+ np.multiply(weights[:, index], difference, dtype=np.float32),
280
+ dtype=np.float32,
281
+ )
282
+ improved = np.logical_and(valid, current_error < best_error)
283
+ labels[improved] = candidate_labels[improved]
284
+ best_error[improved] = current_error[improved]
285
+ scale[improved] = candidate_scale[improved]
286
+ minimum[improved] = candidate_minimum[improved]
287
+
288
+ return scale, np.negative(minimum, dtype=np.float32), labels
289
+
290
+
291
+ def quantize_q2_k(values: np.ndarray) -> np.ndarray:
292
+ """Encode rows as unweighted GGML Q2_K blocks using the DS4 reference path."""
293
+
294
+ rows = np.asarray(values, dtype=np.float32)
295
+ if rows.ndim != 2 or rows.shape[1] % Q2_K_BLOCK_SIZE:
296
+ raise ValueError("Q2_K input must be 2D with columns divisible by 256")
297
+ if not np.isfinite(rows).all():
298
+ raise ValueError("Q2_K input contains NaN or infinity")
299
+ blocks = rows.reshape(-1, Q2_K_BLOCK_SIZE)
300
+ groups = blocks.reshape(-1, 16)
301
+ scales, mins, labels = _make_qkx2_quants(groups)
302
+ scales = scales.reshape(-1, 16)
303
+ mins = mins.reshape(-1, 16)
304
+ labels = labels.reshape(-1, Q2_K_BLOCK_SIZE)
305
+
306
+ max_scale = np.maximum(np.max(scales, axis=1), np.float32(0.0)).astype(
307
+ np.float32, copy=False
308
+ )
309
+ max_min = np.maximum(np.max(mins, axis=1), np.float32(0.0)).astype(
310
+ np.float32, copy=False
311
+ )
312
+ scale_inverse = np.zeros_like(max_scale)
313
+ min_inverse = np.zeros_like(max_min)
314
+ np.divide(
315
+ np.float32(15.0),
316
+ max_scale,
317
+ out=scale_inverse,
318
+ where=max_scale > 0,
319
+ )
320
+ np.divide(np.float32(15.0), max_min, out=min_inverse, where=max_min > 0)
321
+ scale_codes = nearest_int_f32(
322
+ np.multiply(scales, scale_inverse[:, None], dtype=np.float32)
323
+ )
324
+ min_codes = nearest_int_f32(
325
+ np.multiply(mins, min_inverse[:, None], dtype=np.float32)
326
+ )
327
+ if np.any(scale_codes < 0) or np.any(scale_codes > 15):
328
+ raise ValueError("Q2_K scale code is outside four bits")
329
+ if np.any(min_codes < 0) or np.any(min_codes > 15):
330
+ raise ValueError("Q2_K minimum code is outside four bits")
331
+ packed_scales = scale_codes.astype(np.uint8) | (
332
+ min_codes.astype(np.uint8) << np.uint8(4)
333
+ )
334
+
335
+ d_bits = (
336
+ np.divide(max_scale, np.float32(15.0), dtype=np.float32)
337
+ .astype("<f2")
338
+ .view("<u2")
339
+ )
340
+ dmin_bits = (
341
+ np.divide(max_min, np.float32(15.0), dtype=np.float32).astype("<f2").view("<u2")
342
+ )
343
+ d = d_bits.view("<f2").astype(np.float32)
344
+ dmin = dmin_bits.view("<f2").astype(np.float32)
345
+ group_d = np.multiply(
346
+ d[:, None], packed_scales & np.uint8(0x0F), dtype=np.float32
347
+ ).reshape(-1)
348
+ group_min = np.multiply(
349
+ dmin[:, None], packed_scales >> np.uint8(4), dtype=np.float32
350
+ ).reshape(-1)
351
+ fitted_groups = labels.reshape(-1, 16)
352
+ nonzero = group_d != 0
353
+ normalized = np.divide(
354
+ np.add(groups[nonzero], group_min[nonzero, None], dtype=np.float32),
355
+ group_d[nonzero, None],
356
+ dtype=np.float32,
357
+ )
358
+ fitted_groups[nonzero] = np.clip(nearest_int_f32(normalized), 0, 3).astype(np.uint8)
359
+
360
+ encoded = np.zeros((blocks.shape[0], Q2_K_BLOCK_BYTES), dtype=np.uint8)
361
+ encoded[:, :16] = packed_scales
362
+ for start in (0, 128):
363
+ packed = (
364
+ labels[:, start : start + 32]
365
+ | (labels[:, start + 32 : start + 64] << np.uint8(2))
366
+ | (labels[:, start + 64 : start + 96] << np.uint8(4))
367
+ | (labels[:, start + 96 : start + 128] << np.uint8(6))
368
+ )
369
+ offset = 16 + start // 4
370
+ encoded[:, offset : offset + 32] = packed
371
+ encoded[:, 80:82] = d_bits.astype("<u2", copy=False).view(np.uint8).reshape(-1, 2)
372
+ encoded[:, 82:84] = (
373
+ dmin_bits.astype("<u2", copy=False).view(np.uint8).reshape(-1, 2)
374
+ )
375
+ return encoded
376
+
377
+
378
+ def decode_source_mxfp4(
379
+ packed: np.ndarray,
380
+ scales: np.ndarray,
381
+ rows: int,
382
+ cols: int,
383
+ ) -> np.ndarray:
384
+ """Decode one bounded row band of the pinned OCP E2M1/E8M0 source."""
385
+
386
+ if cols % 32:
387
+ raise ValueError("source MXFP4 column count must be divisible by 32")
388
+ blocks = cols // 32
389
+ packed_blocks = np.asarray(packed, dtype=np.uint8).reshape(rows, blocks, 16)
390
+ scale_codes = np.asarray(scales, dtype=np.uint8).reshape(rows, blocks)
391
+ if np.any(scale_codes == 0xFF):
392
+ raise ValueError("source MXFP4 contains reserved E8M0 NaN scale 0xff")
393
+ codes = np.empty((rows, blocks, 32), dtype=np.uint8)
394
+ codes[..., 0::2] = packed_blocks & np.uint8(0x0F)
395
+ codes[..., 1::2] = packed_blocks >> np.uint8(4)
396
+ decoded = FP4_TABLE[codes]
397
+ decoded *= E8M0_TABLE[scale_codes][..., None]
398
+ return decoded.reshape(rows, cols)
399
+
400
+
401
+ def quantize_q8_0(values: np.ndarray) -> np.ndarray:
402
+ """Encode flat F32 data as GGML Q8_0 using Rust/C-style half-away rounding."""
403
+
404
+ flat = np.asarray(values, dtype=np.float32).reshape(-1)
405
+ if flat.size % 32:
406
+ raise ValueError("Q8_0 input length must be divisible by 32")
407
+ blocks = flat.reshape(-1, 32)
408
+ if not np.isfinite(blocks).all():
409
+ raise ValueError("Q8_0 input contains NaN or infinity")
410
+ maxima = np.max(np.abs(blocks), axis=1).astype(np.float32, copy=False)
411
+ scales = maxima / np.float32(127.0)
412
+ inverse = np.zeros_like(scales)
413
+ np.divide(np.float32(1.0), scales, out=inverse, where=scales != 0)
414
+ quantized = round_away_from_zero(blocks * inverse[:, None])
415
+ if np.any(quantized < -127) or np.any(quantized > 127):
416
+ raise ValueError("Q8_0 quantization produced an out-of-range code")
417
+ codes = quantized.astype(np.int8)
418
+ encoded = np.empty((blocks.shape[0], 34), dtype=np.uint8)
419
+ encoded[:, :2] = scales.astype("<f2").view(np.uint8).reshape(-1, 2)
420
+ encoded[:, 2:] = codes.view(np.uint8)
421
+ return encoded
422
+
423
+
424
+ def repack_mxfp4(
425
+ packed: np.ndarray,
426
+ scales: np.ndarray,
427
+ rows: int,
428
+ cols: int,
429
+ ) -> np.ndarray:
430
+ """Purely permute source FP4 nibbles into GGML's 17-byte MXFP4 blocks."""
431
+
432
+ if cols % 32:
433
+ raise ValueError("MXFP4 column count must be divisible by 32")
434
+ blocks = cols // 32
435
+ packed_blocks = np.asarray(packed, dtype=np.uint8).reshape(rows, blocks, 16)
436
+ scale_rows = np.asarray(scales, dtype=np.uint8).reshape(rows, blocks)
437
+ if np.any(scale_rows == 0xFF):
438
+ raise ValueError("MXFP4 source contains reserved E8M0 NaN scale 0xff")
439
+
440
+ low_codes = np.empty((rows, blocks, 16), dtype=np.uint8)
441
+ high_codes = np.empty((rows, blocks, 16), dtype=np.uint8)
442
+ low_bytes = packed_blocks[..., :8]
443
+ high_bytes = packed_blocks[..., 8:]
444
+ low_codes[..., 0::2] = low_bytes & np.uint8(0x0F)
445
+ low_codes[..., 1::2] = low_bytes >> np.uint8(4)
446
+ high_codes[..., 0::2] = high_bytes & np.uint8(0x0F)
447
+ high_codes[..., 1::2] = high_bytes >> np.uint8(4)
448
+
449
+ encoded = np.empty((rows, blocks, 17), dtype=np.uint8)
450
+ encoded[..., 0] = scale_rows
451
+ encoded[..., 1:] = low_codes | (high_codes << np.uint8(4))
452
+ return encoded
453
+
454
+
455
+ class TensorProducer:
456
+ def __init__(self, source: SafeTensorSet):
457
+ self.source = source
458
+
459
+ def __call__(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
460
+ print(f"[convert] {tensor.out_name} ({tensor.byte_len:,} bytes)", flush=True)
461
+ if tensor.kind == KIND_PLAIN_F32:
462
+ return self._plain_f32(tensor, handle)
463
+ if tensor.kind == KIND_RELABEL_F32:
464
+ return self._copy_f32(tensor, handle)
465
+ if tensor.kind == KIND_FP8_TO_Q8_0:
466
+ return self._fp8_to_q8_0(tensor, handle)
467
+ if tensor.kind == KIND_FUSED_EXPERTS_MXFP4:
468
+ return self._fused_experts_mxfp4(tensor, handle)
469
+ if tensor.kind == KIND_FUSED_EXPERTS_Q2_K:
470
+ return self._fused_experts_q2_k(tensor, handle)
471
+ if tensor.kind == KIND_MARKOV_F16:
472
+ return self._markov_f16(tensor, handle)
473
+ raise ValueError(f"unsupported tensor recipe kind: {tensor.kind}")
474
+
475
+ def _plain_f32(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
476
+ if not tensor.src_is_bf16:
477
+ raw = self.source.raw(tensor.src_name)
478
+ try:
479
+ return handle.write(raw)
480
+ finally:
481
+ raw.release()
482
+ bits = self.source.array(tensor.src_name, "<u2").reshape(-1)
483
+ data = bf16_bits_to_f32(bits).tobytes(order="C")
484
+ return handle.write(data)
485
+
486
+ def _copy_f32(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
487
+ raw = self.source.raw(tensor.src_name)
488
+ try:
489
+ return handle.write(raw)
490
+ finally:
491
+ raw.release()
492
+
493
+ def _fp8_to_q8_0(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
494
+ weights = self.source.array(tensor.weight_name, np.uint8).reshape(
495
+ tensor.rows, tensor.cols
496
+ )
497
+ scale_codes = self.source.array(tensor.scale_name, np.uint8).reshape(
498
+ (tensor.rows + 127) // 128,
499
+ (tensor.cols + 127) // 128,
500
+ )
501
+ written = 0
502
+ for block_row in range(scale_codes.shape[0]):
503
+ row_start = block_row * 128
504
+ row_end = min(row_start + 128, tensor.rows)
505
+ decoded = E4M3_TABLE[weights[row_start:row_end]]
506
+ column_scales = np.repeat(E8M0_TABLE[scale_codes[block_row]], 128)[
507
+ : tensor.cols
508
+ ]
509
+ if not np.isfinite(column_scales).all():
510
+ raise ValueError(f"{tensor.scale_name}: contains reserved E8M0 NaN")
511
+ decoded *= column_scales[None, :]
512
+ encoded = quantize_q8_0(decoded)
513
+ written += handle.write(encoded.tobytes(order="C"))
514
+ return written
515
+
516
+ def _fused_experts_mxfp4(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
517
+ written = 0
518
+ for expert in range(N_EXPERTS):
519
+ prefix = f"{tensor.name_prefix}.ffn.experts.{expert}.{tensor.expert_kind}"
520
+ packed = self.source.array(f"{prefix}.weight", np.uint8)
521
+ scales = self.source.array(f"{prefix}.scale", np.uint8)
522
+ encoded = repack_mxfp4(
523
+ packed,
524
+ scales,
525
+ tensor.rows,
526
+ tensor.cols,
527
+ )
528
+ written += handle.write(encoded.tobytes(order="C"))
529
+ return written
530
+
531
+ def _fused_experts_q2_k(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
532
+ written = 0
533
+ with ThreadPoolExecutor(max_workers=Q2_K_EXPERT_WORKERS) as executor:
534
+ for start in range(0, N_EXPERTS, Q2_K_EXPERT_WORKERS):
535
+ futures = [
536
+ executor.submit(self._encode_q2_k_expert, tensor, expert)
537
+ for expert in range(
538
+ start, min(start + Q2_K_EXPERT_WORKERS, N_EXPERTS)
539
+ )
540
+ ]
541
+ # Results are written in expert order, independent of worker
542
+ # completion order, so concurrency cannot change GGUF bytes.
543
+ for future in futures:
544
+ written += handle.write(future.result())
545
+ return written
546
+
547
+ def _encode_q2_k_expert(self, tensor: TensorRecipe, expert: int) -> bytes:
548
+ prefix = f"{tensor.name_prefix}.ffn.experts.{expert}.{tensor.expert_kind}"
549
+ packed = self.source.array(f"{prefix}.weight", np.uint8).reshape(
550
+ tensor.rows, tensor.cols // 2
551
+ )
552
+ scales = self.source.array(f"{prefix}.scale", np.uint8).reshape(
553
+ tensor.rows, tensor.cols // 32
554
+ )
555
+ chunks: list[bytes] = []
556
+ for row_start in range(0, tensor.rows, EXPERT_ROW_BATCH):
557
+ row_end = min(row_start + EXPERT_ROW_BATCH, tensor.rows)
558
+ decoded = decode_source_mxfp4(
559
+ packed[row_start:row_end],
560
+ scales[row_start:row_end],
561
+ row_end - row_start,
562
+ tensor.cols,
563
+ )
564
+ chunks.append(quantize_q2_k(decoded).tobytes(order="C"))
565
+ return b"".join(chunks)
566
+
567
+ def _markov_f16(self, tensor: TensorRecipe, handle: BinaryIO) -> int:
568
+ bits = self.source.array(tensor.src_name, "<u2").reshape(-1)
569
+ chunk_elements = 8 * 1024 * 1024
570
+ written = 0
571
+ for start in range(0, bits.size, chunk_elements):
572
+ f32 = bf16_bits_to_f32(bits[start : start + chunk_elements])
573
+ f16 = f32.astype("<f2")
574
+ written += handle.write(f16.tobytes(order="C"))
575
+ return written
576
+
577
+
578
+ def convert(
579
+ source_dir: Path,
580
+ output: Path,
581
+ *,
582
+ force: bool = False,
583
+ recipe: ArtifactRecipe | str | None = None,
584
+ ) -> tuple[int, str]:
585
+ artifact_recipe = resolve_recipe(recipe)
586
+ source_dir = source_dir.resolve()
587
+ output = output.resolve()
588
+ if output.exists() and not force:
589
+ raise FileExistsError(
590
+ f"output already exists: {output}; pass --force to replace it"
591
+ )
592
+ output.parent.mkdir(parents=True, exist_ok=True)
593
+ print("[convert] validating pinned source sizes and SHA-256 values", flush=True)
594
+ verify_source_files(source_dir)
595
+ plan = build_plan(artifact_recipe)
596
+ temporary = output.with_name(f".{output.name}.partial-{os.getpid()}")
597
+ if temporary.exists():
598
+ raise FileExistsError(f"temporary output already exists: {temporary}")
599
+ try:
600
+ with SafeTensorSet(source_paths(source_dir)) as source:
601
+ source.validate_plan(plan)
602
+ print(
603
+ f"[convert] source layout valid; writing {len(plan)} tensors",
604
+ flush=True,
605
+ )
606
+ write_gguf(temporary, plan, TensorProducer(source))
607
+ size = temporary.stat().st_size
608
+ digest = sha256_path(temporary)
609
+ os.replace(temporary, output)
610
+ directory_fd = os.open(output.parent, os.O_RDONLY | os.O_DIRECTORY)
611
+ try:
612
+ os.fsync(directory_fd)
613
+ finally:
614
+ os.close(directory_fd)
615
+ except Exception:
616
+ temporary.unlink(missing_ok=True)
617
+ raise
618
+ print(f"[convert] wrote {output} ({size:,} bytes)", flush=True)
619
+ print(f"[convert] SHA-256 {digest}", flush=True)
620
+ return size, digest
621
+
622
+
623
+ def parse_args() -> argparse.Namespace:
624
+ parser = argparse.ArgumentParser(description=__doc__)
625
+ parser.add_argument(
626
+ "--sources", type=Path, required=True, help="Pinned shard directory"
627
+ )
628
+ parser.add_argument(
629
+ "--recipe",
630
+ choices=sorted(RECIPES),
631
+ default=DEFAULT_RECIPE.name,
632
+ help=f"Artifact recipe (default: {DEFAULT_RECIPE.name})",
633
+ )
634
+ parser.add_argument(
635
+ "--output",
636
+ type=Path,
637
+ help="Output GGUF path (default: the selected recipe's canonical filename)",
638
+ )
639
+ parser.add_argument(
640
+ "--force", action="store_true", help="Replace an existing output"
641
+ )
642
+ return parser.parse_args()
643
+
644
+
645
+ def main() -> None:
646
+ args = parse_args()
647
+ recipe = resolve_recipe(args.recipe)
648
+ output = args.output if args.output is not None else Path(recipe.output_filename)
649
+ convert(args.sources, output, force=args.force, recipe=recipe)
650
+
651
+
652
+ if __name__ == "__main__":
653
+ main()
scripts/download_sources.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Download exactly the three pinned upstream DSpark shards and verify them."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import shutil
9
+ import subprocess
10
+ from pathlib import Path
11
+
12
+ from recipe import SOURCE_FILES, SOURCE_REPOSITORY, SOURCE_REVISION
13
+
14
+
15
+ def _sha256(path: Path) -> str:
16
+ digest = hashlib.sha256()
17
+ with path.open("rb") as handle:
18
+ while chunk := handle.read(8 * 1024 * 1024):
19
+ digest.update(chunk)
20
+ return digest.hexdigest()
21
+
22
+
23
+ def download(destination: Path, hf_executable: str) -> None:
24
+ destination.mkdir(parents=True, exist_ok=True)
25
+ command = [
26
+ hf_executable,
27
+ "download",
28
+ SOURCE_REPOSITORY,
29
+ "--revision",
30
+ SOURCE_REVISION,
31
+ "--local-dir",
32
+ str(destination),
33
+ ]
34
+ for name in SOURCE_FILES:
35
+ command.extend(["--include", name])
36
+ subprocess.run(command, check=True)
37
+ for name, expected in SOURCE_FILES.items():
38
+ path = destination / name
39
+ if not path.is_file():
40
+ raise FileNotFoundError(f"download did not produce {path}")
41
+ size = path.stat().st_size
42
+ digest = _sha256(path)
43
+ if size != expected["size"] or digest != expected["sha256"]:
44
+ raise ValueError(
45
+ f"{name}: expected {expected['size']} bytes/{expected['sha256']}, "
46
+ f"found {size}/{digest}"
47
+ )
48
+ print(f"[download] verified {name}: {size:,} bytes {digest}", flush=True)
49
+
50
+
51
+ def parse_args() -> argparse.Namespace:
52
+ parser = argparse.ArgumentParser(description=__doc__)
53
+ parser.add_argument("--destination", type=Path, default=Path("sources"))
54
+ parser.add_argument(
55
+ "--hf",
56
+ default=shutil.which("hf"),
57
+ help="Path to the hf executable (the pinned public source needs no token)",
58
+ )
59
+ return parser.parse_args()
60
+
61
+
62
+ def main() -> None:
63
+ args = parse_args()
64
+ if not args.hf:
65
+ raise SystemExit("hf CLI not found on PATH; pass --hf /path/to/hf")
66
+ download(args.destination, args.hf)
67
+
68
+
69
+ if __name__ == "__main__":
70
+ main()
scripts/formats.py ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Minimal safetensors and GGUF v3 I/O used by the reproducible build."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import json
8
+ import mmap
9
+ import os
10
+ import struct
11
+ from dataclasses import dataclass
12
+ from pathlib import Path
13
+ from typing import BinaryIO, Callable, Iterable
14
+
15
+ import numpy as np
16
+
17
+ from recipe import (
18
+ GGML_F16,
19
+ GGML_F32,
20
+ GGML_MXFP4,
21
+ GGML_Q2_K,
22
+ GGML_Q8_0,
23
+ GGUF_METADATA,
24
+ SOURCE_FILES,
25
+ TensorRecipe,
26
+ source_expectations,
27
+ )
28
+
29
+
30
+ ALIGNMENT = 32
31
+ GGUF_VALUE_U32 = 4
32
+ GGUF_VALUE_I32 = 5
33
+ GGUF_VALUE_STRING = 8
34
+ GGUF_VALUE_ARRAY = 9
35
+
36
+ _DTYPE_BYTES = {
37
+ "F8_E4M3": 1,
38
+ "F8_E8M0": 1,
39
+ "I8": 1,
40
+ "BF16": 2,
41
+ "F16": 2,
42
+ "F32": 4,
43
+ }
44
+
45
+
46
+ def align_up(value: int, alignment: int = ALIGNMENT) -> int:
47
+ return (value + alignment - 1) // alignment * alignment
48
+
49
+
50
+ def sha256_path(path: Path, chunk_size: int = 8 * 1024 * 1024) -> str:
51
+ digest = hashlib.sha256()
52
+ with path.open("rb") as handle:
53
+ while chunk := handle.read(chunk_size):
54
+ digest.update(chunk)
55
+ return digest.hexdigest()
56
+
57
+
58
+ def verify_source_files(source_dir: Path) -> dict[str, dict[str, int | str]]:
59
+ observed: dict[str, dict[str, int | str]] = {}
60
+ for name, expected in SOURCE_FILES.items():
61
+ path = source_dir / name
62
+ if not path.is_file():
63
+ raise FileNotFoundError(f"missing pinned source shard: {path}")
64
+ size = path.stat().st_size
65
+ if size != expected["size"]:
66
+ raise ValueError(f"{name}: expected {expected['size']} bytes, found {size}")
67
+ digest = sha256_path(path)
68
+ if digest != expected["sha256"]:
69
+ raise ValueError(
70
+ f"{name}: expected SHA-256 {expected['sha256']}, found {digest}"
71
+ )
72
+ observed[name] = {"size": size, "sha256": digest}
73
+ return observed
74
+
75
+
76
+ @dataclass(frozen=True)
77
+ class SafeTensorInfo:
78
+ dtype: str
79
+ shape: tuple[int, ...]
80
+ start: int
81
+ end: int
82
+ shard_index: int
83
+
84
+
85
+ class SafeTensorSet:
86
+ """Read-only mmap index spanning the three pinned safetensors shards."""
87
+
88
+ def __init__(self, paths: Iterable[Path]):
89
+ self._files: list[BinaryIO] = []
90
+ self._maps: list[mmap.mmap] = []
91
+ self._index: dict[str, SafeTensorInfo] = {}
92
+ try:
93
+ for shard_index, path in enumerate(paths):
94
+ handle = path.open("rb")
95
+ mapping = mmap.mmap(handle.fileno(), 0, access=mmap.ACCESS_READ)
96
+ self._files.append(handle)
97
+ self._maps.append(mapping)
98
+ self._index_shard(path, shard_index, mapping)
99
+ except Exception:
100
+ self.close()
101
+ raise
102
+
103
+ def _index_shard(self, path: Path, shard_index: int, mapping: mmap.mmap) -> None:
104
+ if len(mapping) < 8:
105
+ raise ValueError(f"{path}: shorter than safetensors header length")
106
+ header_len = struct.unpack_from("<Q", mapping, 0)[0]
107
+ data_start = 8 + header_len
108
+ if data_start > len(mapping):
109
+ raise ValueError(f"{path}: safetensors header overruns file")
110
+ try:
111
+ header = json.loads(mapping[8:data_start])
112
+ except (UnicodeDecodeError, json.JSONDecodeError) as error:
113
+ raise ValueError(f"{path}: invalid safetensors header: {error}") from error
114
+ if not isinstance(header, dict):
115
+ raise ValueError(f"{path}: safetensors header is not an object")
116
+ for name, raw in header.items():
117
+ if name == "__metadata__" or not name.startswith("mtp."):
118
+ continue
119
+ if name in self._index:
120
+ raise ValueError(f"duplicate tensor across shards: {name}")
121
+ if not isinstance(raw, dict):
122
+ raise ValueError(f"{path}: tensor {name} metadata is not an object")
123
+ dtype = raw.get("dtype")
124
+ shape = raw.get("shape")
125
+ offsets = raw.get("data_offsets")
126
+ if (
127
+ not isinstance(dtype, str)
128
+ or not isinstance(shape, list)
129
+ or not all(isinstance(dim, int) and dim >= 0 for dim in shape)
130
+ or not isinstance(offsets, list)
131
+ or len(offsets) != 2
132
+ or not all(
133
+ isinstance(offset, int) and offset >= 0 for offset in offsets
134
+ )
135
+ ):
136
+ raise ValueError(f"{path}: malformed metadata for tensor {name}")
137
+ relative_start, relative_end = offsets
138
+ start = data_start + relative_start
139
+ end = data_start + relative_end
140
+ if relative_start > relative_end or end > len(mapping):
141
+ raise ValueError(f"{path}: tensor {name} data range overruns shard")
142
+ if dtype in _DTYPE_BYTES:
143
+ count = 1
144
+ for dim in shape:
145
+ count *= dim
146
+ expected_bytes = count * _DTYPE_BYTES[dtype]
147
+ if end - start != expected_bytes:
148
+ raise ValueError(
149
+ f"{path}: tensor {name} needs {expected_bytes} bytes, "
150
+ f"data range contains {end - start}"
151
+ )
152
+ self._index[name] = SafeTensorInfo(
153
+ dtype=dtype,
154
+ shape=tuple(shape),
155
+ start=start,
156
+ end=end,
157
+ shard_index=shard_index,
158
+ )
159
+
160
+ def close(self) -> None:
161
+ for mapping in reversed(getattr(self, "_maps", [])):
162
+ try:
163
+ mapping.close()
164
+ except BufferError:
165
+ pass
166
+ for handle in reversed(getattr(self, "_files", [])):
167
+ handle.close()
168
+ self._maps = []
169
+ self._files = []
170
+
171
+ def __enter__(self) -> "SafeTensorSet":
172
+ return self
173
+
174
+ def __exit__(self, *_: object) -> None:
175
+ self.close()
176
+
177
+ def info(self, name: str) -> SafeTensorInfo:
178
+ try:
179
+ return self._index[name]
180
+ except KeyError as error:
181
+ raise KeyError(f"source tensor not found: {name}") from error
182
+
183
+ def raw(self, name: str) -> memoryview:
184
+ info = self.info(name)
185
+ return memoryview(self._maps[info.shard_index])[info.start : info.end]
186
+
187
+ def array(self, name: str, dtype: np.dtype | str) -> np.ndarray:
188
+ info = self.info(name)
189
+ return np.frombuffer(
190
+ self._maps[info.shard_index],
191
+ dtype=dtype,
192
+ count=(info.end - info.start) // np.dtype(dtype).itemsize,
193
+ offset=info.start,
194
+ ).reshape(info.shape)
195
+
196
+ def validate_plan(self, plan: Iterable[TensorRecipe]) -> None:
197
+ expected_names: set[str] = set()
198
+ for tensor in plan:
199
+ for name, dtype, shape in source_expectations(tensor):
200
+ if name in expected_names:
201
+ raise ValueError(
202
+ f"recipe consumes source tensor more than once: {name}"
203
+ )
204
+ expected_names.add(name)
205
+ info = self.info(name)
206
+ if info.dtype != dtype:
207
+ raise ValueError(
208
+ f"{name}: expected dtype {dtype}, found {info.dtype}"
209
+ )
210
+ if info.shape != shape:
211
+ raise ValueError(
212
+ f"{name}: expected shape {shape}, found {info.shape}"
213
+ )
214
+ observed_names = self.names()
215
+ if observed_names != expected_names:
216
+ missing = sorted(expected_names - observed_names)
217
+ unexpected = sorted(observed_names - expected_names)
218
+ raise ValueError(
219
+ "source tensor inventory differs from the recipe: "
220
+ f"missing={missing[:5]}, unexpected={unexpected[:5]}"
221
+ )
222
+
223
+ def names(self) -> frozenset[str]:
224
+ return frozenset(self._index)
225
+
226
+
227
+ def _write_string(handle: BinaryIO, value: str) -> None:
228
+ encoded = value.encode("utf-8")
229
+ handle.write(struct.pack("<Q", len(encoded)))
230
+ handle.write(encoded)
231
+
232
+
233
+ def write_gguf(
234
+ path: Path,
235
+ plan: tuple[TensorRecipe, ...],
236
+ produce: Callable[[TensorRecipe, BinaryIO], int],
237
+ ) -> None:
238
+ """Write deterministic GGUF v3 data, streaming each tensor in plan order."""
239
+
240
+ with path.open("wb", buffering=8 * 1024 * 1024) as handle:
241
+ handle.write(b"GGUF")
242
+ handle.write(struct.pack("<IQQ", 3, len(plan), len(GGUF_METADATA)))
243
+ for key, kind, value in GGUF_METADATA:
244
+ _write_string(handle, key)
245
+ if kind == "u32":
246
+ handle.write(struct.pack("<II", GGUF_VALUE_U32, int(value)))
247
+ elif kind == "string":
248
+ handle.write(struct.pack("<I", GGUF_VALUE_STRING))
249
+ _write_string(handle, str(value))
250
+ elif kind == "array_i32":
251
+ values = tuple(int(item) for item in value)
252
+ handle.write(
253
+ struct.pack("<IIQ", GGUF_VALUE_ARRAY, GGUF_VALUE_I32, len(values))
254
+ )
255
+ for item in values:
256
+ handle.write(struct.pack("<i", item))
257
+ else:
258
+ raise ValueError(f"unsupported GGUF metadata kind: {kind}")
259
+
260
+ relative_offset = 0
261
+ relative_offsets: list[int] = []
262
+ for tensor in plan:
263
+ relative_offsets.append(relative_offset)
264
+ relative_offset = align_up(relative_offset + tensor.byte_len)
265
+ for tensor, offset in zip(plan, relative_offsets, strict=True):
266
+ _write_string(handle, tensor.out_name)
267
+ handle.write(struct.pack("<I", len(tensor.dims)))
268
+ for dim in tensor.dims:
269
+ handle.write(struct.pack("<Q", dim))
270
+ handle.write(struct.pack("<IQ", tensor.ggml_type, offset))
271
+
272
+ data_start = align_up(handle.tell())
273
+ handle.write(b"\0" * (data_start - handle.tell()))
274
+ relative_written = 0
275
+ for tensor in plan:
276
+ before = handle.tell()
277
+ produced = produce(tensor, handle)
278
+ observed = handle.tell() - before
279
+ if produced != observed or observed != tensor.byte_len:
280
+ raise ValueError(
281
+ f"{tensor.out_name}: expected {tensor.byte_len} bytes, "
282
+ f"producer reported {produced} and wrote {observed}"
283
+ )
284
+ relative_written += observed
285
+ padded = align_up(relative_written)
286
+ handle.write(b"\0" * (padded - relative_written))
287
+ relative_written = padded
288
+ handle.flush()
289
+ os.fsync(handle.fileno())
290
+
291
+
292
+ @dataclass(frozen=True)
293
+ class GgufTensor:
294
+ name: str
295
+ dims: tuple[int, ...]
296
+ ggml_type: int
297
+ relative_offset: int
298
+ byte_len: int
299
+ absolute_offset: int
300
+
301
+
302
+ class GgufReader:
303
+ def __init__(self, path: Path):
304
+ self.path = path
305
+ self._file = path.open("rb")
306
+ self._map = mmap.mmap(self._file.fileno(), 0, access=mmap.ACCESS_READ)
307
+ self.metadata: dict[str, object] = {}
308
+ self.tensors: tuple[GgufTensor, ...] = ()
309
+ self.directory_end = 0
310
+ self.data_start = 0
311
+ try:
312
+ self._parse()
313
+ except Exception:
314
+ self.close()
315
+ raise
316
+
317
+ def close(self) -> None:
318
+ try:
319
+ self._map.close()
320
+ except BufferError:
321
+ pass
322
+ self._file.close()
323
+
324
+ def __enter__(self) -> "GgufReader":
325
+ return self
326
+
327
+ def __exit__(self, *_: object) -> None:
328
+ self.close()
329
+
330
+ def _unpack(self, fmt: str, cursor: int) -> tuple[tuple[object, ...], int]:
331
+ size = struct.calcsize(fmt)
332
+ if cursor + size > len(self._map):
333
+ raise ValueError("GGUF directory is truncated")
334
+ return struct.unpack_from(fmt, self._map, cursor), cursor + size
335
+
336
+ def _string(self, cursor: int) -> tuple[str, int]:
337
+ (length,), cursor = self._unpack("<Q", cursor)
338
+ end = cursor + int(length)
339
+ if end > len(self._map):
340
+ raise ValueError("GGUF string overruns file")
341
+ try:
342
+ value = self._map[cursor:end].decode("utf-8")
343
+ except UnicodeDecodeError as error:
344
+ raise ValueError(f"GGUF string is not UTF-8: {error}") from error
345
+ return value, end
346
+
347
+ def _parse(self) -> None:
348
+ if self._map[:4] != b"GGUF":
349
+ raise ValueError("not a GGUF file")
350
+ (version, tensor_count, kv_count), cursor = self._unpack("<IQQ", 4)
351
+ if version != 3:
352
+ raise ValueError(f"expected GGUF v3, found v{version}")
353
+ for _ in range(int(kv_count)):
354
+ key, cursor = self._string(cursor)
355
+ (value_type,), cursor = self._unpack("<I", cursor)
356
+ if value_type == GGUF_VALUE_U32:
357
+ (value,), cursor = self._unpack("<I", cursor)
358
+ elif value_type == GGUF_VALUE_STRING:
359
+ value, cursor = self._string(cursor)
360
+ elif value_type == GGUF_VALUE_ARRAY:
361
+ (element_type, length), cursor = self._unpack("<IQ", cursor)
362
+ if element_type != GGUF_VALUE_I32:
363
+ raise ValueError(f"unsupported GGUF array type {element_type}")
364
+ values = []
365
+ for _ in range(int(length)):
366
+ (item,), cursor = self._unpack("<i", cursor)
367
+ values.append(item)
368
+ value = tuple(values)
369
+ else:
370
+ raise ValueError(f"unsupported GGUF metadata type {value_type}")
371
+ if key in self.metadata:
372
+ raise ValueError(f"duplicate GGUF metadata key {key}")
373
+ self.metadata[key] = value
374
+
375
+ directory: list[tuple[str, tuple[int, ...], int, int]] = []
376
+ for _ in range(int(tensor_count)):
377
+ name, cursor = self._string(cursor)
378
+ (ndim,), cursor = self._unpack("<I", cursor)
379
+ dims = []
380
+ for _ in range(int(ndim)):
381
+ (dim,), cursor = self._unpack("<Q", cursor)
382
+ dims.append(int(dim))
383
+ (ggml_type, relative_offset), cursor = self._unpack("<IQ", cursor)
384
+ directory.append((name, tuple(dims), int(ggml_type), int(relative_offset)))
385
+
386
+ self.directory_end = cursor
387
+ self.data_start = align_up(cursor)
388
+ tensors: list[GgufTensor] = []
389
+ seen: set[str] = set()
390
+ previous_end = self.data_start
391
+ for name, dims, ggml_type, relative_offset in directory:
392
+ if name in seen:
393
+ raise ValueError(f"duplicate GGUF tensor {name}")
394
+ seen.add(name)
395
+ byte_len = ggml_nbytes(dims, ggml_type)
396
+ absolute_offset = self.data_start + relative_offset
397
+ if absolute_offset % ALIGNMENT:
398
+ raise ValueError(f"tensor {name} is not {ALIGNMENT}-byte aligned")
399
+ if absolute_offset < previous_end:
400
+ raise ValueError(f"tensor {name} overlaps the previous tensor")
401
+ if absolute_offset + byte_len > len(self._map):
402
+ raise ValueError(f"tensor {name} overruns GGUF file")
403
+ tensors.append(
404
+ GgufTensor(
405
+ name=name,
406
+ dims=dims,
407
+ ggml_type=ggml_type,
408
+ relative_offset=relative_offset,
409
+ byte_len=byte_len,
410
+ absolute_offset=absolute_offset,
411
+ )
412
+ )
413
+ previous_end = absolute_offset + byte_len
414
+ self.tensors = tuple(tensors)
415
+
416
+ def tensor(self, name: str) -> GgufTensor:
417
+ for tensor in self.tensors:
418
+ if tensor.name == name:
419
+ return tensor
420
+ raise KeyError(f"GGUF tensor not found: {name}")
421
+
422
+ def tensor_array(self, tensor: GgufTensor, dtype: np.dtype | str) -> np.ndarray:
423
+ return np.frombuffer(
424
+ self._map,
425
+ dtype=dtype,
426
+ count=tensor.byte_len // np.dtype(dtype).itemsize,
427
+ offset=tensor.absolute_offset,
428
+ )
429
+
430
+ def bytes_at(self, start: int, end: int) -> bytes:
431
+ if start < 0 or start > end or end > len(self._map):
432
+ raise ValueError("GGUF byte range is outside the file")
433
+ return self._map[start:end]
434
+
435
+
436
+ def ggml_nbytes(dims: tuple[int, ...], ggml_type: int) -> int:
437
+ elements = 1
438
+ for dim in dims:
439
+ elements *= dim
440
+ if ggml_type == GGML_F32:
441
+ return elements * 4
442
+ if ggml_type == GGML_F16:
443
+ return elements * 2
444
+ if ggml_type == GGML_Q8_0:
445
+ if elements % 32:
446
+ raise ValueError("Q8_0 tensor is not block aligned")
447
+ return elements // 32 * 34
448
+ if ggml_type == GGML_Q2_K:
449
+ if elements % 256:
450
+ raise ValueError("Q2_K tensor is not block aligned")
451
+ return elements // 256 * 84
452
+ if ggml_type == GGML_MXFP4:
453
+ if elements % 32:
454
+ raise ValueError("MXFP4 tensor is not block aligned")
455
+ return elements // 32 * 17
456
+ raise ValueError(f"unsupported GGML tensor type {ggml_type}")
scripts/recipe.py ADDED
@@ -0,0 +1,519 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Immutable source manifest and deterministic DSpark GGUF tensor recipe."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Iterator
10
+
11
+
12
+ REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
13
+ SOURCE_MANIFEST_PATH = REPOSITORY_ROOT / "manifest" / "source.json"
14
+ with SOURCE_MANIFEST_PATH.open(encoding="utf-8") as _manifest_handle:
15
+ _SOURCE_MANIFEST = json.load(_manifest_handle)
16
+
17
+ SOURCE_REPOSITORY = str(_SOURCE_MANIFEST["repository"])
18
+ SOURCE_REVISION = str(_SOURCE_MANIFEST["revision"])
19
+ SOURCE_FILES = {
20
+ str(name): {"size": int(properties["size"]), "sha256": str(properties["sha256"])}
21
+ for name, properties in _SOURCE_MANIFEST["files"].items()
22
+ }
23
+ if sum(int(properties["size"]) for properties in SOURCE_FILES.values()) != int(
24
+ _SOURCE_MANIFEST["total_size"]
25
+ ):
26
+ raise ValueError(
27
+ f"{SOURCE_MANIFEST_PATH}: total_size does not match its file entries"
28
+ )
29
+
30
+ ARCHITECTURE = "deepseek_v4_flash_dspark_draft"
31
+ GENERAL_NAME = "DeepSeek-V4-Flash-0731-DSpark-Drafter"
32
+ RECIPE_VERSION = 1
33
+
34
+ BLOCK_SIZE = 5
35
+ MARKOV_RANK = 256
36
+ NOISE_TOKEN_ID = 128_799
37
+ TARGET_LAYER_IDS = (40, 41, 42)
38
+ LAYER_COUNT = 3
39
+ HEAD_LAYER = 2
40
+ N_EMBD = 4096
41
+ N_EXPERTS = 256
42
+ VOCAB_SIZE = 129_280
43
+
44
+ GGML_F32 = 0
45
+ GGML_F16 = 1
46
+ GGML_Q8_0 = 8
47
+ GGML_Q2_K = 10
48
+ GGML_MXFP4 = 39
49
+ GGML_TYPE_NAMES = {
50
+ GGML_F32: "F32",
51
+ GGML_F16: "F16",
52
+ GGML_Q8_0: "Q8_0",
53
+ GGML_Q2_K: "Q2_K",
54
+ GGML_MXFP4: "MXFP4",
55
+ }
56
+
57
+ KIND_PLAIN_F32 = "plain_f32"
58
+ KIND_RELABEL_F32 = "relabel_f32"
59
+ KIND_FP8_TO_Q8_0 = "fp8_to_q8_0"
60
+ KIND_FUSED_EXPERTS_MXFP4 = "fused_experts_mxfp4"
61
+ KIND_FUSED_EXPERTS_Q2_K = "fused_experts_q2_k"
62
+ KIND_MARKOV_F16 = "markov_f16"
63
+
64
+ RECIPE_MXFP4_Q8_0 = "mxfp4-q8_0"
65
+ RECIPE_Q2_K_Q8_0 = "q2_k-q8_0"
66
+
67
+
68
+ @dataclass(frozen=True)
69
+ class ArtifactRecipe:
70
+ """One output policy over the shared canonical tensor/source plan."""
71
+
72
+ name: str
73
+ output_filename: str
74
+ routed_expert_kind: str
75
+ routed_expert_type: int
76
+ expected_tensor_bytes: int
77
+ expected_file_size: int
78
+ expected_type_counts: tuple[tuple[int, int], ...]
79
+ q2_k_error_limit: float | None = None
80
+
81
+ def manifest_filename(self, kind: str) -> str:
82
+ if kind not in {"build", "validation"}:
83
+ raise ValueError(f"unknown manifest kind: {kind}")
84
+ if self.name == RECIPE_MXFP4_Q8_0:
85
+ return f"{kind}.json"
86
+ return f"{kind}-{self.name}.json"
87
+
88
+
89
+ MXFP4_Q8_0_RECIPE = ArtifactRecipe(
90
+ name=RECIPE_MXFP4_Q8_0,
91
+ output_filename="DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf",
92
+ routed_expert_kind=KIND_FUSED_EXPERTS_MXFP4,
93
+ routed_expert_type=GGML_MXFP4,
94
+ expected_tensor_bytes=10_897_104_284,
95
+ expected_file_size=10_897_110_272,
96
+ expected_type_counts=(
97
+ (GGML_F32, 45),
98
+ (GGML_F16, 2),
99
+ (GGML_Q8_0, 25),
100
+ (GGML_MXFP4, 9),
101
+ ),
102
+ )
103
+ Q2_K_Q8_0_RECIPE = ArtifactRecipe(
104
+ name=RECIPE_Q2_K_Q8_0,
105
+ output_filename="DeepSeek-V4-Flash-0731-DSpark-Drafter-Q2_K-Q8_0.gguf",
106
+ routed_expert_kind=KIND_FUSED_EXPERTS_Q2_K,
107
+ routed_expert_type=GGML_Q2_K,
108
+ expected_tensor_bytes=6_971_235_740,
109
+ expected_file_size=6_971_241_728,
110
+ expected_type_counts=(
111
+ (GGML_F32, 45),
112
+ (GGML_F16, 2),
113
+ (GGML_Q8_0, 25),
114
+ (GGML_Q2_K, 9),
115
+ ),
116
+ q2_k_error_limit=0.50,
117
+ )
118
+ RECIPES = {recipe.name: recipe for recipe in (MXFP4_Q8_0_RECIPE, Q2_K_Q8_0_RECIPE)}
119
+ DEFAULT_RECIPE = MXFP4_Q8_0_RECIPE
120
+ OUTPUT_FILENAME = DEFAULT_RECIPE.output_filename
121
+
122
+
123
+ def resolve_recipe(recipe: ArtifactRecipe | str | None = None) -> ArtifactRecipe:
124
+ if recipe is None:
125
+ return DEFAULT_RECIPE
126
+ if isinstance(recipe, ArtifactRecipe):
127
+ return recipe
128
+ try:
129
+ return RECIPES[recipe]
130
+ except KeyError as error:
131
+ choices = ", ".join(sorted(RECIPES))
132
+ raise ValueError(
133
+ f"unknown recipe {recipe!r}; choose one of: {choices}"
134
+ ) from error
135
+
136
+
137
+ @dataclass(frozen=True)
138
+ class TensorRecipe:
139
+ out_name: str
140
+ kind: str
141
+ dims: tuple[int, ...]
142
+ ggml_type: int
143
+ src_name: str = ""
144
+ src_is_bf16: bool = False
145
+ src_shape: tuple[int, ...] = ()
146
+ weight_name: str = ""
147
+ scale_name: str = ""
148
+ rows: int = 0
149
+ cols: int = 0
150
+ name_prefix: str = ""
151
+ expert_kind: str = ""
152
+
153
+ @property
154
+ def elements(self) -> int:
155
+ value = 1
156
+ for dim in self.dims:
157
+ value *= dim
158
+ return value
159
+
160
+ @property
161
+ def byte_len(self) -> int:
162
+ if self.ggml_type == GGML_F32:
163
+ return self.elements * 4
164
+ if self.ggml_type == GGML_F16:
165
+ return self.elements * 2
166
+ if self.ggml_type == GGML_Q8_0:
167
+ if self.elements % 32:
168
+ raise ValueError(
169
+ f"{self.out_name}: Q8_0 element count is not block aligned"
170
+ )
171
+ return self.elements // 32 * 34
172
+ if self.ggml_type == GGML_Q2_K:
173
+ if self.elements % 256:
174
+ raise ValueError(
175
+ f"{self.out_name}: Q2_K element count is not block aligned"
176
+ )
177
+ return self.elements // 256 * 84
178
+ if self.ggml_type == GGML_MXFP4:
179
+ if self.elements % 32:
180
+ raise ValueError(
181
+ f"{self.out_name}: MXFP4 element count is not block aligned"
182
+ )
183
+ return self.elements // 32 * 17
184
+ raise ValueError(f"{self.out_name}: unsupported GGML type {self.ggml_type}")
185
+
186
+
187
+ def _plain(
188
+ out_name: str,
189
+ src_name: str,
190
+ *,
191
+ bf16: bool,
192
+ dims: tuple[int, ...],
193
+ src_shape: tuple[int, ...] | None = None,
194
+ ) -> TensorRecipe:
195
+ return TensorRecipe(
196
+ out_name=out_name,
197
+ kind=KIND_PLAIN_F32,
198
+ dims=dims,
199
+ ggml_type=GGML_F32,
200
+ src_name=src_name,
201
+ src_is_bf16=bf16,
202
+ src_shape=dims if src_shape is None else src_shape,
203
+ )
204
+
205
+
206
+ def _fp8(
207
+ out_name: str,
208
+ weight_name: str,
209
+ scale_name: str,
210
+ rows: int,
211
+ cols: int,
212
+ ) -> TensorRecipe:
213
+ return TensorRecipe(
214
+ out_name=out_name,
215
+ kind=KIND_FP8_TO_Q8_0,
216
+ dims=(cols, rows),
217
+ ggml_type=GGML_Q8_0,
218
+ weight_name=weight_name,
219
+ scale_name=scale_name,
220
+ rows=rows,
221
+ cols=cols,
222
+ )
223
+
224
+
225
+ def _layer_plan(layer: int, artifact_recipe: ArtifactRecipe) -> list[TensorRecipe]:
226
+ prefix = f"mtp.{layer}"
227
+ out: list[TensorRecipe] = [
228
+ _plain(
229
+ f"dspark.{layer}.attn_sinks.weight",
230
+ f"{prefix}.attn.attn_sink",
231
+ bf16=False,
232
+ dims=(64,),
233
+ ),
234
+ _plain(
235
+ f"dspark.{layer}.attn_norm.weight",
236
+ f"{prefix}.attn_norm.weight",
237
+ bf16=True,
238
+ dims=(N_EMBD,),
239
+ ),
240
+ _plain(
241
+ f"dspark.{layer}.ffn_norm.weight",
242
+ f"{prefix}.ffn_norm.weight",
243
+ bf16=True,
244
+ dims=(N_EMBD,),
245
+ ),
246
+ _plain(
247
+ f"dspark.{layer}.attn_kv_a_norm.weight",
248
+ f"{prefix}.attn.kv_norm.weight",
249
+ bf16=True,
250
+ dims=(512,),
251
+ ),
252
+ _plain(
253
+ f"dspark.{layer}.attn_q_a_norm.weight",
254
+ f"{prefix}.attn.q_norm.weight",
255
+ bf16=True,
256
+ dims=(1024,),
257
+ ),
258
+ _fp8(
259
+ f"dspark.{layer}.attn_kv.weight",
260
+ f"{prefix}.attn.wkv.weight",
261
+ f"{prefix}.attn.wkv.scale",
262
+ 512,
263
+ N_EMBD,
264
+ ),
265
+ _fp8(
266
+ f"dspark.{layer}.attn_q_a.weight",
267
+ f"{prefix}.attn.wq_a.weight",
268
+ f"{prefix}.attn.wq_a.scale",
269
+ 1024,
270
+ N_EMBD,
271
+ ),
272
+ _fp8(
273
+ f"dspark.{layer}.attn_q_b.weight",
274
+ f"{prefix}.attn.wq_b.weight",
275
+ f"{prefix}.attn.wq_b.scale",
276
+ 32768,
277
+ 1024,
278
+ ),
279
+ _fp8(
280
+ f"dspark.{layer}.attn_output_a.weight",
281
+ f"{prefix}.attn.wo_a.weight",
282
+ f"{prefix}.attn.wo_a.scale",
283
+ 8192,
284
+ N_EMBD,
285
+ ),
286
+ _fp8(
287
+ f"dspark.{layer}.attn_output_b.weight",
288
+ f"{prefix}.attn.wo_b.weight",
289
+ f"{prefix}.attn.wo_b.scale",
290
+ N_EMBD,
291
+ 8192,
292
+ ),
293
+ _fp8(
294
+ f"dspark.{layer}.ffn_gate_shexp.weight",
295
+ f"{prefix}.ffn.shared_experts.w1.weight",
296
+ f"{prefix}.ffn.shared_experts.w1.scale",
297
+ 2048,
298
+ N_EMBD,
299
+ ),
300
+ _fp8(
301
+ f"dspark.{layer}.ffn_up_shexp.weight",
302
+ f"{prefix}.ffn.shared_experts.w3.weight",
303
+ f"{prefix}.ffn.shared_experts.w3.scale",
304
+ 2048,
305
+ N_EMBD,
306
+ ),
307
+ _fp8(
308
+ f"dspark.{layer}.ffn_down_shexp.weight",
309
+ f"{prefix}.ffn.shared_experts.w2.weight",
310
+ f"{prefix}.ffn.shared_experts.w2.scale",
311
+ N_EMBD,
312
+ 2048,
313
+ ),
314
+ _plain(
315
+ f"dspark.{layer}.ffn_gate_inp.weight",
316
+ f"{prefix}.ffn.gate.weight",
317
+ bf16=True,
318
+ dims=(N_EMBD, N_EXPERTS),
319
+ src_shape=(N_EXPERTS, N_EMBD),
320
+ ),
321
+ _plain(
322
+ f"dspark.{layer}.exp_probs_b.bias",
323
+ f"{prefix}.ffn.gate.bias",
324
+ bf16=False,
325
+ dims=(N_EXPERTS,),
326
+ ),
327
+ ]
328
+
329
+ for expert_kind, output_suffix, rows, cols in (
330
+ ("w1", "ffn_gate_exps", 2048, N_EMBD),
331
+ ("w3", "ffn_up_exps", 2048, N_EMBD),
332
+ ("w2", "ffn_down_exps", N_EMBD, 2048),
333
+ ):
334
+ out.append(
335
+ TensorRecipe(
336
+ out_name=f"dspark.{layer}.{output_suffix}.weight",
337
+ kind=artifact_recipe.routed_expert_kind,
338
+ dims=(cols, rows, N_EXPERTS),
339
+ ggml_type=artifact_recipe.routed_expert_type,
340
+ rows=rows,
341
+ cols=cols,
342
+ name_prefix=prefix,
343
+ expert_kind=expert_kind,
344
+ )
345
+ )
346
+
347
+ for suffix in ("hc_attn_fn", "hc_ffn_fn"):
348
+ out.append(
349
+ TensorRecipe(
350
+ out_name=f"dspark.{layer}.{suffix}.weight",
351
+ kind=KIND_RELABEL_F32,
352
+ dims=(16384, 24),
353
+ ggml_type=GGML_F32,
354
+ src_name=f"{prefix}.{suffix}",
355
+ rows=24,
356
+ cols=16384,
357
+ )
358
+ )
359
+ for suffix in ("hc_attn_base", "hc_ffn_base"):
360
+ out.append(
361
+ _plain(
362
+ f"dspark.{layer}.{suffix}.weight",
363
+ f"{prefix}.{suffix}",
364
+ bf16=False,
365
+ dims=(24,),
366
+ )
367
+ )
368
+ for suffix in ("hc_attn_scale", "hc_ffn_scale"):
369
+ out.append(
370
+ _plain(
371
+ f"dspark.{layer}.{suffix}.weight",
372
+ f"{prefix}.{suffix}",
373
+ bf16=False,
374
+ dims=(3,),
375
+ )
376
+ )
377
+ return out
378
+
379
+
380
+ def _global_plan() -> list[TensorRecipe]:
381
+ head = f"mtp.{HEAD_LAYER}"
382
+ out = [
383
+ _fp8(
384
+ "dspark.main_proj.weight",
385
+ "mtp.0.main_proj.weight",
386
+ "mtp.0.main_proj.scale",
387
+ N_EMBD,
388
+ 12288,
389
+ ),
390
+ _plain(
391
+ "dspark.main_norm.weight",
392
+ "mtp.0.main_norm.weight",
393
+ bf16=True,
394
+ dims=(N_EMBD,),
395
+ ),
396
+ _plain(
397
+ "dspark.norm.weight",
398
+ f"{head}.norm.weight",
399
+ bf16=True,
400
+ dims=(N_EMBD,),
401
+ ),
402
+ ]
403
+ for suffix in ("markov_w1", "markov_w2"):
404
+ out.append(
405
+ TensorRecipe(
406
+ out_name=f"dspark.{suffix}.weight",
407
+ kind=KIND_MARKOV_F16,
408
+ dims=(MARKOV_RANK, VOCAB_SIZE),
409
+ ggml_type=GGML_F16,
410
+ src_name=f"{head}.markov_head.{suffix}.weight",
411
+ )
412
+ )
413
+ out.extend(
414
+ [
415
+ TensorRecipe(
416
+ out_name="dspark.hc_head_fn.weight",
417
+ kind=KIND_RELABEL_F32,
418
+ dims=(16384, 4),
419
+ ggml_type=GGML_F32,
420
+ src_name=f"{head}.hc_head_fn",
421
+ rows=4,
422
+ cols=16384,
423
+ ),
424
+ _plain(
425
+ "dspark.hc_head_base.weight",
426
+ f"{head}.hc_head_base",
427
+ bf16=False,
428
+ dims=(4,),
429
+ ),
430
+ _plain(
431
+ "dspark.hc_head_scale.weight",
432
+ f"{head}.hc_head_scale",
433
+ bf16=False,
434
+ dims=(1,),
435
+ ),
436
+ _plain(
437
+ "dspark.confidence_head.weight",
438
+ f"{head}.confidence_head.proj.weight",
439
+ bf16=True,
440
+ dims=(4352,),
441
+ src_shape=(1, 4352),
442
+ ),
443
+ ]
444
+ )
445
+ return out
446
+
447
+
448
+ def build_plan(
449
+ recipe: ArtifactRecipe | str | None = None,
450
+ ) -> tuple[TensorRecipe, ...]:
451
+ artifact_recipe = resolve_recipe(recipe)
452
+ tensors: list[TensorRecipe] = []
453
+ for layer in range(LAYER_COUNT):
454
+ tensors.extend(_layer_plan(layer, artifact_recipe))
455
+ tensors.extend(_global_plan())
456
+ if len(tensors) != 81:
457
+ raise AssertionError(f"recipe contains {len(tensors)} tensors, expected 81")
458
+ if len({tensor.out_name for tensor in tensors}) != len(tensors):
459
+ raise AssertionError("recipe contains duplicate output tensor names")
460
+ tensor_bytes = sum(tensor.byte_len for tensor in tensors)
461
+ if tensor_bytes != artifact_recipe.expected_tensor_bytes:
462
+ raise AssertionError(
463
+ f"{artifact_recipe.name}: tensor payload is {tensor_bytes}, "
464
+ f"expected {artifact_recipe.expected_tensor_bytes}"
465
+ )
466
+ type_counts = tuple(
467
+ (ggml_type, sum(tensor.ggml_type == ggml_type for tensor in tensors))
468
+ for ggml_type, _expected in artifact_recipe.expected_type_counts
469
+ )
470
+ if type_counts != artifact_recipe.expected_type_counts:
471
+ raise AssertionError(
472
+ f"{artifact_recipe.name}: type inventory {type_counts} does not match "
473
+ f"{artifact_recipe.expected_type_counts}"
474
+ )
475
+ return tuple(tensors)
476
+
477
+
478
+ def source_expectations(
479
+ tensor: TensorRecipe,
480
+ ) -> Iterator[tuple[str, str, tuple[int, ...]]]:
481
+ if tensor.kind == KIND_PLAIN_F32:
482
+ yield tensor.src_name, "BF16" if tensor.src_is_bf16 else "F32", tensor.src_shape
483
+ elif tensor.kind == KIND_RELABEL_F32:
484
+ yield tensor.src_name, "F32", (tensor.rows, tensor.cols)
485
+ elif tensor.kind == KIND_FP8_TO_Q8_0:
486
+ yield tensor.weight_name, "F8_E4M3", (tensor.rows, tensor.cols)
487
+ yield (
488
+ tensor.scale_name,
489
+ "F8_E8M0",
490
+ ((tensor.rows + 127) // 128, (tensor.cols + 127) // 128),
491
+ )
492
+ elif tensor.kind in {KIND_FUSED_EXPERTS_MXFP4, KIND_FUSED_EXPERTS_Q2_K}:
493
+ for expert in range(N_EXPERTS):
494
+ prefix = f"{tensor.name_prefix}.ffn.experts.{expert}.{tensor.expert_kind}"
495
+ yield f"{prefix}.weight", "I8", (tensor.rows, tensor.cols // 2)
496
+ yield f"{prefix}.scale", "F8_E8M0", (tensor.rows, tensor.cols // 32)
497
+ elif tensor.kind == KIND_MARKOV_F16:
498
+ yield tensor.src_name, "BF16", (VOCAB_SIZE, MARKOV_RANK)
499
+ else:
500
+ raise ValueError(f"unknown recipe kind {tensor.kind}")
501
+
502
+
503
+ def source_paths(source_dir: Path) -> tuple[Path, ...]:
504
+ return tuple(source_dir / name for name in SOURCE_FILES)
505
+
506
+
507
+ GGUF_METADATA = (
508
+ ("general.architecture", "string", ARCHITECTURE),
509
+ ("general.name", "string", GENERAL_NAME),
510
+ ("general.source.url", "string", f"https://huggingface.co/{SOURCE_REPOSITORY}"),
511
+ ("general.source.revision", "string", SOURCE_REVISION),
512
+ ("general.license", "string", "MIT"),
513
+ ("dspark.recipe_version", "u32", RECIPE_VERSION),
514
+ ("dspark.block_size", "u32", BLOCK_SIZE),
515
+ ("dspark.markov_rank", "u32", MARKOV_RANK),
516
+ ("dspark.noise_token_id", "u32", NOISE_TOKEN_ID),
517
+ ("dspark.target_layer_ids", "array_i32", TARGET_LAYER_IDS),
518
+ ("dspark.layer_count", "u32", LAYER_COUNT),
519
+ )
scripts/reproduce.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Run the pinned conversion, included verification, and optional repeat build."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import json
9
+ import os
10
+ import platform
11
+ import sys
12
+ import tempfile
13
+ from pathlib import Path
14
+
15
+ import numpy as np
16
+
17
+ from convert import convert
18
+ from recipe import (
19
+ ARCHITECTURE,
20
+ DEFAULT_RECIPE,
21
+ RECIPES,
22
+ REPOSITORY_ROOT,
23
+ RECIPE_VERSION,
24
+ SOURCE_REPOSITORY,
25
+ SOURCE_REVISION,
26
+ ArtifactRecipe,
27
+ resolve_recipe,
28
+ )
29
+ from verify import verify, write_report
30
+
31
+
32
+ def _write_json(path: Path, value: object) -> None:
33
+ path.parent.mkdir(parents=True, exist_ok=True)
34
+ temporary = path.with_name(f".{path.name}.partial-{os.getpid()}")
35
+ with temporary.open("w", encoding="utf-8", newline="\n") as handle:
36
+ json.dump(value, handle, indent=2, sort_keys=True)
37
+ handle.write("\n")
38
+ handle.flush()
39
+ os.fsync(handle.fileno())
40
+ os.replace(temporary, path)
41
+
42
+
43
+ def _update_sha256sums(path: Path, digest: str, filename: str) -> None:
44
+ entries: dict[str, str] = {}
45
+ if path.exists():
46
+ with path.open(encoding="ascii") as handle:
47
+ for line_number, line in enumerate(handle, 1):
48
+ stripped = line.rstrip("\n")
49
+ if not stripped:
50
+ continue
51
+ existing_digest, separator, existing_filename = stripped.partition(" ")
52
+ if (
53
+ separator != " "
54
+ or len(existing_digest) != 64
55
+ or any(
56
+ character not in "0123456789abcdef"
57
+ for character in existing_digest
58
+ )
59
+ or not existing_filename
60
+ ):
61
+ raise ValueError(
62
+ f"{path}:{line_number}: malformed SHA256SUMS entry"
63
+ )
64
+ entries[existing_filename] = existing_digest
65
+ entries[filename] = digest
66
+ temporary = path.with_name(f".{path.name}.partial-{os.getpid()}")
67
+ with temporary.open("w", encoding="ascii", newline="\n") as handle:
68
+ for entry_filename in sorted(entries):
69
+ handle.write(f"{entries[entry_filename]} {entry_filename}\n")
70
+ handle.flush()
71
+ os.fsync(handle.fileno())
72
+ os.replace(temporary, path)
73
+
74
+
75
+ def _build_input_hashes() -> dict[str, str]:
76
+ relative_paths = [
77
+ Path("requirements-linux-aarch64-py314.lock"),
78
+ Path("manifest/source.json"),
79
+ *(
80
+ Path("scripts") / name
81
+ for name in (
82
+ "convert.py",
83
+ "download_sources.py",
84
+ "formats.py",
85
+ "recipe.py",
86
+ "reproduce.py",
87
+ "verify.py",
88
+ )
89
+ ),
90
+ ]
91
+ hashes: dict[str, str] = {}
92
+ for relative_path in relative_paths:
93
+ path = REPOSITORY_ROOT / relative_path
94
+ digest = hashlib.sha256()
95
+ with path.open("rb") as handle:
96
+ while chunk := handle.read(1024 * 1024):
97
+ digest.update(chunk)
98
+ hashes[relative_path.as_posix()] = digest.hexdigest()
99
+ return hashes
100
+
101
+
102
+ def reproduce(
103
+ source_dir: Path,
104
+ output: Path,
105
+ manifest_dir: Path,
106
+ *,
107
+ force: bool,
108
+ repeat_check: bool,
109
+ recipe: ArtifactRecipe | str | None = None,
110
+ ) -> None:
111
+ artifact_recipe = resolve_recipe(recipe)
112
+ output = output.resolve()
113
+ if output.exists() and not force:
114
+ raise FileExistsError(
115
+ f"output already exists: {output}; pass --force to replace it"
116
+ )
117
+ output.parent.mkdir(parents=True, exist_ok=True)
118
+ build_input_hashes = _build_input_hashes()
119
+
120
+ repeat_digest: str | None = None
121
+ with tempfile.TemporaryDirectory(
122
+ prefix=f".{output.name}.candidate-", dir=output.parent
123
+ ) as candidate_directory:
124
+ candidate = Path(candidate_directory) / output.name
125
+ size, digest = convert(source_dir, candidate, recipe=artifact_recipe)
126
+ report = verify(source_dir, candidate, recipe=artifact_recipe)
127
+ artifact = report["artifact"]
128
+ if artifact["size"] != size or artifact["sha256"] != digest:
129
+ raise ValueError("converter and verifier disagree on artifact identity")
130
+
131
+ if repeat_check:
132
+ with tempfile.TemporaryDirectory(
133
+ prefix=f".{output.name}.repeat-", dir=output.parent
134
+ ) as repeat_directory:
135
+ repeat_output = Path(repeat_directory) / output.name
136
+ repeat_size, repeat_digest = convert(
137
+ source_dir, repeat_output, recipe=artifact_recipe
138
+ )
139
+ if repeat_size != size or repeat_digest != digest:
140
+ raise ValueError(
141
+ "repeat build is not byte-identical: "
142
+ f"first={size}/{digest}, second={repeat_size}/{repeat_digest}"
143
+ )
144
+
145
+ os.replace(candidate, output)
146
+ directory_fd = os.open(output.parent, os.O_RDONLY | os.O_DIRECTORY)
147
+ try:
148
+ os.fsync(directory_fd)
149
+ finally:
150
+ os.close(directory_fd)
151
+
152
+ manifest_dir = manifest_dir.resolve()
153
+ write_report(manifest_dir / artifact_recipe.manifest_filename("validation"), report)
154
+ build = {
155
+ "artifact": artifact,
156
+ "build_inputs": build_input_hashes,
157
+ "environment": {
158
+ "machine": platform.machine(),
159
+ "numpy": np.__version__,
160
+ "platform": platform.platform(),
161
+ "python": platform.python_version(),
162
+ },
163
+ "format": {
164
+ "architecture": ARCHITECTURE,
165
+ "gguf_version": 3,
166
+ "recipe": artifact_recipe.name,
167
+ "recipe_version": RECIPE_VERSION,
168
+ },
169
+ "repeat_build": {
170
+ "performed": repeat_check,
171
+ "sha256": repeat_digest,
172
+ "status": "byte-identical" if repeat_check else "not-run",
173
+ },
174
+ "source": {
175
+ "repository": SOURCE_REPOSITORY,
176
+ "revision": SOURCE_REVISION,
177
+ },
178
+ }
179
+ _write_json(manifest_dir / artifact_recipe.manifest_filename("build"), build)
180
+ _update_sha256sums(output.parent / "SHA256SUMS", digest, output.name)
181
+ print(f"[reproduce] PASS: {output.name} {size:,} bytes {digest}", flush=True)
182
+
183
+
184
+ def parse_args() -> argparse.Namespace:
185
+ parser = argparse.ArgumentParser(description=__doc__)
186
+ parser.add_argument("--sources", type=Path, required=True)
187
+ parser.add_argument(
188
+ "--recipe",
189
+ choices=sorted(RECIPES),
190
+ default=DEFAULT_RECIPE.name,
191
+ help=f"Artifact recipe (default: {DEFAULT_RECIPE.name})",
192
+ )
193
+ parser.add_argument(
194
+ "--output",
195
+ type=Path,
196
+ help="Output path (default: the selected recipe's canonical filename)",
197
+ )
198
+ parser.add_argument("--manifest-dir", type=Path, default=Path("manifest"))
199
+ parser.add_argument("--force", action="store_true")
200
+ parser.add_argument(
201
+ "--repeat-check",
202
+ action="store_true",
203
+ help="Build a second clean GGUF and require a byte-identical SHA-256",
204
+ )
205
+ return parser.parse_args()
206
+
207
+
208
+ def main() -> None:
209
+ args = parse_args()
210
+ recipe = resolve_recipe(args.recipe)
211
+ output = args.output if args.output is not None else Path(recipe.output_filename)
212
+ try:
213
+ reproduce(
214
+ args.sources,
215
+ output,
216
+ args.manifest_dir,
217
+ force=args.force,
218
+ repeat_check=args.repeat_check,
219
+ recipe=recipe,
220
+ )
221
+ except Exception as error:
222
+ print(f"[reproduce] ERROR: {error}", file=sys.stderr)
223
+ raise SystemExit(1) from error
224
+
225
+
226
+ if __name__ == "__main__":
227
+ main()
scripts/verify.py ADDED
@@ -0,0 +1,613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Independently verify GGUF structure and every tensor against pinned sources."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import math
9
+ import os
10
+ from pathlib import Path
11
+
12
+ import numpy as np
13
+
14
+ from formats import (
15
+ ALIGNMENT,
16
+ GgufReader,
17
+ SafeTensorSet,
18
+ align_up,
19
+ sha256_path,
20
+ verify_source_files,
21
+ )
22
+ from recipe import (
23
+ DEFAULT_RECIPE,
24
+ GGML_F16,
25
+ GGML_F32,
26
+ GGML_MXFP4,
27
+ GGML_Q2_K,
28
+ GGML_Q8_0,
29
+ GGML_TYPE_NAMES,
30
+ GGUF_METADATA,
31
+ KIND_PLAIN_F32,
32
+ N_EXPERTS,
33
+ RECIPES,
34
+ SOURCE_REPOSITORY,
35
+ SOURCE_REVISION,
36
+ ArtifactRecipe,
37
+ TensorRecipe,
38
+ build_plan,
39
+ resolve_recipe,
40
+ source_paths,
41
+ )
42
+
43
+
44
+ def _decode_e4m3_table() -> np.ndarray:
45
+ values = []
46
+ for byte in range(256):
47
+ sign = -1.0 if byte & 0x80 else 1.0
48
+ exponent = (byte >> 3) & 0x0F
49
+ mantissa = byte & 0x07
50
+ if exponent == 0x0F and mantissa == 0x07:
51
+ value = np.nan
52
+ elif exponent == 0:
53
+ value = sign * (mantissa / 8.0) * math.ldexp(1.0, -6)
54
+ else:
55
+ value = sign * (1.0 + mantissa / 8.0) * math.ldexp(1.0, exponent - 7)
56
+ values.append(np.float32(value))
57
+ return np.array(values, dtype=np.float32)
58
+
59
+
60
+ VERIFY_E4M3 = _decode_e4m3_table()
61
+ VERIFY_E8M0 = np.array(
62
+ [
63
+ np.float32(np.nan) if code == 0xFF else np.float32(math.ldexp(1.0, code - 127))
64
+ for code in range(256)
65
+ ],
66
+ dtype=np.float32,
67
+ )
68
+ VERIFY_FP4 = np.array(
69
+ [
70
+ 0.0,
71
+ 0.5,
72
+ 1.0,
73
+ 1.5,
74
+ 2.0,
75
+ 3.0,
76
+ 4.0,
77
+ 6.0,
78
+ 0.0,
79
+ -0.5,
80
+ -1.0,
81
+ -1.5,
82
+ -2.0,
83
+ -3.0,
84
+ -4.0,
85
+ -6.0,
86
+ ],
87
+ dtype=np.float32,
88
+ )
89
+ # Independently decode and compare at most one routed expert at a time.
90
+ VERIFY_EXPERT_ROW_BATCH = 4096
91
+
92
+
93
+ def decode_q2_k_blocks(encoded: np.ndarray) -> np.ndarray:
94
+ """Independently decode GGML Q2_K's 84-byte/256-value block layout."""
95
+
96
+ blocks = np.asarray(encoded, dtype=np.uint8)
97
+ if blocks.ndim != 2 or blocks.shape[1] != 84:
98
+ raise ValueError("Q2_K payload must have shape (n, 84)")
99
+ scale_bytes = blocks[:, :16]
100
+ d = blocks[:, 80:82].copy().reshape(-1).view("<f2").astype(np.float32)
101
+ dmin = blocks[:, 82:84].copy().reshape(-1).view("<f2").astype(np.float32)
102
+ if not np.isfinite(d).all() or not np.isfinite(dmin).all():
103
+ raise ValueError("Q2_K payload contains a non-finite block scale")
104
+
105
+ codes = np.empty((blocks.shape[0], 256), dtype=np.uint8)
106
+ for start in (0, 128):
107
+ offset = 16 + start // 4
108
+ packed = blocks[:, offset : offset + 32]
109
+ codes[:, start : start + 32] = packed & np.uint8(0x03)
110
+ codes[:, start + 32 : start + 64] = (packed >> np.uint8(2)) & np.uint8(0x03)
111
+ codes[:, start + 64 : start + 96] = (packed >> np.uint8(4)) & np.uint8(0x03)
112
+ codes[:, start + 96 : start + 128] = packed >> np.uint8(6)
113
+
114
+ group_scales = np.multiply(
115
+ d[:, None], scale_bytes & np.uint8(0x0F), dtype=np.float32
116
+ )
117
+ group_mins = np.multiply(
118
+ dmin[:, None], scale_bytes >> np.uint8(4), dtype=np.float32
119
+ )
120
+ decoded = np.subtract(
121
+ np.multiply(
122
+ group_scales[..., None],
123
+ codes.reshape(-1, 16, 16),
124
+ dtype=np.float32,
125
+ ),
126
+ group_mins[..., None],
127
+ dtype=np.float32,
128
+ )
129
+ return decoded.reshape(-1, 256)
130
+
131
+
132
+ def _decode_source_mxfp4_rows(
133
+ packed: np.ndarray,
134
+ scale_codes: np.ndarray,
135
+ rows: int,
136
+ cols: int,
137
+ ) -> np.ndarray:
138
+ if cols % 32:
139
+ raise ValueError("source MXFP4 column count must be divisible by 32")
140
+ block_count = cols // 32
141
+ source = np.asarray(packed, dtype=np.uint8).reshape(rows, block_count, 16)
142
+ scales = np.asarray(scale_codes, dtype=np.uint8).reshape(rows, block_count)
143
+ if np.any(scales == 0xFF):
144
+ raise ValueError("source MXFP4 contains reserved E8M0 NaN scale 0xff")
145
+ codes = np.empty((rows, block_count, 32), dtype=np.uint8)
146
+ codes[..., 0::2] = source & np.uint8(0x0F)
147
+ codes[..., 1::2] = source >> np.uint8(4)
148
+ decoded = VERIFY_FP4[codes]
149
+ decoded *= VERIFY_E8M0[scales][..., None]
150
+ return decoded.reshape(rows, cols)
151
+
152
+
153
+ def _expected_metadata() -> dict[str, object]:
154
+ expected: dict[str, object] = {}
155
+ for key, kind, value in GGUF_METADATA:
156
+ if kind == "array_i32":
157
+ expected[key] = tuple(int(item) for item in value)
158
+ elif kind == "u32":
159
+ expected[key] = int(value)
160
+ else:
161
+ expected[key] = str(value)
162
+ return expected
163
+
164
+
165
+ def _assert_equal(name: str, observed: np.ndarray, expected: np.ndarray) -> None:
166
+ if observed.shape != expected.shape:
167
+ raise ValueError(
168
+ f"{name}: expected shape {expected.shape}, found {observed.shape}"
169
+ )
170
+ if not np.array_equal(observed, expected):
171
+ mismatch = np.flatnonzero(observed.reshape(-1) != expected.reshape(-1))
172
+ first = int(mismatch[0]) if mismatch.size else -1
173
+ raise ValueError(f"{name}: exact comparison failed at element {first}")
174
+
175
+
176
+ def _verify_f32(
177
+ source: SafeTensorSet,
178
+ reader: GgufReader,
179
+ tensor: TensorRecipe,
180
+ ) -> None:
181
+ output = reader.tensor_array(reader.tensor(tensor.out_name), "<u4")
182
+ if tensor.kind == KIND_PLAIN_F32 and tensor.src_is_bf16:
183
+ bits = source.array(tensor.src_name, "<u2").reshape(-1)
184
+ expected = bits.astype("<u4") << np.uint32(16)
185
+ else:
186
+ expected = source.array(tensor.src_name, "<u4").reshape(-1)
187
+ _assert_equal(tensor.out_name, output, expected)
188
+
189
+
190
+ def _verify_markov_f16(
191
+ source: SafeTensorSet,
192
+ reader: GgufReader,
193
+ tensor: TensorRecipe,
194
+ ) -> None:
195
+ output = reader.tensor_array(reader.tensor(tensor.out_name), "<u2")
196
+ bits = source.array(tensor.src_name, "<u2").reshape(-1)
197
+ chunk = 8 * 1024 * 1024
198
+ for start in range(0, bits.size, chunk):
199
+ stop = min(start + chunk, bits.size)
200
+ f32_bits = bits[start:stop].astype("<u4") << np.uint32(16)
201
+ expected = f32_bits.view("<f4").astype("<f2").view("<u2")
202
+ _assert_equal(
203
+ f"{tensor.out_name}[{start}:{stop}]",
204
+ output[start:stop],
205
+ expected,
206
+ )
207
+
208
+
209
+ def _verify_q8_0(
210
+ source: SafeTensorSet,
211
+ reader: GgufReader,
212
+ tensor: TensorRecipe,
213
+ ) -> float:
214
+ info = reader.tensor(tensor.out_name)
215
+ encoded = reader.tensor_array(info, np.uint8).reshape(-1, 34)
216
+ weights = source.array(tensor.weight_name, np.uint8).reshape(
217
+ tensor.rows, tensor.cols
218
+ )
219
+ scale_codes = source.array(tensor.scale_name, np.uint8).reshape(
220
+ (tensor.rows + 127) // 128,
221
+ (tensor.cols + 127) // 128,
222
+ )
223
+ max_relative_error = np.float32(0.0)
224
+ block_cursor = 0
225
+ for block_row in range(scale_codes.shape[0]):
226
+ row_start = block_row * 128
227
+ row_end = min(row_start + 128, tensor.rows)
228
+ reference = VERIFY_E4M3[weights[row_start:row_end]]
229
+ column_scales = np.repeat(VERIFY_E8M0[scale_codes[block_row]], 128)[
230
+ : tensor.cols
231
+ ]
232
+ if not np.isfinite(reference).all() or not np.isfinite(column_scales).all():
233
+ raise ValueError(f"{tensor.out_name}: non-finite pinned FP8 source")
234
+ reference *= column_scales[None, :]
235
+ reference_blocks = reference.reshape(-1, 32)
236
+ block_count = reference_blocks.shape[0]
237
+ output_blocks = encoded[block_cursor : block_cursor + block_count]
238
+ maxima = np.max(np.abs(reference_blocks), axis=1).astype(np.float32, copy=False)
239
+ expected_scales = maxima / np.float32(127.0)
240
+ expected_scale_bits = expected_scales.astype("<f2").view("<u2")
241
+ observed_scale_bits = output_blocks[:, :2].copy().reshape(-1).view("<u2")
242
+ _assert_equal(
243
+ f"{tensor.out_name}/scale-bits-{block_cursor}",
244
+ observed_scale_bits,
245
+ expected_scale_bits,
246
+ )
247
+ inverse = np.zeros_like(expected_scales)
248
+ np.divide(
249
+ np.float32(1.0),
250
+ expected_scales,
251
+ out=inverse,
252
+ where=expected_scales != 0,
253
+ )
254
+ normalized = reference_blocks * inverse[:, None]
255
+ truncated = np.trunc(normalized).astype(np.float32, copy=False)
256
+ fraction = np.abs(normalized - truncated)
257
+ expected_codes = np.where(
258
+ fraction >= np.float32(0.5),
259
+ truncated + np.copysign(np.float32(1.0), normalized),
260
+ truncated,
261
+ ).astype(np.int8)
262
+ observed_codes = output_blocks[:, 2:].view(np.int8)
263
+ _assert_equal(
264
+ f"{tensor.out_name}/codes-{block_cursor}",
265
+ observed_codes,
266
+ expected_codes,
267
+ )
268
+ stored_scale = (
269
+ output_blocks[:, :2].copy().reshape(-1).view("<f2").astype(np.float32)
270
+ )
271
+ if not np.isfinite(stored_scale).all():
272
+ raise ValueError(f"{tensor.out_name}: non-finite Q8_0 scale")
273
+ codes = output_blocks[:, 2:].view(np.int8).astype(np.float32)
274
+ decoded = stored_scale[:, None] * codes
275
+ denominator = np.maximum(
276
+ np.max(np.abs(reference_blocks), axis=1), np.float32(1e-6)
277
+ )
278
+ relative = np.abs(reference_blocks - decoded) / denominator[:, None]
279
+ if not np.isfinite(relative).all():
280
+ raise ValueError(f"{tensor.out_name}: non-finite Q8_0 error")
281
+ max_relative_error = np.maximum(max_relative_error, np.max(relative))
282
+ block_cursor += block_count
283
+ if block_cursor != encoded.shape[0]:
284
+ raise ValueError(f"{tensor.out_name}: Q8_0 block count mismatch")
285
+ result = float(max_relative_error)
286
+ if result > 0.01:
287
+ raise ValueError(
288
+ f"{tensor.out_name}: Q8_0 max relative error {result:.6f} > 0.01"
289
+ )
290
+ return result
291
+
292
+
293
+ def _expected_mxfp4_codes(packed: np.ndarray, rows: int, cols: int) -> np.ndarray:
294
+ blocks = cols // 32
295
+ packed_blocks = np.asarray(packed, dtype=np.uint8).reshape(rows, blocks, 16)
296
+ low = np.empty((rows, blocks, 16), dtype=np.uint8)
297
+ high = np.empty((rows, blocks, 16), dtype=np.uint8)
298
+ low[..., 0::2] = packed_blocks[..., :8] & np.uint8(0x0F)
299
+ low[..., 1::2] = packed_blocks[..., :8] >> np.uint8(4)
300
+ high[..., 0::2] = packed_blocks[..., 8:] & np.uint8(0x0F)
301
+ high[..., 1::2] = packed_blocks[..., 8:] >> np.uint8(4)
302
+ return low | (high << np.uint8(4))
303
+
304
+
305
+ def _verify_mxfp4(
306
+ source: SafeTensorSet,
307
+ reader: GgufReader,
308
+ tensor: TensorRecipe,
309
+ ) -> None:
310
+ blocks = tensor.cols // 32
311
+ output = reader.tensor_array(reader.tensor(tensor.out_name), np.uint8).reshape(
312
+ N_EXPERTS, tensor.rows, blocks, 17
313
+ )
314
+ for expert in range(N_EXPERTS):
315
+ prefix = f"{tensor.name_prefix}.ffn.experts.{expert}.{tensor.expert_kind}"
316
+ packed = source.array(f"{prefix}.weight", np.uint8)
317
+ scales = source.array(f"{prefix}.scale", np.uint8).reshape(tensor.rows, blocks)
318
+ if np.any(scales == 0xFF):
319
+ raise ValueError(f"{prefix}.scale: contains reserved E8M0 NaN")
320
+ _assert_equal(
321
+ f"{tensor.out_name}/expert-{expert}/scale",
322
+ output[expert, ..., 0],
323
+ scales,
324
+ )
325
+ expected_codes = _expected_mxfp4_codes(packed, tensor.rows, tensor.cols)
326
+ _assert_equal(
327
+ f"{tensor.out_name}/expert-{expert}/codes",
328
+ output[expert, ..., 1:],
329
+ expected_codes,
330
+ )
331
+
332
+
333
+ def _verify_q2_k(
334
+ source: SafeTensorSet,
335
+ reader: GgufReader,
336
+ tensor: TensorRecipe,
337
+ error_limit: float,
338
+ ) -> float:
339
+ blocks_per_row = tensor.cols // 256
340
+ output = reader.tensor_array(reader.tensor(tensor.out_name), np.uint8).reshape(
341
+ N_EXPERTS, tensor.rows, blocks_per_row, 84
342
+ )
343
+ max_relative_error = np.float32(0.0)
344
+ source_scale_blocks = tensor.cols // 32
345
+ for expert in range(N_EXPERTS):
346
+ prefix = f"{tensor.name_prefix}.ffn.experts.{expert}.{tensor.expert_kind}"
347
+ packed = source.array(f"{prefix}.weight", np.uint8).reshape(
348
+ tensor.rows, tensor.cols // 2
349
+ )
350
+ scales = source.array(f"{prefix}.scale", np.uint8).reshape(
351
+ tensor.rows, source_scale_blocks
352
+ )
353
+ for row_start in range(0, tensor.rows, VERIFY_EXPERT_ROW_BATCH):
354
+ row_end = min(row_start + VERIFY_EXPERT_ROW_BATCH, tensor.rows)
355
+ row_count = row_end - row_start
356
+ reference = _decode_source_mxfp4_rows(
357
+ packed[row_start:row_end],
358
+ scales[row_start:row_end],
359
+ row_count,
360
+ tensor.cols,
361
+ ).reshape(-1, 256)
362
+ encoded = output[expert, row_start:row_end].reshape(-1, 84)
363
+ decoded = decode_q2_k_blocks(encoded)
364
+ if not np.isfinite(reference).all() or not np.isfinite(decoded).all():
365
+ raise ValueError(f"{tensor.out_name}: non-finite Q2_K comparison")
366
+ denominator = np.max(np.abs(reference), axis=1)
367
+ absolute_error = np.max(np.abs(reference - decoded), axis=1)
368
+ relative = np.zeros_like(absolute_error)
369
+ np.divide(
370
+ absolute_error,
371
+ denominator,
372
+ out=relative,
373
+ where=denominator != 0,
374
+ )
375
+ relative[np.logical_and(denominator == 0, absolute_error != 0)] = np.inf
376
+ max_relative_error = np.maximum(max_relative_error, np.max(relative))
377
+ result = float(max_relative_error)
378
+ if result > error_limit:
379
+ raise ValueError(
380
+ f"{tensor.out_name}: Q2_K max block-relative error "
381
+ f"{result:.6f} > {error_limit:.6f}"
382
+ )
383
+ return result
384
+
385
+
386
+ def _verify_zero_padding(reader: GgufReader) -> None:
387
+ header_padding = reader.bytes_at(reader.directory_end, reader.data_start)
388
+ if any(header_padding):
389
+ raise ValueError("non-zero GGUF padding before tensor data")
390
+ tensors = reader.tensors
391
+ for index, tensor in enumerate(tensors):
392
+ data_end = tensor.absolute_offset + tensor.byte_len
393
+ next_start = (
394
+ tensors[index + 1].absolute_offset
395
+ if index + 1 < len(tensors)
396
+ else reader.data_start + align_up(tensor.relative_offset + tensor.byte_len)
397
+ )
398
+ padding = reader.bytes_at(data_end, next_start)
399
+ if any(padding):
400
+ raise ValueError(f"non-zero GGUF alignment padding after {tensor.name}")
401
+
402
+
403
+ def verify(
404
+ source_dir: Path,
405
+ gguf_path: Path,
406
+ *,
407
+ recipe: ArtifactRecipe | str | None = None,
408
+ ) -> dict[str, object]:
409
+ artifact_recipe = resolve_recipe(recipe)
410
+ source_dir = source_dir.resolve()
411
+ gguf_path = gguf_path.resolve()
412
+ print("[verify] validating pinned source sizes and SHA-256 values", flush=True)
413
+ sources = verify_source_files(source_dir)
414
+ plan = build_plan(artifact_recipe)
415
+ max_q8_error = 0.0
416
+ max_q2_k_error = 0.0
417
+ exact_f32 = 0
418
+ exact_f16 = 0
419
+ exact_mxfp4 = 0
420
+ q2_k_tensors = 0
421
+ q8_tensors = 0
422
+ with (
423
+ SafeTensorSet(source_paths(source_dir)) as source,
424
+ GgufReader(gguf_path) as reader,
425
+ ):
426
+ source.validate_plan(plan)
427
+ expected_metadata = _expected_metadata()
428
+ if reader.metadata != expected_metadata:
429
+ raise ValueError(
430
+ f"GGUF metadata mismatch: expected {expected_metadata}, found {reader.metadata}"
431
+ )
432
+ observed_names = tuple(tensor.name for tensor in reader.tensors)
433
+ expected_names = tuple(tensor.out_name for tensor in plan)
434
+ if observed_names != expected_names:
435
+ raise ValueError("GGUF tensor order or names do not match the recipe")
436
+ expected_relative_offset = 0
437
+ for recipe_tensor, gguf_tensor in zip(plan, reader.tensors, strict=True):
438
+ if gguf_tensor.relative_offset != expected_relative_offset:
439
+ raise ValueError(
440
+ f"{recipe_tensor.out_name}: expected relative offset "
441
+ f"{expected_relative_offset}, found {gguf_tensor.relative_offset}"
442
+ )
443
+ expected_relative_offset = align_up(
444
+ expected_relative_offset + recipe_tensor.byte_len
445
+ )
446
+ if gguf_tensor.dims != recipe_tensor.dims:
447
+ raise ValueError(
448
+ f"{recipe_tensor.out_name}: expected dims {recipe_tensor.dims}, "
449
+ f"found {gguf_tensor.dims}"
450
+ )
451
+ if gguf_tensor.ggml_type != recipe_tensor.ggml_type:
452
+ raise ValueError(
453
+ f"{recipe_tensor.out_name}: expected type {recipe_tensor.ggml_type}, "
454
+ f"found {gguf_tensor.ggml_type}"
455
+ )
456
+ print(f"[verify] {recipe_tensor.out_name}", flush=True)
457
+ if recipe_tensor.ggml_type == GGML_F32:
458
+ _verify_f32(source, reader, recipe_tensor)
459
+ exact_f32 += 1
460
+ elif recipe_tensor.ggml_type == GGML_F16:
461
+ _verify_markov_f16(source, reader, recipe_tensor)
462
+ exact_f16 += 1
463
+ elif recipe_tensor.ggml_type == GGML_Q8_0:
464
+ q8_tensors += 1
465
+ max_q8_error = max(
466
+ max_q8_error, _verify_q8_0(source, reader, recipe_tensor)
467
+ )
468
+ elif recipe_tensor.ggml_type == GGML_MXFP4:
469
+ _verify_mxfp4(source, reader, recipe_tensor)
470
+ exact_mxfp4 += 1
471
+ elif recipe_tensor.ggml_type == GGML_Q2_K:
472
+ if artifact_recipe.q2_k_error_limit is None:
473
+ raise ValueError(
474
+ f"{artifact_recipe.name}: Q2_K tensor has no error limit"
475
+ )
476
+ q2_k_tensors += 1
477
+ max_q2_k_error = max(
478
+ max_q2_k_error,
479
+ _verify_q2_k(
480
+ source,
481
+ reader,
482
+ recipe_tensor,
483
+ artifact_recipe.q2_k_error_limit,
484
+ ),
485
+ )
486
+ else:
487
+ raise ValueError(f"unsupported GGML type {recipe_tensor.ggml_type}")
488
+ _verify_zero_padding(reader)
489
+ expected_file_size = reader.data_start + align_up(
490
+ plan[-1].byte_len + reader.tensors[-1].relative_offset
491
+ )
492
+ actual_file_size = gguf_path.stat().st_size
493
+ if expected_file_size != artifact_recipe.expected_file_size:
494
+ raise ValueError(
495
+ f"{artifact_recipe.name}: recipe computes file size "
496
+ f"{expected_file_size}, expected {artifact_recipe.expected_file_size}"
497
+ )
498
+ if actual_file_size != expected_file_size:
499
+ raise ValueError(
500
+ f"GGUF size mismatch: expected {expected_file_size}, found {actual_file_size}"
501
+ )
502
+ data_start = reader.data_start
503
+
504
+ all_type_counts = {
505
+ GGML_F32: exact_f32,
506
+ GGML_F16: exact_f16,
507
+ GGML_Q8_0: q8_tensors,
508
+ GGML_Q2_K: q2_k_tensors,
509
+ GGML_MXFP4: exact_mxfp4,
510
+ }
511
+ observed_type_counts = tuple(
512
+ (ggml_type, all_type_counts[ggml_type])
513
+ for ggml_type, _count in artifact_recipe.expected_type_counts
514
+ )
515
+ unexpected_types = {
516
+ ggml_type: count
517
+ for ggml_type, count in all_type_counts.items()
518
+ if count and ggml_type not in dict(artifact_recipe.expected_type_counts)
519
+ }
520
+ if observed_type_counts != artifact_recipe.expected_type_counts or unexpected_types:
521
+ raise ValueError(
522
+ f"unexpected tensor type inventory for {artifact_recipe.name}: "
523
+ f"observed={observed_type_counts}, unexpected={unexpected_types}, "
524
+ f"expected={artifact_recipe.expected_type_counts}"
525
+ )
526
+
527
+ type_report = {
528
+ GGML_TYPE_NAMES[ggml_type]: count
529
+ for ggml_type, count in artifact_recipe.expected_type_counts
530
+ }
531
+ validation: dict[str, object] = {
532
+ "f32_exact_tensors": exact_f32,
533
+ "f16_exact_tensors": exact_f16,
534
+ "q8_0_max_block_relative_error": max_q8_error,
535
+ "q8_0_limit": 0.01,
536
+ "status": "pass",
537
+ }
538
+ if exact_mxfp4:
539
+ validation["mxfp4_exact_tensors"] = exact_mxfp4
540
+ if q2_k_tensors:
541
+ validation.update(
542
+ {
543
+ "q2_k_tensors": q2_k_tensors,
544
+ "q2_k_max_block_relative_error": max_q2_k_error,
545
+ "q2_k_limit": artifact_recipe.q2_k_error_limit,
546
+ }
547
+ )
548
+
549
+ report: dict[str, object] = {
550
+ "artifact": {
551
+ "filename": gguf_path.name,
552
+ "size": gguf_path.stat().st_size,
553
+ "sha256": sha256_path(gguf_path),
554
+ },
555
+ "source": {
556
+ "repository": SOURCE_REPOSITORY,
557
+ "revision": SOURCE_REVISION,
558
+ "files": sources,
559
+ },
560
+ "gguf": {
561
+ "version": 3,
562
+ "data_start": data_start,
563
+ "alignment": ALIGNMENT,
564
+ "tensor_count": len(plan),
565
+ "types": type_report,
566
+ },
567
+ "recipe": artifact_recipe.name,
568
+ "validation": validation,
569
+ }
570
+ print(json.dumps(report, indent=2, sort_keys=True), flush=True)
571
+ return report
572
+
573
+
574
+ def write_report(path: Path, report: dict[str, object]) -> None:
575
+ path.parent.mkdir(parents=True, exist_ok=True)
576
+ temporary = path.with_name(f".{path.name}.partial-{os.getpid()}")
577
+ with temporary.open("w", encoding="utf-8", newline="\n") as handle:
578
+ json.dump(report, handle, indent=2, sort_keys=True)
579
+ handle.write("\n")
580
+ handle.flush()
581
+ os.fsync(handle.fileno())
582
+ os.replace(temporary, path)
583
+
584
+
585
+ def parse_args() -> argparse.Namespace:
586
+ parser = argparse.ArgumentParser(description=__doc__)
587
+ parser.add_argument("--sources", type=Path, required=True)
588
+ parser.add_argument(
589
+ "--recipe",
590
+ choices=sorted(RECIPES),
591
+ default=DEFAULT_RECIPE.name,
592
+ help=f"Artifact recipe (default: {DEFAULT_RECIPE.name})",
593
+ )
594
+ parser.add_argument(
595
+ "--gguf",
596
+ type=Path,
597
+ help="GGUF path (default: the selected recipe's canonical filename)",
598
+ )
599
+ parser.add_argument("--report", type=Path)
600
+ return parser.parse_args()
601
+
602
+
603
+ def main() -> None:
604
+ args = parse_args()
605
+ recipe = resolve_recipe(args.recipe)
606
+ gguf = args.gguf if args.gguf is not None else Path(recipe.output_filename)
607
+ report = verify(args.sources, gguf, recipe=recipe)
608
+ if args.report:
609
+ write_report(args.report, report)
610
+
611
+
612
+ if __name__ == "__main__":
613
+ main()
tests/test_recipe.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ # ruff: noqa: E402
4
+
5
+ import json
6
+ import io
7
+ import struct
8
+ import sys
9
+ import tempfile
10
+ import time
11
+ import unittest
12
+ from pathlib import Path
13
+ from unittest import mock
14
+
15
+ import numpy as np
16
+
17
+ ROOT = Path(__file__).resolve().parents[1]
18
+ sys.path.insert(0, str(ROOT / "scripts"))
19
+
20
+ import convert as convert_module
21
+ from convert import (
22
+ E4M3_TABLE,
23
+ TensorProducer,
24
+ decode_source_mxfp4,
25
+ quantize_q2_k,
26
+ quantize_q8_0,
27
+ repack_mxfp4,
28
+ round_away_from_zero,
29
+ )
30
+ from formats import GgufReader, SafeTensorSet, write_gguf
31
+ from recipe import (
32
+ ARCHITECTURE,
33
+ GGML_Q2_K,
34
+ GGML_F16,
35
+ GGML_F32,
36
+ GGML_MXFP4,
37
+ GGML_Q8_0,
38
+ GGUF_METADATA,
39
+ KIND_PLAIN_F32,
40
+ MXFP4_Q8_0_RECIPE,
41
+ Q2_K_Q8_0_RECIPE,
42
+ TensorRecipe,
43
+ build_plan,
44
+ source_expectations,
45
+ )
46
+ from reproduce import _update_sha256sums
47
+ from verify import decode_q2_k_blocks
48
+
49
+
50
+ class RecipeTests(unittest.TestCase):
51
+ def test_plan_inventory_and_source_coverage(self) -> None:
52
+ mxfp4_plan = build_plan(MXFP4_Q8_0_RECIPE)
53
+ q2_k_plan = build_plan(Q2_K_Q8_0_RECIPE)
54
+ self.assertEqual(len(mxfp4_plan), 81)
55
+ self.assertEqual(len(q2_k_plan), 81)
56
+ mxfp4_counts = {
57
+ kind: sum(tensor.ggml_type == kind for tensor in mxfp4_plan)
58
+ for kind in (GGML_F32, GGML_F16, GGML_Q8_0, GGML_MXFP4)
59
+ }
60
+ self.assertEqual(
61
+ mxfp4_counts,
62
+ {GGML_F32: 45, GGML_F16: 2, GGML_Q8_0: 25, GGML_MXFP4: 9},
63
+ )
64
+ q2_k_counts = {
65
+ kind: sum(tensor.ggml_type == kind for tensor in q2_k_plan)
66
+ for kind in (GGML_F32, GGML_F16, GGML_Q8_0, GGML_Q2_K)
67
+ }
68
+ self.assertEqual(
69
+ q2_k_counts,
70
+ {GGML_F32: 45, GGML_F16: 2, GGML_Q8_0: 25, GGML_Q2_K: 9},
71
+ )
72
+ self.assertEqual(sum(tensor.byte_len for tensor in mxfp4_plan), 10_897_104_284)
73
+ self.assertEqual(sum(tensor.byte_len for tensor in q2_k_plan), 6_971_235_740)
74
+ self.assertEqual(
75
+ tuple((tensor.out_name, tensor.dims) for tensor in q2_k_plan),
76
+ tuple((tensor.out_name, tensor.dims) for tensor in mxfp4_plan),
77
+ )
78
+ inputs = [
79
+ name
80
+ for tensor in mxfp4_plan
81
+ for name, _dtype, _shape in source_expectations(tensor)
82
+ ]
83
+ self.assertEqual(len(inputs), 4_705)
84
+ self.assertEqual(len(set(inputs)), 4_705)
85
+ self.assertEqual(mxfp4_plan[0].out_name, "dspark.0.attn_sinks.weight")
86
+ self.assertEqual(mxfp4_plan[-1].out_name, "dspark.confidence_head.weight")
87
+
88
+ def test_0731_metadata_and_recipe_outputs_are_stable(self) -> None:
89
+ self.assertEqual(ARCHITECTURE, "deepseek_v4_flash_dspark_draft")
90
+ self.assertEqual(
91
+ GGUF_METADATA,
92
+ (
93
+ ("general.architecture", "string", "deepseek_v4_flash_dspark_draft"),
94
+ ("general.name", "string", "DeepSeek-V4-Flash-0731-DSpark-Drafter"),
95
+ (
96
+ "general.source.url",
97
+ "string",
98
+ "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-0731",
99
+ ),
100
+ (
101
+ "general.source.revision",
102
+ "string",
103
+ "9e165c30e2704aec5d9d593cce3eebd58bbef1cb",
104
+ ),
105
+ ("general.license", "string", "MIT"),
106
+ ("dspark.recipe_version", "u32", 1),
107
+ ("dspark.block_size", "u32", 5),
108
+ ("dspark.markov_rank", "u32", 256),
109
+ ("dspark.noise_token_id", "u32", 128_799),
110
+ ("dspark.target_layer_ids", "array_i32", (40, 41, 42)),
111
+ ("dspark.layer_count", "u32", 3),
112
+ ),
113
+ )
114
+ self.assertEqual(
115
+ MXFP4_Q8_0_RECIPE.output_filename,
116
+ "DeepSeek-V4-Flash-0731-DSpark-Drafter-MXFP4-Q8_0.gguf",
117
+ )
118
+ self.assertEqual(
119
+ Q2_K_Q8_0_RECIPE.output_filename,
120
+ "DeepSeek-V4-Flash-0731-DSpark-Drafter-Q2_K-Q8_0.gguf",
121
+ )
122
+ self.assertEqual(MXFP4_Q8_0_RECIPE.expected_file_size, 10_897_110_272)
123
+ self.assertEqual(Q2_K_Q8_0_RECIPE.expected_file_size, 6_971_241_728)
124
+ self.assertEqual(
125
+ Q2_K_Q8_0_RECIPE.expected_file_size
126
+ - Q2_K_Q8_0_RECIPE.expected_tensor_bytes,
127
+ MXFP4_Q8_0_RECIPE.expected_file_size
128
+ - MXFP4_Q8_0_RECIPE.expected_tensor_bytes,
129
+ )
130
+ self.assertEqual(MXFP4_Q8_0_RECIPE.manifest_filename("build"), "build.json")
131
+ self.assertEqual(
132
+ Q2_K_Q8_0_RECIPE.manifest_filename("build"),
133
+ "build-q2_k-q8_0.json",
134
+ )
135
+
136
+ def test_e4m3_known_values(self) -> None:
137
+ self.assertEqual(float(E4M3_TABLE[0x00]), 0.0)
138
+ self.assertEqual(float(E4M3_TABLE[0x01]), 2**-9)
139
+ self.assertEqual(float(E4M3_TABLE[0x38]), 1.0)
140
+ self.assertEqual(float(E4M3_TABLE[0x40]), 2.0)
141
+ self.assertEqual(float(E4M3_TABLE[0xB8]), -1.0)
142
+ self.assertTrue(np.isnan(E4M3_TABLE[0x7F]))
143
+
144
+ def test_q8_rounds_half_away_from_zero(self) -> None:
145
+ values = np.zeros(32, dtype=np.float32)
146
+ values[:5] = [127.0, 0.5, 1.5, -0.5, -1.5]
147
+ encoded = quantize_q8_0(values)
148
+ scale = encoded[0, :2].copy().view("<f2")[0]
149
+ codes = encoded[0, 2:].view(np.int8)
150
+ self.assertEqual(float(scale), 1.0)
151
+ np.testing.assert_array_equal(codes[:5], [127, 1, 2, -1, -2])
152
+
153
+ def test_q8_rounding_does_not_promote_values_below_half(self) -> None:
154
+ below_half = np.nextafter(np.float32(0.5), np.float32(0.0), dtype=np.float32)
155
+ values = np.array(
156
+ [below_half, -below_half, np.float32(0.5), np.float32(-0.5)],
157
+ dtype=np.float32,
158
+ )
159
+ np.testing.assert_array_equal(
160
+ round_away_from_zero(values),
161
+ np.array([0.0, -0.0, 1.0, -1.0], dtype=np.float32),
162
+ )
163
+
164
+ def test_mxfp4_low16_high16_layout_and_nan_rejection(self) -> None:
165
+ codes = np.arange(32, dtype=np.uint8) & np.uint8(0x0F)
166
+ packed = codes[0::2] | (codes[1::2] << np.uint8(4))
167
+ encoded = repack_mxfp4(packed, np.array([127], dtype=np.uint8), 1, 32)
168
+ self.assertEqual(int(encoded[0, 0, 0]), 127)
169
+ expected = codes[:16] | (codes[16:] << np.uint8(4))
170
+ np.testing.assert_array_equal(encoded[0, 0, 1:], expected)
171
+ with self.assertRaisesRegex(ValueError, "0xff"):
172
+ repack_mxfp4(packed, np.array([0xFF], dtype=np.uint8), 1, 32)
173
+
174
+ def test_q2_k_matches_ds4_reference_block_and_decodes_independently(self) -> None:
175
+ values = np.empty((1, 256), dtype=np.float32)
176
+ for index in range(256):
177
+ raw = ((index * 37) % 31) - 15
178
+ multiplier = 1 << ((index // 16) % 4)
179
+ values[0, index] = (
180
+ np.float32(0.0)
181
+ if index % 19 == 0
182
+ else np.float32(raw) * np.float32(multiplier) * np.float32(0.125)
183
+ )
184
+ expected = bytes.fromhex(
185
+ "123357ee124467fe124357ef124467ff"
186
+ "9194e9294e8294e4294e8294d4294e42"
187
+ "e4e9ba4e93a4e93a4e9b94e5394e53a4"
188
+ "4e8294e4694d8294e4294e4690d4294d9"
189
+ "3a4e53a4f5394a53a4f5394e5fa7b5fe038193c"
190
+ )
191
+ encoded = quantize_q2_k(values)
192
+ self.assertEqual(encoded.tobytes(), expected)
193
+ self.assertEqual(encoded[0, :16].tobytes(), expected[:16])
194
+ decoded = decode_q2_k_blocks(encoded)
195
+ relative_error = np.max(np.abs(values - decoded)) / np.max(np.abs(values))
196
+ self.assertLess(float(relative_error), Q2_K_Q8_0_RECIPE.q2_k_error_limit)
197
+
198
+ batched = quantize_q2_k(np.concatenate((values, -values), axis=0))
199
+ separate = np.concatenate(
200
+ (quantize_q2_k(values), quantize_q2_k(-values)), axis=0
201
+ )
202
+ np.testing.assert_array_equal(batched, separate)
203
+
204
+ def test_threaded_q2_experts_are_written_in_canonical_order(self) -> None:
205
+ rows = 1
206
+ cols = 256
207
+
208
+ def source_arrays(expert: int) -> tuple[np.ndarray, np.ndarray]:
209
+ codes = (np.arange(cols, dtype=np.uint16) + expert * 3).astype(np.uint8)
210
+ codes &= np.uint8(0x0F)
211
+ packed = codes[0::2] | (codes[1::2] << np.uint8(4))
212
+ scales = np.full(cols // 32, 127 + expert, dtype=np.uint8)
213
+ return packed, scales
214
+
215
+ class DelayedSource:
216
+ def array(self, name: str, _dtype: object) -> np.ndarray:
217
+ expert = int(name.split(".experts.", 1)[1].split(".", 1)[0])
218
+ packed, scales = source_arrays(expert)
219
+ if name.endswith(".weight"):
220
+ # Later experts finish first, exercising ordered futures.
221
+ time.sleep(0.01 * (3 - expert))
222
+ return packed
223
+ return scales
224
+
225
+ tensor = TensorRecipe(
226
+ out_name="dspark.test.ffn_gate_exps.weight",
227
+ kind=convert_module.KIND_FUSED_EXPERTS_Q2_K,
228
+ dims=(cols, rows, 4),
229
+ ggml_type=GGML_Q2_K,
230
+ rows=rows,
231
+ cols=cols,
232
+ name_prefix="mtp.blocks.40",
233
+ expert_kind="w1",
234
+ )
235
+ output = io.BytesIO()
236
+ with (
237
+ mock.patch.object(convert_module, "N_EXPERTS", 4),
238
+ mock.patch.object(convert_module, "Q2_K_EXPERT_WORKERS", 4),
239
+ ):
240
+ written = TensorProducer(DelayedSource())._fused_experts_q2_k(
241
+ tensor, output
242
+ )
243
+
244
+ expected = bytearray()
245
+ for expert in range(4):
246
+ packed, scales = source_arrays(expert)
247
+ decoded = decode_source_mxfp4(packed, scales, rows, cols)
248
+ expected.extend(quantize_q2_k(decoded).tobytes(order="C"))
249
+ self.assertEqual(written, 4 * 84)
250
+ self.assertEqual(output.getvalue(), bytes(expected))
251
+
252
+ def test_sha256sums_update_preserves_other_recipe(self) -> None:
253
+ with tempfile.TemporaryDirectory() as directory:
254
+ path = Path(directory) / "SHA256SUMS"
255
+ legacy_digest = "1" * 64
256
+ q2_digest = "2" * 64
257
+ _update_sha256sums(path, legacy_digest, "legacy.gguf")
258
+ _update_sha256sums(path, q2_digest, "q2.gguf")
259
+ self.assertEqual(
260
+ path.read_text(encoding="ascii"),
261
+ f"{legacy_digest} legacy.gguf\n{q2_digest} q2.gguf\n",
262
+ )
263
+
264
+ def test_tiny_gguf_round_trip(self) -> None:
265
+ tensor = TensorRecipe(
266
+ out_name="dspark.test.weight",
267
+ kind=KIND_PLAIN_F32,
268
+ dims=(4,),
269
+ ggml_type=GGML_F32,
270
+ src_name="mtp.test",
271
+ src_shape=(4,),
272
+ )
273
+ data = struct.pack("<4f", 1.0, 2.0, 3.0, 4.0)
274
+ with tempfile.TemporaryDirectory() as directory:
275
+ path = Path(directory) / "tiny.gguf"
276
+
277
+ def produce(_tensor: TensorRecipe, handle: object) -> int:
278
+ return handle.write(data)
279
+
280
+ write_gguf(path, (tensor,), produce)
281
+ with GgufReader(path) as reader:
282
+ self.assertEqual(reader.tensors[0].name, tensor.out_name)
283
+ self.assertEqual(reader.tensors[0].dims, tensor.dims)
284
+ self.assertEqual(reader.tensors[0].ggml_type, GGML_F32)
285
+ observed = reader.tensor_array(reader.tensors[0], "<f4").copy()
286
+ np.testing.assert_array_equal(observed, [1.0, 2.0, 3.0, 4.0])
287
+ self.assertEqual(path.stat().st_size % 32, 0)
288
+
289
+ def test_safetensors_rejects_bad_offsets(self) -> None:
290
+ with tempfile.TemporaryDirectory() as directory:
291
+ path = Path(directory) / "bad.safetensors"
292
+ header = {
293
+ "mtp.bad": {
294
+ "dtype": "F32",
295
+ "shape": [1],
296
+ "data_offsets": [0, 8],
297
+ }
298
+ }
299
+ encoded = json.dumps(header, separators=(",", ":")).encode()
300
+ path.write_bytes(struct.pack("<Q", len(encoded)) + encoded + b"\0" * 4)
301
+ with self.assertRaisesRegex(ValueError, "overruns|needs"):
302
+ SafeTensorSet([path])
303
+
304
+
305
+ if __name__ == "__main__":
306
+ unittest.main()