ASHQ1 / imatrix_reader.py
wepiqx's picture
ASHQ1 v6: IQ tier spectrum, --allow-q3-or-lower, has_imatrix safety
c99f13f
Raw
History Blame Contribute Delete
5.58 kB
import gguf
import numpy as np
from typing import List
def read_imatrix(path: str) -> dict:
"""Parse imatrix GGUF, return per-tensor importance data."""
r = gguf.GGUFReader(path)
raw = {}
meta = {}
for k, v in r.fields.items():
try:
meta[k] = v.data
except:
meta[k] = str(v)
for t in r.tensors:
name = t.name
arr = np.array(t.data, dtype=np.float64)
if name.endswith(".in_sum2"):
base = name[:-8]
if base not in raw:
raw[base] = {}
raw[base]["in_sum2"] = arr
elif name.endswith(".counts"):
base = name[:-7]
if base not in raw:
raw[base] = {}
raw[base]["counts"] = float(np.mean(arr))
result = {}
for base, data in raw.items():
if "in_sum2" not in data:
continue
arr = data["in_sum2"]
result[base] = {
"importance_mean": float(np.mean(arr)),
"importance_sum": float(np.sum(arr)),
"importance_max": float(np.max(arr)),
"importance_min": float(np.min(arr)),
"n_elements": arr.size,
"in_sum2_raw": arr,
}
return {
"path": path,
"tensors": result,
"n_tensors": len(result),
"meta": meta,
}
def combine_imatrix(imatrix_list: List[dict], method: str = "max") -> dict:
"""Combine multiple imatrix into one by aggregating importance.
Args:
imatrix_list: List of imatrix dicts from read_imatrix()
method: "max", "mean", or "weighted_mean"
"""
if not imatrix_list:
return {}
if len(imatrix_list) == 1:
return imatrix_list[0]
# Get all tensor names across all imatrix
all_names = set()
for im in imatrix_list:
all_names.update(im["tensors"].keys())
combined_tensors = {}
for name in all_names:
vals = []
in_sum2_raw = None
n_elements = 0
for im in imatrix_list:
if name in im["tensors"]:
t = im["tensors"][name]
vals.append(t["importance_mean"])
if in_sum2_raw is None and "in_sum2_raw" in t:
in_sum2_raw = t["in_sum2_raw"]
n_elements = max(n_elements, t["n_elements"])
if not vals:
continue
if method == "max":
imp_mean = max(vals)
elif method == "mean":
imp_mean = sum(vals) / len(vals)
elif method == "weighted_mean":
# Could weight by n_elements or dataset size
imp_mean = sum(vals) / len(vals)
else:
imp_mean = max(vals)
combined_tensors[name] = {
"importance_mean": imp_mean,
"importance_sum": imp_mean * n_elements,
"importance_max": max(v.get("importance_max", 0) for im in imatrix_list if name in im["tensors"] for v in [im["tensors"][name]]),
"importance_min": min(v.get("importance_min", float('inf')) for im in imatrix_list if name in im["tensors"] for v in [im["tensors"][name]]),
"n_elements": n_elements,
"in_sum2_raw": in_sum2_raw,
}
# Merge metadata
combined_meta = {}
for im in imatrix_list:
for k, v in im["meta"].items():
if k not in combined_meta:
combined_meta[k] = v
return {
"path": "+".join(im["path"] for im in imatrix_list),
"tensors": combined_tensors,
"n_tensors": len(combined_tensors),
"meta": combined_meta,
}
def detect_tied_groups(imatrix: dict, atol: float = 1e-5) -> list:
"""Find tied tensor groups (identical importance arrays)."""
names = sorted(imatrix["tensors"].keys())
tied_groups = []
visited = set()
for i, n1 in enumerate(names):
if n1 in visited:
continue
group = [n1]
arr1 = imatrix["tensors"][n1].get("in_sum2_raw")
if arr1 is None:
tied_groups.append(group)
visited.add(n1)
continue
for j in range(i + 1, len(names)):
n2 = names[j]
if n2 in visited:
continue
arr2 = imatrix["tensors"][n2].get("in_sum2_raw")
if arr2 is None:
continue
if arr1.shape == arr2.shape and np.allclose(arr1, arr2, atol=atol):
group.append(n2)
visited.add(n2)
tied_groups.append(group)
visited.add(n1)
return tied_groups
def build_importance_table(imatrix: dict, model: dict) -> dict:
"""Build unified importance table, merging imatrix with model tensor info."""
table = {}
for tname, info in imatrix["tensors"].items():
ttype = _imatrix_type(tname)
table[tname] = {
"importance_mean": info["importance_mean"],
"importance_sum": info["importance_sum"],
"importance_max": info["importance_max"],
"importance_min": info["importance_min"],
"n_elements": info["n_elements"],
"type": ttype,
}
# Also index by name without trailing dot (safety for old code)
for tname, info in list(table.items()):
if tname.endswith("."):
alt = tname.rstrip(".")
table[alt] = info
return table
def _imatrix_type(name: str) -> str:
parts = name.split(".")
if len(parts) >= 3 and parts[0] == "blk":
return parts[2]
return name