## [1.2.3] — 2026-08-20 — Perplexity Suite & 9B Benchmark Data
Browse files## [1.2.3] — 2026-08-20 — Perplexity Suite & 9B Benchmark Data
# Changelog
All notable changes to the AutoRound + ASHQ1 suite are documented in this file.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
### Added
- **`03_perplexity_test.py`**: Automated perplexity evaluation tool wrapping `llama-perplexity`:
- Auto-detection of CUDA/ROCm compute backends and free VRAM.
- Adaptive `-ngl` layer offloading with CPU fallback.
- Automated retrieval and extraction of `wiki.test.raw` (Wikitext-2 reference corpus).
- Real-time chunk progression and ETA streaming.
- Comparative perplexity summary table with Δ relative to baseline.
- **Reference Benchmarks (`README.md`)**: Empirical PPL measurements on Ornith-1.5-9B:
- `Quality-36pc`: **8.0932** (baseline)
- `Compact-33pc`: **8.1290** (+0.0358 Δ)
- `Mini-27pc`: **9.5101** (+1.4169 Δ)
### Documentation
- Updated `USAGE.md` with Step 3 verification workflow.
- Updated toolchain index in `README.md`.
- 03_perplexity_test.py +240 -0
- README.md +17 -0
- USAGE.md +12 -0
|
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Perplexity sweep over GGUF tiers using llama-perplexity, with optional wiki.test.raw reference corpus."""
|
| 3 |
+
import glob,os,re,shutil,subprocess,sys,threading,time,urllib.request,zipfile
|
| 4 |
+
|
| 5 |
+
if os.name=="nt":os.environ.setdefault("KMP_AFFINITY","disabled")
|
| 6 |
+
os.environ.setdefault("GGML_CUDA_ENABLE_UNIFIED_MEMORY","1")
|
| 7 |
+
|
| 8 |
+
SCRIPT_DIR=os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
LLAMA_CPP=os.path.join(SCRIPT_DIR,"llama-cpp")
|
| 10 |
+
WIKI_URL="https://huggingface.co/datasets/ggml-org/ci/resolve/main/wikitext-2-raw-v1.zip?download=true"
|
| 11 |
+
WIKI_PATH=os.path.join(SCRIPT_DIR,"wiki.test.raw")
|
| 12 |
+
FALLBACK_TXT=os.path.join(SCRIPT_DIR,"01_create-calibration-dataset-and-imatrix","experimental.txt")
|
| 13 |
+
CHUNKS=64
|
| 14 |
+
CTX=2048
|
| 15 |
+
THREADS=max(1,(os.cpu_count() or 4)-1)
|
| 16 |
+
|
| 17 |
+
def _detect_gpu():
|
| 18 |
+
if sys.platform=="win32" or shutil.which("nvidia-smi"):
|
| 19 |
+
try:
|
| 20 |
+
out=subprocess.check_output(
|
| 21 |
+
["nvidia-smi","--query-gpu=memory.total,memory.used","--format=csv,noheader,nounits"],
|
| 22 |
+
stderr=subprocess.DEVNULL,text=True,timeout=5
|
| 23 |
+
).strip().splitlines()[0]
|
| 24 |
+
tot,usd=[int(x.strip()) for x in out.split(",")]
|
| 25 |
+
return "cuda",tot,max(0,tot-usd)
|
| 26 |
+
except Exception:pass
|
| 27 |
+
try:
|
| 28 |
+
out=subprocess.check_output(["rocm-smi","--showmeminfo","vram","--csv"],stderr=subprocess.DEVNULL,text=True,timeout=5)
|
| 29 |
+
m=re.search(r"(\d+)\s*MiB",out)
|
| 30 |
+
if m:
|
| 31 |
+
tot=int(m.group(1))
|
| 32 |
+
return "rocm",tot,tot
|
| 33 |
+
except Exception:pass
|
| 34 |
+
return None,0,0
|
| 35 |
+
|
| 36 |
+
GPU_BACKEND,GPU_TOTAL_VRAM,GPU_FREE_VRAM=_detect_gpu()
|
| 37 |
+
|
| 38 |
+
def _ngl_for_model(model_path,vram_free):
|
| 39 |
+
if vram_free<=0:return 0
|
| 40 |
+
model_mib=os.path.getsize(model_path)/1024/1024
|
| 41 |
+
if model_mib+768<=vram_free:return 99
|
| 42 |
+
headroom=max(0,vram_free-768)
|
| 43 |
+
return max(1,min(99,int(99*(headroom/model_mib))))
|
| 44 |
+
|
| 45 |
+
def find_binary():
|
| 46 |
+
names=("llama-perplexity.exe","llama-perplexity")
|
| 47 |
+
if os.path.isdir(LLAMA_CPP):
|
| 48 |
+
cand=[]
|
| 49 |
+
for root,dirs,files in os.walk(LLAMA_CPP):
|
| 50 |
+
dirs[:]=[d for d in dirs if d.lower() not in(".git","models","sources","vendor")]
|
| 51 |
+
for n in names:
|
| 52 |
+
if n in files:cand.append(os.path.join(root,n))
|
| 53 |
+
if cand:
|
| 54 |
+
def score(p):
|
| 55 |
+
s=p.lower()
|
| 56 |
+
return(0 if"release"in s else 1 if"debug"not in s else 2,len(s))
|
| 57 |
+
cand.sort(key=score)
|
| 58 |
+
return cand[0]
|
| 59 |
+
for n in names:
|
| 60 |
+
p=shutil.which(n)
|
| 61 |
+
if p:return p
|
| 62 |
+
return None
|
| 63 |
+
|
| 64 |
+
def fetch_wiki():
|
| 65 |
+
if os.path.isfile(WIKI_PATH) and os.path.getsize(WIKI_PATH)>1_000_000:
|
| 66 |
+
print(f"[Corpus] Using existing {WIKI_PATH}")
|
| 67 |
+
return WIKI_PATH
|
| 68 |
+
print("[Corpus] Downloading wiki.test.raw …")
|
| 69 |
+
tmp=WIKI_PATH+".zip"
|
| 70 |
+
try:
|
| 71 |
+
req=urllib.request.Request(WIKI_URL,headers={"User-Agent":"perplexity-test/1.0"})
|
| 72 |
+
with urllib.request.urlopen(req,timeout=300) as r,open(tmp,"wb") as f:
|
| 73 |
+
shutil.copyfileobj(r,f)
|
| 74 |
+
with zipfile.ZipFile(tmp) as z:
|
| 75 |
+
member=next((n for n in z.namelist() if n.endswith("wiki.test.raw")),None)
|
| 76 |
+
if member is None:raise ValueError("wiki.test.raw absent from ZIP")
|
| 77 |
+
with z.open(member) as src,open(WIKI_PATH,"wb") as out:
|
| 78 |
+
shutil.copyfileobj(src,out)
|
| 79 |
+
print(f"[Corpus] Saved {WIKI_PATH} ({os.path.getsize(WIKI_PATH)/1024:.0f} KiB)")
|
| 80 |
+
return WIKI_PATH
|
| 81 |
+
except Exception as e:
|
| 82 |
+
for junk in(tmp,WIKI_PATH):
|
| 83 |
+
try:os.remove(junk)
|
| 84 |
+
except OSError:pass
|
| 85 |
+
print(f"[Corpus] ✗ Download failed ({e})")
|
| 86 |
+
if os.path.isfile(FALLBACK_TXT):
|
| 87 |
+
print(f"[Corpus] Falling back to {FALLBACK_TXT} — Δ between tiers stays valid, absolute PPL differs from published wiki benchmarks.")
|
| 88 |
+
return FALLBACK_TXT
|
| 89 |
+
return None
|
| 90 |
+
|
| 91 |
+
def pick_models():
|
| 92 |
+
seen=set();out=[]
|
| 93 |
+
for p in sorted(glob.glob(os.path.join(SCRIPT_DIR,"*.gguf"))):
|
| 94 |
+
if p in seen:continue
|
| 95 |
+
seen.add(p)
|
| 96 |
+
bn=os.path.basename(p).lower()
|
| 97 |
+
if any(bn.startswith(x) for x in("mmproj","imatrix")) or any(x in bn for x in("-bench","_bench",".tmp",".bak")):continue
|
| 98 |
+
out.append(p)
|
| 99 |
+
return out
|
| 100 |
+
|
| 101 |
+
def menu(models):
|
| 102 |
+
print("\nAvailable models:")
|
| 103 |
+
for i,p in enumerate(models,1):
|
| 104 |
+
mib=os.path.getsize(p)/1024/1024
|
| 105 |
+
ngl=_ngl_for_model(p,GPU_FREE_VRAM)
|
| 106 |
+
tag=f"ngl={ngl}" if ngl>0 else "CPU"
|
| 107 |
+
print(f" {i:2d}. {os.path.basename(p):<48} ({mib:5.0f} MiB · {tag})")
|
| 108 |
+
print(" a. ALL · q. quit")
|
| 109 |
+
while True:
|
| 110 |
+
choice=input("Select model(s) [1/a/1,3,5/q]: ").strip().lower()
|
| 111 |
+
if choice in("q","quit",""):return None
|
| 112 |
+
if choice=="a":return models
|
| 113 |
+
try:
|
| 114 |
+
idx=[int(x) for x in re.split(r"[,\s]+",choice) if x]
|
| 115 |
+
if idx and all(1<=i<=len(models) for i in idx):
|
| 116 |
+
return [models[i-1] for i in dict.fromkeys(idx)]
|
| 117 |
+
except ValueError:pass
|
| 118 |
+
print(" Invalid selection.")
|
| 119 |
+
|
| 120 |
+
def parse_output(text):
|
| 121 |
+
ppl=tps=None
|
| 122 |
+
m=re.search(r"Final estimate:\s*PPL\s*=\s*([\d.]+)",text,re.I)
|
| 123 |
+
if not m:m=re.search(r"final estimate of PPL:\s*([\d.]+)",text,re.I)
|
| 124 |
+
if not m:m=re.search(r"^\s*ppl\s*=\s*([\d.]+)",text,re.M)
|
| 125 |
+
if m:
|
| 126 |
+
ppl=float(m.group(1))
|
| 127 |
+
else:
|
| 128 |
+
chunks=re.findall(r"\[\d+\]([\d.]+)",text)
|
| 129 |
+
if chunks:ppl=float(chunks[-1])
|
| 130 |
+
t=re.search(r"([\d.]+)\s*tokens per second",text,re.I)
|
| 131 |
+
if t:tps=float(t.group(1))
|
| 132 |
+
else:
|
| 133 |
+
p=re.search(r"([\d.]+)\s*seconds per pass",text,re.I)
|
| 134 |
+
if p:tps=CTX/max(float(p.group(1)),0.001)
|
| 135 |
+
return ppl,tps
|
| 136 |
+
|
| 137 |
+
def _get_flags(binary):
|
| 138 |
+
try:help_txt=subprocess.run([binary,"-h"],capture_output=True,text=True,timeout=5).stdout
|
| 139 |
+
except Exception:help_txt=""
|
| 140 |
+
extra=[]
|
| 141 |
+
if "-fa" in help_txt or "--flash-attn" in help_txt:extra+=["-fa","on"]
|
| 142 |
+
return extra
|
| 143 |
+
|
| 144 |
+
def _run_single(binary,model,corpus,ngl,flags,label):
|
| 145 |
+
cmd=[binary,"-m",model,"-f",corpus,"-c",str(CTX),"-b","512","-ub","512","-t",str(THREADS),"--chunks",str(CHUNKS),"--no-warmup"]
|
| 146 |
+
if ngl>0:cmd+=["-ngl",str(ngl)]
|
| 147 |
+
cmd+=flags
|
| 148 |
+
print(f"\n── {label} ──")
|
| 149 |
+
print(f" ngl={ngl} · ctx={CTX} · batch=512 · chunks={CHUNKS} · threads={THREADS}"+(" · Flash-Attention" if "-fa" in flags else ""))
|
| 150 |
+
t0=time.perf_counter()
|
| 151 |
+
try:
|
| 152 |
+
proc=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)
|
| 153 |
+
except FileNotFoundError:
|
| 154 |
+
print(" ✗ binary not found");return None
|
| 155 |
+
out_lines=[];err_lines=[]
|
| 156 |
+
current_chunk=0
|
| 157 |
+
last_ppl=""
|
| 158 |
+
lock=threading.Lock()
|
| 159 |
+
def on_text(line):
|
| 160 |
+
nonlocal current_chunk,last_ppl
|
| 161 |
+
m=re.search(r"\[(\d+)\]([\d.]+)?",line)
|
| 162 |
+
if m:
|
| 163 |
+
current_chunk=int(m.group(1))
|
| 164 |
+
if m.group(2):last_ppl=f" PPL={m.group(2)}"
|
| 165 |
+
with lock:
|
| 166 |
+
if current_chunk>0:
|
| 167 |
+
el=time.perf_counter()-t0
|
| 168 |
+
speed=current_chunk/el if el>0 else 0
|
| 169 |
+
rem=(CHUNKS-current_chunk)/speed if speed>0 else 0
|
| 170 |
+
sys.stdout.write(f"\r [{current_chunk:2d}/{CHUNKS}] {current_chunk/CHUNKS*100:4.1f}%{last_ppl} · {el:.0f}s elapsed · ETA {rem:.0f}s ")
|
| 171 |
+
sys.stdout.flush()
|
| 172 |
+
def drain(stream,buf):
|
| 173 |
+
for line in stream:
|
| 174 |
+
buf.append(line)
|
| 175 |
+
on_text(line)
|
| 176 |
+
th_out=threading.Thread(target=drain,args=(proc.stdout,out_lines),daemon=True)
|
| 177 |
+
th_err=threading.Thread(target=drain,args=(proc.stderr,err_lines),daemon=True)
|
| 178 |
+
th_out.start();th_err.start()
|
| 179 |
+
proc.wait()
|
| 180 |
+
th_out.join(timeout=3);th_err.join(timeout=3)
|
| 181 |
+
sys.stdout.write("\r"+" "*90+"\r")
|
| 182 |
+
elapsed=time.perf_counter()-t0
|
| 183 |
+
out="".join(out_lines)+"\n"+"".join(err_lines)
|
| 184 |
+
ppl,tps=parse_output(out)
|
| 185 |
+
if proc.returncode!=0 or ppl is None:
|
| 186 |
+
return None
|
| 187 |
+
tps=tps or (CHUNKS*CTX/elapsed if elapsed>0 else 0)
|
| 188 |
+
print(f" PPL={ppl:.4f} · {tps:.1f} tok/s · {elapsed:.1f}s")
|
| 189 |
+
return ppl,tps
|
| 190 |
+
|
| 191 |
+
def run_ppl(binary,model,corpus,flags,label):
|
| 192 |
+
ngl=_ngl_for_model(model,GPU_FREE_VRAM)
|
| 193 |
+
res=_run_single(binary,model,corpus,ngl,flags,label)
|
| 194 |
+
if res is not None:return res
|
| 195 |
+
if ngl>0:
|
| 196 |
+
print(" ⚠ Run failed on GPU — retrying CPU-only …")
|
| 197 |
+
res=_run_single(binary,model,corpus,0,[],label)
|
| 198 |
+
if res is not None:return res
|
| 199 |
+
print(" ✗ Run failed.")
|
| 200 |
+
return None
|
| 201 |
+
|
| 202 |
+
def main():
|
| 203 |
+
binary=find_binary()
|
| 204 |
+
if not binary:
|
| 205 |
+
print("Error: llama-perplexity binary not found under llama-cpp/.");sys.exit(1)
|
| 206 |
+
print(f"Binary : {binary}")
|
| 207 |
+
if GPU_BACKEND:
|
| 208 |
+
print(f"GPU : {GPU_BACKEND} · {GPU_FREE_VRAM}/{GPU_TOTAL_VRAM} MiB VRAM available")
|
| 209 |
+
else:
|
| 210 |
+
print("GPU : none detected — CPU only")
|
| 211 |
+
corpus=fetch_wiki()
|
| 212 |
+
if not corpus:
|
| 213 |
+
print("Error: no corpus available.");sys.exit(1)
|
| 214 |
+
models=pick_models()
|
| 215 |
+
if not models:
|
| 216 |
+
print("Error: no model-*.gguf found next to this script.");sys.exit(1)
|
| 217 |
+
sel=menu(models)
|
| 218 |
+
if not sel:return
|
| 219 |
+
flags=_get_flags(binary)
|
| 220 |
+
results=[]
|
| 221 |
+
for m in sel:
|
| 222 |
+
res=run_ppl(binary,m,corpus,flags,os.path.basename(m))
|
| 223 |
+
if res:results.append((os.path.basename(m),res[0],res[1]))
|
| 224 |
+
if len(results)<2:
|
| 225 |
+
if results:print(f"\n Final result: {results[0][0]} → PPL = {results[0][1]:.4f}")
|
| 226 |
+
return
|
| 227 |
+
base=results[0][1]
|
| 228 |
+
print("\n"+"="*64)
|
| 229 |
+
print(" PERPLEXITY SUMMARY (lower is better)")
|
| 230 |
+
print("="*64)
|
| 231 |
+
print(f" {'Model':<46}{'PPL':>9}{'+Δ':>9}{'Speed':>11}")
|
| 232 |
+
print(f" {'-'*46}{'-'*9}{'-'*9}{'-'*11}")
|
| 233 |
+
for name,ppl,tps in results:
|
| 234 |
+
print(f" {name:<46}{ppl:>9.4f}{ppl-base:>+9.4f}{tps:>8.1f} t/s")
|
| 235 |
+
print(f"\n Δ relative to {results[0][0]} · corpus: {os.path.basename(corpus)}")
|
| 236 |
+
if corpus==WIKI_PATH:
|
| 237 |
+
print(" wiki.test.raw corpus: absolute PPL comparable to llama.cpp published benchmarks.")
|
| 238 |
+
|
| 239 |
+
if __name__=="__main__":
|
| 240 |
+
main()
|
|
@@ -74,6 +74,22 @@ All tiers maintain strict byte-budget percentages relative to the original unqua
|
|
| 74 |
>
|
| 75 |
> Measured on a 9B `qwen35` source (17 091 MiB BF16): Nano **21.10%**, Mini **27.01%**, Compact **33.06%**, Quality **35.49%**. `Quality` stops short of its nominal target because the surviving upgrades are indivisible blocks of 129 MiB and above.
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
### 🎯 Recommended Minimum Tiers by Model Size
|
| 78 |
|
| 79 |
Smaller parameter architectures require higher relative bit precision to prevent degradation of core reasoning representations:
|
|
@@ -94,6 +110,7 @@ Smaller parameter architectures require higher relative bit precision to prevent
|
|
| 94 |
| `01_create-calibration-dataset-and-imatrix.py` | End-to-end dataset builder (Agentic/Frontier/Logic) and GPU-autotuned `llama-imatrix` runner. |
|
| 95 |
| `01b_BF16-GGUF-modules-fusion.py` | Lossless merger combining base models, vision projectors (`mmproj`), and MTP heads. |
|
| 96 |
| `02_BF16-GGUF-to-ASHQ1.py` | Automated orchestrator executing batch quantization across all target tiers. |
|
|
|
|
| 97 |
| `ASHQ1.py` | Core hybrid quantization optimizer with greedy knapsack utility scheduling and tied-weight detection. |
|
| 98 |
| `ASHQ1-mmproj.py` | Vision projector quantizer applying selective deep-block boosting and critical layer pinning. |
|
| 99 |
|
|
|
|
| 74 |
>
|
| 75 |
> Measured on a 9B `qwen35` source (17 091 MiB BF16): Nano **21.10%**, Mini **27.01%**, Compact **33.06%**, Quality **35.49%**. `Quality` stops short of its nominal target because the surviving upgrades are indivisible blocks of 129 MiB and above.
|
| 76 |
|
| 77 |
+
### Perplexity Benchmarks (Ornith-1.5-9B)
|
| 78 |
+
|
| 79 |
+
Evaluated on `wiki.test.raw` (Wikitext-2), `n_ctx=2048`, 64 chunks, Flash-Attention enabled:
|
| 80 |
+
|
| 81 |
+
| Tier | Size | VRAM Budget | PPL | Δ vs Quality | Speed (RTX 8GB) |
|
| 82 |
+
|---|---|---|---|---|---|
|
| 83 |
+
| **Quality-36pc** | 6.06 GiB | ~7.5 GiB | **8.0932** | baseline | ~1241 tok/s |
|
| 84 |
+
| **Compact-33pc** | 5.65 GiB | ~7.0 GiB | **8.1290** | +0.0358 | ~1241 tok/s |
|
| 85 |
+
| **Mini-27pc** | 4.62 GiB | ~5.8 GiB | **9.5101** | +1.4169 | ~1442 tok/s |
|
| 86 |
+
| **Nano-21pc** | 3.60 GiB | ~4.5 GiB | 430.7392 | collapse | ~1321 tok/s |
|
| 87 |
+
|
| 88 |
+
> **Takeaways:**
|
| 89 |
+
> - `Quality-36pc` provides near-lossless perplexity for production inference.
|
| 90 |
+
> - `Compact-33pc` loses only **0.0358 PPL** while saving ~416 MiB, ideal for 8 GB VRAM setups.
|
| 91 |
+
> - `Mini-27pc` maintains strong conversational coherence under tight memory constraints.
|
| 92 |
+
|
| 93 |
### 🎯 Recommended Minimum Tiers by Model Size
|
| 94 |
|
| 95 |
Smaller parameter architectures require higher relative bit precision to prevent degradation of core reasoning representations:
|
|
|
|
| 110 |
| `01_create-calibration-dataset-and-imatrix.py` | End-to-end dataset builder (Agentic/Frontier/Logic) and GPU-autotuned `llama-imatrix` runner. |
|
| 111 |
| `01b_BF16-GGUF-modules-fusion.py` | Lossless merger combining base models, vision projectors (`mmproj`), and MTP heads. |
|
| 112 |
| `02_BF16-GGUF-to-ASHQ1.py` | Automated orchestrator executing batch quantization across all target tiers. |
|
| 113 |
+
| `03_perplexity_test.py` | Perplexity validation suite using `llama-perplexity` over reference corpora.
|
| 114 |
| `ASHQ1.py` | Core hybrid quantization optimizer with greedy knapsack utility scheduling and tied-weight detection. |
|
| 115 |
| `ASHQ1-mmproj.py` | Vision projector quantizer applying selective deep-block boosting and critical layer pinning. |
|
| 116 |
|
|
@@ -15,6 +15,7 @@ workspace/
|
|
| 15 |
├── 01_create-calibration-dataset-and-imatrix.py
|
| 16 |
├── 01b_BF16-GGUF-modules-fusion.py
|
| 17 |
├── 02_BF16-GGUF-to-ASHQ1.py
|
|
|
|
| 18 |
├── ASHQ1.py
|
| 19 |
├── ASHQ1-mmproj.py
|
| 20 |
├── llama-cpp/ # Cloned or linked llama.cpp repository
|
|
@@ -88,6 +89,17 @@ python ASHQ1.py --model model-BF16.gguf --imatrix imatrix.gguf --tier quality --
|
|
| 88 |
|
| 89 |
---
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
## 🎯 3. Recommended Minimum Tiers by Model Size
|
| 92 |
|
| 93 |
Smaller parameter architectures require higher relative bit precision to prevent degradation of core reasoning representations:
|
|
|
|
| 15 |
├── 01_create-calibration-dataset-and-imatrix.py
|
| 16 |
├── 01b_BF16-GGUF-modules-fusion.py
|
| 17 |
├── 02_BF16-GGUF-to-ASHQ1.py
|
| 18 |
+
├── 03_perplexity_test.py
|
| 19 |
├── ASHQ1.py
|
| 20 |
├── ASHQ1-mmproj.py
|
| 21 |
├── llama-cpp/ # Cloned or linked llama.cpp repository
|
|
|
|
| 89 |
|
| 90 |
---
|
| 91 |
|
| 92 |
+
### Step 3: Perplexity Evaluation (`03_perplexity_test.py`)
|
| 93 |
+
|
| 94 |
+
Interactive CLI tool to benchmark GGUF files against `wiki.test.raw` (auto-downloaded from HuggingFace) or a local corpus:
|
| 95 |
+
|
| 96 |
+
- Auto-detects NVIDIA (CUDA) and AMD (ROCm) hardware and available VRAM.
|
| 97 |
+
- Automatically sets `-ngl`, `-b 512`, `-ub 512`, and `-fa` (Flash-Attention).
|
| 98 |
+
- Real-time ETA and chunk progression streaming.
|
| 99 |
+
- Generates a comparative summary table with Δ PPL.
|
| 100 |
+
|
| 101 |
+
---
|
| 102 |
+
|
| 103 |
## 🎯 3. Recommended Minimum Tiers by Model Size
|
| 104 |
|
| 105 |
Smaller parameter architectures require higher relative bit precision to prevent degradation of core reasoning representations:
|