YuE2 on 16 GB: Two Patches and One Retracted Finding
Field report: the official yue2-infer runtime versus ComfyUI's nodes — truncation flags, semantic CFG, per-stage timing, and a corrected claim that the model ignores BPM.
TL;DR — Moving YuE2 off ComfyUI and onto the project's own
yue2-inferruntime surfaced a truncation flag, a CFG knob and a per-stage receipt that the ComfyUI nodes never expose — and the first thing they proved was that a conclusion I had written down three days earlier was wrong.
A week of local K-pop generation with YuE2 on one RTX 5080 (16 GB), first through ComfyUI's built-in nodes, then rebuilt on the official Python runtime. Reporting date: 15 September 2026. The delta is observability, not audio quality — and observability is what corrected a published finding.
Retraction first: YuE2 follows BPM
Prior finding: the model ignores tempo instructions. That was wrong. Tempo written into the generated score, against the tempo requested in the style prompt, all 28 runs:
| Requested in style | Written into the score |
|---|---|
| 112 BPM | 118 |
| 118 BPM | 122 |
| 124 BPM | 128 |
| 126 BPM | 128–132 |
| 132 BPM | 132 |
| 136 BPM | 134 |
| 140 BPM | 145 |
| 144 BPM | 140 |
Mean absolute error 3.5 BPM, monotonic. The failure case that produced the original claim was a prompt containing a range — "128–145" — which yielded a score marked 177. One malformed input, over-generalised. Single integer works.
Capability gap: node graph vs official request
ComfyUI exposes eleven sampling inputs across YuE2GenerateABC and YuE2GenerateMusic. The official request schema carries seven fields: id, style, lyrics, cot, seed, abc, cfg_scale. The gaps are asymmetric.
| Capability | ComfyUI YuE2 nodes | Official yue2-infer 0.1.6 |
|---|---|---|
| Truncation reporting | none | truncated.abc and truncated.semantic in result.json |
Semantic CFG (cfg_scale) |
not exposed at all | request field; defaults 1.0 for full/melody, 1.01 for off |
| Conditioning-mode contract | a mode string, no rules |
cot = full / melody / off, each with a documented ABC-input contract |
| Synthesis steps | whatever you set on KSampler (the template ships 20) | the release preset is fixed: 32 midpoint steps, context 24576 |
| Per-stage timing | none | seconds and tokens/s for ABC, semantic, NAR and VAE separately |
| Reproducibility receipt | none | weight SHA-256, config hash, request, seed, decoder identity, artifact hashes |
| Re-decode a finished song | not offered | latent.npy is saved; swap the decoder without regenerating the music |
| Memory levers | none | offload_ar, memory_budget_gib, vae_core_frames, query_chunk_size |
| Plan round-trip | manual string wiring between nodes | plan.save() / SymbolicPlan.load() with integrity validation |
Assessment: these are instrumentation, not quality. Their absence means a bad result and a misread result are indistinguishable.
Runtime: two patches for 16 GB
Documented baseline is "a BF16-capable NVIDIA GPU with 24GB memory and one active request per pipeline." Two stock failures on 16 GB:
USE_FLASH_ATTENTION was not enabled for build. Windows PyTorch wheels ship without the kernel; YuE2's auto-detection tests only for operator existence and aseqused_kschema mention. The operator is registered on Windows, so detection passes and execution fails. Backend is keyword-only and not forwarded by the pipeline — defaultGraphARto cuDNN. CUDA graphs retained.- NAR OOM, single 3.77 GiB allocation. On CUDA the NAR attention helper sets block size to full query length. Fix:
offload_ar(moves the ~6 GB AR model to CPU during synthesis) plusquery_chunk_size=2048. Both inside the documented API; mathematically identical splits.
Throughput after the patches, project example: 213.8 s of audio in 238.7 s. ABC 20.5 s, semantic 48.7 s, NAR 161.4 s (68%), VAE 4.0 s. ComfyUI's apparent 4x speed advantage is 20 sampler steps against the release preset's 32.
Signal: truncated resolves the length question
ComfyUI: request 180 s, receive 98 s, no way to distinguish a cut-off song from a finished one. The official runtime writes truncated.abc and truncated.semantic to result.json.
29 runs, both flags false in all 29. Not truncated — finished. Length is a function of lyric volume; the project's 213-second example simply carries more words. One boolean retired a week of speculation and a workaround script.
Language: determined by lyrics, not by the style token
Controlled test — lyrics held fixed, language token varied, automatic transcription measuring detected language and lyric fidelity:
| Lyrics | Language token in style | Language detected | Lyric fidelity |
|---|---|---|---|
| Korean | Korean |
Korean, 97% | 74% |
| Korean | English |
Korean, 97% | 57% |
| Korean | none | Korean, 97% | 71% |
| English | English |
English, 69% | 28% |
| English | Korean |
English, 71% | 3% |
| Korean + English mixed | both | Korean, 89% | 19% |
Korean lyrics tagged English still read as Korean at 97% confidence. The mismatch costs fidelity, not language: the English track fell 28% → 3% and degenerated to "Ah, ah, ah." Omitting the token is near-free; the project's showcase example names no language and sings entirely in Chinese. Mixed-language lyrics scored lowest of any condition at 19%.
Notes-per-syllable: bounded on both sides
- Korean: 185 syllables / 208 notes → 1.12 → faithful (74%)
- English: 119 syllables / 240 notes → 2.02 → half filled with "oh oh oh" (28%)
Too few notes per syllable produces rapping; too many produce invented vocalisations. Usable band ≈ 1.0–1.3.
Candidate selection is part of the published protocol
Documentation, generation page: "One pipeline call produces one candidate. The benchmark's candidate selection is a separate evaluation step." Benchmark page: "Standard YuE2 selects the lower-PER candidate from two generations."
Scores in context: YuE2 best-of-8 6.9632 SongBench average, Suno v5 6.8721, Suno v6 6.5562, unselected YuE2 6.7316. Eight seed-only variations measured here: 0, 31, 44, 45, 50, 57, 66, 70% lyric fidelity. The worst had normal audio — 136 s, normal dynamics and spectrum — and an empty transcript. Audible, unintelligible. A single call samples that distribution blind.
All four clips were generated locally by YuE2 for this write-up, at 128 kbps. Nothing was edited, mixed or re-taken.
FAQ
Can YuE2 run on a 16 GB GPU?
Yes, with two changes. The documented baseline is a 24 GB NVIDIA card, and a stock install fails twice on 16 GB: once because the Windows PyTorch wheel has no FlashAttention kernel, and once because the non-autoregressive synthesis stage feeds its whole query sequence into a single attention call. Forcing the cuDNN attention backend, enabling offload_ar, and chunking the query fixed both without changing the output. A 213.8-second song then took 238.7 seconds end to end.
Does the style prompt control BPM in YuE2?
Yes, if you write a single number. Across 28 runs the tempo written into the generated score tracked the requested BPM with a mean absolute error of 3.5 BPM, monotonically from 112 to 144. A tempo range in the prompt ("128–145") is what breaks it — that produced a score marked 177 BPM.
Why does YuE2 sing "oh oh oh" instead of my lyrics?
Usually because there are more notes in the plan than syllables in the lyrics. In a matched pair, Korean lyrics at 185 syllables over 208 notes (1.12 notes per syllable) were sung faithfully, while English lyrics at 119 syllables over 240 notes (2.02) were half-filled with vocalisations. Aim for roughly 1.0–1.3 notes per syllable.
Should I mix languages in one set of lyrics?
No. In this test the bilingual lyric set scored the lowest fidelity of any condition, 19%, and the transcript degraded at each point where the language switched mid-line.
Is one generation enough?
No. Eight runs that differed only by seed scored 0, 31, 44, 45, 50, 57, 66 and 70% on lyric fidelity. The published benchmark numbers use candidate selection, so a single unselected call is not the same setting.
Sources: YuE2 repository (multimodal-art-projection/YuE), YuE2 generation docs, YuE2 benchmark results, generation and covers reference, m-a-p/YuE2-3B on Hugging Face, WildSongBench dataset.
Image: Johann Ernst Bach, Magnificat autograph manuscript, Public domain, via Wikimedia Commons.
← Back to all posts