Qwen3.5-4B 逐层混合动态量化 - 实验汇总报告

GPU: NVIDIA RTX 4070 Ti SUPER | 校准数据: 4源混合5万token | 生成时间: 2026-08-31

目录

第1章 方案总览与架构 第2章 实验日志与调参记录 第3章 竞品数据对比
第1章 方案总览与架构

1.1 项目目标

对 Qwen3.5-4B(BF16, 8.07GB)进行逐层混合动态量化,在保持模型质量(PPL)的前提下,将模型压缩到4~5bit平均位宽。

1.2 四个方案按时间排序

graph TD A["目标: Qwen3.5-4B 逐层混合量化"] --> B["方案A: 固定比例混合
最早 2026-08-27"] A --> C["方案B: 贝叶斯逐层分配
2026-08-29"] A --> D["方案C: K-quant 分块混合
2026-08-31"] A --> E["方案D: 混合比例 sweep
2026-08-31"] B --> B1["uniform_8bit"] B --> B2["uniform_4bit"] B --> B3["Q4-8-mix (上8下4)"] C --> C1["v1 基础GP+UCB"] C --> C2["v2 扩展bit池"] C --> C3["v3 +低bit惩罚"] C --> C4["v4 +imatrix ★最优"] D --> D1["h5l3 / h4l3 / h4l2"] E --> E1["avg2.5~4.8 共5个"] style C4 fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px

1.3 方案A:固定比例混合(最早 2026-08-27)

核心思想:最简单的方案。所有层统一 bit(uniform),或按固定比例分上/下层(Q4-8-mix 上层8bit下层4bit)。不需要校准数据,不需要搜索算法。

flowchart LR subgraph 输入 A1["FP16 模型
346层"] end subgraph 处理 A2["策略选择
uniform 或 mixed"] A3["apply_quantization()
逐层替换 QuantLinear"] end subgraph 输出 A4["量化模型
保存 safetensors"] end A1 --> A2 --> A3 --> A4
# scripts/export_gguf.py — 生成固定比例量化模型 # scripts/run_quant_vram.py — 量化+显存监控 # dynquant/pipeline.py — apply_quantization() 通用流水线 # 生成配置: uniform_8bit: 所有层8bit uniform_4bit: 所有层4bit Q4-8-mix: 上层8bit + 下层4bit (固定分界)

方案A 实验结果

配置策略平均bitPPL模型大小
FP16 基线不量化1610.408.07GB
uniform_8bit全部8bit810.394.14GB
Q4-8-mix上层8bit+下层4bit~5.510.692.63GB
uniform_4bit全部4bit411.262.19GB

1.4 方案B:贝叶斯逐层分配(v1~v4, 2026-08-29)

核心思想:346个线性层,每层独立选 bit 位宽。用贝叶斯优化(高斯过程 + UCB acquisition)搜索最优分配,避免固定比例的"一刀切"问题。

flowchart LR subgraph 输入 B1["FP16 模型
346层"] B2["校准数据
4源混合5万token"] B3["imatrix
per-column L2能量"] end subgraph 处理 B4["compute_sensitivity()
逐层灵敏度"] B5["load_layer_importance()
imatrix排序"] B6["allocate_bits_bayesian()
GP+UCB搜索"] B7["apply_quantization()
替换 QuantLinear"] end subgraph 输出 B8["每层 bit 分配"] B9["量化模型"] B10["PPL 评测"] end B1 --> B4 --> B6 B2 --> B4 B3 --> B5 --> B6 B6 --> B8 B8 --> B7 --> B9 B9 --> B10
# dynquant/bayes_alloc.py — 贝叶斯分配核心 def allocate_bits_bayesian(sensitivity, budget, bits, n_eval=48, lowbit_penalty=0): """GP+UCB 贝叶斯搜索346层最优bit分配""" ... def load_layer_importance(imatrix_path): """读取imatrix,返回per-column L2能量""" ... # scripts/run_p2_v4_imatrix.py — v4主入口 # scripts/compute_imatrix.py — imatrix计算

方案B 版本演进

版本改进点bit池平均bitPPL备注
v1 bayes基础GP+UCB{3,4,8}4.0011.35首次跑通
v2 bayes扩展bit池{2,3,4,5,6,8}5.0614.632bit引入后变差
v3 bayes+低bit惩罚(3.0){2,3,4,5,6,8}5.0610.88惩罚2/3bit
v4 bayes ★+imatrix感知{2,3,4,5,6,8}5.0510.49项目最优

1.5 方案C:K-quant 分块混合(v5, 2026-08-31)

核心思想:参考 llama.cpp Q4_K_M。用 imatrix 对权重列排序,每 group_size 个元素一块,块内用 hi/lo 两种 bit 混合量化。不同于贝叶斯逐层选bit,K-quant是在层内做混合。

flowchart LR subgraph 输入 C1["线性层权重
(out, in)"] C2["imatrix
列重要性"] end subgraph 处理 C3["argsort(im)
重要列排前面"] C4["分块
每gs=32元素一块"] C5["块内混合
前半 hi-bit
后半 lo-bit"] C6["量化存储
qweight+scale+zp"] end subgraph 输出 C7["KQuantLinear
替换 nn.Linear"] end C1 --> C3 C2 --> C3 C3 --> C4 --> C5 --> C6 --> C7
# dynquant/quant.py — K-quant核心 class KQuantLinear(nn.Module): """K-quant: imatrix排序 + 块内hi/lo混合""" def from_linear(cls, linear, im, group_size=32, hi_bits=5, lo_bits=3): ... def kquant_quantize_weight(W, im, group_size, hi_bits, lo_bits): """单层K-quant量化""" ... # scripts/run_p2_v5_kquant.py — 单次评测 # scripts/run_p2_v5b_kquant_sweep.py — sweep评测

方案C 实验结果

配置hi bitlo bitgroup_size平均bitPPL
h5l3 ★53324.010.77
h4l343323.510.89
h4l24232~3.013.44

1.6 方案D:混合比例 sweep(2026-08-31)

核心思想:扫描不同平均 bit 下限(2.5~4.8),观察 PPL 随压缩率的变化曲线,找到质量-大小的拐点。

# scripts/bench_our_models.py — 批量评测 # 扫描配置:mixed_avg2.5 ~ mixed_avg4.8 # 用 compute_ppl (transformers) 评测

方案D 实验结果

配置平均bitPPL模型大小状态
mixed_avg2.52.526813.650.34GB崩溃
mixed_avg3.03.014.960.69GB可用但差
mixed_avg3.53.514.221.03GB可用但差
mixed_avg4.04.011.082.84GB接近uniform_4bit
mixed_avg4.84.811.043.10GB最优混合比例

结论:avg < 3.5 时质量急剧下降,avg 4.0~4.8 区间收益递减。


1.7 代码与方案对应关系

代码文件方案关键函数/类说明
dynquant/pipeline.py A 固定D sweep apply_quantization(), compute_sensitivity(), save_quantized(), load_quantized() 通用流水线:灵敏度计算+量化替换+存储
scripts/export_gguf.py A 固定 build_multisource(), tok_blocks() 生成固定比例量化模型(uniform/mixed)
scripts/run_quant_vram.py A 固定 sampler(), stage() 量化+VRAM监控
dynquant/bayes_alloc.py B 贝叶斯 allocate_bits_bayesian(), greedy_restricted(), simulated_annealing(), load_layer_importance() v1~v4核心:GP+UCB搜索+imatrix+lowbit惩罚
scripts/run_p2_v4_imatrix.py B 贝叶斯 主入口 v4: imatrix+lowbit_penalty+bayesian
scripts/compute_imatrix.py BC imatrix计算 per-column L2激活能量
dynquant/quant.py C K-quantA 均匀 QuantLinear, KQuantLinear, KMeansQuantLinear, kquant_quantize_weight() 量化内核:均匀4/8bit+K-quant+K-means
scripts/run_p2_v5_kquant.py C K-quant 单次评测 KQuantLinear.from_linear()替换
scripts/run_p2_v5b_kquant_sweep.py C K-quant hi/lo配置遍历 扫描不同hi/lo组合
scripts/bench_our_models.py AD 批量compute_ppl评测 批量评测所有固定比例+sweep配置
scripts/bench_all_unsloth_v6.py 竞品评测 llama-perplexity批量调用 unsloth GGUF全量评测
第2章 实验日志与调参记录

2.1 实验时间线(按时间排序)

2026-08-27 22:13 — 原始模型下载
下载 Qwen3.5-4B BF16 原始模型(8.07GB)到 models/Qwen3.5-4B
2026-08-27 22:32 — 方案A:Q4-8-mix 生成
策略:上层8bit + 下层4bit,固定分界
代码:scripts/export_gguf.py
输出:models/Qwen3.5-4B-Q4-8-mix/
2026-08-28 16:38 — 方案A:固定比例批量生成
生成配置:mixed_avg2.5/3.0/3.5/4.0/4.8, uniform_8bit/4bit/3bit/2bit
代码:scripts/export_gguf.py + scripts/run_quant_vram.py
输出:models/quant_gguf/*
备注:uniform_3bit/2bit 已生成但未评测(质量预期太差)
2026-08-29 18:01 — 方案B:v1 贝叶斯基础版
参数:bits={3,4,8}, avg=4.0, group_size=128, budget=80, per=1024
校准数据:4源混合5万token
代码:scripts/run_p2_v4_imatrix.py(早期版本)
结果:greedy PPL=8357.97 (崩溃), bayes PPL=11.35
备注:greedy分配2bit=129层导致崩溃,bayes找到合理分配
2026-08-30 19:51 — 竞品评测:unsloth 第一轮
评测工具:llama-perplexity (llama.cpp b10679)
代码:scripts/bench_all_unsloth_v6.py
结果:Q4_K_M PPL=9.98, Q3_K_M PPL=10.06, Q8_0 PPL=10.04, Q5_K_M PPL=10.17, UD-Q4_K_XL PPL=10.19, UD-Q8_K_XL PPL=10.02
2026-08-30 20:39 — 方案B:v2 扩展bit池
参数:bits={2,3,4,5,6,8}, avg=4.0, group_size=128
新增2bit、5bit、6bit位宽
结果:bayes PPL=14.63 (变差!)
分析:2bit引入后贝叶斯过度分配低bit,质量崩溃
2026-08-30 22:09 — 竞品评测:unsloth 第二轮(补全)
补充评测:Q3_K_S=10.52, Q4_0=10.11, Q4_1=9.98, Q4_K_S=10.04, Q5_K_S=10.15, Q6_K=10.06, IQ4_NL=10.65, IQ4_XS=10.58, UD-IQ2_M=11.48, UD-IQ3_XXS=10.55, UD-Q2_K_XL=11.32, UD-Q3_K_XL=10.19, UD-Q6_K_XL=10.02, BF16=10.06
2026-08-30 22:11 — 方案B:v3 低bit惩罚
参数:bits={2,3,4,5,6,8}, avg=4.0, lowbit_penalty=3.0
改进:对分配2/3bit的层施加PPL惩罚,迫使贝叶斯少用低bit
结果:greedy PPL=8357.97 (仍崩溃), bayes PPL=10.88, SA PPL=6569.74 (崩溃)
bayes分配:5bit=99层, 4bit=124层, 6bit=83层, 8bit=30层, 2bit=7层, 3bit=3层
2026-08-30 22:44 — 方案B:v4 imatrix + 低bit惩罚 ★最优★
参数:bits={2,3,4,5,6,8}, avg=4.0, lowbit_penalty=3.0, imatrix=imatrix.json
改进:引入per-column L2激活能量作为量化优先级参考
结果:greedy PPL=8357.97 (崩溃), bayes PPL=10.49 ★
bayes分配:8bit=30层, 6bit=76层, 5bit=92层, 4bit=114层, 3bit=22层, 2bit=12层
分析:imatrix让贝叶斯知道哪些层的哪些列更重要,显著提升质量
2026-08-31 01:12 — 方案C:v5 K-quant 单次
参数:hi=4, lo=2, gs=32
代码:scripts/run_p2_v5_kquant.py
结果:PPL=13.44 (差)
分析:hi/lo差距太大,lo=2bit质量太差
2026-08-31 01:17 — 方案C:v5b K-quant sweep
代码:scripts/run_p2_v5b_kquant_sweep.py
配置1:hi=5, lo=3, gs=32, avg=4.0bit → PPL=10.77
配置2:hi=4, lo=3, gs=32, avg=3.5bit → PPL=10.89
分析:hi=5/lo=3最优,接近uniform_4bit(11.26)但更好
2026-08-31 06:42 — 方案A/D:批量评测
代码:scripts/bench_our_models.py
FP16 PPL=10.40 | uniform_8bit PPL=10.39 | uniform_4bit PPL=11.26
mixed_avg4.8 PPL=11.04 | mixed_avg4.0 PPL=11.08 | mixed_avg3.5 PPL=14.22
mixed_avg3.0 PPL=14.96 | mixed_avg2.5 PPL=26813.65 (崩溃)
Q4-8-mix PPL=10.69 | Q6-mix (报错,visual层不支持)

2.2 调参关系图

graph TD subgraph "方案B演进: v1→v2→v3→v4" V1["v1 bits={3,4,8}
PPL=11.35"] -->|"加入2/5/6bit"| V2["v2 bits={2,3,4,5,6,8}
PPL=14.63 ↑变差"] V2 -->|"lowbit_penalty=3.0"| V3["v3 bayes
PPL=10.88 ↓改善"] V3 -->|"+imatrix感知"| V4["v4 bayes
PPL=10.49 ★最优"] end subgraph "方案C演进: K-quant" K1["K-quant h4l2
PPL=13.44"] -->|"提高lo bit"| K2["K-quant h4l3
PPL=10.89"] K1 -->|"提高hi bit"| K3["K-quant h5l3
PPL=10.77 ★"] end style V4 fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px style K3 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px

2.3 关键调参发现

发现证据结论
贪心分配必崩溃v1/v3/v4 greedy 均 PPL>8000必须用贝叶斯/启发式搜索
2bit引入有害v1→v2: PPL 11.35→14.63需 lowbit_penalty 抑制
lowbit_penalty 有效v2→v3: PPL 14.63→10.88penalty=3.0 是合理值
imatrix 显著提升v3→v4: PPL 10.88→10.49感知量化比盲搜好
K-quant hi=5/lo=3 最优v5b sweep: 10.77 vs 10.89 vs 13.44hi/lo差距不宜超过2bit
avg<3.5 质量崩塌sweep: avg3.0→PPL=14.96, avg2.5→崩溃4bit是下限

2.4 备份归档

备份目录时间内容
p2_alloc_bak_202609292026-08-29 18:01v1原始分配结果
p2_unsloth_20260830_1951142026-08-30 19:51unsloth竞品评测结果
p2_v2_extended_20260830_2039572026-08-30 20:39v2扩展bit池结果
p2_v3_lowbit_20260830_2211262026-08-30 22:11v3低bit惩罚结果
p2_v4_imatrix_20260830_2244482026-08-30 22:45v4 imatrix结果
p2_v5_kquant_20260831_0112312026-08-31 01:17v5 K-quant单次结果
p2_v5b_sweep_20260831_0117102026-08-31 01:17v5b K-quant sweep结果
第3章 竞品数据对比

3.1 评测说明

评测框架差异
• 项目模型:用 transformers compute_ppl 评测,权重先反量化为float再计算PPL,评测数据为 wikitext-2 parquet test set,80k tokens
• unsloth模型:用 llama.cpp llama-perplexity(b10679)评测,实际量化内核运算,评测数据为 wikitext-2-test-short.txt,~12.5k tokens
• 两个框架的 tokenization、batch处理、数值精度不同,且评测数据规模不同(80k vs 12.5k),PPL 数值不完全可直接对比
• 公平对比方案:需将项目模型转为 GGUF 后用 llama-perplexity 评测(尚未完成)

3.2 项目自研方案(compute_ppl 评测)

对比量化方式 模型归属 校准数据 评测数据 评测数据规模 评测数据来源 PPL(越低越好) 模型文件大小
FP16 基线 我们的 无 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.40 8.07GB
uniform_8bit 我们的 无 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.39 4.14GB
uniform_4bit 我们的 无 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 11.26 2.19GB
Q4-8-mix (上层8bit+下层4bit) 我们的 无 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.69 2.63GB
mixed_avg4.8 (贝叶斯4.8bit) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 11.04 3.10GB
mixed_avg4.0 (贝叶斯4.0bit) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 11.08 2.84GB
mixed_avg3.5 (贝叶斯3.5bit) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 14.22 1.03GB
mixed_avg3.0 (贝叶斯3.0bit) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 14.96 0.69GB
mixed_avg2.5 (贝叶斯2.5bit) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 26813.65 (崩溃) 0.34GB
v3 bayes (低bit惩罚, avg=5.06) 我们的 4源混合5万token wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.88 —
v4 bayes imatrix+lowbit (avg=5.05) ★ 我们的 4源混合5万token+imatrix wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.49 —
v5 K-quant h5l3 (hi=5,lo=3,avg=4.0) 我们的 imatrix排序 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.77 —
v5b K-quant h4l3 (hi=4,lo=3,avg=3.5) 我们的 imatrix排序 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 10.89 —
v5 K-quant h4l2 (hi=4,lo=2) 我们的 imatrix排序 wikitext-2 parquet test 80k tokens 本地测试 compute_ppl 13.44 —

3.3 竞品 unsloth GGUF(llama-perplexity 评测)

对比量化方式 模型归属 校准数据 评测数据 评测数据规模 评测数据来源 PPL(越低越好) 模型文件大小
BF16 unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.06 8.07GB
Q3_K_S unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.52 2.03GB
Q3_K_M unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.06 2.37GB
Q4_0 unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.11 2.49GB
Q4_1 unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 9.98 2.68GB
Q4_K_S unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.04 2.50GB
Q4_K_M ★ unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 9.98 2.83GB
Q5_K_S unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.15 2.91GB
Q5_K_M unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.17 3.21GB
Q6_K unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.06 3.39GB
Q8_0 unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.04 4.61GB
IQ4_NL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.65 2.54GB
IQ4_XS unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.58 2.46GB
UD-IQ2_M unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 11.48 1.81GB
UD-IQ3_XXS unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.55 1.96GB
UD-Q2_K_XL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 11.32 1.98GB
UD-Q3_K_XL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.19 2.36GB
UD-Q4_K_XL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.19 2.99GB
UD-Q6_K_XL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.02 3.97GB
UD-Q8_K_XL unsloth 无 wikitext-2-test-short.txt ~12.5k tokens llama-perplexity (llama.cpp b10679) 10.02 6.07GB

3.4 跨框架对比小结

项目最优

v4 imatrix+lowbit

PPL = 10.49 | avg=5.05bit

框架: compute_ppl (transformers)

评测数据: wikitext-2 parquet test

数据规模: 80k tokens

竞品最优

unsloth Q4_K_M

PPL = 9.98 | 2.83GB

框架: llama-perplexity (llama.cpp)

评测数据: wikitext-2-test-short.txt

数据规模: ~12.5k tokens

差距 0.51 PPL,但框架不同(transformers vs llama.cpp)且数据规模不同(80k vs 12.5k tokens),PPL 不完全可直接对比。下一步需将项目模型转为 GGUF 后用同一框架、同一数据规模公平评测。

Qwen3.5-4B 逐层混合动态量化项目 | 2026-08-31

华杉的技术博客 · 苏ICP备2026063680号-1
首页