Download vlib/compute.py from Wiself/Voice: direct link, hf CLI and curl.
- Browser
- Download file 58.4 kB
-
https://huggingface.co/Wiself/Voice/resolve/main/vlib/compute.py
- Command line
-
hf download hf://Wiself/Voice/vlib/compute.py
-
curl -L -o compute.py https://huggingface.co/Wiself/Voice/resolve/main/vlib/compute.py
58.4 kB
| """Cast math: orient, fuse, quantize, pack writes.""" | |
| from pathlib import Path | |
| import os | |
| import struct | |
| import sys | |
| import time | |
| from vlib import ctx | |
| from vlib.ui import _confirm, _fail, _noninteractive, _note, _ok, _progress_pref, _say, _step, _transform, _warn | |
| from vlib.tensors import _gguf_raw_to_f32, _is_delta_safetensors, _is_ggml_quant, _is_gguf_file, _safetensors_write_repl, decode_to_f32, encode_from_f32, read_safetensors, rewrite_safetensors_tensor | |
| from vlib.sources import OUTPUT_ALIASES, _nested, detect_output_tensor, largest_2d, open_source | |
| from vlib.registry import log_operation | |
| def _load_voice(voice_path): | |
| """Load a voice artifact. Returns (f32_array_or_None, ref, raw_bytes_or_None, ggml_type_or_None). | |
| Quantized GGUF artifacts carry raw blocks; safetensors artifacts decode to f32.""" | |
| src = open_source(str(voice_path)) | |
| names = [n for n in src.names() if n != "delta.voice.marker"] | |
| if not names: | |
| _fail(f" ✗ No tensors found in {voice_path}.") | |
| tname = names[0] if len(names) == 1 else "output.weight" if "output.weight" in names else names[0] | |
| ref = src.ref(tname) | |
| if src.kind == "gguf" and _is_ggml_quant(ref.dtype): | |
| return None, ref, src.read_raw(tname), ref.dtype | |
| return src.read_f32(tname), ref, None, None | |
| def _orient(arr, shape, target_shape): | |
| import numpy as np | |
| if tuple(shape) == tuple(target_shape): | |
| return arr | |
| if tuple(shape) == tuple(target_shape[::-1]): | |
| if ctx.VERBOSE: | |
| _note("Transposing to match the target layout…") | |
| return np.ascontiguousarray(arr.T) | |
| return None | |
| def _cast_st_prepare(target, tensors, vf32, vref, meta, args, vraw=None, vqtype=None, strict_target=False, target_name=None): | |
| """Per-tensor compute for a safetensors target. Returns (tname, data, tdtype, tshape). | |
| target_name (from _resolve_pack_targets) overrides lookup; None keeps the | |
| original single-tensor behavior byte-for-byte.""" | |
| import numpy as np | |
| if vraw is not None: | |
| # quant artifact -> safetensors target: dequant is the only requant path | |
| from gguf.constants import GGMLQuantizationType as Q | |
| from gguf.quants import quant_shape_to_byte_shape | |
| vf32 = _gguf_raw_to_f32(vraw, Q[vqtype], tuple(reversed(tuple(int(x) for x in vref.shape)))) | |
| names = list(tensors.keys()) | |
| if target_name is not None: | |
| tname = target_name if target_name in names else None | |
| if tname is None: | |
| _fail(f" ✗ Resolved target '{target_name}' for '{vref.name}' not in {target}.") | |
| else: | |
| tname = vref.name if vref.name in names else None | |
| if tname is None and strict_target: | |
| _fail(f" ✗ Tensor '{vref.name}' not found in target {target}. Voicepack requires exact match (not mapping to another tensor).") | |
| if tname is None: | |
| tname = detect_output_tensor(names, None) or largest_2d(names, {n: tensors[n]["shape"] for n in names}) | |
| if tname is None: | |
| _fail(" ✗ Could not find a matching tensor in the target.") | |
| tshape = tuple(tensors[tname]["shape"]) | |
| tdtype = tensors[tname]["dtype"] | |
| # --quant override for safetensors target: only F32/F16/BF16/keep/target make sense (no GGUF quants). | |
| _qo = _parse_quant_override(getattr(args, "quant", None) or "keep") | |
| if _qo is None: | |
| _fail(f" ✗ Invalid --quant '{getattr(args, 'quant', None)}' for safetensors target. Use keep|target|f32|f16|bf16.") | |
| if _qo not in ("keep", "target", "f32", "f16", "bf16"): | |
| _fail(f" ✗ --quant {_qo} needs GGUF target (safetensors has no quant {_qo}). Use keep|target|f32|f16|bf16.") | |
| if _qo in ("f32", "f16", "bf16"): | |
| _want = {"f32": "F32", "f16": "F16", "bf16": "BF16"}[_qo] | |
| if _want != tdtype.upper(): | |
| from vlib.tensors import dtype_bytes as _db | |
| try: | |
| _same_size = _db(_want) == _db(tdtype.upper()) | |
| except Exception: | |
| _same_size = False | |
| if not _same_size: | |
| _fail(f" ✗ --quant {_qo} would change '{tname}' {tdtype} → {_want} (different byte size; safetensors casts keep byte size). Use --quant keep|target.") | |
| _warn(f" Re-encoding target {tdtype} → {_want} for --quant {_qo} (extra conversion).") | |
| tdtype = _want | |
| # Show quant/target by default for tensor commands (advanced) and verbose for voice. | |
| try: | |
| _svq = vqtype if vraw is not None else vref.dtype | |
| except Exception: | |
| _svq = "?" | |
| if ctx.VERBOSE: | |
| _note(f"Voice '{vref.name}' is {_svq} {tuple(vref.shape)} → target '{tname}' is {tdtype} {tshape}") | |
| if vraw is not None and ctx.VERBOSE: | |
| _note(f"Dequanting {vqtype} once to F32 for safetensors target (unavoidable, safetensors has no quant).") | |
| oriented = _orient(vf32, vref.shape, tshape) | |
| if oriented is None: | |
| _fail(f" ✗ Voice shape {vref.shape} doesn't fit target tensor {tname} {tshape}.") | |
| if (meta or {}).get("type") == "delta": | |
| _step(f"Fusing style into {tname} (delta + head → {tdtype}, kept)…") | |
| with open(target, "rb") as f: | |
| _hs = struct.unpack("<Q", f.read(8))[0] | |
| info = tensors[tname] | |
| with open(target, "rb") as f: | |
| f.seek(8 + _hs + info["data_offsets"][0]) | |
| head_f32 = decode_to_f32(f.read(info["data_offsets"][1] - info["data_offsets"][0]), tdtype, tshape) | |
| oriented = np.ascontiguousarray(head_f32 + oriented) | |
| data = encode_from_f32(oriented, tdtype) | |
| return tname, data, tdtype, tshape | |
| def _cast_core(target, target_format, out_path, vf32, vref, meta, args, op="cast", vraw=None, vqtype=None, strict_target=False, target_name=None): | |
| if getattr(args, "speak", False) and target_format != "gguf": | |
| _fail(" ✗ --speak needs a .gguf target. Re-run without --speak for .safetensors, or point cast at a .gguf file.") | |
| if target_format == "gguf": | |
| _cast_gguf(target, out_path, vf32, vref, meta, args, op, vraw=vraw, vqtype=vqtype, strict_target=strict_target, target_name=target_name) | |
| return | |
| # safetensors target | |
| header, tensors = read_safetensors(target) | |
| t0s = time.time() | |
| tname, data, tdtype, tshape = _cast_st_prepare(target, tensors, vf32, vref, meta, args, | |
| vraw=vraw, vqtype=vqtype, strict_target=strict_target, | |
| target_name=target_name) | |
| _step(f"Replacing {tname} ({tdtype} {tshape})…") | |
| rewrite_safetensors_tensor(target, out_path, tname, data, tdtype, tshape) | |
| file_size = os.path.getsize(out_path) | |
| try: | |
| _mb = len(data) / 1e6 | |
| _rate = f" @ {(_mb) / max(time.time() - t0s, 1e-6):.0f} MB/s" if _mb >= 0.1 else "" | |
| _note(f"Kept '{tname}': {_mb:.1f} MB → {tdtype}{_rate}") | |
| except Exception: | |
| pass | |
| log_operation({"op": op, "target": target, "format": "safetensors", "tensor": tname, | |
| "dtype": tdtype, "shape": list(tshape), "output": out_path, "status": "ok"}) | |
| _ok(f"Done → {out_path}") | |
| _say(f" Saved → {out_path} ({tdtype} {list(tshape)})") | |
| def _is_head_name(name): | |
| if not name: | |
| return False | |
| try: | |
| if name in OUTPUT_ALIASES or name in ("token_embd.weight",): | |
| return True | |
| for a in OUTPUT_ALIASES: | |
| if name.endswith(a): | |
| return True | |
| except Exception: | |
| pass | |
| return False | |
| def _parse_quant_override(s): | |
| # Returns normalized key: keep|target or Q-type name upper (e.g. Q4_0). Trivial: accept all GGML quants. | |
| if s is None: | |
| return "keep" | |
| k = str(s).strip().lower().replace("-", "_") | |
| if k in ("keep", "target"): | |
| return k | |
| # Aliases for float family. | |
| if k in ("fp32",): | |
| k = "f32" | |
| if k in ("fp16",): | |
| k = "f16" | |
| # Try any GGMLQuantizationType name. | |
| try: | |
| from gguf.constants import GGMLQuantizationType as _Qp | |
| # Case-insensitive match against all Q names. | |
| for _q in _Qp: | |
| if _q.name.lower() == k: | |
| return k | |
| except Exception: | |
| pass | |
| # Fallback known list (when gguf import fails). | |
| _known = {"f32", "f16", "bf16", "q8_0", "q8_1", "q8_k", "q1_0", "q4_0", "q4_1", "q5_0", "q5_1", | |
| "q2_k", "q3_k", "q4_k", "q5_k", "q6_k", "iq1_s", "iq1_m", "iq2_xxs", "iq2_xs", "iq2_s", | |
| "iq3_xxs", "iq3_s", "iq4_nl", "iq4_xs", "tq1_0", "tq2_0", "mxfp4", "nvfp4"} | |
| if k in _known: | |
| return k | |
| return None | |
| def _quant_from_key(key): | |
| # key normalized via _parse_quant_override (lower). Returns Q type or None for keep/target. | |
| if key in ("keep", "target", None): | |
| return None | |
| try: | |
| from gguf.constants import GGMLQuantizationType as _Qq | |
| for _q in _Qq: | |
| if _q.name.lower() == key: | |
| return _q | |
| # Upper direct (e.g. Q4_0). | |
| return _Qq[key.upper()] | |
| except Exception: | |
| return None | |
| def _qerr(e): | |
| """Readable lib error: gguf often raises bare NotImplementedError ('').""" | |
| s = str(e).strip() | |
| return f"{type(e).__name__}: {s}" if s else type(e).__name__ | |
| _NEAREST_CACHE = {} | |
| def _nearest_encodable(target_q): | |
| """Nearest gguf-encodable quant to target_q by bits/param (ties → larger = | |
| quality-preserving). The lib decodes everything but encodes only a subset | |
| (no K/IQ quants); this keeps fused tensors near the original size instead | |
| of ballooning to F16. Support probed once per process (version-proof).""" | |
| import numpy as np | |
| from gguf.constants import GGMLQuantizationType as Q | |
| from gguf.constants import GGML_QUANT_SIZES as S | |
| from gguf.quants import quantize | |
| key = getattr(target_q, "name", str(target_q)) | |
| if key in _NEAREST_CACHE: | |
| return _NEAREST_CACHE[key] | |
| tbpp = S[target_q][1] * 8 / S[target_q][0] | |
| probe = (np.arange(64 * 64, dtype=np.float32).reshape(64, 64) - 2048) / 64 | |
| scored = [] | |
| for name in ("Q8_0", "Q5_1", "Q5_0", "Q4_1", "Q4_0", "MXFP4", "F16"): | |
| cand = getattr(Q, name, None) | |
| if cand is None or cand == target_q: | |
| continue | |
| try: | |
| quantize(probe, cand) | |
| except Exception: | |
| continue | |
| cbpp = S[cand][1] * 8 / S[cand][0] | |
| scored.append((abs(cbpp - tbpp), -cbpp, cand)) | |
| best = min(scored)[2] if scored else None | |
| _NEAREST_CACHE[key] = best | |
| return best | |
| def _quantize_to_Q(fused, req_q): | |
| # Quantize F32 fused array to any Q (F32/F16/BF16 via astype, else gguf quantize). | |
| # Returns (q_head, out_qtype). Raises on unsupported (e.g. Q1_0/Q8_1/Q8_K NotImplemented). | |
| import numpy as np | |
| from gguf.constants import GGMLQuantizationType as Q | |
| from gguf.quants import quantize | |
| if req_q in (Q.F32,): | |
| return fused.astype(np.float32), Q.F32 | |
| if req_q in (Q.F16,): | |
| return fused.astype(np.float16), Q.F16 | |
| try: | |
| _b = getattr(Q, "BF16", None) | |
| except Exception: | |
| _b = None | |
| if _b is not None and req_q == _b: | |
| _u32 = fused.astype(np.float32).view(np.uint32) | |
| return (((_u32 + 0x7FFF + ((_u32 >> 16) & 1)) >> 16).astype(np.uint16), _b) | |
| # All other GGML quants (Q4_0/Q4_K/Q6_K/IQ*/TQ*/MXFP4/...) via single quantize call (trivial). | |
| return quantize(fused, req_q), req_q | |
| def _fuse_delta(target_tensor, delta_f32, strict=False): | |
| """Dequant the target head once to F32 and fuse the delta (head + delta). | |
| Single seam for the three dequant→fuse sites in _gguf_fuse_one. | |
| strict (safetensors delta path only): fail clean on shape mismatch, exactly as before.""" | |
| import numpy as np | |
| from gguf.constants import GGMLQuantizationType as Q | |
| if target_tensor.tensor_type in (Q.F32, Q.F16): | |
| try: | |
| head_f32 = target_tensor.data.astype(np.float32) | |
| except Exception: | |
| head_f32 = np.asarray(target_tensor.data, dtype=np.float32) | |
| else: | |
| from gguf.quants import dequantize as _deq | |
| head_f32 = _deq(target_tensor.data, target_tensor.tensor_type) | |
| if strict and head_f32.shape != delta_f32.shape: | |
| sys.stdout.write("\n") | |
| _fail(f" ✗ Style shape {delta_f32.shape} doesn't match model head {head_f32.shape}.") | |
| return np.ascontiguousarray(head_f32 + delta_f32) | |
| def _gguf_fuse_one(target, target_tensor, tname, logical, vf32, vref, meta, args, op, vraw=None, vqtype=None): | |
| """Fuse one voice tensor into its target GGUF tensor form. Returns (q_head, out_qtype).""" | |
| import numpy as np | |
| from gguf.constants import GGMLQuantizationType as Q | |
| from gguf.quants import quantize | |
| # Philosophy: preserve quality, avoid dequant->quant cycles. | |
| # - GGUF quant voice (vraw) is kept at its obtained quant (never upscale Q2->Q6, no inventing data). | |
| # - Safetensors high-fidelity lm_head (voice) is quantized once to Q8_0. | |
| # - Generic tensors keep target quant (F32 norms stay F32, never forced Q8_0). | |
| # - All GGML quants supported (trivial passthrough + quantize where implemented). | |
| _quant_override = _parse_quant_override(getattr(args, "quant", None) or "keep") | |
| if _quant_override is None: | |
| _fail(f" ✗ Invalid --quant '{getattr(args, 'quant', None)}'. Use keep|target|<any quant like q8_0,q4_0,q4_k,q6_k,iq4_nl,f16,f32,bf16>.") | |
| _is_head = _is_head_name(vref.name) or _is_head_name(tname) | |
| _is_delta = (meta or {}).get("type") == "delta" | |
| # Show quant/target by default for advanced tensor commands (and verbose for voice) | |
| try: | |
| _tq = target_tensor.tensor_type.name | |
| except Exception: | |
| _tq = "?" | |
| try: | |
| _vq = vqtype if vraw is not None else vref.dtype | |
| except Exception: | |
| _vq = "?" | |
| if ctx.VERBOSE: | |
| _note(f"Voice '{vref.name}' is {_vq} {tuple(vref.shape)} → target '{tname}' is {_tq} {logical}") | |
| if vraw is not None: | |
| # GGUF quant voice: keep obtained quant (no upscale, no extra cycle). | |
| try: | |
| _vqtype = Q[vqtype] | |
| except Exception: | |
| _fail(f" ✗ Unknown voice quant '{vqtype}'.") | |
| if tuple(vref.shape) != logical: | |
| _fail(f" ✗ Voice shape {vref.shape} doesn't fit target tensor {tname} {logical}.") | |
| if _quant_override in ("keep",): | |
| # Transplant quant type as-is (may differ from target type — intentional, preserves quality). | |
| if _vqtype.name != target_tensor.tensor_type.name and ctx.VERBOSE: | |
| _note(f"Keeping voice quant {_vqtype.name} (target was {target_tensor.tensor_type.name}, not upscaling).") | |
| _step(f"Casting onto {os.path.basename(target)} ({_vqtype.name}, kept)…") | |
| from gguf.quants import quant_shape_to_byte_shape as _q2b_keep | |
| _keep_shape = _q2b_keep(tuple(int(x) for x in vref.shape), _vqtype) | |
| _need = 1 | |
| for _d in _keep_shape: | |
| _need *= _d | |
| _raw = np.frombuffer(vraw, dtype=np.uint8) | |
| if _raw.size < _need: | |
| _fail(f" ✗ Short voice data for transplant ({_raw.size}/{_need} bytes).") | |
| q_head, out_qtype = _raw[:_need].reshape(_keep_shape), _vqtype | |
| elif _quant_override == "target": | |
| # Explicit: dequant once then quant to target (extra cycle, warn). | |
| _warn(f"Re-quanting voice {_vqtype.name} → target {target_tensor.tensor_type.name} (extra dequant→quant cycle).") | |
| from gguf.quants import dequantize as _deq2 | |
| from gguf.quants import quant_shape_to_byte_shape as _q2b | |
| # vref.shape is logical already checked | |
| _rshape = tuple(vref.shape) | |
| try: | |
| _f32v = _deq2(np.frombuffer(vraw, dtype=np.uint8).reshape(_q2b(_rshape, _vqtype)), _vqtype) | |
| except Exception as e: | |
| _fail(f" ✗ Could not dequant voice for --quant target: {e}") | |
| if _is_delta: | |
| _f32v = _fuse_delta(target_tensor, _f32v, strict=True) | |
| t_quant0 = time.time() | |
| _tq2 = target_tensor.tensor_type | |
| if _tq2 in (Q.F32,): | |
| q_head, out_qtype = _f32v.astype(np.float32), Q.F32 | |
| elif _tq2 in (Q.F16,): | |
| q_head, out_qtype = _f32v.astype(np.float16), Q.F16 | |
| else: | |
| try: | |
| _bf = getattr(Q, "BF16", None) | |
| except Exception: | |
| _bf = None | |
| if _bf is not None and _tq2 == _bf: | |
| # BF16 target: gguf lib has no BF16 encoder here; keep F32 to avoid loss | |
| q_head, out_qtype = _f32v.astype(np.float32), Q.F32 | |
| _warn(" BF16 target: keeping F32 to avoid loss (use --quant f16/bf16 explicitly if needed).") | |
| else: | |
| try: | |
| q_head, out_qtype = quantize(_f32v, _tq2), _tq2 | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant to target {_tq2.name}: {e}") | |
| _note(f"Re-quantized {_f32v.nbytes/1e6:.1f} MB → {_tq2.name} @ {(_f32v.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| else: | |
| # Explicit q8_0/f16/f32/bf16 for quant voice: dequant once then quant. | |
| from gguf.quants import dequantize as _deq2 | |
| from gguf.quants import quant_shape_to_byte_shape as _q2b | |
| _rshape = tuple(vref.shape) | |
| try: | |
| _f32v = _deq2(np.frombuffer(vraw, dtype=np.uint8).reshape(_q2b(_rshape, _vqtype)), _vqtype) | |
| except Exception as e: | |
| _fail(f" ✗ Could not dequant voice for --quant {_quant_override}: {e}") | |
| if _is_delta: | |
| _f32v = _fuse_delta(target_tensor, _f32v, strict=True) | |
| _qn = _quant_from_key(_quant_override) | |
| if _qn is None: | |
| _fail(f" ✗ Invalid --quant '{_quant_override}'.") | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = _quantize_to_Q(_f32v, _qn) | |
| except NotImplementedError as e: | |
| _fail(f" ✗ Quant {getattr(_qn, 'name', _quant_override)} not implemented by gguf lib ({e}). Keeping original is recommended.") | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant to {_quant_override}: {e}") | |
| _note(f"Quantized {_f32v.nbytes/1e6:.1f} MB → {out_qtype.name} @ {(_f32v.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| else: | |
| oriented = _orient(vf32, vref.shape, logical) | |
| if oriented is None: | |
| _fail(f" ✗ Voice shape {vref.shape} doesn't fit target tensor {tname} {logical}.") | |
| t_fuse0 = time.time() | |
| # Decide out quant: Q8_0 once only for safetensors high-fidelity heads; else keep target. | |
| # vref.dtype here is F32/F16/BF16 (high-fidelity, since vraw is None). | |
| _target_q = target_tensor.tensor_type | |
| # Explicit override wins (any quant trivially supported via _quantize_to_Q). | |
| _req = None | |
| if _quant_override != "keep": | |
| if _quant_override == "target": | |
| _req = _target_q | |
| else: | |
| _req = _quant_from_key(_quant_override) | |
| if _req is None: | |
| _fail(f" ✗ Invalid --quant '{_quant_override}'.") | |
| t_fuse0 = time.time() | |
| if _is_delta: | |
| # Fuse first (F32 math preserves quality), decide quant after. | |
| fused = _fuse_delta(target_tensor, oriented, strict=True) | |
| if _req is not None: | |
| # Explicit --quant for delta (all quants trivial via helper). | |
| _step(f"Fusing style into {tname} (delta + head → {_req.name})…") | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = _quantize_to_Q(fused, _req) | |
| except NotImplementedError as e: | |
| _fail(f" ✗ Quant {_req.name} not implemented by gguf lib ({e}). Keeping original is recommended.") | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant delta to {_req.name}: {e}") | |
| _note(f"Quantized {fused.nbytes/1e6:.1f} MB → {_req.name} @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| elif _is_head: | |
| # Head delta from high-fidelity: Q8_0 once (old behavior, with %32 fallback). | |
| if fused.shape[-1] % 32 != 0: | |
| _warn(f"Head last dim {fused.shape[-1]} not ×32 — Q8_0 needs %32, keeping F16 (larger, compatible).") | |
| _step(f"Fusing style into {tname} (delta + head → F16 fallback)…") | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| else: | |
| _step(f"Fusing style into {tname} (delta + head → Q8_0)…") | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = quantize(fused, Q.Q8_0), Q.Q8_0 | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant delta to Q8_0: {e}") | |
| _note(f"Quantized {fused.nbytes/1e6:.1f} MB → Q8_0 @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| else: | |
| # Generic delta: keep target quant (never force Q8_0). Never upscale implicitly. | |
| _step(f"Fusing style into {tname} (delta + head → {_target_q.name}, kept)…") | |
| t_quant0 = time.time() | |
| if _target_q in (Q.F32,): | |
| q_head, out_qtype = fused.astype(np.float32), Q.F32 | |
| elif _target_q in (Q.F16,): | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| else: | |
| try: | |
| _b = getattr(Q, "BF16", None) | |
| except Exception: | |
| _b = None | |
| if _b is not None and _target_q == _b: | |
| q_head, out_qtype = fused.astype(np.float32), Q.F32 | |
| _warn(" BF16 target: keeping F32 to avoid loss (use --quant bf16 explicitly if needed).") | |
| out_qtype = Q.F32 | |
| else: | |
| try: | |
| q_head, out_qtype = quantize(fused, _target_q), _target_q | |
| except Exception as e: | |
| _near = _nearest_encodable(_target_q) | |
| if _near is not None: | |
| _warn(f" {_target_q.name} not encodable ({_qerr(e)}); keeping {_near.name} (nearest size) instead of F16.") | |
| q_head, out_qtype = _quantize_to_Q(fused, _near) | |
| else: | |
| _warn(f" Could not quant to {_target_q.name} ({_qerr(e)}), keeping F16.") | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| try: | |
| _note(f"Fused {fused.nbytes/1e6:.1f} MB → {out_qtype.name} @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| except Exception: | |
| pass | |
| else: | |
| # Not delta: voice replace (all quants trivial). | |
| if _req is not None: | |
| _step(f"Casting onto {os.path.basename(target)} ({_req.name})…") | |
| fused = oriented | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = _quantize_to_Q(fused, _req) | |
| except NotImplementedError as e: | |
| _fail(f" ✗ Quant {_req.name} not implemented by gguf lib ({e}).") | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant to {_req.name}: {e}") | |
| _note(f"Quantized {fused.nbytes/1e6:.1f} MB → {_req.name} @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| elif _is_head: | |
| # lm_head high-fidelity: quant once to Q8_0 (preserve quality, Q4 saves little). | |
| if oriented.shape[-1] % 32 != 0: | |
| _warn(f"Head last dim {oriented.shape[-1]} not ×32 — Q8_0 needs %32, keeping F16 (larger, compatible).") | |
| _step(f"Casting onto {os.path.basename(target)} (F16 fallback)…") | |
| fused = oriented | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| else: | |
| _step(f"Casting onto {os.path.basename(target)} (Q8_0)…") | |
| fused = oriented | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = quantize(fused, Q.Q8_0), Q.Q8_0 | |
| except Exception as e: | |
| sys.stdout.write("\n") | |
| if ctx.VERBOSE: | |
| _say(f" Details: {e}") | |
| _fail(" ✗ Could not prepare the voiced model. Try again.") | |
| _note(f"Quantized {fused.nbytes/1e6:.1f} MB → Q8_0 @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| else: | |
| # Generic tensor: keep target quant (fix crash: F32 norms stay F32, never forced Q8_0). | |
| _tq = _target_q | |
| try: | |
| _tqn = _tq.name | |
| except Exception: | |
| _tqn = str(_tq) | |
| try: | |
| _vqn = vref.dtype | |
| except Exception: | |
| _vqn = "?" | |
| # Mismatch prompt only for safetensors non-head high-fidelity differing from target. | |
| _need_prompt = (_vqn.upper() in ("F32", "F16", "BF16", "FP32", "FP16") and _tqn.upper() != _vqn.upper()) | |
| _custom_done = False | |
| if _need_prompt and _quant_override == "keep" and not _noninteractive(args): | |
| try: | |
| _say(f" Target '{tname}' is {_tqn}, fetched is {_vqn}.") | |
| _ans = input(f" Press enter to quantize to {_tqn} or enter custom quant (any like Q8_0/Q4_0/Q6_K/F16/F32/BF16): ").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| _say(" âš Cancelled.") | |
| sys.exit(1) | |
| _ans_n = _ans.strip().upper().replace("-", "_") | |
| if _ans.strip() == "" or _ans_n == _tqn.upper(): | |
| pass | |
| else: | |
| _ck = _parse_quant_override(_ans) | |
| _cq = _quant_from_key(_ck) if _ck not in (None, "keep", "target") else None | |
| if _ck is None or (_cq is None and _ck not in ("keep", "target")): | |
| _warn(f" Unknown quant '{_ans}', using target {_tqn}.") | |
| elif _ck == "target" or _ans_n == _tqn.upper(): | |
| pass | |
| else: | |
| _warn(f"Forcing {_ans} for generic tensor (extra quant cycle).") | |
| fused = oriented | |
| t_quant0 = time.time() | |
| try: | |
| q_head, out_qtype = _quantize_to_Q(fused, _cq) | |
| except NotImplementedError as e: | |
| _fail(f" ✗ Quant {_cq.name} not implemented ({e}).") | |
| except Exception as e: | |
| _fail(f" ✗ Could not quant to {_cq.name}: {e}") | |
| _note(f"Quantized {fused.nbytes/1e6:.1f} MB → {_cq.name} @ {(fused.nbytes/1e6)/max(time.time()-t_quant0,1e-6):.0f} MB/s") | |
| _fd = time.time() - t_fuse0 | |
| if _fd >= 0.5: | |
| _note(f"Fusing done in {_fd:.1f}s") | |
| _custom_done = True | |
| # keep-target path (default, silent when match, Enter=target when mismatch) | |
| if not _custom_done: | |
| _step(f"Casting '{vref.name}' ({_vqn}) onto '{tname}' ({_tqn}, kept)…") | |
| fused = oriented | |
| t_quant0 = time.time() | |
| if _tq in (Q.F32,): | |
| q_head, out_qtype = fused.astype(np.float32), Q.F32 | |
| elif _tq in (Q.F16,): | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| else: | |
| try: | |
| _b = getattr(Q, "BF16", None) | |
| except Exception: | |
| _b = None | |
| if _b is not None and _tq == _b: | |
| q_head, out_qtype = fused.astype(np.float32), Q.F32 | |
| _warn(" BF16 target: keeping F32 to avoid loss (use --quant bf16 explicitly if needed).") | |
| out_qtype = Q.F32 | |
| else: | |
| try: | |
| q_head, out_qtype = quantize(fused, _tq), _tq | |
| except Exception as e: | |
| _near = _nearest_encodable(_tq) | |
| if _near is not None: | |
| _warn(f" {_tqn} not encodable ({_qerr(e)}); keeping {_near.name} (nearest size) instead of F16.") | |
| q_head, out_qtype = _quantize_to_Q(fused, _near) | |
| else: | |
| q_head, out_qtype = fused.astype(np.float16), Q.F16 | |
| try: | |
| _mbk = fused.nbytes / 1e6 | |
| _note(f"Kept '{tname}': {_mbk:.1f} MB → {out_qtype.name}" + (f" @ {_mbk / max(time.time() - t_quant0, 1e-6):.0f} MB/s" if fused.nbytes >= 100000 else "")) | |
| except Exception: | |
| pass | |
| try: | |
| t_fuse0 | |
| except Exception: | |
| t_fuse0 = time.time() | |
| _fd = time.time() - t_fuse0 | |
| if _fd >= 0.5: | |
| _note(f"Fusing done in {_fd:.1f}s") | |
| return q_head, out_qtype | |
| def _gguf_write_repl(target, reader, arch, repl, out_path, args, op, detail=None, _extra_names=()): | |
| """Single-pass GGUF write. repl maps tensor name -> (array, ggml_type). | |
| detail (single-tensor callers): (tname, logical, vref, vraw, vqtype, meta) for rich messages.""" | |
| from gguf import GGUFWriter | |
| from gguf.gguf_writer import GGUFValue | |
| from gguf.constants import GGMLQuantizationType as Q | |
| if not arch: | |
| _warn(" Target architecture unknown — labeling output 'llama' (GGUF requires an arch).") | |
| writer = GGUFWriter(out_path, arch or "llama", use_temp_file=True) | |
| for field in reader.fields.values(): | |
| if field.name in ("general.architecture",) or field.name.startswith("GGUF."): | |
| continue | |
| try: | |
| val = field.contents() | |
| except Exception: | |
| continue | |
| vtype = field.types[0] if field.types else None | |
| if vtype is None: | |
| continue | |
| subtype = field.types[-1] if len(field.types) > 1 else None | |
| try: | |
| writer.kv_data[0][field.name] = GGUFValue(value=val, type=vtype, sub_type=subtype) | |
| except Exception: | |
| try: | |
| writer.add_key_value(field.name, val, vtype, subtype) | |
| except Exception: | |
| if ctx.VERBOSE: | |
| _warn(f"Could not copy field {field.name}") | |
| for t in reader.tensors: | |
| if t.name in repl: | |
| _qh, _qt = repl[t.name] | |
| writer.add_tensor(t.name, _qh, raw_dtype=_qt) | |
| elif t.tensor_type in (Q.F32, Q.F16): | |
| writer.add_tensor(t.name, t.data) | |
| else: | |
| writer.add_tensor(t.name, t.data, raw_dtype=t.tensor_type) | |
| for name in _extra_names: | |
| if name in repl and name not in [t.name for t in reader.tensors]: | |
| _qh, _qt = repl[name] | |
| writer.add_tensor(name, _qh, raw_dtype=_qt) | |
| # writing GGUF is the long wait (often 5-30s for 26GB) — show bar with speed, internet or local | |
| _step(f"Writing {out_path} …") | |
| # estimate total bytes for progress — use data.nbytes | |
| try: | |
| total_write = 8192 | |
| for t in reader.tensors: | |
| if t.name in repl: | |
| continue | |
| try: | |
| total_write += int(t.data.nbytes) | |
| except Exception as e: | |
| if ctx.VERBOSE: | |
| _warn(f"progress estimate for {t.name} failed: {e}") | |
| try: | |
| for _qh, _qt in repl.values(): | |
| total_write += int(_qh.nbytes) | |
| except Exception: | |
| try: | |
| for _qh, _qt in repl.values(): | |
| total_write += int(_qh.size * _qh.itemsize) | |
| except Exception: | |
| pass | |
| if ctx.VERBOSE: | |
| _note(f"Estimated write {total_write/1e6:.1f} MB ({len(repl)} replaced + {len([t for t in reader.tensors if t.name not in repl])} copied)") | |
| except Exception as e: | |
| if ctx.VERBOSE: | |
| _warn(f"progress estimate failed: {e}") | |
| total_write = 0 | |
| # ensure total_write is at least header + heads for small models, never 0 for progress | |
| if total_write < 1000: | |
| try: | |
| total_write = 8192 | |
| for _qh, _qt in repl.values(): | |
| try: | |
| total_write += int(_qh.nbytes) | |
| except Exception: | |
| pass | |
| for t in reader.tensors: | |
| if t.name not in repl: | |
| try: | |
| total_write += int(t.data.nbytes) | |
| except Exception: | |
| pass | |
| except Exception: | |
| pass | |
| if total_write < 1000: | |
| total_write = 0 | |
| t_write0 = time.time() | |
| last_w = [0.0] | |
| # progress poll for GGUF write (local disk, but user is waiting) | |
| import threading | |
| _stop_poll = [False] | |
| _tiny_w = bool(total_write) and total_write < 100000 | |
| def _poll_gguf(): | |
| # poll output file (or temp file) size | |
| target_path = getattr(writer, 'fname', out_path) | |
| # GGUFWriter with use_temp_file=True writes to temp file with suffix | |
| # fallback to out_path | |
| poll_path = target_path if os.path.exists(target_path) else out_path | |
| # try to find temp file if not yet at final path | |
| while not _stop_poll[0]: | |
| try: | |
| cur = 0 | |
| if os.path.exists(poll_path): | |
| cur = os.path.getsize(poll_path) | |
| else: | |
| # try temp file pattern | |
| import glob | |
| tmps = glob.glob(str(out_path) + "*") | |
| for p in tmps: | |
| if os.path.isfile(p): | |
| try: | |
| cur = max(cur, os.path.getsize(p)) | |
| except Exception: | |
| pass | |
| elapsed = time.time() - t_write0 or 1e-6 | |
| mbps = cur / elapsed / 1e6 | |
| pct = (cur / total_write * 100) if total_write else 0 | |
| if pct > 100: | |
| pct = 100 | |
| if total_write: | |
| msg = f" → writing {pct:3.0f}% · {cur/1e6:.1f}/{total_write/1e6:.1f} MB · {mbps:.0f} MB/s " | |
| else: | |
| msg = f" → writing {cur/1e6:.1f} MB · {mbps:.0f} MB/s " | |
| sys.stdout.write(_transform(msg) + ("\n" if _progress_pref() else "\r")) | |
| sys.stdout.flush() | |
| except Exception: | |
| pass | |
| time.sleep(0.25) | |
| _thr = threading.Thread(target=_poll_gguf, daemon=True) | |
| if not _tiny_w: | |
| _thr.start() | |
| try: | |
| writer.write_header_to_file() | |
| writer.write_kv_data_to_file() | |
| writer.write_tensors_to_file() | |
| writer.close() | |
| except Exception as e: | |
| _stop_poll[0] = True | |
| if not _tiny_w: | |
| try: | |
| _thr.join(timeout=0.5) | |
| except Exception: | |
| pass | |
| sys.stdout.write("\n") | |
| if ctx.VERBOSE: | |
| _say(f" Details: {e}") | |
| _fail(f" ✗ Could not save the voiced model to {out_path}.") | |
| _stop_poll[0] = True | |
| if not _tiny_w: | |
| try: | |
| _thr.join(timeout=0.5) | |
| except Exception: | |
| pass | |
| sys.stdout.write("\n") | |
| elapsed_w = time.time() - t_write0 or 1e-6 | |
| try: | |
| final_sz = os.path.getsize(out_path) | |
| _rate_w = f" @ {final_sz / elapsed_w / 1e6:.0f} MB/s" if final_sz >= 100000 else "" | |
| _note(f"Wrote {final_sz / 1e6:.1f} MB{_rate_w}") | |
| except Exception: | |
| pass | |
| file_size = os.path.getsize(out_path) | |
| if detail is None: | |
| summed = [(n, _qt.name if hasattr(_qt, "name") else str(_qt)) for n, (_qh, _qt) in repl.items()] | |
| log_operation({"op": op, "target": target, "format": "gguf", "tensors": summed, | |
| "output": out_path, "status": "ok"}) | |
| _ok(f"Done → {out_path}") | |
| for n, _qt in summed: | |
| _say(f" Cast '{n}' → {_qt} ({file_size/1e6:.1f} MB total).") | |
| _say(f" Load it: llama serve -m {out_path}") | |
| return | |
| tname, logical, vref, vraw, vqtype, meta = detail | |
| _qh0, out_qtype = repl[tname] | |
| log_operation({"op": op, "target": target, "format": "gguf", "tensor": tname, | |
| "dtype": out_qtype.name, "shape": list(logical), "output": out_path, "status": "ok"}) | |
| _ok(f"Done → {out_path}") | |
| is_fallback = 'fallback_to_f16' in locals() and locals().get('fallback_to_f16') | |
| _is_head_msg = _is_head_name(tname) or _is_head_name(getattr(vref, "name", None)) | |
| _label = "Head" if _is_head_msg else "Tensor" | |
| if (meta or {}).get("type") == "delta" and is_fallback: | |
| _say(f" Style fused and head kept as F16 (Q8_0 needs %32, fallback) ({file_size/1e6:.1f} MB).") | |
| elif (meta or {}).get("type") == "delta": | |
| # Delta head keeps Q8_0 for heads, keeps target for generic. | |
| if _is_head_msg and out_qtype == Q.Q8_0: | |
| _say(f" Style fused and head quantized to Q8_0 ({file_size/1e6:.1f} MB).") | |
| else: | |
| _say(f" Style fused into '{tname}' → {out_qtype.name}, kept ({file_size/1e6:.1f} MB).") | |
| elif is_fallback: | |
| _say(f" Head kept as F16 (Q8_0 needs last dim %32, fallback) ({file_size/1e6:.1f} MB).") | |
| elif out_qtype == Q.Q8_0 and _is_head_msg: | |
| _qo = _parse_quant_override(getattr(args, "quant", None) or "keep") | |
| _kept_q8 = (vraw is not None and isinstance(vqtype, str) and vqtype == Q.Q8_0.name and _qo in ("keep",)) | |
| if _kept_q8: | |
| _say(f" Head kept as Q8_0 (from {vqtype}, {file_size/1e6:.1f} MB).") | |
| else: | |
| _say(f" Head quantized to Q8_0 ({file_size/1e6:.1f} MB).") | |
| else: | |
| _from = vqtype if vraw is not None else getattr(vref, "dtype", "?") | |
| _say(f" {_label} '{tname}' kept as {out_qtype.name} (from {_from}, {file_size/1e6:.1f} MB).") | |
| _say(f" Load it: llama serve -m {out_path}") | |
| def _read_gguf_arch(reader): | |
| """Single arch-reader for GGUF targets. Returns the general.architecture string or None.""" | |
| import numpy as np | |
| for field in reader.fields.values(): | |
| if field.name == "general.architecture": | |
| try: | |
| raw = field.parts[field.data[0]] | |
| return raw.tobytes().decode() if isinstance(raw, np.ndarray) else str(raw) | |
| except Exception: | |
| return None | |
| return None | |
| def _confirm_arch_mismatch(varch, arch, args): | |
| """Single mismatch warn (+ confirm) shared by single and pack GGUF casts.""" | |
| if varch and arch and varch.lower() != arch.lower(): | |
| _warn(f"This voice was trained for a {varch} model, but the target is {arch}. It may not sound right.") | |
| if not _confirm(" Continue anyway? [y/N]: ", args): | |
| _note("Cancelled.") | |
| sys.exit(1) | |
| def _cast_gguf_speak(target, reader, arch, out_path, vf32, vref, meta, args, op, vraw=None, vqtype=None): | |
| """--speak: voice onto output.weight, invented if absent. GGUF only.""" | |
| import numpy as np | |
| from gguf.constants import GGMLQuantizationType as Q | |
| from gguf.quants import quantize, quant_shape_to_byte_shape | |
| if (meta or {}).get("type") == "delta": | |
| _fail(" ✗ --speak cannot place a delta voice (differences are not weights).") | |
| names = [t.name for t in reader.tensors] | |
| ot = next((t for t in reader.tensors if t.name == "output.weight"), None) | |
| et = next((t for t in reader.tensors if t.name == "token_embd.weight"), None) | |
| if ot is not None: | |
| olog = tuple(reversed(tuple(int(x) for x in ot.shape))) | |
| invented = False | |
| elif et is not None: | |
| olog = tuple(reversed(tuple(int(x) for x in et.shape))) | |
| invented = True | |
| else: | |
| _fail(" ✗ Target has no output.weight or token_embd.weight to mirror geometry from.") | |
| varch = (meta or {}).get("architecture") | |
| _confirm_arch_mismatch(varch, arch, args) | |
| tname = "output.weight" | |
| if vraw is not None: | |
| _vqtype = Q[vqtype] | |
| if tuple(vref.shape) != olog: | |
| _fail(f" ✗ Voice shape {vref.shape} doesn't fit {tname} {olog}.") | |
| _qo = _parse_quant_override(getattr(args, "quant", None) or "keep") | |
| if _qo not in ("keep",): | |
| fitted = _gguf_raw_to_f32(vraw, _vqtype, tuple(reversed(tuple(int(x) for x in vref.shape)))) | |
| q_head, out_qtype = _quantize_to_Q(np.ascontiguousarray(fitted), Q[_qo.upper()]) | |
| else: | |
| _need = 1 | |
| for _d in quant_shape_to_byte_shape(tuple(int(x) for x in vref.shape), _vqtype): | |
| _need *= _d | |
| _raw = np.frombuffer(vraw, dtype=np.uint8) | |
| if _raw.size < _need: | |
| _fail(f" ✗ Voice data too short for {vqtype} {tuple(vref.shape)}.") | |
| q_head = np.ascontiguousarray(_raw[:_need].reshape( | |
| quant_shape_to_byte_shape(tuple(int(x) for x in vref.shape), _vqtype))) | |
| out_qtype = _vqtype | |
| else: | |
| fitted = _orient(vf32, vref.shape, olog) | |
| if fitted is None: | |
| _fail(f" ✗ Voice shape {vref.shape} doesn't fit {tname} {olog}.") | |
| fitted = np.ascontiguousarray(fitted) | |
| _qo = _parse_quant_override(getattr(args, "quant", None) or "keep") | |
| if _qo is None: | |
| _fail(f" ✗ Invalid --quant '{getattr(args, 'quant', None)}'.") | |
| if _qo not in ("keep",): | |
| q_head, out_qtype = _quantize_to_Q(fitted, Q[_qo.upper()]) | |
| elif fitted.shape[-1] % 32 == 0: | |
| q_head, out_qtype = quantize(fitted, Q.Q8_0), Q.Q8_0 | |
| else: | |
| _note(f" Head last dim {fitted.shape[-1]} not ×32 — Q8_0 needs %32, keeping F16 (larger, compatible).") | |
| q_head, out_qtype = fitted.astype(np.float16), Q.F16 | |
| if invented: | |
| _note(" speak: voice → invented output.weight (file untied)") | |
| else: | |
| _note(" speak: voice → output.weight") | |
| _gguf_write_repl(target, reader, arch, {tname: (q_head, out_qtype)}, out_path, args, op, | |
| detail=(tname, olog, vref, vraw, vqtype, meta), | |
| _extra_names=(tname,) if invented else ()) | |
| def _cast_gguf(target, out_path, vf32, vref, meta, args, op, vraw=None, vqtype=None, strict_target=False, target_name=None): | |
| import numpy as np | |
| from gguf import GGUFReader | |
| reader = GGUFReader(target) | |
| arch = _read_gguf_arch(reader) | |
| if getattr(args, "speak", False): | |
| _cast_gguf_speak(target, reader, arch, out_path, vf32, vref, meta, args, op, vraw=vraw, vqtype=vqtype) | |
| return | |
| target_tensor = None | |
| if target_name is not None: | |
| # Explicitly routed (requested subset): honor it, never fall back. | |
| for t in reader.tensors: | |
| if t.name == target_name: | |
| target_tensor = t | |
| break | |
| if target_tensor is None: | |
| _fail(f" ✗ Resolved target '{target_name}' for '{vref.name}' not in {target}.") | |
| if target_tensor is None and vref.name: | |
| for t in reader.tensors: | |
| if t.name == vref.name: | |
| target_tensor = t | |
| break | |
| if target_tensor is None and strict_target: | |
| _fail(f" ✗ Tensor '{vref.name}' not found in target {target}. Voicepack requires exact match (not mapping to another tensor).") | |
| if target_tensor is None: | |
| for preferred in ("output.weight", "token_embd.weight"): | |
| for t in reader.tensors: | |
| if t.name == preferred: | |
| target_tensor = t | |
| break | |
| if target_tensor is not None: | |
| break | |
| if target_tensor is None: | |
| _fail(" ✗ Target has no output.weight or token_embd.weight to receive the voice.") | |
| tname = target_tensor.name | |
| logical = tuple(reversed(tuple(int(x) for x in target_tensor.shape))) | |
| # arch mismatch warning | |
| varch = (meta or {}).get("architecture") | |
| _confirm_arch_mismatch(varch, arch, args) | |
| q_head, out_qtype = _gguf_fuse_one(target, target_tensor, tname, logical, vf32, vref, meta, args, op, vraw=vraw, vqtype=vqtype) | |
| _gguf_write_repl(target, reader, arch, {tname: (q_head, out_qtype)}, out_path, args, op, | |
| detail=(tname, logical, vref, vraw, vqtype, meta)) | |
| # GGUF (llama.cpp) <-> safetensors (HF) tensor-name aliases, matched by | |
| # (block index, role). Exact name match always wins; aliases only fire on a | |
| # miss, and only when exactly one candidate matches. Anything else fails loud | |
| # at the call site — never a silent mapping to another tensor. | |
| _ROLE_ALIASES = ( | |
| ("embed_tokens.weight", "token_embd.weight"), | |
| ("word_embeddings.weight", "token_embd.weight"), | |
| ("wte.weight", "token_embd.weight"), | |
| ("output_layer.weight", "output.weight"), | |
| ("lm_head.weight", "output.weight"), | |
| ("final_layernorm.weight", "output_norm.weight"), | |
| ("self_attention.dense.weight", "attn_output.weight"), | |
| ("mlp.dense_4h_to_h.weight", "ffn_down.weight"), | |
| ("model.norm.weight", "output_norm.weight"), | |
| ("ln_f.weight", "output_norm.weight"), | |
| ("input_layernorm.weight", "attn_norm.weight"), | |
| ("self_attn.q_proj.weight", "attn_q.weight"), | |
| ("self_attn.k_proj.weight", "attn_k.weight"), | |
| ("self_attn.v_proj.weight", "attn_v.weight"), | |
| ("self_attn.o_proj.weight", "attn_o.weight"), | |
| ("self_attn.o_proj.weight", "attn_output.weight"), | |
| ("post_attention_layernorm.weight", "post_attention_norm.weight"), | |
| ("mlp.down_proj.weight", "ffn_down.weight"), | |
| ("experts.down_proj", "ffn_down_exps.weight"), | |
| ("mlp.up_proj.weight", "ffn_up.weight"), | |
| ) | |
| def _block_index(name): | |
| import re | |
| m = re.search(r"(?<![A-Za-z0-9_])(?:layers|layer|blk|blks|blocks|h)\.(\d+)\b", name) | |
| if m: | |
| return int(m.group(1)) | |
| m = re.search(r"\.(\d+)\.", name) | |
| return int(m.group(1)) if m else None | |
| def _pack_aliases(vname, target_names): | |
| """All alias matches for vname in target_names (either naming direction). | |
| Exact match is handled by callers first; this only fires on a miss.""" | |
| hits = [] | |
| for st_suf, gg_suf in _ROLE_ALIASES: | |
| for t in target_names: | |
| st_v = vname.endswith(st_suf) | |
| gg_v = vname.endswith(gg_suf) | |
| st_t = t.endswith(st_suf) | |
| gg_t = t.endswith(gg_suf) | |
| if (st_v and gg_t) or (gg_v and st_t): | |
| if _block_index(vname) == _block_index(t) and t not in hits: | |
| hits.append(t) | |
| return hits | |
| def _role_key(name): | |
| """(block_index, trailing_role) canonical key for same-format matching. | |
| Trailing role is everything after the block number (e.g. | |
| 'self_attn.o_proj.weight'); unblocked names fall back to their last two | |
| components (e.g. 'embed_tokens.weight'). The .weight/.bias suffix stays | |
| in the key so a bias never matches a weight. The block keyword | |
| (layers/blk/...) is left-guarded against mid-word hits; the generic | |
| dotted-number fallback still fires on version-like segments, so the | |
| elem-count gate remains the real false-friend veto.""" | |
| import re | |
| m = re.search(r"(?<![A-Za-z0-9_])(?:layers|layer|blk|blks|blocks|h)\.(\d+)\b", name) | |
| if m: | |
| return (int(m.group(1)), name[m.end():].strip(".")) | |
| m = re.search(r"\.(\d+)\.", name) | |
| if m: | |
| return (int(m.group(1)), name[m.end():].strip(".")) | |
| parts = name.split(".") | |
| return (None, ".".join(parts[-2:])) | |
| def _same_role(vname, target_names): | |
| """Targets sharing vname's (block, trailing role). Cross-format pairs | |
| (ST suffix vs GGUF suffix) never collide here — _ROLE_ALIASES owns those. | |
| Only fires on a miss; callers gate on elem-count and uniqueness.""" | |
| want = _role_key(vname) | |
| return [t for t in target_names if _role_key(t) == want] | |
| def _cast_gguf_pack(target, out_path, items, args, op): | |
| """Single-pass pack cast onto GGUF. items: [(vf32, vref, meta, vraw, vqtype)].""" | |
| import numpy as np | |
| from gguf import GGUFReader | |
| reader = GGUFReader(target) | |
| arch = _read_gguf_arch(reader) | |
| varch = (items[0][2] or {}).get("architecture") if items else None | |
| _confirm_arch_mismatch(varch, arch, args) | |
| _names = [t.name for t in reader.tensors] | |
| _counts = {} | |
| for t in reader.tensors: | |
| try: | |
| n = 1 | |
| for d in t.shape: | |
| n *= int(d) | |
| _counts[t.name] = n | |
| except Exception: | |
| pass | |
| _map = _resolve_pack_targets([(ref.name, ref.shape) for (_, ref, _, _, _) in items], | |
| _names, target, _counts) | |
| repl = {} | |
| for vf32, vref, meta, vraw, vqtype in items: | |
| target_tensor = next(t for t in reader.tensors if t.name == _map[vref.name]) | |
| tname = target_tensor.name | |
| logical = tuple(reversed(tuple(int(x) for x in target_tensor.shape))) | |
| q_head, out_qtype = _gguf_fuse_one(target, target_tensor, tname, logical, vf32, vref, meta, args, op, vraw=vraw, vqtype=vqtype) | |
| repl[tname] = (q_head, out_qtype) | |
| _gguf_write_repl(target, reader, arch, repl, out_path, args, op) | |
| def _resolve_pack_targets(pairs, target_names, target, counts=None): | |
| """Map every voice tensor to a target tensor (exact, else one alias, | |
| else one same-role same-format match). | |
| Resolves ALL up front so a pack fails once with every miss — never | |
| fix-forward one at a time. Same-size targets are offered as hints only. | |
| pairs: [(voice_name, voice_shape)]; counts: {target_name: elem_count}. | |
| Voice shapes are logical-as-is (GgufSource.ref already reverses); | |
| only elem-counts are compared, so transposes pass and nothing double-flips.""" | |
| def _want(vshape): | |
| if vshape is None: | |
| return None | |
| n = 1 | |
| for d in vshape: | |
| n *= int(d) | |
| return n | |
| mapping, misses = {}, [] | |
| for vname, vshape in pairs: | |
| if vname in target_names: | |
| mapping[vname] = vname | |
| continue | |
| cands = _pack_aliases(vname, target_names) | |
| if len(cands) == 1: | |
| mapping[vname] = cands[0] | |
| _note(f" Aliased '{vname}' → '{cands[0]}' ({target} naming).") | |
| elif len(cands) > 1: | |
| misses.append(f" '{vname}' is ambiguous: {', '.join(cands)}") | |
| else: | |
| roles = [t for t in _same_role(vname, target_names) | |
| if _want(vshape) is None or counts is None | |
| or counts.get(t, _want(vshape)) == _want(vshape)] | |
| if len(roles) == 1: | |
| mapping[vname] = roles[0] | |
| _note(f" Aliased '{vname}' → '{roles[0]}' (same role).") | |
| continue | |
| if len(roles) > 1: | |
| misses.append(f" '{vname}' is ambiguous: {', '.join(roles)}") | |
| continue | |
| hint = "" | |
| if counts is not None and vshape is not None: | |
| same = [t for t in target_names if counts.get(t) == _want(vshape)][:3] | |
| if same: | |
| hint = f" (same size: {', '.join(same)})" | |
| misses.append(f" '{vname}' not found{hint}") | |
| if misses: | |
| _fail(f" ✗ {len(misses)} tensor(s) have no match in target {target}:\n" | |
| + "\n".join(misses) | |
| + "\n Voicepack requires exact match (not mapping to another tensor).") | |
| return mapping | |
| def _cast_pack(target, src_path, out_path, args, op, excludes=(), meta=None, order=()): | |
| """Cast every tensor in a pack file onto target (minus excludes). | |
| GGUF and safetensors targets each get one write pass (repl-dict fused first). | |
| Delta marker on the pack is detected once and threaded into every tensor. | |
| order (requested subset): process in the user's order, not file order.""" | |
| if getattr(args, "speak", False) and not _is_gguf_file(target): | |
| _fail(" ✗ --speak needs a .gguf target. Re-run without --speak for .safetensors, or point cast at a .gguf file.") | |
| src = open_source(str(src_path)) | |
| all_names = [n for n in src.names() if n != "delta.voice.marker"] | |
| for e in excludes: | |
| if e not in all_names and not any(e in n for n in all_names): | |
| _warn(f" --exclude '{e}' not in pack (has {len(all_names)} tensors). Ignoring.") | |
| resolved_ex = set() | |
| for e in excludes: | |
| if e in all_names: | |
| resolved_ex.add(e) | |
| else: | |
| _m = [n for n in all_names if e in n] | |
| if len(_m) == 1: | |
| resolved_ex.add(_m[0]) | |
| elif len(_m) > 1: | |
| _fail(f" ✗ --exclude '{e}' is ambiguous: {', '.join(_m)}. Name one tensor exactly.") | |
| to_cast = [n for n in all_names if n not in resolved_ex] | |
| if order: | |
| _pos = {n: i for i, n in enumerate(order)} | |
| to_cast.sort(key=lambda n: (_pos.get(n, len(_pos)), n)) | |
| if not to_cast: | |
| _fail(" ✗ --exclude removes all tensors. Nothing to cast.") | |
| _step(f"Casting {len(to_cast)} tensors from {Path(src_path).name} onto {Path(target).name}…") | |
| if resolved_ex: | |
| _note(f"Excluding {len(resolved_ex)}: {', '.join(sorted(resolved_ex))}") | |
| is_delta_file = str(src_path).endswith(".safetensors") and _is_delta_safetensors(str(src_path)) | |
| if is_delta_file: | |
| _note("Detected delta voice — fusing style (delta + head)…") | |
| if meta is None and is_delta_file: | |
| meta = {"type": "delta", "source": str(src_path)} | |
| items = [] | |
| for i, tname in enumerate(to_cast): | |
| f32, ref, raw, qtype = _load_tensor(src_path, tname, _src=src) | |
| _step(f"[{i+1}/{len(to_cast)}] {tname} ({ref.dtype} {tuple(ref.shape)})…") | |
| items.append((f32, ref, meta, raw, qtype)) | |
| if _is_gguf_file(target): | |
| _cast_gguf_pack(target, out_path, items, args, op) | |
| return | |
| _header, _tensors = read_safetensors(target) | |
| _st_names = list(_tensors.keys()) | |
| _st_counts = {} | |
| for _n, _info in _tensors.items(): | |
| try: | |
| _c = 1 | |
| for _d in _info["shape"]: | |
| _c *= int(_d) | |
| _st_counts[_n] = _c | |
| except Exception: | |
| pass | |
| _st_map = _resolve_pack_targets([(ref.name, ref.shape) for (_, ref, _, _, _) in items], | |
| _st_names, target, _st_counts) | |
| repl = {} | |
| for f32, ref, m, raw, qtype in items: | |
| tname, data, tdtype, tshape = _cast_st_prepare(target, _tensors, f32, ref, m, args, | |
| vraw=raw, vqtype=qtype, strict_target=True, | |
| target_name=_st_map[ref.name]) | |
| repl[tname] = (data, tdtype, tshape) | |
| _step(f"Replacing {len(repl)} tensors in {Path(target).name}…") | |
| _safetensors_write_repl(target, repl, out_path) | |
| file_size = os.path.getsize(out_path) | |
| log_operation({"op": op, "target": target, "format": "safetensors", | |
| "tensors": [(n, d) for n, (_b, d, _s) in repl.items()], | |
| "output": out_path, "status": "ok"}) | |
| _ok(f"Done → {out_path}") | |
| for n, (_b, d, _s) in repl.items(): | |
| _say(f" Tensor '{n}' replaced at {d} ({file_size/1e6:.1f} MB total).") | |
| def _parse_tensor_list(args): | |
| # Tensor positionals (get/cast tensors...), with comma-split for shell convenience. | |
| raw = getattr(args, "tensors", None) or [] | |
| if isinstance(raw, str): | |
| raw = [raw] | |
| # Split comma-separated entries, strip, drop empties. | |
| out = [] | |
| for r in raw: | |
| if r is None: | |
| continue | |
| for part in str(r).split(","): | |
| part = part.strip() | |
| if part: | |
| out.append(part) | |
| return out | |
| def _parse_exclude_list(args): | |
| raw = getattr(args, "excludes", None) or getattr(args, "exclude", None) or [] | |
| if isinstance(raw, str): | |
| raw = [raw] | |
| out = [] | |
| for r in (raw or []): | |
| for part in str(r).split(","): | |
| part = part.strip() | |
| if part: | |
| out.append(part) | |
| return out | |
| def _resolve_one_tensor(req, names): | |
| # Exact match first, then single substring match, else fail. Returns resolved name. | |
| if req in names: | |
| return req | |
| matches = [n for n in names if req and req in n] | |
| if len(matches) == 1: | |
| return matches[0] | |
| if len(matches) > 1: | |
| _fail(f" ✗ '{req}' is ambiguous: {', '.join(matches[:8])}…") | |
| _fail(f" ✗ Tensor '{req}' not found. Try one of: {', '.join(names[:10])}") | |
| def _tensor_src_meta(src_path): | |
| """File-level delta detection for the tensor path (the marker lives in the file; no voice.json).""" | |
| if str(src_path).endswith(".safetensors"): | |
| try: | |
| if _is_delta_safetensors(str(src_path)): | |
| return {"type": "delta", "source": str(src_path)} | |
| except Exception: | |
| pass | |
| return None | |
| def _load_tensor(path, name=None, _src=None): | |
| src = _src if _src is not None else open_source(str(path)) | |
| names = src.names() | |
| if not names: | |
| _fail(f" ✗ No tensors found in {path}.") | |
| if name is None: | |
| name = "output.weight" if "output.weight" in names else names[0] | |
| if name not in names: | |
| matches = [n for n in names if name in n] | |
| if len(matches) == 1: | |
| name = matches[0] | |
| else: | |
| _fail(f" ✗ Tensor '{name}' not found in {path}.") | |
| ref = src.ref(name) | |
| if src.kind == "gguf" and _is_ggml_quant(ref.dtype): | |
| return None, ref, src.read_raw(name), ref.dtype | |
| return src.read_f32(name), ref, None, None | |