recipe: BPW footnote inputs (GGUF weight counts) + card scripts
Browse files- recipe/pipeline/nex_aggregate.py +14 -0
- recipe/pipeline/nex_render.py +16 -5
- recipe/results_summary.json +6 -0
recipe/pipeline/nex_aggregate.py
CHANGED
|
@@ -59,6 +59,15 @@ def sha_file(p):
|
|
| 59 |
return h.hexdigest()
|
| 60 |
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
def tensors(p):
|
| 63 |
"""name -> (type, bytes); {} if the file cannot be read (e.g. still being written by a running quantize)."""
|
| 64 |
out = {}
|
|
@@ -158,6 +167,8 @@ S["bf16"] = {
|
|
| 158 |
"n_ctx": nctx,
|
| 159 |
"scored_tokens": chunks * (nctx // 2 - 1) if chunks and nctx else None,
|
| 160 |
"size_bytes": exists_size(bf_path),
|
|
|
|
|
|
|
| 161 |
"file": bf_fn,
|
| 162 |
"readback": bf_line.split()[0] if bf_line else None,
|
| 163 |
"arch": f(r"arch=(\S+)", bf_line, cast=str),
|
|
@@ -281,6 +292,8 @@ for im, st in TWINS:
|
|
| 281 |
S["tiers"][im]["same_tensor_types_as_standard"] = TEN[st] == TEN[im]
|
| 282 |
else:
|
| 283 |
S["tiers"][im]["same_tensor_types_as_standard"] = None
|
|
|
|
|
|
|
| 284 |
sa, sb = S["tiers"][st]["size_bytes"], S["tiers"][im]["size_bytes"]
|
| 285 |
S["tiers"][im]["file_size_delta_bytes"] = (sb - sa) if None not in (sa, sb) else None
|
| 286 |
ha, hb = (sha_file(pa), sha_file(pb)) if os.path.exists(pa) and os.path.exists(pb) else (None, None)
|
|
@@ -292,6 +305,7 @@ S["aux"] = {mm_fn: exists_size(f"{W}/out/{mm_fn}")}
|
|
| 292 |
S["mmproj"] = {
|
| 293 |
"file": mm_fn,
|
| 294 |
"size_bytes": S["aux"][mm_fn],
|
|
|
|
| 295 |
"readback": mm_line.split()[0] if mm_line else None,
|
| 296 |
"arch": f(r"arch=(\S+)", mm_line, cast=str),
|
| 297 |
"ftype": f(r"ftype=(\d+)", mm_line, cast=int),
|
|
|
|
| 59 |
return h.hexdigest()
|
| 60 |
|
| 61 |
|
| 62 |
+
def n_elements(p, prefix=None):
|
| 63 |
+
"""Weight count of a GGUF (only tensors whose name starts with prefix, if given); None if unreadable."""
|
| 64 |
+
try:
|
| 65 |
+
reader = gguf.GGUFReader(p)
|
| 66 |
+
except (ValueError, OSError):
|
| 67 |
+
return None
|
| 68 |
+
return sum(int(t.n_elements) for t in reader.tensors if prefix is None or t.name.startswith(prefix))
|
| 69 |
+
|
| 70 |
+
|
| 71 |
def tensors(p):
|
| 72 |
"""name -> (type, bytes); {} if the file cannot be read (e.g. still being written by a running quantize)."""
|
| 73 |
out = {}
|
|
|
|
| 167 |
"n_ctx": nctx,
|
| 168 |
"scored_tokens": chunks * (nctx // 2 - 1) if chunks and nctx else None,
|
| 169 |
"size_bytes": exists_size(bf_path),
|
| 170 |
+
"elements": n_elements(bf_path) if os.path.exists(bf_path) else None,
|
| 171 |
+
"bpw_logged": f(r"model size\s*=\s*[\d.]+ MiB \(([\d.]+) BPW\)", rd(f"{W}/logs/Q1_q106.log"), cast=str),
|
| 172 |
"file": bf_fn,
|
| 173 |
"readback": bf_line.split()[0] if bf_line else None,
|
| 174 |
"arch": f(r"arch=(\S+)", bf_line, cast=str),
|
|
|
|
| 292 |
S["tiers"][im]["same_tensor_types_as_standard"] = TEN[st] == TEN[im]
|
| 293 |
else:
|
| 294 |
S["tiers"][im]["same_tensor_types_as_standard"] = None
|
| 295 |
+
# what that comparison covers: every tensor's name, type and byte size (tensors() above)
|
| 296 |
+
S["tiers"][im]["same_tensor_names_types_bytes_as_standard"] = S["tiers"][im]["same_tensor_types_as_standard"]
|
| 297 |
sa, sb = S["tiers"][st]["size_bytes"], S["tiers"][im]["size_bytes"]
|
| 298 |
S["tiers"][im]["file_size_delta_bytes"] = (sb - sa) if None not in (sa, sb) else None
|
| 299 |
ha, hb = (sha_file(pa), sha_file(pb)) if os.path.exists(pa) and os.path.exists(pb) else (None, None)
|
|
|
|
| 305 |
S["mmproj"] = {
|
| 306 |
"file": mm_fn,
|
| 307 |
"size_bytes": S["aux"][mm_fn],
|
| 308 |
+
"elements": n_elements(f"{W}/out/{mm_fn}") if os.path.exists(f"{W}/out/{mm_fn}") else None,
|
| 309 |
"readback": mm_line.split()[0] if mm_line else None,
|
| 310 |
"arch": f(r"arch=(\S+)", mm_line, cast=str),
|
| 311 |
"ftype": f(r"ftype=(\d+)", mm_line, cast=int),
|
recipe/pipeline/nex_render.py
CHANGED
|
@@ -102,7 +102,7 @@ PROTOCOL = (
|
|
| 102 |
f"instruction), a unique nonce per request and `cache_prompt: false` (`cache_n = 0` asserted on "
|
| 103 |
f"every timed request), 1 warm-up then the median of {REPS}. Decode numbers are the server's own "
|
| 104 |
f"`predicted_per_second`. Box iced: no other model loaded.")
|
| 105 |
-
TABLE_HEAD = ("| File | ftype | Size | BPW | KLD vs BF16 ↓² | Same top-1 ↑ | PPL (× BF16) | TG ROCm0 | TG Vulkan0 | PP ROCm0 |\n"
|
| 106 |
"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |")
|
| 107 |
TG_NOTE = f"TG = decode tokens/s after the {PN_TXT}-token code prompt, no draft head. PP = prefill tokens/s on ROCm0."
|
| 108 |
|
|
@@ -121,7 +121,7 @@ def quality_blurb():
|
|
| 121 |
|
| 122 |
def bf16_row():
|
| 123 |
b = S.get("bf16") or {}
|
| 124 |
-
return (f"| *BF16 reference* | {g(b.get('ftype'), '{}')} | {gib(b.get('size_bytes'))}³ |
|
| 125 |
f"{pm(b.get('ppl_paired'), b.get('ppl_paired_err'))}¹ | — | — | — |")
|
| 126 |
|
| 127 |
|
|
@@ -131,7 +131,18 @@ def footnotes(where="below"):
|
|
| 131 |
f"¹ The BF16 PPL shown is the paired base every \"×\" ratio is computed against (averaged over the same scored tokens "
|
| 132 |
f"in the KL-divergence runs). The standalone BF16 run's own summary line reads {pm(b.get('ppl'), b.get('ppl_err'))}.\n"
|
| 133 |
f"² Quality columns: see *Where the quality numbers come from* {where}.\n"
|
| 134 |
-
f"³ BF16 conversion of the checkpoint; not published."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
|
| 136 |
|
| 137 |
YAML = """---
|
|
@@ -643,8 +654,8 @@ def imat_card():
|
|
| 643 |
Importance-matrix-calibrated ROCmFP4 quantizations of
|
| 644 |
**[nex-agi/Nex-N2.5-mini](https://huggingface.co/nex-agi/Nex-N2.5-mini)** ({g(SRC.get('params'), '{:,}')} parameters,
|
| 645 |
{intro_arch()}, text + image). Companion to the standard build **[{STD}](https://huggingface.co/{STD})** — the same
|
| 646 |
-
three 4-bit tiers, same vision projector, same unpatched `d3ca537` server; the only difference
|
| 647 |
-
block's scale was chosen. There is no MTP head on either repo.
|
| 648 |
|
| 649 |
## What the imatrix changes
|
| 650 |
|
|
|
|
| 102 |
f"instruction), a unique nonce per request and `cache_prompt: false` (`cache_n = 0` asserted on "
|
| 103 |
f"every timed request), 1 warm-up then the median of {REPS}. Decode numbers are the server's own "
|
| 104 |
f"`predicted_per_second`. Box iced: no other model loaded.")
|
| 105 |
+
TABLE_HEAD = ("| File | ftype | Size | BPW⁴ | KLD vs BF16 ↓² | Same top-1 ↑ | PPL (× BF16) | TG ROCm0 | TG Vulkan0 | PP ROCm0 |\n"
|
| 106 |
"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |")
|
| 107 |
TG_NOTE = f"TG = decode tokens/s after the {PN_TXT}-token code prompt, no draft head. PP = prefill tokens/s on ROCm0."
|
| 108 |
|
|
|
|
| 121 |
|
| 122 |
def bf16_row():
|
| 123 |
b = S.get("bf16") or {}
|
| 124 |
+
return (f"| *BF16 reference* | {g(b.get('ftype'), '{}')} | {gib(b.get('size_bytes'))}³ | {g(b.get('bpw_logged'), '{}')} | 0 | 100 % | "
|
| 125 |
f"{pm(b.get('ppl_paired'), b.get('ppl_paired_err'))}¹ | — | — | — |")
|
| 126 |
|
| 127 |
|
|
|
|
| 131 |
f"¹ The BF16 PPL shown is the paired base every \"×\" ratio is computed against (averaged over the same scored tokens "
|
| 132 |
f"in the KL-divergence runs). The standalone BF16 run's own summary line reads {pm(b.get('ppl'), b.get('ppl_err'))}.\n"
|
| 133 |
f"² Quality columns: see *Where the quality numbers come from* {where}.\n"
|
| 134 |
+
f"³ BF16 conversion of the checkpoint; not published.\n"
|
| 135 |
+
f"{bpw_note()}")
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def bpw_note():
|
| 139 |
+
b, m = S.get("bf16") or {}, S.get("mmproj") or {}
|
| 140 |
+
n, v, p = b.get("elements"), m.get("elements"), SRC.get("params")
|
| 141 |
+
s = f"⁴ BPW as printed by `llama-quantize`: bits per weight over the {g(n, '{:,}')} weights in each GGUF."
|
| 142 |
+
if None not in (n, v, p) and n + v == p:
|
| 143 |
+
s += (f" The {p:,}-parameter count above also includes the {v:,}-weight vision tower, which ships in the "
|
| 144 |
+
f"projector file.")
|
| 145 |
+
return s
|
| 146 |
|
| 147 |
|
| 148 |
YAML = """---
|
|
|
|
| 654 |
Importance-matrix-calibrated ROCmFP4 quantizations of
|
| 655 |
**[nex-agi/Nex-N2.5-mini](https://huggingface.co/nex-agi/Nex-N2.5-mini)** ({g(SRC.get('params'), '{:,}')} parameters,
|
| 656 |
{intro_arch()}, text + image). Companion to the standard build **[{STD}](https://huggingface.co/{STD})** — the same
|
| 657 |
+
three 4-bit tiers, same vision projector, same unpatched `d3ca537` server; the only difference in the weights is how
|
| 658 |
+
each 4-bit block's scale was chosen. There is no MTP head on either repo.
|
| 659 |
|
| 660 |
## What the imatrix changes
|
| 661 |
|
recipe/results_summary.json
CHANGED
|
@@ -45,6 +45,8 @@
|
|
| 45 |
"n_ctx": 2048,
|
| 46 |
"scored_tokens": 40920,
|
| 47 |
"size_bytes": 69376636928,
|
|
|
|
|
|
|
| 48 |
"file": "Nex-N2.5-mini-BF16.gguf",
|
| 49 |
"readback": "PASS",
|
| 50 |
"arch": "qwen35moe",
|
|
@@ -680,6 +682,7 @@
|
|
| 680 |
"rms_dp": 8.201
|
| 681 |
},
|
| 682 |
"same_tensor_types_as_standard": true,
|
|
|
|
| 683 |
"file_size_delta_bytes": 256,
|
| 684 |
"differs_from_standard": true,
|
| 685 |
"header_keys_only_in_imatrix": [
|
|
@@ -728,6 +731,7 @@
|
|
| 728 |
"rms_dp": 7.783
|
| 729 |
},
|
| 730 |
"same_tensor_types_as_standard": true,
|
|
|
|
| 731 |
"file_size_delta_bytes": 256,
|
| 732 |
"differs_from_standard": true,
|
| 733 |
"header_keys_only_in_imatrix": [
|
|
@@ -776,6 +780,7 @@
|
|
| 776 |
"rms_dp": 8.509
|
| 777 |
},
|
| 778 |
"same_tensor_types_as_standard": true,
|
|
|
|
| 779 |
"file_size_delta_bytes": 256,
|
| 780 |
"differs_from_standard": true,
|
| 781 |
"header_keys_only_in_imatrix": [
|
|
@@ -794,6 +799,7 @@
|
|
| 794 |
"mmproj": {
|
| 795 |
"file": "mmproj-Nex-N2.5-mini-BF16.gguf",
|
| 796 |
"size_bytes": 902821920,
|
|
|
|
| 797 |
"readback": "PASS",
|
| 798 |
"arch": "clip",
|
| 799 |
"ftype": 32,
|
|
|
|
| 45 |
"n_ctx": 2048,
|
| 46 |
"scored_tokens": 40920,
|
| 47 |
"size_bytes": 69376636928,
|
| 48 |
+
"elements": 34660610688,
|
| 49 |
+
"bpw_logged": "16.01",
|
| 50 |
"file": "Nex-N2.5-mini-BF16.gguf",
|
| 51 |
"readback": "PASS",
|
| 52 |
"arch": "qwen35moe",
|
|
|
|
| 682 |
"rms_dp": 8.201
|
| 683 |
},
|
| 684 |
"same_tensor_types_as_standard": true,
|
| 685 |
+
"same_tensor_names_types_bytes_as_standard": true,
|
| 686 |
"file_size_delta_bytes": 256,
|
| 687 |
"differs_from_standard": true,
|
| 688 |
"header_keys_only_in_imatrix": [
|
|
|
|
| 731 |
"rms_dp": 7.783
|
| 732 |
},
|
| 733 |
"same_tensor_types_as_standard": true,
|
| 734 |
+
"same_tensor_names_types_bytes_as_standard": true,
|
| 735 |
"file_size_delta_bytes": 256,
|
| 736 |
"differs_from_standard": true,
|
| 737 |
"header_keys_only_in_imatrix": [
|
|
|
|
| 780 |
"rms_dp": 8.509
|
| 781 |
},
|
| 782 |
"same_tensor_types_as_standard": true,
|
| 783 |
+
"same_tensor_names_types_bytes_as_standard": true,
|
| 784 |
"file_size_delta_bytes": 256,
|
| 785 |
"differs_from_standard": true,
|
| 786 |
"header_keys_only_in_imatrix": [
|
|
|
|
| 799 |
"mmproj": {
|
| 800 |
"file": "mmproj-Nex-N2.5-mini-BF16.gguf",
|
| 801 |
"size_bytes": 902821920,
|
| 802 |
+
"elements": 446571248,
|
| 803 |
"readback": "PASS",
|
| 804 |
"arch": "clip",
|
| 805 |
"ftype": 32,
|