"""Offline Kitten ternary checkpoint reader for GGML Q8_0/Q4_0/TQ2_1 storage. Packing follows KittenML/KittenTTS kittenml/kittentts2/ternary.py. Updated exports require NumPy, PyTorch and safetensors during conversion only. TQ2_1 uses audio.cpp's type ID 44, not the Kitten llama.cpp fork's ID 43. """ from __future__ import annotations import json import math import re import shutil import struct import tempfile from pathlib import Path import numpy as np import torch from safetensors import safe_open def unpack_ternary(codes, scale, shape): if len(shape) != 2 or shape[1] % 128 or tuple(scale.shape) != (shape[0], shape[1] // 128): raise ValueError("invalid ternary matrix geometry") packed = codes.numpy() count = math.prod(shape) if packed.dtype != np.uint8 or packed.size != (count + 4) // 5 or np.any(packed > 242): raise ValueError("invalid base-3 ternary codes") digits = ((packed[:, None].astype(np.int16) // np.array([1, 3, 9, 27, 81])) % 3 - 1) values = torch.from_numpy(digits.reshape(-1)[:count].copy()).to(torch.bfloat16) return (values.reshape(shape[0], -1, 128) * scale[..., None]).reshape(shape) def exact_ternary_blocks(tensor, bits): """Encode BF16 ternary values exactly in ordinary Q4_0 or Q8_0 blocks.""" if bits not in (4, 8) or tensor.ndim != 2 or tensor.shape[-1] % 32: raise ValueError("invalid GGML block geometry") values = tensor.float().numpy().reshape(-1, 32) gamma = np.max(np.abs(values), axis=1) if not np.all(np.isfinite(values)) or np.any((values != 0) & (np.abs(values) != gamma[:, None])): raise ValueError("matrix is not ternary within each GGML block") magnitude = np.full(gamma.shape, 4 if bits == 4 else 64, dtype=np.float32) scale = (gamma / magnitude).astype(' 4 or any(dim <= 0 for dim in shape): raise ValueError(f'invalid tensor shape: {name}') offset = data.tell() entries.append((name, shape, dtype, offset)) data.write(payload) data.write(bytes(-data.tell() % 32)) with path.open('wb') as target: target.write(struct.pack('<4sIQQ', b'GGUF', 3, len(entries), 0)) for name, shape, dtype, offset in entries: target.write(string(name) + struct.pack('