DKmode22 commited on
Commit
0306b76
·
verified ·
1 Parent(s): 216cf63

YuE2-3B AR NVFP4 (nvfp4a16-gptq) — llm-compressor requant, 2026-09-13

Browse files
Files changed (7) hide show
  1. README.md +120 -0
  2. config.json +100 -0
  3. generation_config.json +4 -0
  4. model.safetensors +3 -0
  5. patch_fast.py +57 -0
  6. quant-manifest.json +22 -0
  7. recipe.yaml +12 -0
README.md ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: cc-by-nc-4.0
3
+ base_model: m-a-p/YuE2-3B
4
+ base_model_relation: quantized
5
+ pipeline_tag: text-to-audio
6
+ tags:
7
+ - yue2
8
+ - music-generation
9
+ - nvfp4
10
+ - compressed-tensors
11
+ - vllm
12
+ - dgx-spark
13
+ language:
14
+ - en
15
+ - zh
16
+ ---
17
+
18
+ # YuE2-3B — NVFP4 autoregressive checkpoint (W4A16, GPTQ)
19
+
20
+ This is an **NVFP4 requantisation of the autoregressive (AR) half of
21
+ [m-a-p/YuE2-3B](https://huggingface.co/m-a-p/YuE2-3B)**, packaged as the
22
+ `Qwen3ForCausalLM`-shaped checkpoint that the official `yue2_infer` pipeline
23
+ derives internally for its vLLM backend. It is a drop-in for that derived
24
+ checkpoint: the pipeline's planning (`abc`) and semantic-token stages run on
25
+ these weights; the NAR flow-matching stage and the VAE keep running on the
26
+ original bf16/fp32 weights, unchanged.
27
+
28
+ It exists because on unified-memory hardware (DGX Spark / GB10, 273 GB/s) the
29
+ AR stages are weight-bandwidth-bound and the bf16 AR checkpoint is 4.33 GB.
30
+
31
+ | | bf16 (derived by `yue2_infer`) | this checkpoint |
32
+ |---|---|---|
33
+ | AR weights on disk | 4.33 GB | 2.31 GB |
34
+ | Linear layers | bf16 | NVFP4 (W4A16: e2m1 weights, e4m3 per-16 scales + fp32 per-tensor global scale, bf16 activations), group 16 |
35
+ | `embed_tokens`, `lm_head` (vocab 184,704) | bf16 | bf16 (kept) |
36
+ | AR decode, DGX Spark GB10, vLLM 0.27.1, batch 1 | 44.8 / 43.0 tok/s (abc / semantic) | 100–107 / 95–97 tok/s (2.3×; 76 tok/s on a 9,000-token run) |
37
+
38
+ ## What was quantised, and how
39
+
40
+ - Source: `m-a-p/YuE2-3B` `model.safetensors` (sha256 `1d55c42c…`), AR tensors
41
+ extracted exactly as `yue2.fast.derive_ar_checkpoint` does (311 tensors:
42
+ attention q/k/v/o + q/k norms, AR `mlp.*`, layer norms, `embed_tokens`,
43
+ `lm_head`). The NAR MLPs (`nar_mlp.*`), `llm2vae`/`vae2llm`, the timestep
44
+ embedder and the VAE are **not** in this checkpoint and are not quantised.
45
+ - Tool: [llm-compressor](https://github.com/vllm-project/llm-compressor) 0.13.0 /
46
+ compressed-tensors 0.18.0. Recipe: `GPTQModifier(targets=["Linear"], scheme="NVFP4A16", ignore=["lm_head"], dampening_frac=0.01, block_size=128, actorder="static")`. `lm_head` excluded.
47
+ - Calibration: **pre-tokenised YuE2 sequences the bf16 model generated itself**
48
+ — 32 requests × (abc + semantic phases), 16 lyric sets × 2 contrasting style
49
+ prompts, English and Mandarin, `cot=full` and `cot=melody`; 58 windows /
50
+ 200K tokens, 51% codec tokens. Text corpora never exercise the codec-token
51
+ activations, so they were not used.
52
+ - Format: `compressed-tensors` `nvfp4-pack-quantized`, loadable by vLLM ≥ 0.10
53
+ on Blackwell (SM100/SM120/SM121) with native NVFP4 kernels, and by
54
+ transformers (weights dequantised to bf16).
55
+
56
+ ## Quality — teacher-forced logit agreement vs bf16
57
+
58
+ Measured through vLLM 0.27.1's real NVFP4 kernels on 4 held-out requests
59
+ (not in calibration), every output position teacher-forced against the bf16
60
+ model's own sampled sequences (6,286 abc positions, 17,931 semantic positions).
61
+ Top-1 agreement is entropy-sensitive: the codec distribution is flat almost
62
+ everywhere (bf16 itself puts its argmax on the sampled token only 22% of the
63
+ time), so the NLL and logprob-shift columns are the ones to read. The
64
+ bf16-vs-bf16 row is the numerics floor across two engine builds.
65
+
66
+ | Checkpoint | abc top-1 agree | abc NLL | semantic top-1 agree | semantic NLL | mean \|Δlogprob\| |
67
+ |---|---|---|---|---|---|
68
+ | bf16 vs bf16 (engine builds) | 0.999 | 0.141 / 0.141 | 0.982 | 3.414 / 3.414 | 0.02 |
69
+ | **this checkpoint — NVFP4 W4A16, GPTQ** | **0.996** | **0.141 / 0.142** | **0.905** | **3.414 / 3.424 (+0.3%)** | **0.10** |
70
+ | NVFP4 W4A16, AWQ+RTN | 0.993 | 0.141 / 0.143 | 0.896 | 3.414 / 3.433 (+0.6%) | 0.12 |
71
+ | NVFP4 W4A4, GPTQ | 0.992 | 0.141 / 0.144 | 0.854 | 3.414 / 3.446 (+0.9%) | 0.17 |
72
+ | NVFP4 W4A4, AWQ+RTN | 0.991 | 0.141 / 0.145 | 0.847 | 3.414 / 3.457 (+1.2%) | 0.18 |
73
+
74
+ Binned by the bf16 model's own top-1 probability, the W4A16 GPTQ checkpoint agrees
75
+ ~100% where bf16 is confident (p₁ > 0.5) and the disagreements sit in the near-tie
76
+ buckets (p₁ < 0.15: 45% of semantic positions), where a 0.1-nat shift swaps two
77
+ candidates the sampler was already choosing between at temperature 1.0. A
78
+ per-layer sensitivity pass found no dominant layer (all 28 within ±0.008 nats of
79
+ the ±0.005 noise), so no layer is kept in bf16. W4A4 is slower than W4A16 at
80
+ batch 1 on this hardware as well as less accurate, so it was not published.
81
+
82
+ ## How to use
83
+
84
+ The official pipeline derives its own bf16 AR checkpoint and does not (yet)
85
+ accept an alternative. A 5-line patch to `yue2/fast.py` adds a
86
+ `YUE2_AR_CHECKPOINT` environment override:
87
+ [`patch_fast.py`](patch_fast.py) (idempotent; also in this repo).
88
+
89
+ ```bash
90
+ pip install "yue2_infer[fast]" # the wheel from m-a-p/YuE2-3B
91
+ python patch_fast.py "$(python -c 'import yue2.fast,os;print(os.path.abspath(yue2.fast.__file__))')"
92
+ hf download DKmode22/YuE2-3B-AR-NVFP4 --local-dir ./yue2-ar-nvfp4
93
+ export YUE2_AR_CHECKPOINT=$PWD/yue2-ar-nvfp4
94
+ python - <<'EOF'
95
+ from yue2 import YuE2Pipeline
96
+ pipe = YuE2Pipeline.from_pretrained("m-a-p/YuE2-3B", backend="vllm", memory_budget_gib=16)
97
+ song = pipe(style="Indie folk, warm acoustic guitar, male vocal", lyrics="[Verse]\n...")
98
+ song.save("song.flac")
99
+ EOF
100
+ ```
101
+
102
+ Notes:
103
+ - The vLLM path is used only when `cfg_scale == 1` (the default for
104
+ `cot=full|melody`) and `quantization="none"`. `cot=off` uses guidance 1.01 and
105
+ the pipeline silently falls back to its torch backend, where this checkpoint
106
+ is not used.
107
+ - On DGX Spark (sm_121) the `vllm==0.19.0` PyPI wheel the package pins has no
108
+ usable NVFP4 kernel path (the W4A4 arm fails to initialise; the W4A16 arm
109
+ runs but returns wrong logits). Use a vLLM build with SM121 support
110
+ (we used 0.27.1) and widen the version assert in `yue2/fast.py`.
111
+ - Everything else about the pipeline is unchanged: `max_num_seqs=1`, the
112
+ windowed repetition-penalty logits processor, 24,576 context.
113
+
114
+ ## Licence and attribution
115
+
116
+ The base model is released by the M-A-P team under **CC-BY-NC-4.0**; this
117
+ derivative carries the same licence and is for non-commercial use. All credit
118
+ for the model goes to the YuE2 authors — please cite their work
119
+ (`arxiv:2503.08638`). Quantisation, calibration corpus and evaluation by
120
+ DKmode22 on DGX Spark (GB10) hardware, 2026-09-13.
config.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Qwen3ForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": null,
8
+ "dtype": "bfloat16",
9
+ "eos_token_id": null,
10
+ "head_dim": 128,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 2048,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 6144,
15
+ "layer_types": [
16
+ "full_attention",
17
+ "full_attention",
18
+ "full_attention",
19
+ "full_attention",
20
+ "full_attention",
21
+ "full_attention",
22
+ "full_attention",
23
+ "full_attention",
24
+ "full_attention",
25
+ "full_attention",
26
+ "full_attention",
27
+ "full_attention",
28
+ "full_attention",
29
+ "full_attention",
30
+ "full_attention",
31
+ "full_attention",
32
+ "full_attention",
33
+ "full_attention",
34
+ "full_attention",
35
+ "full_attention",
36
+ "full_attention",
37
+ "full_attention",
38
+ "full_attention",
39
+ "full_attention",
40
+ "full_attention",
41
+ "full_attention",
42
+ "full_attention",
43
+ "full_attention"
44
+ ],
45
+ "max_position_embeddings": 24576,
46
+ "max_window_layers": 0,
47
+ "model_type": "qwen3",
48
+ "num_attention_heads": 16,
49
+ "num_hidden_layers": 28,
50
+ "num_key_value_heads": 8,
51
+ "pad_token_id": null,
52
+ "quantization_config": {
53
+ "config_groups": {
54
+ "group_0": {
55
+ "format": "nvfp4-pack-quantized",
56
+ "input_activations": null,
57
+ "output_activations": null,
58
+ "targets": [
59
+ "Linear"
60
+ ],
61
+ "weights": {
62
+ "actorder": "static",
63
+ "block_structure": null,
64
+ "dynamic": false,
65
+ "group_size": 16,
66
+ "num_bits": 4,
67
+ "observer": "memoryless_minmax",
68
+ "observer_kwargs": {},
69
+ "scale_dtype": "torch.float8_e4m3fn",
70
+ "strategy": "tensor_group",
71
+ "symmetric": true,
72
+ "type": "float",
73
+ "zp_dtype": null
74
+ }
75
+ }
76
+ },
77
+ "format": "nvfp4-pack-quantized",
78
+ "global_compression_ratio": null,
79
+ "ignore": [
80
+ "lm_head"
81
+ ],
82
+ "kv_cache_scheme": null,
83
+ "quant_method": "compressed-tensors",
84
+ "quantization_status": "compressed",
85
+ "sparsity_config": {},
86
+ "transform_config": {},
87
+ "version": "0.18.0"
88
+ },
89
+ "rms_norm_eps": 1e-06,
90
+ "rope_parameters": {
91
+ "rope_theta": 1000000,
92
+ "rope_type": "default"
93
+ },
94
+ "sliding_window": null,
95
+ "tie_word_embeddings": false,
96
+ "transformers_version": "5.14.1",
97
+ "use_cache": true,
98
+ "use_sliding_window": false,
99
+ "vocab_size": 184704
100
+ }
generation_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "transformers_version": "5.14.1"
4
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:61ce7cfaf6c4d5807d254961df24ae78e2e813eea9d921e939c1cd89efd97674
3
+ size 2306149080
patch_fast.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Idempotent patch for the installed yue2_infer `fast.py` (vLLM backend).
3
+
4
+ Adds ONE lever: if the env var YUE2_AR_CHECKPOINT names a directory, the vLLM
5
+ worker serves THAT checkpoint instead of the bf16 AR checkpoint it derives from
6
+ model.safetensors. That is how an NVFP4 (compressed-tensors) requant of the
7
+ derived Qwen3-shaped AR checkpoint is put on the real generation path. Nothing
8
+ else changes (dtype, KV sizing from config.json, logits processor, max_num_seqs=1).
9
+
10
+ Usage: patch_fast.py <site-packages>/yue2/fast.py [--check]
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import re
15
+ import sys
16
+
17
+ MARK = "# s5-patch: YUE2_AR_CHECKPOINT override (services/yue2-nvfp4/patch_fast.py)"
18
+ OLD = 'derived = derive_ar_checkpoint(setup["model_dir"])'
19
+ NEW = (
20
+ MARK + "\n"
21
+ ' _override = os.environ.get("YUE2_AR_CHECKPOINT")\n'
22
+ ' derived = Path(_override) if _override else derive_ar_checkpoint(setup["model_dir"])\n'
23
+ ' if _override and not (derived / "config.json").exists():\n'
24
+ ' raise FileNotFoundError(f"YUE2_AR_CHECKPOINT has no config.json: {derived}")\n'
25
+ ' print(f"s5-patch: AR checkpoint = {derived} (override={bool(_override)})", file=sys.stderr, flush=True)'
26
+ )
27
+
28
+
29
+ def main() -> int:
30
+ path = sys.argv[1]
31
+ check = "--check" in sys.argv
32
+ src = open(path).read()
33
+ if MARK in src:
34
+ print("already patched")
35
+ return 0
36
+ if check:
37
+ print("NOT patched")
38
+ return 1
39
+ if src.count(OLD) != 1:
40
+ print(f"expected exactly one occurrence of {OLD!r}, found {src.count(OLD)}")
41
+ return 2
42
+ # the derive call is indented 4 spaces inside _worker_main
43
+ new_src = re.sub(r"^(\s+)" + re.escape(OLD) + r"$",
44
+ lambda m: m.group(1) + NEW.replace("\n ", "\n" + m.group(1)), src, count=1, flags=re.M)
45
+ if new_src == src:
46
+ print("substitution failed")
47
+ return 3
48
+ if "from pathlib import Path" not in new_src and "import Path" not in new_src:
49
+ print("fast.py has no Path import; refusing")
50
+ return 4
51
+ open(path, "w").write(new_src)
52
+ print("patched", path)
53
+ return 0
54
+
55
+
56
+ if __name__ == "__main__":
57
+ sys.exit(main())
quant-manifest.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "src": "/opt/yue2/cache/yue2-ar/39f337a6c2354ed0063701cdd090b0eab7461450451ec02c3fec32f1ec125777",
3
+ "corpus": "corpus/bf16.jsonl",
4
+ "scheme": "NVFP4A16",
5
+ "awq": false,
6
+ "method": "gptq",
7
+ "ignore": [
8
+ "lm_head"
9
+ ],
10
+ "holdout": [
11
+ "r28",
12
+ "r29",
13
+ "r30",
14
+ "r31"
15
+ ],
16
+ "max_seq_len": 8192,
17
+ "num_samples": 58,
18
+ "tokens": 200116,
19
+ "codec_share": 0.514191768774111,
20
+ "seed": 0,
21
+ "started": "2026-09-13T01:21:33Z"
22
+ }
recipe.yaml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ default_stage:
2
+ default_modifiers:
3
+ GPTQModifier:
4
+ targets: [Linear]
5
+ ignore: [lm_head]
6
+ scheme: NVFP4A16
7
+ bypass_divisibility_checks: false
8
+ requires_calibration_data: true
9
+ block_size: 128
10
+ dampening_frac: 0.01
11
+ actorder: static
12
+ offload_hessians: false