Instructions to use brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Trellis
How to use brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78 with Trellis:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Document and validate BF16-shared online K6 revision
Browse files## Summary
Follow up the BF16-shared checkpoint revision with reproducible lineage,
independent runtime evidence, focused converter tests, and two metadata
corrections. This PR does not replace or upload any model shard.
## Metadata corrections
- Set safetensors `metadata.total_size` to **346,196,508,248**, the sum of all
186,905 tensor payloads parsed from the 157 shard headers. The current value
is 22,130,880 bytes too high.
- Preserve the old R7 assembly manifest as `SOURCE_R7_MANIFEST.json` and remove
its stale seals. It describes the parent layout (187,580 tensors and 75
rewritten carriers through layer 77), not the current BF16-shared layout
(186,905 tensors and 76 carriers through layer 78).
## Reproducibility and validation
- Add the source/donor revisions, hashes, central-shard identity, byte
accounting, validation totals, and an exact 228-tensor comparison of the
canonical central shard against the pinned BF16 donor.
- Add a converter matching the canonical central-shard layout and focused
tests for carrier rewriting, metadata ownership, and manifest lifecycle.
- Record the independent TP4 MTP0/MTP3, prefill, CUDA-graph, memory, and paired
KLD validation that motivated the canonical revision.
Checks: **3 passed**; Ruff check and format passed; all JSON parsed; the
corrected `total_size` was independently recomputed from every safetensors
header.
This supersedes PR #2, which was uploaded from the old parent concurrently
with the canonical BF16-shared commit and therefore conflicts with it.
- .manifest_verified +0 -1
- BF16_SHARED_ONLINE_K6_VALIDATION.md +126 -0
- R7_BF16_SHARED_DERIVATION.json +33 -0
- README.md +4 -0
- MANIFEST.json → SOURCE_R7_MANIFEST.json +0 -0
- MANIFEST.sha256 → SOURCE_R7_MANIFEST.sha256 +1 -1
- model.safetensors.index.json +2 -2
- reproducibility/bf16-shared/build_shared_bf16_revision.py +368 -0
- reproducibility/bf16-shared/independent-kld-summary.json +66 -0
- reproducibility/bf16-shared/test_build_shared_bf16_revision.py +105 -0
|
@@ -1 +0,0 @@
|
|
| 1 |
-
bfb6dc39f28da08c1cfc5b89603414046adf7003152d69e9ee350e11f7a1fa63
|
|
|
|
|
|
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BF16 shared experts with runtime-merged K6
|
| 2 |
+
|
| 3 |
+
Date: 2026-08-10
|
| 4 |
+
|
| 5 |
+
## Canonical checkpoint layout
|
| 6 |
+
|
| 7 |
+
Revision `9ab9579774cc432df91567a36f6e9e863e0d4c9f` keeps the routed R7
|
| 8 |
+
K3/K4/K5 expert payload and rotations unchanged. It removes the separate
|
| 9 |
+
shared-expert K6 payloads from layers 3-77 and moves all original BF16 shared
|
| 10 |
+
experts from layers 3-78 into one `model-sharedbf16.safetensors` shard.
|
| 11 |
+
|
| 12 |
+
Header-only safetensors inspection of that revision found:
|
| 13 |
+
|
| 14 |
+
| Check | Result |
|
| 15 |
+
|---|---:|
|
| 16 |
+
| BF16 shared tensors | 228 |
|
| 17 |
+
| Covered layers | 3-78 |
|
| 18 |
+
| Non-BF16 or unexpected tensors | 0 |
|
| 19 |
+
| Tensor payload bytes | 5,737,807,872 |
|
| 20 |
+
| Central shard file bytes | 5,737,837,256 |
|
| 21 |
+
| Central shard SHA-256 | `ee1e7d9b2adb5d49c0895dc2f4b7d6d424b108cdb796879eee4c55d040408c6a` |
|
| 22 |
+
|
| 23 |
+
The canonical central shard was also downloaded at the pinned revision and
|
| 24 |
+
all 228 tensors were compared element-for-element with the pinned BF16 donor.
|
| 25 |
+
Every tensor matched.
|
| 26 |
+
|
| 27 |
+
The runtime concatenates each BF16 gate/up pair before online K6 encoding, so
|
| 28 |
+
it executes one merged `gate_up_proj` instead of two separately encoded
|
| 29 |
+
matrices. The first load writes a content-addressed cache; warm loads reuse it.
|
| 30 |
+
|
| 31 |
+
## Independent runtime validation
|
| 32 |
+
|
| 33 |
+
The independent POC used the same 228 BF16 tensors and the same runtime tensor
|
| 34 |
+
map. Its only physical difference was storing layers 3-77 back in their layer
|
| 35 |
+
carrier shards; physical shard placement does not change loaded tensors or
|
| 36 |
+
kernel selection.
|
| 37 |
+
|
| 38 |
+
All 228 BF16 tensors in the independent POC were also compared exactly with
|
| 39 |
+
`willfalco/GLM-5.2-EXL3-TR3-3.42bpw@a350292cb2038f2c31732569a711a89e5d72fd46`
|
| 40 |
+
and an independent 3.25 bpw lineage checkpoint. The conversion replaced 225
|
| 41 |
+
prequantized tensors in layers 3-77 and validated the three existing BF16
|
| 42 |
+
tensors in layer 78.
|
| 43 |
+
|
| 44 |
+
A clean TP4 load encoded exactly 300 merged `gate_up_proj` and 300 `down_proj`
|
| 45 |
+
matrices: 75 routed layers on four ranks. Warm restarts performed zero encodes.
|
| 46 |
+
MTP0 and MTP3 both produced coherent output.
|
| 47 |
+
|
| 48 |
+
### MTP0 decode
|
| 49 |
+
|
| 50 |
+
Four RTX PRO 6000 Blackwell GPUs on independent PCIe root ports, TP4/DCP1,
|
| 51 |
+
A16, online K6, NVFP4 DS-MLA KV, 20-second sustained runs:
|
| 52 |
+
|
| 53 |
+
| Concurrency | Separate shared K6 | BF16 + merged K6 | Delta |
|
| 54 |
+
|---:|---:|---:|---:|
|
| 55 |
+
| C1 | 50.62 tok/s | 53.67 tok/s | +6.0% |
|
| 56 |
+
| C4 | 157.34 tok/s | 170.04 tok/s | +8.1% |
|
| 57 |
+
| C8 | 258.81 tok/s | 279.75 tok/s | +8.1% |
|
| 58 |
+
|
| 59 |
+
A separate 40-second C1 run measured 54.03 tok/s. This controlled MTP0 A/B
|
| 60 |
+
isolates the merged shared-expert change.
|
| 61 |
+
|
| 62 |
+
### Prefill
|
| 63 |
+
|
| 64 |
+
| Prompt | Separate shared K6 | BF16 + merged K6 | Delta |
|
| 65 |
+
|---:|---:|---:|---:|
|
| 66 |
+
| 8.2k | 3,280 tok/s | 3,265 tok/s | -0.5% |
|
| 67 |
+
| 64.4k | 3,034 tok/s | 3,254 tok/s | +7.3% |
|
| 68 |
+
|
| 69 |
+
The 8k result is parity. Each 64k value is one long sample, so that uplift is
|
| 70 |
+
indicative rather than a standalone release claim.
|
| 71 |
+
|
| 72 |
+
### Quality
|
| 73 |
+
|
| 74 |
+
The paired 2,047-position full-vocabulary test used the same BF16 teacher, FP8
|
| 75 |
+
KV cache, and three repeats per candidate.
|
| 76 |
+
|
| 77 |
+
| Candidate | Mean KLD | Run SD |
|
| 78 |
+
|---|---:|---:|
|
| 79 |
+
| Original R7 + online K6 | 0.064467 | 0.001973 |
|
| 80 |
+
| BF16 source + online K6 | 0.065339 | 0.001285 |
|
| 81 |
+
|
| 82 |
+
The absolute mean difference is 0.000873, smaller than observed run-to-run
|
| 83 |
+
variation, and the run distributions overlap. This independent gate found no
|
| 84 |
+
measurable quality regression from the BF16-source merge. The repository README
|
| 85 |
+
also records the canonical revision's separate five-run KLD gate.
|
| 86 |
+
|
| 87 |
+
### CUDA graphs and memory
|
| 88 |
+
|
| 89 |
+
- MTP0 target steps were captured in full CUDA graphs.
|
| 90 |
+
- MTP3 target verification and all three draft forwards were captured in full
|
| 91 |
+
CUDA graphs, with no eager fallback in the trace.
|
| 92 |
+
- No new host synchronization or K6 bottleneck appeared.
|
| 93 |
+
- At a 65,536-token model limit, MTP0 at GMU 0.97 exposed 79,104 KV tokens.
|
| 94 |
+
- MTP3 at GMU 0.98 exposed 75,072 KV tokens.
|
| 95 |
+
|
| 96 |
+
## Metadata correction
|
| 97 |
+
|
| 98 |
+
The first BF16-shared commit wrote `metadata.total_size=346218639128` in the
|
| 99 |
+
safetensors index. Parsing all 157 safetensors headers gives exactly
|
| 100 |
+
`346196508248` tensor payload bytes, a difference of 22,130,880 bytes. The
|
| 101 |
+
follow-up uses the computed tensor-byte value.
|
| 102 |
+
|
| 103 |
+
The old `MANIFEST.json` describes the parent R7 assembly: 187,580 tensors and
|
| 104 |
+
75 rewritten carriers ending at layer 77. The BF16-shared revision has 186,905
|
| 105 |
+
tensors and rewrites 76 carriers through layer 78. Rather than silently mutate
|
| 106 |
+
the old schema, the follow-up preserves it as `SOURCE_R7_MANIFEST.json` and
|
| 107 |
+
removes its no-longer-current verification seals.
|
| 108 |
+
|
| 109 |
+
## Reproduction
|
| 110 |
+
|
| 111 |
+
The converter and focused tests are under `reproducibility/bf16-shared/`:
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
python reproducibility/bf16-shared/build_shared_bf16_revision.py \
|
| 115 |
+
--source /path/to/parent-c55c1cd \
|
| 116 |
+
--source-repo-id brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78 \
|
| 117 |
+
--source-revision c55c1cd4ca4216c27b0dddb51a4c6757c1765d1e \
|
| 118 |
+
--donor /path/to/GLM-5.2-EXL3-TR3-3.42bpw \
|
| 119 |
+
--donor-repo-id willfalco/GLM-5.2-EXL3-TR3-3.42bpw \
|
| 120 |
+
--donor-revision a350292cb2038f2c31732569a711a89e5d72fd46 \
|
| 121 |
+
--output /path/to/output
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
Serve through the compatible Gilded Gnosis R7 helper with
|
| 125 |
+
`MODEL_FAMILY=glm52-exl3`, `QUANTIZATION=exl3`, and
|
| 126 |
+
`ONLINE_QUANT=exl3-b6`. Keep `JIT_CACHE` persistent.
|
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"added_bf16_tensor_bytes": 5737807872,
|
| 3 |
+
"canonical_revision": "9ab9579774cc432df91567a36f6e9e863e0d4c9f",
|
| 4 |
+
"canonical_tensors_compared_to_donor": 228,
|
| 5 |
+
"central_shard": {
|
| 6 |
+
"file_bytes": 5737837256,
|
| 7 |
+
"path": "model-sharedbf16.safetensors",
|
| 8 |
+
"sha256": "ee1e7d9b2adb5d49c0895dc2f4b7d6d424b108cdb796879eee4c55d040408c6a",
|
| 9 |
+
"tensor_bytes": 5737807872,
|
| 10 |
+
"tensors": 228
|
| 11 |
+
},
|
| 12 |
+
"donor_config_sha256": "7d42e3a21873412b39c3741e5b9166362d25b05f40c0e66a968e79d422c7dea1",
|
| 13 |
+
"donor_index_sha256": "b34398df3830a13d23e25a9582112d38f7da982a48d50b95bc7e0867c94e9fdc",
|
| 14 |
+
"donor_repo_id": "willfalco/GLM-5.2-EXL3-TR3-3.42bpw",
|
| 15 |
+
"donor_revision": "a350292cb2038f2c31732569a711a89e5d72fd46",
|
| 16 |
+
"indexed_tensors": 186905,
|
| 17 |
+
"output_tensor_bytes": 346196508248,
|
| 18 |
+
"removed_source_shared_tensor_bytes": 2202551172,
|
| 19 |
+
"replaced_layers": "3-78",
|
| 20 |
+
"replaced_projections": ["down_proj", "gate_proj", "up_proj"],
|
| 21 |
+
"runtime_intent": "ONLINE_QUANT=exl3-b6",
|
| 22 |
+
"source_config_sha256": "a231e816fb3495a33ba4f89b5cb7d2ffc86f0c66f71a42a0e792dead3868bf5c",
|
| 23 |
+
"source_index_sha256": "3077bb6d01f0831c62775d0504b06c45989d2efe8fec944ab50ed911902e5678",
|
| 24 |
+
"source_manifest_sha256": "df2f4c87b22c21c5234ef216149f5b5adc556820bb97ae4bc6dd7f4f0647b8db",
|
| 25 |
+
"source_repo_id": "brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78",
|
| 26 |
+
"source_revision": "c55c1cd4ca4216c27b0dddb51a4c6757c1765d1e",
|
| 27 |
+
"validation": {
|
| 28 |
+
"bf16_shared_tensors": 228,
|
| 29 |
+
"covered_layers": [3, 78],
|
| 30 |
+
"non_bf16_or_unexpected_tensors": 0,
|
| 31 |
+
"stale_shared_exl3_records": 0
|
| 32 |
+
}
|
| 33 |
+
}
|
|
@@ -100,6 +100,10 @@ The pre-update revision remains available at
|
|
| 100 |
[`c55c1cd4ca42`](https://huggingface.co/brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78/tree/c55c1cd4ca4216c27b0dddb51a4c6757c1765d1e)
|
| 101 |
if you need the old offline-encoded shared payloads.
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
## Run it
|
| 104 |
|
| 105 |
Docker image (public on Docker Hub):
|
|
|
|
| 100 |
[`c55c1cd4ca42`](https://huggingface.co/brandonmusic/GLM-5.2-EXL3-TR3v4-3.5bpw-MTP78/tree/c55c1cd4ca4216c27b0dddb51a4c6757c1765d1e)
|
| 101 |
if you need the old offline-encoded shared payloads.
|
| 102 |
|
| 103 |
+
The exact source lineage, independent TP4 validation, conversion tool, and
|
| 104 |
+
focused tests are recorded in
|
| 105 |
+
[BF16_SHARED_ONLINE_K6_VALIDATION.md](./BF16_SHARED_ONLINE_K6_VALIDATION.md).
|
| 106 |
+
|
| 107 |
## Run it
|
| 108 |
|
| 109 |
Docker image (public on Docker Hub):
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
| 1 |
-
df2f4c87b22c21c5234ef216149f5b5adc556820bb97ae4bc6dd7f4f0647b8db
|
|
|
|
| 1 |
+
df2f4c87b22c21c5234ef216149f5b5adc556820bb97ae4bc6dd7f4f0647b8db SOURCE_R7_MANIFEST.json
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:20ed38193742d442a5ba444b07945527d49b5d68f152aa88131adf668ca54727
|
| 3 |
+
size 16284634
|
|
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Build the R7 BF16-shared checkpoint from its parent and BF16 donor."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import copy
|
| 8 |
+
import hashlib
|
| 9 |
+
import json
|
| 10 |
+
import os
|
| 11 |
+
import shutil
|
| 12 |
+
import tempfile
|
| 13 |
+
from datetime import datetime, timezone
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
from typing import Any
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from safetensors import safe_open
|
| 19 |
+
from safetensors.torch import save_file
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
PROJECTIONS = ("down_proj", "gate_proj", "up_proj")
|
| 23 |
+
SHARED_LAYERS = tuple(range(3, 79))
|
| 24 |
+
QUANTIZED_SHARED_LAYERS = tuple(range(3, 78))
|
| 25 |
+
CENTRAL_SHARD = "model-sharedbf16.safetensors"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _json(path: Path) -> dict[str, Any]:
|
| 29 |
+
with path.open(encoding="utf-8") as handle:
|
| 30 |
+
return json.load(handle)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _atomic_json(path: Path, value: Any) -> None:
|
| 34 |
+
fd, temporary_name = tempfile.mkstemp(
|
| 35 |
+
dir=path.parent, prefix=f".{path.name}.", suffix=".tmp"
|
| 36 |
+
)
|
| 37 |
+
try:
|
| 38 |
+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
| 39 |
+
json.dump(value, handle, indent=1)
|
| 40 |
+
handle.write("\n")
|
| 41 |
+
os.replace(temporary_name, path)
|
| 42 |
+
except BaseException:
|
| 43 |
+
try:
|
| 44 |
+
os.unlink(temporary_name)
|
| 45 |
+
except FileNotFoundError:
|
| 46 |
+
pass
|
| 47 |
+
raise
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def _atomic_text(path: Path, value: str) -> None:
|
| 51 |
+
fd, temporary_name = tempfile.mkstemp(
|
| 52 |
+
dir=path.parent, prefix=f".{path.name}.", suffix=".tmp"
|
| 53 |
+
)
|
| 54 |
+
try:
|
| 55 |
+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
| 56 |
+
handle.write(value)
|
| 57 |
+
os.replace(temporary_name, path)
|
| 58 |
+
except BaseException:
|
| 59 |
+
try:
|
| 60 |
+
os.unlink(temporary_name)
|
| 61 |
+
except FileNotFoundError:
|
| 62 |
+
pass
|
| 63 |
+
raise
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def _sha256(path: Path) -> str:
|
| 67 |
+
digest = hashlib.sha256()
|
| 68 |
+
with path.open("rb") as handle:
|
| 69 |
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
| 70 |
+
digest.update(chunk)
|
| 71 |
+
return digest.hexdigest()
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _shared_prefix(layer: int) -> str:
|
| 75 |
+
return f"model.layers.{layer}.mlp.shared_experts."
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def _bf16_names(layer: int) -> tuple[str, ...]:
|
| 79 |
+
prefix = _shared_prefix(layer)
|
| 80 |
+
return tuple(f"{prefix}{projection}.weight" for projection in PROJECTIONS)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def _copy_tree_with_hardlinked_weights(source: Path, output: Path) -> None:
|
| 84 |
+
if output.exists():
|
| 85 |
+
raise FileExistsError(f"output already exists: {output}")
|
| 86 |
+
if (source / CENTRAL_SHARD).exists():
|
| 87 |
+
raise ValueError("source already contains the BF16 shared shard")
|
| 88 |
+
output.mkdir(parents=True)
|
| 89 |
+
for source_path in source.rglob("*"):
|
| 90 |
+
relative = source_path.relative_to(source)
|
| 91 |
+
output_path = output / relative
|
| 92 |
+
if source_path.is_dir():
|
| 93 |
+
output_path.mkdir(exist_ok=True)
|
| 94 |
+
elif source_path.suffix == ".safetensors":
|
| 95 |
+
os.link(source_path, output_path)
|
| 96 |
+
else:
|
| 97 |
+
shutil.copy2(source_path, output_path)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def _strip_shared_from_carrier(
|
| 101 |
+
*, layer: int, source_file: Path, output_file: Path
|
| 102 |
+
) -> tuple[list[str], int]:
|
| 103 |
+
prefix = _shared_prefix(layer)
|
| 104 |
+
expected = 12 if layer in QUANTIZED_SHARED_LAYERS else 3
|
| 105 |
+
with safe_open(source_file, framework="pt", device="cpu") as handle:
|
| 106 |
+
keys = list(handle.keys())
|
| 107 |
+
removed = [key for key in keys if key.startswith(prefix)]
|
| 108 |
+
if len(removed) != expected:
|
| 109 |
+
raise ValueError(
|
| 110 |
+
f"layer {layer}: expected {expected} shared tensors, "
|
| 111 |
+
f"found {len(removed)}"
|
| 112 |
+
)
|
| 113 |
+
tensors = {
|
| 114 |
+
key: handle.get_tensor(key) for key in keys if not key.startswith(prefix)
|
| 115 |
+
}
|
| 116 |
+
removed_bytes = sum(
|
| 117 |
+
handle.get_tensor(key).numel() * handle.get_tensor(key).element_size()
|
| 118 |
+
for key in removed
|
| 119 |
+
)
|
| 120 |
+
metadata = handle.metadata()
|
| 121 |
+
|
| 122 |
+
temporary = output_file.with_name(f".{output_file.name}.rewrite.tmp")
|
| 123 |
+
try:
|
| 124 |
+
save_file(tensors, temporary, metadata=metadata)
|
| 125 |
+
os.replace(temporary, output_file)
|
| 126 |
+
finally:
|
| 127 |
+
temporary.unlink(missing_ok=True)
|
| 128 |
+
return removed, removed_bytes
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def _load_donor_shared(
|
| 132 |
+
donor: Path, donor_weight_map: dict[str, str]
|
| 133 |
+
) -> dict[str, torch.Tensor]:
|
| 134 |
+
wanted = {name for layer in SHARED_LAYERS for name in _bf16_names(layer)}
|
| 135 |
+
by_file: dict[str, list[str]] = {}
|
| 136 |
+
for name in wanted:
|
| 137 |
+
by_file.setdefault(donor_weight_map[name], []).append(name)
|
| 138 |
+
|
| 139 |
+
tensors: dict[str, torch.Tensor] = {}
|
| 140 |
+
for file_name, names in sorted(by_file.items()):
|
| 141 |
+
with safe_open(donor / file_name, framework="pt", device="cpu") as handle:
|
| 142 |
+
for name in sorted(names):
|
| 143 |
+
tensor = handle.get_tensor(name)
|
| 144 |
+
if tensor.dtype != torch.bfloat16:
|
| 145 |
+
raise TypeError(f"{name} is {tensor.dtype}, expected bfloat16")
|
| 146 |
+
tensors[name] = tensor
|
| 147 |
+
if len(tensors) != len(SHARED_LAYERS) * len(PROJECTIONS):
|
| 148 |
+
raise ValueError(f"expected 228 donor tensors, found {len(tensors)}")
|
| 149 |
+
return tensors
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def _patch_config(
|
| 153 |
+
source_config: dict[str, Any],
|
| 154 |
+
*,
|
| 155 |
+
quantized_shared_layers: tuple[int, ...] = QUANTIZED_SHARED_LAYERS,
|
| 156 |
+
) -> dict[str, Any]:
|
| 157 |
+
config = copy.deepcopy(source_config)
|
| 158 |
+
storage = config["quantization_config"]["tensor_storage"]
|
| 159 |
+
removed = [
|
| 160 |
+
key
|
| 161 |
+
for key in storage
|
| 162 |
+
if ".mlp.shared_experts." in key
|
| 163 |
+
and int(key.split(".layers.", 1)[1].split(".", 1)[0]) in quantized_shared_layers
|
| 164 |
+
]
|
| 165 |
+
if len(removed) != len(quantized_shared_layers) * len(PROJECTIONS):
|
| 166 |
+
raise ValueError(f"expected 225 shared storage records, found {len(removed)}")
|
| 167 |
+
for key in removed:
|
| 168 |
+
del storage[key]
|
| 169 |
+
return config
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def _archive_source_manifest(output: Path) -> str | None:
|
| 173 |
+
manifest = output / "MANIFEST.json"
|
| 174 |
+
if not manifest.exists():
|
| 175 |
+
(output / "MANIFEST.sha256").unlink(missing_ok=True)
|
| 176 |
+
(output / ".manifest_verified").unlink(missing_ok=True)
|
| 177 |
+
return None
|
| 178 |
+
|
| 179 |
+
digest = _sha256(manifest)
|
| 180 |
+
archived = output / "SOURCE_R7_MANIFEST.json"
|
| 181 |
+
manifest.replace(archived)
|
| 182 |
+
_atomic_text(
|
| 183 |
+
output / "SOURCE_R7_MANIFEST.sha256",
|
| 184 |
+
f"{digest} {archived.name}\n",
|
| 185 |
+
)
|
| 186 |
+
(output / "MANIFEST.sha256").unlink(missing_ok=True)
|
| 187 |
+
(output / ".manifest_verified").unlink(missing_ok=True)
|
| 188 |
+
return digest
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def _actual_weight_map(checkpoint: Path) -> tuple[dict[str, str], int]:
|
| 192 |
+
weight_map: dict[str, str] = {}
|
| 193 |
+
tensor_bytes = 0
|
| 194 |
+
for shard in sorted(checkpoint.glob("*.safetensors")):
|
| 195 |
+
with safe_open(shard, framework="pt", device="cpu") as handle:
|
| 196 |
+
for key in handle.keys():
|
| 197 |
+
previous = weight_map.setdefault(key, shard.name)
|
| 198 |
+
if previous != shard.name:
|
| 199 |
+
raise ValueError(f"tensor {key} occurs in two shards")
|
| 200 |
+
tensor = handle.get_tensor(key)
|
| 201 |
+
tensor_bytes += tensor.numel() * tensor.element_size()
|
| 202 |
+
return weight_map, tensor_bytes
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def _validate(*, source: Path, donor: Path, output: Path) -> dict[str, int]:
|
| 206 |
+
source_config = _json(source / "config.json")
|
| 207 |
+
output_config = _json(output / "config.json")
|
| 208 |
+
if (
|
| 209 |
+
source_config["quantization_config"]["r7_routed_experts"]
|
| 210 |
+
!= output_config["quantization_config"]["r7_routed_experts"]
|
| 211 |
+
):
|
| 212 |
+
raise ValueError("r7_routed_experts metadata changed")
|
| 213 |
+
if output_config["quantization_config"] != _json(
|
| 214 |
+
output / "quantization_config.json"
|
| 215 |
+
):
|
| 216 |
+
raise ValueError("embedded and standalone quantization configs differ")
|
| 217 |
+
|
| 218 |
+
stale_storage = [
|
| 219 |
+
key
|
| 220 |
+
for key in output_config["quantization_config"]["tensor_storage"]
|
| 221 |
+
if ".mlp.shared_experts." in key
|
| 222 |
+
]
|
| 223 |
+
if stale_storage:
|
| 224 |
+
raise ValueError(f"stale shared storage entries: {stale_storage[:4]}")
|
| 225 |
+
|
| 226 |
+
index = _json(output / "model.safetensors.index.json")
|
| 227 |
+
actual, tensor_bytes = _actual_weight_map(output)
|
| 228 |
+
if index["weight_map"] != actual:
|
| 229 |
+
raise ValueError("safetensors index does not match checkpoint files")
|
| 230 |
+
if index["metadata"]["total_size"] != tensor_bytes:
|
| 231 |
+
raise ValueError("index total_size does not equal tensor payload bytes")
|
| 232 |
+
|
| 233 |
+
shared = {
|
| 234 |
+
key: file_name
|
| 235 |
+
for key, file_name in actual.items()
|
| 236 |
+
if ".mlp.shared_experts." in key
|
| 237 |
+
}
|
| 238 |
+
if len(shared) != 228 or set(shared.values()) != {CENTRAL_SHARD}:
|
| 239 |
+
raise ValueError("shared experts are not isolated in the central shard")
|
| 240 |
+
|
| 241 |
+
donor_map = _json(donor / "model.safetensors.index.json")["weight_map"]
|
| 242 |
+
compared = 0
|
| 243 |
+
with safe_open(
|
| 244 |
+
output / CENTRAL_SHARD, framework="pt", device="cpu"
|
| 245 |
+
) as output_handle:
|
| 246 |
+
for name in sorted(shared):
|
| 247 |
+
if output_handle.get_tensor(name).dtype != torch.bfloat16:
|
| 248 |
+
raise TypeError(f"{name} is not BF16")
|
| 249 |
+
with safe_open(
|
| 250 |
+
donor / donor_map[name], framework="pt", device="cpu"
|
| 251 |
+
) as donor_handle:
|
| 252 |
+
if not torch.equal(
|
| 253 |
+
output_handle.get_tensor(name), donor_handle.get_tensor(name)
|
| 254 |
+
):
|
| 255 |
+
raise ValueError(f"derived tensor differs from donor: {name}")
|
| 256 |
+
compared += 1
|
| 257 |
+
|
| 258 |
+
return {
|
| 259 |
+
"indexed_tensors": len(actual),
|
| 260 |
+
"tensor_bytes": tensor_bytes,
|
| 261 |
+
"bf16_shared_tensors": len(shared),
|
| 262 |
+
"donor_tensors_compared": compared,
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def build(args: argparse.Namespace) -> dict[str, Any]:
|
| 267 |
+
source = args.source.resolve()
|
| 268 |
+
donor = args.donor.resolve()
|
| 269 |
+
output = args.output.resolve()
|
| 270 |
+
_copy_tree_with_hardlinked_weights(source, output)
|
| 271 |
+
|
| 272 |
+
source_index_path = source / "model.safetensors.index.json"
|
| 273 |
+
source_index = _json(source_index_path)
|
| 274 |
+
donor_index = _json(donor / "model.safetensors.index.json")
|
| 275 |
+
weight_map = copy.deepcopy(source_index["weight_map"])
|
| 276 |
+
removed_bytes = 0
|
| 277 |
+
|
| 278 |
+
for layer in SHARED_LAYERS:
|
| 279 |
+
old_names = [key for key in weight_map if key.startswith(_shared_prefix(layer))]
|
| 280 |
+
expected = 12 if layer in QUANTIZED_SHARED_LAYERS else 3
|
| 281 |
+
if len(old_names) != expected:
|
| 282 |
+
raise ValueError(
|
| 283 |
+
f"layer {layer}: expected {expected} indexed shared tensors, "
|
| 284 |
+
f"found {len(old_names)}"
|
| 285 |
+
)
|
| 286 |
+
source_files = {weight_map[name] for name in old_names}
|
| 287 |
+
if len(source_files) != 1:
|
| 288 |
+
raise ValueError(f"layer {layer}: shared tensors span {source_files}")
|
| 289 |
+
source_file_name = source_files.pop()
|
| 290 |
+
removed, removed_layer_bytes = _strip_shared_from_carrier(
|
| 291 |
+
layer=layer,
|
| 292 |
+
source_file=source / source_file_name,
|
| 293 |
+
output_file=output / source_file_name,
|
| 294 |
+
)
|
| 295 |
+
if set(removed) != set(old_names):
|
| 296 |
+
raise ValueError(f"layer {layer}: index and carrier disagree")
|
| 297 |
+
removed_bytes += removed_layer_bytes
|
| 298 |
+
for name in old_names:
|
| 299 |
+
del weight_map[name]
|
| 300 |
+
|
| 301 |
+
shared = _load_donor_shared(donor, donor_index["weight_map"])
|
| 302 |
+
temporary = output / f".{CENTRAL_SHARD}.tmp"
|
| 303 |
+
try:
|
| 304 |
+
save_file(shared, temporary)
|
| 305 |
+
os.replace(temporary, output / CENTRAL_SHARD)
|
| 306 |
+
finally:
|
| 307 |
+
temporary.unlink(missing_ok=True)
|
| 308 |
+
added_bytes = sum(
|
| 309 |
+
tensor.numel() * tensor.element_size() for tensor in shared.values()
|
| 310 |
+
)
|
| 311 |
+
for name in shared:
|
| 312 |
+
weight_map[name] = CENTRAL_SHARD
|
| 313 |
+
|
| 314 |
+
source_total = int(source_index["metadata"]["total_size"])
|
| 315 |
+
source_index["metadata"]["total_size"] = source_total - removed_bytes + added_bytes
|
| 316 |
+
source_index["weight_map"] = dict(sorted(weight_map.items()))
|
| 317 |
+
_atomic_json(output / "model.safetensors.index.json", source_index)
|
| 318 |
+
|
| 319 |
+
patched_config = _patch_config(_json(source / "config.json"))
|
| 320 |
+
_atomic_json(output / "config.json", patched_config)
|
| 321 |
+
_atomic_json(
|
| 322 |
+
output / "quantization_config.json", patched_config["quantization_config"]
|
| 323 |
+
)
|
| 324 |
+
source_manifest_sha256 = _archive_source_manifest(output)
|
| 325 |
+
validation = _validate(source=source, donor=donor, output=output)
|
| 326 |
+
|
| 327 |
+
derivation = {
|
| 328 |
+
"created_utc": datetime.now(timezone.utc).isoformat(),
|
| 329 |
+
"source": str(source),
|
| 330 |
+
"source_repo_id": args.source_repo_id,
|
| 331 |
+
"source_revision": args.source_revision,
|
| 332 |
+
"source_config_sha256": _sha256(source / "config.json"),
|
| 333 |
+
"source_index_sha256": _sha256(source_index_path),
|
| 334 |
+
"source_manifest_sha256": source_manifest_sha256,
|
| 335 |
+
"donor": str(donor),
|
| 336 |
+
"donor_repo_id": args.donor_repo_id,
|
| 337 |
+
"donor_revision": args.donor_revision,
|
| 338 |
+
"donor_config_sha256": _sha256(donor / "config.json"),
|
| 339 |
+
"donor_index_sha256": _sha256(donor / "model.safetensors.index.json"),
|
| 340 |
+
"removed_source_shared_tensor_bytes": removed_bytes,
|
| 341 |
+
"added_bf16_tensor_bytes": added_bytes,
|
| 342 |
+
"runtime_intent": "ONLINE_QUANT=exl3-b6",
|
| 343 |
+
"validation": validation,
|
| 344 |
+
}
|
| 345 |
+
_atomic_json(output / "R7_BF16_SHARED_DERIVATION.json", derivation)
|
| 346 |
+
return derivation
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
def parse_args() -> argparse.Namespace:
|
| 350 |
+
parser = argparse.ArgumentParser()
|
| 351 |
+
parser.add_argument("--source", type=Path, required=True)
|
| 352 |
+
parser.add_argument("--donor", type=Path, required=True)
|
| 353 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 354 |
+
parser.add_argument("--source-repo-id")
|
| 355 |
+
parser.add_argument("--source-revision")
|
| 356 |
+
parser.add_argument("--donor-repo-id")
|
| 357 |
+
parser.add_argument("--donor-revision")
|
| 358 |
+
return parser.parse_args()
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
def main() -> int:
|
| 362 |
+
result = build(parse_args())
|
| 363 |
+
print(json.dumps(result, indent=2, sort_keys=True))
|
| 364 |
+
return 0
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
if __name__ == "__main__":
|
| 368 |
+
raise SystemExit(main())
|
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"kv_cache_dtype": "fp8",
|
| 3 |
+
"label": "bf16-shared-online-k6-fp8-r3",
|
| 4 |
+
"mean_kld": 0.06533933927615483,
|
| 5 |
+
"model": "R7 BF16-shared runtime-equivalent POC",
|
| 6 |
+
"quantization_config": {
|
| 7 |
+
"ignore": [
|
| 8 |
+
"re:.*\\.fused_qkv_a_proj$",
|
| 9 |
+
"re:.*\\.q_a_proj$",
|
| 10 |
+
"re:.*kv_a_proj_with_mqa",
|
| 11 |
+
"re:.*\\.mlp\\.gate$",
|
| 12 |
+
"model.layers.78.eh_proj",
|
| 13 |
+
"lm_head"
|
| 14 |
+
],
|
| 15 |
+
"linear": {
|
| 16 |
+
"weight": "mxfp8"
|
| 17 |
+
},
|
| 18 |
+
"shared_experts": {
|
| 19 |
+
"weight": "mxfp8"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"reference_logits": "paired BF16 teacher fixture",
|
| 23 |
+
"results": [
|
| 24 |
+
{
|
| 25 |
+
"elapsed_sec": 139.84551430889405,
|
| 26 |
+
"mean_kld": 0.06484639644622803,
|
| 27 |
+
"positions": 2047,
|
| 28 |
+
"run": 1,
|
| 29 |
+
"sd_across_positions": 0.25165143609046936
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"elapsed_sec": 177.6037294138223,
|
| 33 |
+
"mean_kld": 0.06437408179044724,
|
| 34 |
+
"positions": 2047,
|
| 35 |
+
"run": 2,
|
| 36 |
+
"sd_across_positions": 0.2576864957809448
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"elapsed_sec": 101.13696675701067,
|
| 40 |
+
"mean_kld": 0.06679753959178925,
|
| 41 |
+
"positions": 2047,
|
| 42 |
+
"run": 3,
|
| 43 |
+
"sd_across_positions": 0.27730751037597656
|
| 44 |
+
}
|
| 45 |
+
],
|
| 46 |
+
"run_sd": 0.0012847300899035373,
|
| 47 |
+
"supports_prompt_logits": false,
|
| 48 |
+
"token_first16": [
|
| 49 |
+
284,
|
| 50 |
+
8396,
|
| 51 |
+
425,
|
| 52 |
+
10960,
|
| 53 |
+
465,
|
| 54 |
+
284,
|
| 55 |
+
14721,
|
| 56 |
+
8396,
|
| 57 |
+
425,
|
| 58 |
+
10960,
|
| 59 |
+
465,
|
| 60 |
+
374,
|
| 61 |
+
458,
|
| 62 |
+
6364,
|
| 63 |
+
4531,
|
| 64 |
+
1154
|
| 65 |
+
]
|
| 66 |
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import importlib.util
|
| 5 |
+
import os
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
from safetensors import safe_open
|
| 10 |
+
from safetensors.torch import save_file
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
SCRIPT = Path(__file__).with_name("build_shared_bf16_revision.py")
|
| 14 |
+
SPEC = importlib.util.spec_from_file_location("build_shared_bf16_revision", SCRIPT)
|
| 15 |
+
assert SPEC is not None and SPEC.loader is not None
|
| 16 |
+
MODULE = importlib.util.module_from_spec(SPEC)
|
| 17 |
+
SPEC.loader.exec_module(MODULE)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_strip_quantized_shared_tensors_preserves_other_tensors(
|
| 21 |
+
tmp_path: Path,
|
| 22 |
+
) -> None:
|
| 23 |
+
layer = 3
|
| 24 |
+
prefix = MODULE._shared_prefix(layer)
|
| 25 |
+
source_file = tmp_path / "source.safetensors"
|
| 26 |
+
output_file = tmp_path / "output.safetensors"
|
| 27 |
+
tensors = {"model.layers.3.other.weight": torch.arange(8, dtype=torch.float16)}
|
| 28 |
+
for projection in MODULE.PROJECTIONS:
|
| 29 |
+
tensors[f"{prefix}{projection}.mcg"] = torch.tensor(0, dtype=torch.int32)
|
| 30 |
+
tensors[f"{prefix}{projection}.suh"] = torch.arange(4, dtype=torch.float16)
|
| 31 |
+
tensors[f"{prefix}{projection}.svh"] = torch.arange(2, dtype=torch.float16)
|
| 32 |
+
tensors[f"{prefix}{projection}.trellis"] = torch.arange(
|
| 33 |
+
8, dtype=torch.int16
|
| 34 |
+
).reshape(2, 2, 2)
|
| 35 |
+
save_file(tensors, source_file, metadata={"origin": "r7"})
|
| 36 |
+
os.link(source_file, output_file)
|
| 37 |
+
|
| 38 |
+
removed, removed_bytes = MODULE._strip_shared_from_carrier(
|
| 39 |
+
layer=layer, source_file=source_file, output_file=output_file
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
assert len(removed) == 12
|
| 43 |
+
assert removed_bytes == sum(
|
| 44 |
+
value.numel() * value.element_size()
|
| 45 |
+
for name, value in tensors.items()
|
| 46 |
+
if name.startswith(prefix)
|
| 47 |
+
)
|
| 48 |
+
with safe_open(source_file, framework="pt", device="cpu") as handle:
|
| 49 |
+
assert len([name for name in handle.keys() if name.startswith(prefix)]) == 12
|
| 50 |
+
with safe_open(output_file, framework="pt", device="cpu") as handle:
|
| 51 |
+
assert handle.metadata() == {"origin": "r7"}
|
| 52 |
+
assert not any(name.startswith(prefix) for name in handle.keys())
|
| 53 |
+
assert torch.equal(
|
| 54 |
+
handle.get_tensor("model.layers.3.other.weight"),
|
| 55 |
+
tensors["model.layers.3.other.weight"],
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def test_patch_config_changes_only_shared_tensor_ownership() -> None:
|
| 60 |
+
storage = {
|
| 61 |
+
f"model.layers.3.mlp.shared_experts.{projection}": {"format": "exl3"}
|
| 62 |
+
for projection in MODULE.PROJECTIONS
|
| 63 |
+
}
|
| 64 |
+
storage["model.layers.3.self_attn.o_proj"] = {"format": "exl3"}
|
| 65 |
+
config = {
|
| 66 |
+
"quantization_config": {
|
| 67 |
+
"tensor_storage": storage,
|
| 68 |
+
"r7_routed_experts": {"schema": "preserve"},
|
| 69 |
+
"ignore": ["lm_head"],
|
| 70 |
+
"exl3_dense": {"include_prefixes": list(storage)},
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
original_include = list(
|
| 75 |
+
config["quantization_config"]["exl3_dense"]["include_prefixes"]
|
| 76 |
+
)
|
| 77 |
+
patched = MODULE._patch_config(config, quantized_shared_layers=(3,))
|
| 78 |
+
|
| 79 |
+
assert patched["quantization_config"]["tensor_storage"] == {
|
| 80 |
+
"model.layers.3.self_attn.o_proj": {"format": "exl3"}
|
| 81 |
+
}
|
| 82 |
+
assert (
|
| 83 |
+
patched["quantization_config"]["exl3_dense"]["include_prefixes"]
|
| 84 |
+
== original_include
|
| 85 |
+
)
|
| 86 |
+
assert patched["quantization_config"]["ignore"] == ["lm_head"]
|
| 87 |
+
assert len(config["quantization_config"]["tensor_storage"]) == 4
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def test_archive_source_manifest_removes_stale_seals(tmp_path: Path) -> None:
|
| 91 |
+
manifest = b'{"schema":"r7"}\n'
|
| 92 |
+
(tmp_path / "MANIFEST.json").write_bytes(manifest)
|
| 93 |
+
(tmp_path / "MANIFEST.sha256").write_text("stale\n", encoding="utf-8")
|
| 94 |
+
(tmp_path / ".manifest_verified").write_text("stale\n", encoding="utf-8")
|
| 95 |
+
|
| 96 |
+
digest = MODULE._archive_source_manifest(tmp_path)
|
| 97 |
+
|
| 98 |
+
assert digest == hashlib.sha256(manifest).hexdigest()
|
| 99 |
+
assert not (tmp_path / "MANIFEST.json").exists()
|
| 100 |
+
assert not (tmp_path / "MANIFEST.sha256").exists()
|
| 101 |
+
assert not (tmp_path / ".manifest_verified").exists()
|
| 102 |
+
assert (tmp_path / "SOURCE_R7_MANIFEST.json").read_bytes() == manifest
|
| 103 |
+
assert (tmp_path / "SOURCE_R7_MANIFEST.sha256").read_text(
|
| 104 |
+
encoding="utf-8"
|
| 105 |
+
) == f"{digest} SOURCE_R7_MANIFEST.json\n"
|