McBopomofoLM v3.1.2 models: decoder with next-token functions (n16-n96), dec_next_first.tsv
d8edfe6 verified Download scripts/dec/build_dec_tn.py from workfunction/McBopomofoLM-models: direct link, hf CLI and curl.
- Browser
- Download file 3.96 kB
-
https://huggingface.co/workfunction/McBopomofoLM-models/resolve/main/scripts/dec/build_dec_tn.py
- Command line
-
hf download hf://workfunction/McBopomofoLM-models/scripts/dec/build_dec_tn.py
-
curl -L -o build_dec_tn.py https://huggingface.co/workfunction/McBopomofoLM-models/resolve/main/scripts/dec/build_dec_tn.py
3.96 kB
| """v3.1b decoder package: the shipped t16/t32/t64/t96 (B=3 scorers) + the next-token n16/n32/n64/n96 (B=1, | |
| reports/ane-dec.md "next-token function") in ONE multifunction package with shared weights, from the same parts. | |
| 1. the parts are the shipped ones: a t-only merge of ane/dec/mf/parts/*_fp16 has the shipped | |
| ane/dec/mf/dec_mf_fp16.mlpackage's weight.bin byte for byte and the same t16..t96 program functions; | |
| 2. t + n merge -> McBopomofoLM/build/v31b/dec_mf_tn_fp16.mlpackage (default function t16, as shipped): its t16..t96 | |
| program functions equal the shipped ones and its weight.bin holds the shipped blobs at the same offsets (only | |
| the header's blob count differs), so every weight a t function reads is the shipped bytes; | |
| 3. SlothE/v31b/dec_next_first.tsv: char \t token ids whose decoded text starts with that char (partial-byte and | |
| whitespace-initial tokens dropped) = typo/t2.py _dinit / typo/t2c.py, the study's first-char grouping. | |
| usage: nice -n 15 $W/ane/dec/.venv/bin/python SlothE/v31b/build_dec_tn.py | |
| """ | |
| import hashlib | |
| import shutil | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| HERE = Path(__file__).resolve().parent | |
| W = HERE.parents[2] | |
| DEC = W / "ane" / "dec" | |
| sys.path.insert(0, str(DEC)) | |
| import coremltools as ct # noqa: E402 | |
| from coremltools.models.utils import MultiFunctionDescriptor, save_multifunction # noqa: E402 | |
| from tokenizers import decoders # noqa: E402 | |
| from common import TOK # noqa: E402 | |
| TS = (16, 32, 64, 96) | |
| OUT = W / "McBopomofoLM" / "build" / "v31b" | |
| def sha(p): | |
| return hashlib.sha256(Path(p).read_bytes()).hexdigest() | |
| def merge(fns, dst): | |
| d = MultiFunctionDescriptor() | |
| for name, p in fns.items(): | |
| d.add_function(str(p), src_function_name="main", target_function_name=name) | |
| d.default_function_name = "t16" | |
| shutil.rmtree(dst, ignore_errors=True) | |
| save_multifunction(d, str(dst)) | |
| tparts = {f"t{T}": DEC / "mf" / "parts" / f"dec_b3_t{T}_fp16.mlpackage" for T in TS} | |
| nparts = {f"n{T}": DEC / "mf_next" / "parts" / f"dec_b1_n{T}_fp16.mlpackage" for T in TS} | |
| SHIPPED = DEC / "mf" / "dec_mf_fp16.mlpackage" | |
| shipped_spec = ct.utils.load_spec(str(SHIPPED)) | |
| shipped_w = (SHIPPED / "Data" / "com.apple.CoreML" / "weights" / "weight.bin").read_bytes() | |
| def same_t(pkg): | |
| spec = ct.utils.load_spec(str(pkg)) | |
| w = (Path(pkg) / "Data" / "com.apple.CoreML" / "weights" / "weight.bin").read_bytes() | |
| fns = all(spec.mlProgram.functions[f"t{T}"] == shipped_spec.mlProgram.functions[f"t{T}"] for T in TS) | |
| # the 64-byte storage header starts with the blob count; every blob after it must be the shipped bytes | |
| return fns, w[64:len(shipped_w)] == shipped_w[64:], len(w) | |
| with tempfile.TemporaryDirectory() as tmp: | |
| t_only = Path(tmp) / "t_only.mlpackage" | |
| merge(tparts, t_only) | |
| fns, prefix, n = same_t(t_only) | |
| print(f"t-only merge vs shipped: t functions equal {fns}, weight blobs equal {prefix and n == len(shipped_w)}") | |
| assert fns and prefix and n == len(shipped_w), "the t parts are not the shipped ones" | |
| OUT.mkdir(parents=True, exist_ok=True) | |
| dst = OUT / "dec_mf_tn_fp16.mlpackage" | |
| merge(tparts | nparts, dst) | |
| fns, prefix, n = same_t(dst) | |
| size = sum(f.stat().st_size for f in dst.rglob("*") if f.is_file()) / 1e6 | |
| print(f"merged t16..t96 + n16..n96 -> {dst} {size:.1f} MB; t functions equal shipped {fns}; " | |
| f"weight.bin = the shipped blobs at the same offsets {prefix} (+{n - len(shipped_w)} B of n-only blobs appended)") | |
| assert fns and prefix | |
| if TOK.decoder is None: | |
| TOK.decoder = decoders.ByteLevel() | |
| first = {} | |
| for t in range(TOK.get_vocab_size()): | |
| s = TOK.decode([t]) | |
| if s and s[0] != "�" and not s[0].isspace(): | |
| first.setdefault(s[0], []).append(t) | |
| with open(HERE / "dec_next_first.tsv", "w", encoding="utf-8") as f: | |
| for c in sorted(first): | |
| f.write(c + "\t" + " ".join(map(str, first[c])) + "\n") | |
| print(f"first-char table: {len(first)} chars, {sum(map(len, first.values()))} tokens") | |