Download scripts/flow_edit_overlay_smoke.py from dvanh/ace-studio-v3-mashup: direct link, hf CLI and curl.
- Browser
- Download file 4.57 kB
-
https://huggingface.co/dvanh/ace-studio-v3-mashup/resolve/main/scripts/flow_edit_overlay_smoke.py
- Command line
-
hf download hf://dvanh/ace-studio-v3-mashup/scripts/flow_edit_overlay_smoke.py
-
curl -L -o flow_edit_overlay_smoke.py https://huggingface.co/dvanh/ace-studio-v3-mashup/resolve/main/scripts/flow_edit_overlay_smoke.py
4.57 kB
| """Flow-edit overlay smoke test (#1156, post-redesign). | |
| Drives ``inference.generate_music`` with ``task_type='cover'`` + | |
| ``flow_edit_morph=True`` so the V_delta overlay layers on top of the | |
| existing cover dispatch. This is the architecturally correct shape: | |
| the user's caption/lyrics are the *target*; the overlay's | |
| ``flow_edit_source_caption`` / ``flow_edit_source_lyrics`` describe | |
| the original audio. | |
| Run on jieyue (or any GPU host): | |
| cd /root/data/repo/gongjunmin/workspace/ACE-Step-1.5 | |
| conda activate acestep_v15_train | |
| CUDA_VISIBLE_DEVICES=1 python scripts/flow_edit_overlay_smoke.py | |
| Outputs go to ``flow_edit_test_outputs/overlay_*.wav``. | |
| """ | |
| import json | |
| import os | |
| import sys | |
| import time | |
| from pathlib import Path | |
| REPO = Path(__file__).resolve().parent.parent | |
| sys.path.insert(0, str(REPO)) | |
| os.environ.setdefault("CUDA_VISIBLE_DEVICES", "1") | |
| import torch | |
| import torchaudio | |
| from loguru import logger | |
| from acestep.handler import AceStepHandler | |
| from acestep.inference import GenerationConfig, GenerationParams, generate_music | |
| from acestep.llm_inference import LLMHandler | |
| OUT = REPO / "flow_edit_test_outputs" | |
| OUT.mkdir(exist_ok=True) | |
| SEED = 42 | |
| DIT_CONFIG = "acestep-v15-sft" | |
| ex = json.loads((REPO / "examples/text2music/example_01.json").read_text()) | |
| src_path = OUT / f"baseline_01_seed{SEED}.wav" | |
| assert src_path.exists(), f"missing baseline wav at {src_path}; run flow_edit_smoke_test.py first" | |
| NEW_VERSE1 = ( | |
| "[Verse 1]\n清晨阳光洒在花园里\n鸟儿欢唱迎接早晨\n" | |
| "露珠闪耀在叶尖上\n微风轻拂带来安宁\n" | |
| "远方传来悠扬钢琴声\n阳光穿过透明的窗户\n" | |
| "花香弥漫在空气中\n心情舒畅自由飞翔\n" | |
| ) | |
| ORIG_VERSE1 = ( | |
| "[Verse 1]\n黑夜里的风吹过耳畔\n甜蜜时光转瞬即万\n" | |
| "脚步飘摇在星光上\n心追节奏心跳狂乱\n" | |
| "耳边传来电吉他呼唤\n手指轻触碰点流点燃\n" | |
| "梦在云端任它蔓延\n疯狂跳跃自由无间\n" | |
| ) | |
| TGT_LYRICS = ex["lyrics"].replace(ORIG_VERSE1, NEW_VERSE1) | |
| assert TGT_LYRICS != ex["lyrics"], "verse-1 replace marker not found" | |
| logger.info(f"Initializing DiT ({DIT_CONFIG})") | |
| dit = AceStepHandler() | |
| _, ok = dit.initialize_service( | |
| project_root=str(REPO), config_path=DIT_CONFIG, device="cuda", | |
| use_flash_attention=False, compile_model=False, | |
| offload_to_cpu=False, offload_dit_to_cpu=False, quantization=None, | |
| use_mlx_dit=False, | |
| ) | |
| assert ok | |
| llm = LLMHandler() | |
| def run(label, n_min, n_max, n_avg, infer_steps=60, shift=3.0, guidance_scale=15.0): | |
| p = GenerationParams( | |
| # text2music task — silence-derived context for prepare_condition, | |
| # real src_latents only used for zt formation in the sampling loop. | |
| task_type="text2music", | |
| src_audio=str(src_path), | |
| caption=ex["caption"], # target = original style (keep melody) | |
| lyrics=TGT_LYRICS, # target = NEW lyrics | |
| # Flow-edit overlay — describes the source side for V_src. | |
| flow_edit_morph=True, | |
| flow_edit_source_caption=ex["caption"], | |
| flow_edit_source_lyrics=ex["lyrics"], | |
| flow_edit_n_min=n_min, | |
| flow_edit_n_max=n_max, | |
| flow_edit_n_avg=n_avg, | |
| instrumental=False, | |
| vocal_language=ex.get("language", "en"), | |
| bpm=ex.get("bpm"), | |
| keyscale=ex.get("keyscale", ""), | |
| timesignature=str(ex.get("timesignature", "")), | |
| duration=float(ex.get("duration", 120)), | |
| inference_steps=infer_steps, | |
| seed=SEED, | |
| guidance_scale=guidance_scale, | |
| shift=shift, | |
| thinking=False, | |
| ) | |
| cfg = GenerationConfig(batch_size=1, use_random_seed=False, seeds=[SEED]) | |
| logger.info(f"[{label}] n_min={n_min} n_max={n_max} n_avg={n_avg}") | |
| t0 = time.time() | |
| r = generate_music(dit, llm, p, cfg, save_dir=str(OUT)) | |
| dt = time.time() - t0 | |
| if not r.success: | |
| logger.error(f"[{label}] FAILED: {r.error}") | |
| return | |
| audio = r.audios[0] | |
| out_path = OUT / f"overlay_{label}.wav" | |
| if isinstance(audio, dict) and "tensor" in audio: | |
| torchaudio.save(str(out_path), audio["tensor"].to(torch.float32), | |
| audio.get("sample_rate", 48000)) | |
| logger.info(f"[{label}] {dt:.1f}s -> {out_path}") | |
| # Match ACE-Step 1.0 defaults exactly: shift=3.0 (FlowMatchEulerDiscreteScheduler | |
| # default), guidance=15, infer=60, n_min=0, n_max=1, n_avg=1. | |
| run("v10_shift3", 0.0, 1.0, 1, infer_steps=60, shift=3.0) | |
| # Sanity: shift=1.0 (uniform schedule) for comparison. | |
| run("v10_shift1", 0.0, 1.0, 1, infer_steps=60, shift=1.0) | |