Bruce001's picture
download
raw
7.09 kB
#!/usr/bin/env python3
import argparse
import json
import os
import sys
from model_reader import read_model
from imatrix_reader import read_imatrix, detect_tied_groups, build_importance_table
from classifier import optimal_classify, compute_stats
from config_generator import generate_flags, format_flags
from quantizer import run_dry_run, run_quantization
from constants import CLASS_HARD_FLOORS
def _get_base_type(model: dict) -> str:
is_qat = model.get("features", {}).get("is_qat", False)
return "IQ4_XS" if is_qat else "Q5_K_M"
def main():
parser = argparse.ArgumentParser(
description="SHQ-program: imatrix-driven hybrid quantization"
)
parser.add_argument("--model", help="BF16 GGUF model path")
parser.add_argument("--imatrix", action="append", default=[],
help="Imatrix GGUF path (can be specified multiple times)")
parser.add_argument("--imatrix-method", choices=["max", "mean"], default="max",
help="How to combine multiple imatrix: max (conservative) or mean (default: max)")
parser.add_argument("--size", type=float, default=6800,
help="Target file size in MiB (default: 6800 = ~6.6 GB)")
parser.add_argument("--output", default=None, help="Output GGUF path")
parser.add_argument("--run", action="store_true", help="Execute quantization")
parser.add_argument("--show-config", action="store_true", help="Print config and exit")
parser.add_argument("--verbose", action="store_true", help="Detailed output")
parser.add_argument("--allow-q3-or-lower", action="store_true",
help="Allow Q3_K for low-importance tensors (risk of quality loss)")
parser.add_argument("--aggro", type=float, default=None,
help="[deprecated] Use --size instead")
parser.add_argument("--show-floors", action="store_true",
help="Print class hard floors and exit")
args = parser.parse_args()
if args.show_floors:
_show_floors()
return
if not args.model or not args.imatrix:
parser.print_usage()
print("main.py: error: --model and --imatrix are required")
sys.exit(1)
target_mib = args.size
print("=== SHQ-program ===")
print(f"Model: {args.model}")
if len(args.imatrix) == 1:
print(f"Imatrix: {args.imatrix[0]}")
else:
print(f"Imatrix: {len(args.imatrix)} files ({args.imatrix_method})")
for p in args.imatrix:
print(f" - {p}")
print(f"Target: {target_mib:.0f} MiB ({target_mib / 1024:.2f} GB)")
if args.allow_q3_or_lower:
print(" --allow-q3-or-lower: low-importance tensors may go to Q3_K")
print()
print("[1/4] Reading model...")
model = read_model(args.model)
print(f" Architecture: {model['architecture']}")
print(f" Tensors: {model['n_tensors']}")
print(f" Features: {json.dumps(model['features'], indent=2)}")
print("\n[2/4] Reading imatrix...")
imatrix_list = [read_imatrix(p) for p in args.imatrix]
for im in imatrix_list:
print(f" {im['path']}: {im['n_tensors']} tensors, datasets={im['meta'].get('imatrix.datasets', '?')}")
from imatrix_reader import combine_imatrix
imatrix = combine_imatrix(imatrix_list, method=args.imatrix_method)
print(f" Combined: {imatrix['n_tensors']} tensors")
print("\n[3/4] Detecting tied groups...")
tied_groups = detect_tied_groups(imatrix)
print(f" Found {len(tied_groups)} tied groups:")
for g in tied_groups:
if len(g) > 1:
print(f" TIED ({len(g)}): {g[0].replace('.weight', '')} = "
f"{g[1].replace('.weight', '')}")
imp_table = build_importance_table(imatrix, model)
print("\n[4/4] Classifying tensors (greedy imatrix-driven)...")
# Получаем и маппинг тиров, и точную карту паддингов напрямую из классификатора
assignments, padded_ne_map = optimal_classify(
imp_table, tied_groups, model,
target_size_mib=target_mib,
allow_q3=args.allow_q3_or_lower,
)
ne_map = {k: v["n_elements"] for k, v in model.get("tensors", {}).items()}
for tname, info in imp_table.items():
if tname not in ne_map:
ne_map[tname] = info["n_elements"]
# Передаем padded_ne_map для корректного вывода логов на экран
_show_tier_summary(assignments, imp_table, ne_map, padded_ne_map)
base_type = _get_base_type(model)
flags = generate_flags(assignments, model, base_type, target_mib)
flags["imatrix"] = args.imatrix
print(f"\nConfig (base={flags['base_type']}):")
print(format_flags(flags))
if args.show_config:
return
print("\n--- Dry Run ---")
dry_size = run_dry_run(flags, args.model)
_show_size_result(dry_size, target_mib)
if not args.run:
print("\nDry run only. Use --run to execute quantization.")
return
if not args.output:
base = os.path.splitext(os.path.basename(args.model))[0]
args.output = base + "-SHQ.gguf"
print(f"\n--- Running quantization: {args.output} ---")
success = run_quantization(flags, args.model, args.output)
if success:
print("Done!")
else:
print("Failed!")
sys.exit(1)
def _show_tier_summary(assignments, imp_table, ne_map, padded_ne_map=None):
stats = compute_stats(assignments, ne_map, padded_ne_map)
print("\n Tier distribution:")
for tier in sorted(stats["by_tier_count"].keys()):
count = stats["by_tier_count"][tier]
mib = stats["by_tier_mib"].get(tier, 0.0)
print(f" {tier}: {count} tensors ({mib:.1f} MiB)")
print(f" Total estimated size: {stats['total_mib']:.1f} MiB")
ranked = sorted(
[(n, v) for n, v in imp_table.items()],
key=lambda x: -x[1]["importance_mean"],
)
print("\n Top 10 by importance:")
for n, v in ranked[:10]:
tier = assignments.get(n, "base")
display = n.replace(".weight", "").replace(".bias", "")
print(f" {display[:52]:52s} imp={v['importance_mean']:10.0f} tier={tier}")
def _show_size_result(dry_size, target_mib):
if dry_size:
print(f" Estimated size: {dry_size:.0f} MiB ({dry_size / 1024:.2f} GB)")
diff = dry_size - target_mib
if diff > 0:
print(f" ⚠ Over target by {diff:.0f} MiB")
else:
print(f" ✓ Under target by {-diff:.0f} MiB")
else:
print(" ⚠ Could not parse size from dry-run output")
def _show_floors():
print(" Class hard floors (never below without --allow-q3-or-lower):\n")
max_n = max(len(c) for c in CLASS_HARD_FLOORS)
for cls, floor in sorted(CLASS_HARD_FLOORS.items()):
print(f" {cls:<{max_n}} → {floor}")
print(f"\n Default floor (unknown class): Q4_K")
print(f" --allow-q3-or-lower enables Q3_K for: ffn_down, attn_output, ssm_out")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
7.09 kB
·
Xet hash:
47956bbaf3233553bae2d39c9dfa4a9763ccca0a04404034465be57834ce2a36

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.