# ComfyUI-YuE2 文生音乐：部署与实测记录

**日期**：2026-09-13（GPU 机本地时间 09-14 00:xx）
**机器**：GPU 机 192.168.31.31（RTX 5060 Ti **16GB** / 32GB RAM）
**仓库**：[ScryptHunter/ComfyUI-YuE2](https://github.com/ScryptHunter/ComfyUI-YuE2)（`piscesbody/ComfyUI-YuE2` 的兼容性 fork）
**结论**：**已跑通**。16GB 卡上文生音乐（cot=off 与 cot=full 两档）+ 参考音频转乐谱（SheetSage2）全部成功，零 OOM。你贴的那段"改哈希"偏方**在本 fork 上不需要**。

---

## 一、一句话结论（对应你贴的那段文字）

| 你贴的说法 | 实测核实结果 |
|---|---|
| 第二页之后功能都报"拒绝跨站请求" | 属于 **T8 整合包**（另一套东西）的问题，与 ComfyUI 版无关；本机未复现 |
| ComfyUI 版文生音乐会爆显存 | **成因确定**：没按 fork 的 Memory Preset 设显存档。按 **16GB 档**（`memory_budget_gib=16` + `offload_ar=True` + `vae_decode=tiled` + `tile=384`）实测**峰值仅 9.26–10.05 GiB**，完全不爆 |
| 参考生音乐（参考音频）正常 | 本机 SheetSage2 参考音频链路同样正常（另有独立坑，见第四节 nvrtc） |
| 改 `modeling_sheetsage2.py` 的 `BASE_CODE_HASHES` 才能跑 | **说法本身是真的**（该哈希表确实存在，见第二节），**但本 fork 不需要改**：fork 是在**运行时内存里**重算 `inv_freq`，不动磁盘上的 `modeling_mert2.py`，所以完整性校验本来就通过 |
| 与 custom_nodes 里的 qwen asr 冲突 | **本机未安装 qwen asr 节点，无法验证**（标注为未核实）。机理上两者确实会撞同一个地方：都可能往 `~/.cache/huggingface/modules/` 注入同名模型代码目录 |

### 关于 `BASE_CODE_HASHES` 的核实（你贴的那两行）

已核对上游 `m-a-p/SheetSage2` 仓库源码 —— `modeling_sheetsage2.py` 第 26 行确有：

```python
BASE_CODE_HASHES = {
    "configuration_mert2.py": "77b53ec9d7ee31a599d744fb006e812c7eeaf7390deb46e2f460cf8c17b00bd6",
    "modeling_mert2.py": "b1a3174e5649c4b26b0c90d8626f0adacfbbba111a58ed3bb72ad651945a2f5c",
}
```

用途是 **MERT-v2 父模型完整性校验**（第 245–249 行）：加载时把本地 `configuration_mert2.py` / `modeling_mert2.py` 的 sha256 与表中值比对，不符即抛 `MERT-v2 parent integrity check failed`。

它只在**你手工改过 MERT2 代码文件**时才会触发。而本 fork 的做法是 `compat/sheetsage2.py` 里的 `fix_rotary_inv_freq()` —— 在**加载后对内存里的 buffer** 重算 `inv_freq`（幂等），磁盘文件保持原样。所以：

> **改哈希 = 上游老版本/手工打补丁的绕法；用这个 fork 就别改**，改了反而失去一层完整性保护。

---

## 二、环境（现成条件，未动 torch 栈）

| 项 | 值 |
|---|---|
| ComfyUI | 0.34.0（`--lowvram --force-fp16 --reserve-vram 1.0 --fast-disk --cache-lru 20`） |
| Python / torch | 3.12.3 / **2.11.0+cu130** |
| transformers | **5.14.1**（fork 的 `compat/transformers5.py` 负责适配） |
| numpy | 2.4.4 |
| GPU | RTX 5060 Ti 16311 MiB，驱动 610.43.02 |

装完依赖后 **torch / transformers / numpy 版本一个都没变**（这正是该 fork 的主打卖点）：

```
Successfully installed decorator-5.3.1 importlib_resources-7.1.0 mido-1.3.3
  mir_eval-0.8.2 pretty_midi-0.2.11.post0 tiktoken-0.14.0
```

---

## 三、安装步骤（复现用）

```bash
# 1) 节点
cd /home/zyw/ComfyUI/custom_nodes
git clone --depth 1 https://github.com/ScryptHunter/ComfyUI-YuE2.git
/home/zyw/ComfyUI/venv/bin/python -m pip install -r ComfyUI-YuE2/requirements.txt

# 2) 模型（放 /home/zyw/ComfyUI/models/）
#    YuE2/YuE2-3B/（含 yue2_infer-0.1.5-py3-none-any.whl）  6.8 GiB  sha256 1d55c42c…（官方 manifest 一致）
#    YuE2/YuE2-Vae/                                          507 MiB  sha256 校验一致
#    SheetSage2/                                             223 MiB
#    MERT2/MERT-v2-FullSong/  @d8ba1c745e733b3908ce6ad16ebeb17ac7600a42  2.4 GiB  sha256 e6dd2ab1…（一致）
# 注意：不要 pip install 那个 whl（fork 会自己隔离解压到 .yue2_runtime/）

# 3) 重启 ComfyUI（脚本已固化，见第五节）
bash /home/zyw/start-comfyui.sh
```

重启后节点注册情况：**25 个**——`YuE2Loader / YuE2Sampler / YuE2Plan / YuE2RenderPlan / YuE2MemoryPreset / SheetSage2Loader / SheetSage2Transcribe / …`，零导入报错。

---

## 四、踩到的四个坑与修复（**这是本次最有价值的部分**）

### 坑 1：`hf` CLI 下载大文件 401（HF Xet 与镜像不兼容）

```
RuntimeError: File reconstruction error: CAS Client Error:
  HTTP status client error (401 Unauthorized), domain: https://cas-server.xethub.hf.co/...
```

- **原因**：huggingface.co 直连不通，用 `hf-mirror.com` 只能拿到元数据；**官方 Xet(CAS) 存储**的 blob 会 302 到 `cas-bridge.xethub.hf.co` 并在重构阶段 401。设 `HF_HUB_DISABLE_XET=1` 也按不住（`hf` 1.26 仍走 Xet 路径），且失败时 `hf download ... | tail` 会**静默 exit 0**，看着像成功、其实一个字节没下。
- **修复**：绕开 `hf` 客户端，**直接 curl 镜像的 resolve 直链**（302 后 200，签名 URL 可用 1 小时），并且因为镜像**限单连接速度（实测 3 MiB/s）**，改用**分块并行**（8 通道实测 **~20 MiB/s**，7.26GB 主权重约 6 分钟）。
- 脚本：`yue2-get.sh`（分块 + sha256 校验 + 原子落位）、`yue2-par-dl.sh`、`yue2-par-finish.sh`（续传拼接）。
- ⚠️ **血泪细节**：中途 `pkill` 顺序下载脚本时，**孤儿 curl 仍持有同一 inode 继续追加**，把"已下载头部"从 1.32GB 撑到 3.66GB，拼接必错。**杀下载要 `pkill -x curl`，不能只杀脚本**。

### 坑 2：文生音乐首跑必崩 —— cuDNN SDPA 建不出执行计划

```
RuntimeError: cuDNN Frontend error: [cudnn_frontend] Error: No valid execution plans built.
  at yue2/cuda_graph.py:153 in _decode()   ← CUDA Graph 捕获阶段
```

- **原因**：fork 的 `attention_backend="auto"` 在探测不到内置 FlashAttention 时会**强制切到 cuDNN SDPA**（作者是为 Windows 打包写的补丁）；本机 torch 2.11+cu130 的 cuDNN 前端在这组「GQA + bool mask + CUDA Graph 捕获」条件下建不出计划。
- **修复**（已写入 fork，备份 `models/yue2_patch.py.bak-yue2sdpa`）：
  1. 模块导入时 `torch.backends.cuda.enable_cudnn_sdp(False)`（否则即使选 `sdpa`，torch 仍可能把 SDPA 路由回 cuDNN）；
  2. `auto` 的兜底后端由 `cudnn` 改成 `sdpa`；
  3. 提交时显式传 `attention_backend="sdpa"`。
- 实测 `sdpa` 分支稳定跑通（CUDA Graph 捕获正常）。

### 坑 3：SheetSage2 报 `nvrtc: error: failed to open libnvrtc-builtins.so.13.0`

- **现象**：`MERT2.forward → torchaudio Spectrogram → torch.stft` 抛 RuntimeError，异常消息是一大坨 CUDA C 源码，**真正的错误藏在末尾**：`nvrtc: error: failed to open libnvrtc-builtins.so.13.0`。
- **原因**：该库**明明存在**于 `venv/lib/python3.12/site-packages/nvidia/cu13/lib/libnvrtc-builtins.so.13.0`，只是不在动态库搜索路径里，JIT 编译内核时 dlopen 失败。
- **修复**：启动时给 `LD_LIBRARY_PATH` 加上 `nvidia/cu13/lib` 与 `nvidia/cuda_nvrtc/lib`（已固化进 `/home/zyw/start-comfyui.sh`）。
- 独立验证：裸 `torch.stft` 两种环境都正常，**只有 torchaudio 的 Spectrogram 走 JIT** 才暴露；带 `LD_LIBRARY_PATH` 后 `torchaudio Spectrogram OK (1, 201, 3001)`。

### 坑 4（本机工具链）：`ssh_exec.sh` 静默 30 秒即杀会话

`~/Downloads/ssh_exec.sh` 里 `set timeout 30` —— 远程命令**只要静默超过 30 秒**（sleep、长下载、等服务起来），expect 就超时并**杀掉整个 SSH 会话**，表现为"输出莫名断半截"。已改为 `set timeout -1`（备份 `ssh_exec.sh.bak-20260913`），并把固定启动命令固化成 `/home/zyw/start-comfyui.sh`。

---

## 五、实测数据

### 1) 烟测：短中文歌，`cot=off`（不做乐谱规划）

```
[YuE2] 63.3s @48000Hz | cot=off seed=831001 | abc_tokens=0 sem_tokens=1583
       | e2e=59.5s | semantic=40.0s | peak_vram=9.26GiB
```
端到端 **66 秒**，产出 48kHz 立体声 FLAC 63.28 秒。

### 2) 完整版：中文完整歌，`cot=full`（先出乐谱规划再渲染）

```
[YuE2] 171.7s @48000Hz | cot=full seed=831001 | abc_tokens=1394 sem_tokens=4293
       | e2e=222.1s | abc=27.8s semantic=145.4s | peak_vram=10.05GiB
```
端到端 **222 秒（3.7 分钟）**，产出 **2 分 52 秒**、48kHz 立体声 FLAC（28MB 无损）。同时保存了 AI 生成的 **ABC 乐谱规划**（F 调 / 73 BPM / 带 Bbmaj7、Am7 等和弦与 Vocal+Ins 双声部）。

### 3) 参考音频转乐谱（SheetSage2 + 本地 MERT2）

输入上面那首 63 秒的歌：

```
[ComfyUI-YuE2] SheetSage2 is using local MERT2: /home/zyw/ComfyUI/models/MERT2/MERT-v2-FullSong
[SheetSage2] duration=63.3s vocal_notes=35 ins_notes=99 chords=19 sections=5 elapsed=2.9s
```

- **本地 MERT2 加载成功、完整性校验一次通过**（未改任何哈希）。
- 输出 ABC（F 调 70 BPM，带 F/Dm7/A#sus2/Am/Gm7 和弦）、MIDI、分段结构、节奏事件。
- 耗时 **2.9 秒**，显存占用极低。

### 显存档位参考（fork 的 Memory Preset）

| 档位 | memory_budget_gib | offload_ar | vae_decode | tile |
|---|---|---|---|---|
| 12 GB | 12 | True | tiled | 256 |
| **16 GB（本机）** | **16** | **True** | **tiled** | **384** |
| 24/32 GB | 24/32 | False | tiled | 0(自动) |
| 48 GB+ | 48 | False | full | 0 |

**"爆显存"几乎肯定是没设这个档**（默认 `memory_budget_gib=24` + `offload_ar=False` + 48GB 工作流里的 `vae_decode=full`）。

---

## 六、怎么用

**方式 A（推荐，GUI）**：ComfyUI 打开 http://192.168.31.31:8189 → 菜单 Workflow → Open → `custom_nodes/ComfyUI-YuE2/example_workflows/YuE2_Text_to_Song.json`（另有 `YuE2_Reference_Remix.json`）。
**改动点**：`YuE2MemoryPreset` 选 **16 GB**；`YuE2Loader.attention_backend` 选 **sdpa**（别用 auto/cudnn）。

**方式 B（API 脚本，本次用的）**：

```bash
python3 yue2-run.py --cot full --sem-mx 9000 --attn sdpa \
  --lyrics-file yue2-lyrics-zh.txt --style "Mandarin pop ballad, warm female vocal, ..." --tag zh-full
# 参考音频转乐谱：先把音频放进 GPU 机 ComfyUI/input/，再
python3 yue2-sheetsage.py --audio ref-song.flac --tag refsong
```

---

## 七、本次文件清单

| 文件 | 说明 |
|---|---|
| `01-烟测63秒-cot-off.flac` | 烟测成品（63.3s / 48kHz 立体声） |
| `02-中文完整版2分52秒-cot-full.flac` | 完整版成品（171.7s / 48kHz 立体声） |
| `zh-full-AI生成的乐谱规划.abc` | 完整版由 AI 生成的 ABC 乐谱规划（cot=full 阶段产物） |
| `参考音频转乐谱/` | SheetSage2 对烟测成品转谱的 8 个产物（abc/mid/json/lab） |
| `yue2-run.py` | 文生音乐 API 提交+轮询+回传脚本 |
| `yue2-sheetsage.py` | SheetSage2 转谱 API 脚本 |
| `yue2-dl.sh` / `yue2-get.sh` / `yue2-par-*.sh` | 镜像直链分块并行下载器（含 sha256 校验） |
| `start-comfyui.sh` | GPU 机 ComfyUI 启动脚本（含 LD_LIBRARY_PATH 修复） |
| `yue2-lyrics-zh.txt` | 本次用的中文歌词 |
| `ComfyUI工作流/` | 5 个已装进 ComfyUI 的本机适配版工作流（json）+ 两个生成脚本 |

**GPU 机关键路径**：节点 `~/ComfyUI/custom_nodes/ComfyUI-YuE2/`，模型 `~/ComfyUI/models/{YuE2,SheetSage2,MERT2}/`，产出 `~/ComfyUI/output/{YuE2,SheetSage2}/`，日志 `~/comfyui_8189_opt.log`。

## 七之二、ComfyUI 内置工作流（已装进 Workflows 侧边栏）

安装位置：GPU 机 `/home/zyw/ComfyUI/user/default/workflows/YuE2/` —— ComfyUI 页面里 **Workflows 侧边栏 → YuE2 分组**，刷新页面即可见。

| 工作流 | 用途 |
|---|---|
| `YuE2-1-文生音乐-中文-16GB.json` | 风格 + 中文歌词 → 完整歌曲（已预填本次那首中文歌） |
| `YuE2-2-文生音乐-英文示例-16GB.json` | 官方英文示例，同样已适配 |
| `YuE2-3-参考音频改编-16GB.json` | 参考音频 → 转谱 → 改编重渲染（Reference Remix） |
| `YuE2-4-全节点总览-16GB.json` | 全部 25 个节点的视觉总览 |
| `YuE2-5-参考音频转谱-16GB.json` | 单独跑 SheetSage2 转谱（不需要 YuE2），出 ABC/MIDI/分段 |

**每个工作流都做了这些本机适配**（原始示例直接 Queue 会崩）：

1. `YuE2MemoryPreset` = **16 GB**（原 48 GB）
2. `YuE2Loader.memory_budget_gib` = **16**（原 24）
3. `YuE2Loader.offload_ar` = **True**（原 False）← 这就是"爆显存"的直接原因
4. `YuE2Loader.attention_backend` = **sdpa**（原 auto → 会切 cuDNN 报 "No valid execution plans built"）
5. `YuE2Sampler.vae_decode` = **tiled**、`vae_tile_frames` = **384**
6. 每个工作流里放了一个 **Note 节点**，写清上述原因和显存档位对照表

> ⚠️ **顺带修掉一个上游示例的隐藏 bug**：两个文生音乐示例里 `vae_decode` 存的是旧版布尔值 `true`，而节点校验只接受 `tiled`/`full`/`false`，直接 Queue 会报 `vae_decode must be 'tiled' or 'full'`。已改。
>
> 上游自带示例（`custom_nodes/ComfyUI-YuE2/example_workflows/`）**保持原样未改**（避免 git pull 冲突），统一用上面这 5 个本机版。

生成/校验脚本：`yue2-install-workflows.py`（改参数 + 加 Note）、`yue2-extra-workflow.py`（生成第 5 个转谱工作流 + 连线一致性自检）。

## 八、仍未验证 / 待办

- **与 qwen asr 的冲突**：本机没装该节点，未复现；机理上两者都可能往 `~/.cache/huggingface/modules/` 注入同名模型代码（SheetSage2 确实会写 `.../modules/SheetSage2/<rev>/`），"用时互相移出 custom_nodes"这个规避手段**合理但未在本机证实**。
- **`4.7`/更大 `semantic_max_tokens`**：只测到 9000（未截断，`truncated={'abc': False, 'semantic': False}`），更长歌可再压。
- **参考旋律改编闭环**（SheetSage2 ABC → 编辑 → `YuE2RenderPlan` 用 `abc_override` 重渲染）：链路已具备，尚未实操。
- `YuE2-Vae-legacy` 未下载（仅基准复现用，非必需）。
