## [1.2.0] — 2026-08-20
Browse files# Changelog
All notable changes to the AutoRound + ASHQ1 Suite are documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [1.2.0] — 2026-08-20
Supersedes the unreleased 1.1.0 and folds it in. Validated on a 9B `qwen35` dense
model with SSM blocks, W4G128 AutoRound lineage, 17091 MiB BF16 source, 427 tensors,
129 tied groups, 249 imatrix entries over 696 chunks.
### Changed
- **`Compact` tier raised from 30% to 33% of the source BF16 footprint.**
Measured output: 5632 MiB against a 5640 MiB target, a 32.95% effective ratio.
The added budget lifts attention and FFN projections to the `Q5_K` lineage cap
instead of leaving them at `IQ4_XS` and `IQ3_S`.
- **`Quality` tier retargets to 36% on AutoRound int4 lineage.**
At 39% the scheduler exhausted its upgrade queue against `INT4_LINEAGE_CAP` and
left 364 MiB unspent, shipping 36.87%. The new target matches delivered size, so
filenames and metadata state the real ratio. Non-int4 lineages keep 39%.
- Tier ladder is now a clean 3% modulo: `Nano` 21%, `Mini` 27%, `Compact` 33%,
`Quality` 36% on int4 and 39% elsewhere, `Fidelity` 48%.
### Added
- `INT4_TIER_RATIOS` table with `resolve_ratio(tier,int4)` and `resolve_pct(tier,model)`
in `ASHQ1.py`, giving per-lineage tier budgets a single resolution point.
- Output filenames derive their percentage from the resolved ratio across `ASHQ1.py`
and the batch orchestrator, so an int4 `Quality` build is written as
`-Quality-36pc.gguf` and detected as such on resume.
- Tier size table printed at startup reflects the resolved per-lineage targets.
- Cap saturation rationale documented in `CHARTER.md` section 3, `README.md`,
and `USAGE.md`.
### Notes
- `free-embd` stays disabled across all tiers on this model: `token_embd` weighs
1031 MiB, which is 18.3% of the `Compact` target and exceeds the 15% threshold.
- Four-tier batch quantization completed in 14m58s; `Nano` is the slowest pass at
5m07s due to low-bit IQ search cost.
- `did not find weights for token_embd.weight` from llama.cpp is benign on tied
embeddings and does not affect the produced files.
- 02_BF16-GGUF-to-ASHQ1.py +3 -3
- ASHQ1.py +26 -6
- CHARTER.md +2 -1
- README.md +3 -1
- USAGE.md +1 -1
|
@@ -9,7 +9,7 @@ The COMPLETE model (including MTP head) is preferred over the no-mtp trunk:
|
|
| 9 |
ASHQ1 keeps the nextn layer at Q8_0 (Q6_K on int4 lineage) and excludes it from the size budget.
|
| 10 |
Final naming: model-AutoRound-ASHQ1-Compact-33pc.gguf (AutoRound lineage detected
|
| 11 |
via step 00 sidecar), model-ASHQ1-…-NNpc.gguf otherwise; mmproj-ASHQ1-Balanced-NNpc.gguf
|
| 12 |
-
(pct relative to source mmproj).
|
| 13 |
Lineage override: ASHQ1_LINEAGE=autoround|plain.
|
| 14 |
"""
|
| 15 |
import os,re,sys,subprocess
|
|
@@ -17,7 +17,7 @@ import os,re,sys,subprocess
|
|
| 17 |
SCRIPT_DIR=os.path.dirname(os.path.abspath(__file__))
|
| 18 |
sys.path.insert(0,SCRIPT_DIR)
|
| 19 |
sys.path.insert(0,os.path.join(SCRIPT_DIR,"llama-cpp","gguf-py"))
|
| 20 |
-
from ASHQ1 import ALL_RATIOS,int4_lineage_of,lineage_tag,tier_label
|
| 21 |
|
| 22 |
MAIN_TIERS=["mini","compact","quality","fidelity"]
|
| 23 |
# Longest running and least used: executed last
|
|
@@ -79,7 +79,7 @@ def process_model(base_dir,ashq1_script,imatrix,model_path,tiers_list):
|
|
| 79 |
print(f"{'='*60}")
|
| 80 |
for tier in tiers_list:
|
| 81 |
label=tier_label(tier)
|
| 82 |
-
pct=
|
| 83 |
new_name=f"{clean_base}-{tag}-{label}-{pct}pc.gguf"
|
| 84 |
new_file=os.path.join(base_dir,new_name)
|
| 85 |
if os.path.isfile(new_file):
|
|
|
|
| 9 |
ASHQ1 keeps the nextn layer at Q8_0 (Q6_K on int4 lineage) and excludes it from the size budget.
|
| 10 |
Final naming: model-AutoRound-ASHQ1-Compact-33pc.gguf (AutoRound lineage detected
|
| 11 |
via step 00 sidecar), model-ASHQ1-…-NNpc.gguf otherwise; mmproj-ASHQ1-Balanced-NNpc.gguf
|
| 12 |
+
(pct relative to source mmproj). On int4 lineage Quality targets 36% instead of 39%.
|
| 13 |
Lineage override: ASHQ1_LINEAGE=autoround|plain.
|
| 14 |
"""
|
| 15 |
import os,re,sys,subprocess
|
|
|
|
| 17 |
SCRIPT_DIR=os.path.dirname(os.path.abspath(__file__))
|
| 18 |
sys.path.insert(0,SCRIPT_DIR)
|
| 19 |
sys.path.insert(0,os.path.join(SCRIPT_DIR,"llama-cpp","gguf-py"))
|
| 20 |
+
from ASHQ1 import ALL_RATIOS,int4_lineage_of,lineage_tag,resolve_pct,tier_label
|
| 21 |
|
| 22 |
MAIN_TIERS=["mini","compact","quality","fidelity"]
|
| 23 |
# Longest running and least used: executed last
|
|
|
|
| 79 |
print(f"{'='*60}")
|
| 80 |
for tier in tiers_list:
|
| 81 |
label=tier_label(tier)
|
| 82 |
+
pct=resolve_pct(tier,model_path)
|
| 83 |
new_name=f"{clean_base}-{tag}-{label}-{pct}pc.gguf"
|
| 84 |
new_file=os.path.join(base_dir,new_name)
|
| 85 |
if os.path.isfile(new_file):
|
|
@@ -1350,7 +1350,7 @@ def run_main_cli(args_list=None)->int:
|
|
| 1350 |
return 0
|
| 1351 |
if not args.output:
|
| 1352 |
base=clean_name(args.model)
|
| 1353 |
-
pct=
|
| 1354 |
args.output=f"{base}-{lineage_tag(args.model,args.lineage)}-{tier_label(args.profile)}-{pct}pc.gguf"
|
| 1355 |
print(f"\n--- Running quantization: {args.output} ---")
|
| 1356 |
success=run_quantization(flags,args.model,args.output)
|
|
@@ -1415,12 +1415,30 @@ TIER_RATIOS={
|
|
| 1415 |
"fidelity":0.48,
|
| 1416 |
}
|
| 1417 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1418 |
ALL_RATIOS=dict(TIER_RATIOS)
|
|
|
|
| 1419 |
TIER_DISPLAY={"nano":"Nano"}
|
| 1420 |
|
| 1421 |
def tier_label(tier:str)->str:
|
| 1422 |
return TIER_DISPLAY.get(tier.lower(),tier.capitalize())
|
| 1423 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1424 |
def file_size_mib(path:str)->float:
|
| 1425 |
return os.path.getsize(path)/1024/1024
|
| 1426 |
|
|
@@ -1471,19 +1489,20 @@ def gen_imatrix(model:str,data:str,output:str,chunks:int)->bool:
|
|
| 1471 |
return False
|
| 1472 |
return result.returncode==0
|
| 1473 |
|
| 1474 |
-
def print_tier_table(bf16_mib:float,model_name:str):
|
| 1475 |
print(f"\n Model: {model_name}")
|
| 1476 |
print(f" BF16 source: {bf16_mib:.0f} MiB ({bf16_mib/1024:.2f} GB)\n")
|
| 1477 |
print(f" {'Tier':<12}{'Ratio':>6}{'Target(MiB)':>14}{'Target(GB)':>12}")
|
| 1478 |
print(f" {'-'*12}{'-'*6}{'-'*14}{'-'*12}")
|
| 1479 |
-
for tier
|
|
|
|
| 1480 |
target=bf16_mib*ratio
|
| 1481 |
print(f" {tier_label(tier):<12}{ratio*100:>5.0f}%{target:>13.0f}{target/1024:>11.2f}")
|
| 1482 |
print()
|
| 1483 |
|
| 1484 |
def run_tier(model:str,imatrix_paths:list,tier:str,target_mib:float,output_dir:str,run:bool,extra_args:list,lineage:str="auto")->bool:
|
| 1485 |
name=clean_name(model)
|
| 1486 |
-
pct=
|
| 1487 |
output=os.path.join(output_dir,f"{name}-{lineage_tag(model,lineage)}-{tier_label(tier)}-{pct}pc.gguf")
|
| 1488 |
cmd_args=[
|
| 1489 |
"--model",model,
|
|
@@ -1531,7 +1550,7 @@ def tiers_main(args_list=None):
|
|
| 1531 |
output_dir=args.output_dir or os.path.dirname(os.path.abspath(args.model))
|
| 1532 |
os.makedirs(output_dir,exist_ok=True)
|
| 1533 |
print("=== ASHQ1 Tier Runner ===")
|
| 1534 |
-
print_tier_table(bf16_mib,model_name)
|
| 1535 |
if args.show_sizes:return
|
| 1536 |
imatrix_paths=list(args.imatrix)
|
| 1537 |
if args.gen_imatrix:
|
|
@@ -1559,9 +1578,10 @@ def tiers_main(args_list=None):
|
|
| 1559 |
if args.allow_q3_or_lower:extra_args.append("--allow-q3-or-lower")
|
| 1560 |
extra_args.extend(["--imatrix-method",args.imatrix_method,"--lineage",args.lineage])
|
| 1561 |
if args.verbose:extra_args.append("--verbose")
|
|
|
|
| 1562 |
results={}
|
| 1563 |
for tier in tiers:
|
| 1564 |
-
target=bf16_mib*
|
| 1565 |
success=run_tier(args.model,imatrix_paths,tier,target,output_dir,args.run,extra_args,args.lineage)
|
| 1566 |
results[tier]=success
|
| 1567 |
print(f"\n{'='*60}")
|
|
|
|
| 1350 |
return 0
|
| 1351 |
if not args.output:
|
| 1352 |
base=clean_name(args.model)
|
| 1353 |
+
pct=resolve_pct(args.profile,args.model)
|
| 1354 |
args.output=f"{base}-{lineage_tag(args.model,args.lineage)}-{tier_label(args.profile)}-{pct}pc.gguf"
|
| 1355 |
print(f"\n--- Running quantization: {args.output} ---")
|
| 1356 |
success=run_quantization(flags,args.model,args.output)
|
|
|
|
| 1415 |
"fidelity":0.48,
|
| 1416 |
}
|
| 1417 |
|
| 1418 |
+
INT4_TIER_RATIOS={"quality":0.36}
|
| 1419 |
+
|
| 1420 |
+
def resolve_tier_ratio(tier,lineage):
|
| 1421 |
+
# int4 upgrades stall against INT4_LINEAGE_CAP; high tiers get a truthful target
|
| 1422 |
+
if lineage=="int4" and tier in INT4_TIER_RATIOS:
|
| 1423 |
+
return INT4_TIER_RATIOS[tier]
|
| 1424 |
+
return TIER_RATIOS[tier]
|
| 1425 |
+
|
| 1426 |
ALL_RATIOS=dict(TIER_RATIOS)
|
| 1427 |
+
INT4_TIER_RATIOS={"quality":0.36}
|
| 1428 |
TIER_DISPLAY={"nano":"Nano"}
|
| 1429 |
|
| 1430 |
def tier_label(tier:str)->str:
|
| 1431 |
return TIER_DISPLAY.get(tier.lower(),tier.capitalize())
|
| 1432 |
|
| 1433 |
+
def resolve_ratio(tier:str,int4:bool)->float:
|
| 1434 |
+
# int4 upgrades stall against INT4_LINEAGE_CAP: high tiers get a truthful target
|
| 1435 |
+
t=tier.lower()
|
| 1436 |
+
if int4 and t in INT4_TIER_RATIOS:return INT4_TIER_RATIOS[t]
|
| 1437 |
+
return ALL_RATIOS.get(t,0.0)
|
| 1438 |
+
|
| 1439 |
+
def resolve_pct(tier:str,model_path:str)->int:
|
| 1440 |
+
return round(resolve_ratio(tier,int4_lineage_of(model_path))*100)
|
| 1441 |
+
|
| 1442 |
def file_size_mib(path:str)->float:
|
| 1443 |
return os.path.getsize(path)/1024/1024
|
| 1444 |
|
|
|
|
| 1489 |
return False
|
| 1490 |
return result.returncode==0
|
| 1491 |
|
| 1492 |
+
def print_tier_table(bf16_mib:float,model_name:str,int4:bool=False):
|
| 1493 |
print(f"\n Model: {model_name}")
|
| 1494 |
print(f" BF16 source: {bf16_mib:.0f} MiB ({bf16_mib/1024:.2f} GB)\n")
|
| 1495 |
print(f" {'Tier':<12}{'Ratio':>6}{'Target(MiB)':>14}{'Target(GB)':>12}")
|
| 1496 |
print(f" {'-'*12}{'-'*6}{'-'*14}{'-'*12}")
|
| 1497 |
+
for tier in ALL_RATIOS:
|
| 1498 |
+
ratio=resolve_ratio(tier,int4)
|
| 1499 |
target=bf16_mib*ratio
|
| 1500 |
print(f" {tier_label(tier):<12}{ratio*100:>5.0f}%{target:>13.0f}{target/1024:>11.2f}")
|
| 1501 |
print()
|
| 1502 |
|
| 1503 |
def run_tier(model:str,imatrix_paths:list,tier:str,target_mib:float,output_dir:str,run:bool,extra_args:list,lineage:str="auto")->bool:
|
| 1504 |
name=clean_name(model)
|
| 1505 |
+
pct=resolve_pct(tier,model)
|
| 1506 |
output=os.path.join(output_dir,f"{name}-{lineage_tag(model,lineage)}-{tier_label(tier)}-{pct}pc.gguf")
|
| 1507 |
cmd_args=[
|
| 1508 |
"--model",model,
|
|
|
|
| 1550 |
output_dir=args.output_dir or os.path.dirname(os.path.abspath(args.model))
|
| 1551 |
os.makedirs(output_dir,exist_ok=True)
|
| 1552 |
print("=== ASHQ1 Tier Runner ===")
|
| 1553 |
+
print_tier_table(bf16_mib,model_name,int4_lineage_of(args.model))
|
| 1554 |
if args.show_sizes:return
|
| 1555 |
imatrix_paths=list(args.imatrix)
|
| 1556 |
if args.gen_imatrix:
|
|
|
|
| 1578 |
if args.allow_q3_or_lower:extra_args.append("--allow-q3-or-lower")
|
| 1579 |
extra_args.extend(["--imatrix-method",args.imatrix_method,"--lineage",args.lineage])
|
| 1580 |
if args.verbose:extra_args.append("--verbose")
|
| 1581 |
+
int4=int4_lineage_of(args.model)
|
| 1582 |
results={}
|
| 1583 |
for tier in tiers:
|
| 1584 |
+
target=bf16_mib*resolve_ratio(tier,int4)
|
| 1585 |
success=run_tier(args.model,imatrix_paths,tier,target,output_dir,args.run,extra_args,args.lineage)
|
| 1586 |
results[tier]=success
|
| 1587 |
print(f"\n{'='*60}")
|
|
@@ -52,7 +52,8 @@ When tied layers are detected (such as shared input/output embeddings or symmetr
|
|
| 52 |
When weights are derived from an AutoRound W4A16 source (recorded via `.provenance.json` sidecars):
|
| 53 |
* **Information Saturation**: Because the underlying weights have been pre-conditioned for 4-bit representations, assigning container formats above `Q5_K` yields negligible signal recovery ($\Delta \mathcal{Q} \to 0$).
|
| 54 |
* **Automated Capping**: The ASHQ1 optimizer caps attention and FFN blocks at `Q5_K`, attention gates at `Q6_K`, and MTP heads at `Q6_K`, while recurrent memory states hold `Q8_0`. The bit-budget freed by these ceilings flows to the imatrix-ranked tensors that convert it into measurable error reduction.
|
| 55 |
-
* **Tier Pruning**: On AutoRound int4 lineage, generation of the 48% `Fidelity` tier is skipped by default, focusing compute resources on optimal `Quality` (
|
|
|
|
| 56 |
|
| 57 |
---
|
| 58 |
|
|
|
|
| 52 |
When weights are derived from an AutoRound W4A16 source (recorded via `.provenance.json` sidecars):
|
| 53 |
* **Information Saturation**: Because the underlying weights have been pre-conditioned for 4-bit representations, assigning container formats above `Q5_K` yields negligible signal recovery ($\Delta \mathcal{Q} \to 0$).
|
| 54 |
* **Automated Capping**: The ASHQ1 optimizer caps attention and FFN blocks at `Q5_K`, attention gates at `Q6_K`, and MTP heads at `Q6_K`, while recurrent memory states hold `Q8_0`. The bit-budget freed by these ceilings flows to the imatrix-ranked tensors that convert it into measurable error reduction.
|
| 55 |
+
* **Tier Pruning**: On AutoRound int4 lineage, generation of the 48% `Fidelity` tier is skipped by default, focusing compute resources on optimal `Quality` (36%), `Compact` (33%), `Mini` (27%), and `Nano` (21%) variants.
|
| 56 |
+
* **Cap Saturation**: On AutoRound int4 lineage, `Compact` (33%) drives every attention and FFN projection to the `Q5_K` cap. Measured on a 9B `qwen35` source: `Compact` delivers 32.95% of the BF16 footprint with 8 MiB of slack, while `Quality` at a 39% target exhausts its upgrade queue and ships 36.87%. `Quality` therefore retargets to 36% on this lineage; other lineages keep 39%.
|
| 57 |
|
| 58 |
---
|
| 59 |
|
|
@@ -68,7 +68,9 @@ All tiers maintain strict byte-budget percentages relative to the original unqua
|
|
| 68 |
| **Quality** | **39%** | `Q5_K_M` | Near-lossless general deployment | Full `Q4_K`/`Q5_K` attention coverage |
|
| 69 |
| **Fidelity** | **48%** | `Q6_K` | Maximum analytical precision (raw BF16 lineage) | High-precision `Q5_K`/`Q6_K`/`Q8_0` mix |
|
| 70 |
|
| 71 |
-
*Note: Models originating from an AutoRound int4 lineage cap their weight allocations at
|
|
|
|
|
|
|
| 72 |
|
| 73 |
### 🎯 Recommended Minimum Tiers by Model Size
|
| 74 |
|
|
|
|
| 68 |
| **Quality** | **39%** | `Q5_K_M` | Near-lossless general deployment | Full `Q4_K`/`Q5_K` attention coverage |
|
| 69 |
| **Fidelity** | **48%** | `Q6_K` | Maximum analytical precision (raw BF16 lineage) | High-precision `Q5_K`/`Q6_K`/`Q8_0` mix |
|
| 70 |
|
| 71 |
+
*Note: Models originating from an AutoRound int4 lineage cap their weight allocations at `Q5_K`, as theoretical information saturation is fully realized. Attention gates settle at `Q6_K` and recurrent states at `Q8_0` on that lineage, and every tensor missing from the imatrix keeps `IQ4_XS` or above.*
|
| 72 |
+
|
| 73 |
+
> **Int4 lineage tier ladder**: `Compact` (33%) already drives every attention and FFN projection to the `Q5_K` cap. Budget beyond that point buys `token_embd` and `output` precision only, so `Quality` retargets to **36%** on this lineage and writes `-Quality-36pc.gguf`. `Fidelity` stays pruned.
|
| 74 |
|
| 75 |
### 🎯 Recommended Minimum Tiers by Model Size
|
| 76 |
|
|
@@ -94,7 +94,7 @@ Smaller parameter architectures require higher relative bit precision to prevent
|
|
| 94 |
|
| 95 |
* **≥ 9B Models**: Select **Mini** (27% ratio) or higher. Large parameter capacity preserves semantic integrity at lower bit rates.
|
| 96 |
* **~ 4B Models**: Select **Compact** (33% ratio) or higher. Optimal balance between memory footprint and dense layer preservation.
|
| 97 |
-
* **~ 3B Models**: Select **Quality** (39% ratio) or higher. Higher baseline precision protects critical routing and attention projections.
|
| 98 |
* **≤ 1B Models**: Select **Fidelity** (48% ratio) or higher. Compact architectures require maximum parameter density.
|
| 99 |
|
| 100 |
---
|
|
|
|
| 94 |
|
| 95 |
* **≥ 9B Models**: Select **Mini** (27% ratio) or higher. Large parameter capacity preserves semantic integrity at lower bit rates.
|
| 96 |
* **~ 4B Models**: Select **Compact** (33% ratio) or higher. Optimal balance between memory footprint and dense layer preservation.
|
| 97 |
+
* **~ 3B Models**: Select **Quality** (39% ratio, 36% on AutoRound int4 lineage) or higher. Higher baseline precision protects critical routing and attention projections.
|
| 98 |
* **≤ 1B Models**: Select **Fidelity** (48% ratio) or higher. Compact architectures require maximum parameter density.
|
| 99 |
|
| 100 |
---
|