Add files using upload-large-folder tool
Browse files
code/models/autoports/minimaxai_minimax_music3/reference/pipeline.py
CHANGED
|
@@ -230,10 +230,13 @@ class Music3Reference:
|
|
| 230 |
guidance_scale: float = DIT_GUIDANCE_SCALE,
|
| 231 |
record_steps: Sequence[int] = (),
|
| 232 |
dit_forward=None,
|
|
|
|
| 233 |
) -> dict:
|
| 234 |
"""before_denoise.py + denoise.py. Returns dict(latent_chunks [list of [1,128,L]], chunk_starts, and when
|
| 235 |
record_steps: per-chunk dicts with condition / noise / timesteps / (t, latents_in, pred_cond, pred_uncond)).
|
| 236 |
-
`dit_forward(latents [B,128,L], t [B], cond [B,L,2048]) -> velocity` lets a TT DiT drive the same loop.
|
|
|
|
|
|
|
| 237 |
dit_forward = dit_forward or (lambda x, t, c: self.dit(x, t, c))
|
| 238 |
starts = chunk_starts(frame_hiddens.shape[1])
|
| 239 |
timesteps, sigmas = flow_schedule(num_steps)
|
|
@@ -288,25 +291,37 @@ class Music3Reference:
|
|
| 288 |
oe = max(os_, latents.shape[-1] - OVERLAP_LATENT_LENGTH)
|
| 289 |
prev_latent, prev_cond = latents[..., os_:oe], condition[:, os_:oe]
|
| 290 |
latent_chunks.append(latents)
|
|
|
|
|
|
|
| 291 |
if rec is not None:
|
| 292 |
rec["latents_out"] = latents.detach().cpu()
|
| 293 |
chunk_records.append(rec)
|
| 294 |
return {"latent_chunks": latent_chunks, "chunk_starts": starts, "chunk_records": chunk_records}
|
| 295 |
|
| 296 |
@torch.no_grad()
|
| 297 |
-
def
|
| 298 |
-
"""decoders.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
vocoder = vocoder or self.vocoder
|
| 300 |
hop = vocoder.hop_length
|
| 301 |
-
n = len(
|
| 302 |
chunks = []
|
| 303 |
-
for i,
|
| 304 |
-
wav = vocoder(lat.to(vocoder.dec_in_proj.weight.dtype).to(self.device))
|
| 305 |
left = 0 if i == 0 else CROP_LEFT_LATENT * hop
|
| 306 |
right = 0 if i == n - 1 else CROP_RIGHT_LATENT * hop
|
| 307 |
chunks.append(wav[..., left : wav.shape[-1] - right])
|
| 308 |
return torch.cat(chunks, dim=-1).float().clamp(-1.0, 1.0).cpu()
|
| 309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
# ------------------------------------------------------------------ end to end
|
| 311 |
@torch.no_grad()
|
| 312 |
def generate(
|
|
|
|
| 230 |
guidance_scale: float = DIT_GUIDANCE_SCALE,
|
| 231 |
record_steps: Sequence[int] = (),
|
| 232 |
dit_forward=None,
|
| 233 |
+
on_chunk=None,
|
| 234 |
) -> dict:
|
| 235 |
"""before_denoise.py + denoise.py. Returns dict(latent_chunks [list of [1,128,L]], chunk_starts, and when
|
| 236 |
record_steps: per-chunk dicts with condition / noise / timesteps / (t, latents_in, pred_cond, pred_uncond)).
|
| 237 |
+
`dit_forward(latents [B,128,L], t [B], cond [B,L,2048]) -> velocity` lets a TT DiT drive the same loop.
|
| 238 |
+
`on_chunk(k, latents)` is called as soon as window k is final (the caller may start vocoding it while the
|
| 239 |
+
next window denoises); the latents handed over are never mutated afterwards."""
|
| 240 |
dit_forward = dit_forward or (lambda x, t, c: self.dit(x, t, c))
|
| 241 |
starts = chunk_starts(frame_hiddens.shape[1])
|
| 242 |
timesteps, sigmas = flow_schedule(num_steps)
|
|
|
|
| 291 |
oe = max(os_, latents.shape[-1] - OVERLAP_LATENT_LENGTH)
|
| 292 |
prev_latent, prev_cond = latents[..., os_:oe], condition[:, os_:oe]
|
| 293 |
latent_chunks.append(latents)
|
| 294 |
+
if on_chunk is not None:
|
| 295 |
+
on_chunk(k, latents)
|
| 296 |
if rec is not None:
|
| 297 |
rec["latents_out"] = latents.detach().cpu()
|
| 298 |
chunk_records.append(rec)
|
| 299 |
return {"latent_chunks": latent_chunks, "chunk_starts": starts, "chunk_records": chunk_records}
|
| 300 |
|
| 301 |
@torch.no_grad()
|
| 302 |
+
def vocode(self, latents: torch.Tensor, vocoder=None) -> torch.Tensor:
|
| 303 |
+
"""decoders.py, one window: latents [1,128,L] -> uncropped waveform [1, 2, L*hop]."""
|
| 304 |
+
vocoder = vocoder or self.vocoder
|
| 305 |
+
return vocoder(latents.to(vocoder.dec_in_proj.weight.dtype).to(self.device))
|
| 306 |
+
|
| 307 |
+
@torch.no_grad()
|
| 308 |
+
def stitch(self, wavs: List[torch.Tensor], vocoder=None) -> torch.Tensor:
|
| 309 |
+
"""decoders.py: crop the window overlaps and concatenate -> [1, 2, samples] float32 in [-1, 1] at 44.1 kHz."""
|
| 310 |
vocoder = vocoder or self.vocoder
|
| 311 |
hop = vocoder.hop_length
|
| 312 |
+
n = len(wavs)
|
| 313 |
chunks = []
|
| 314 |
+
for i, wav in enumerate(wavs):
|
|
|
|
| 315 |
left = 0 if i == 0 else CROP_LEFT_LATENT * hop
|
| 316 |
right = 0 if i == n - 1 else CROP_RIGHT_LATENT * hop
|
| 317 |
chunks.append(wav[..., left : wav.shape[-1] - right])
|
| 318 |
return torch.cat(chunks, dim=-1).float().clamp(-1.0, 1.0).cpu()
|
| 319 |
|
| 320 |
+
@torch.no_grad()
|
| 321 |
+
def decode(self, latent_chunks: List[torch.Tensor], vocoder=None) -> torch.Tensor:
|
| 322 |
+
"""decoders.py: vocode each window, crop overlaps, stitch -> [1, 2, samples] float32 in [-1, 1] at 44.1 kHz."""
|
| 323 |
+
return self.stitch([self.vocode(lat, vocoder) for lat in latent_chunks], vocoder)
|
| 324 |
+
|
| 325 |
# ------------------------------------------------------------------ end to end
|
| 326 |
@torch.no_grad()
|
| 327 |
def generate(
|
code/models/autoports/minimaxai_minimax_music3/tt/config_defaults.json
CHANGED
|
@@ -11,4 +11,4 @@
|
|
| 11 |
"depth_top1": 0.9,
|
| 12 |
"depth_top5": 0.98
|
| 13 |
}
|
| 14 |
-
}
|
|
|
|
| 11 |
"depth_top1": 0.9,
|
| 12 |
"depth_top5": 0.98
|
| 13 |
}
|
| 14 |
+
}
|
code/models/autoports/minimaxai_minimax_music3/tt/generator.py
CHANGED
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
| 9 |
|
| 10 |
import os
|
| 11 |
import time
|
|
|
|
| 12 |
from dataclasses import dataclass
|
| 13 |
from pathlib import Path
|
| 14 |
from typing import Callable, Dict, List, Optional
|
|
@@ -49,6 +50,7 @@ class GenStats:
|
|
| 49 |
depth_s: float = 0.0
|
| 50 |
denoise_s: float = 0.0
|
| 51 |
decode_s: float = 0.0
|
|
|
|
| 52 |
total_s: float = 0.0
|
| 53 |
audio_s: float = 0.0
|
| 54 |
chunks: int = 0
|
|
@@ -183,6 +185,8 @@ class Music3Generator:
|
|
| 183 |
]
|
| 184 |
if load_vocoder and self.vocoder_dtype != torch.float32:
|
| 185 |
self.ref.vocoder = self.ref.vocoder.to(self.vocoder_dtype)
|
|
|
|
|
|
|
| 186 |
self.dit = None
|
| 187 |
if load_dit and dit_device == "tt":
|
| 188 |
from models.autoports.minimaxai_minimax_music3.tt.dit import TTDiT
|
|
@@ -366,9 +370,16 @@ class Music3Generator:
|
|
| 366 |
return self.dit(latents, timestep, condition)
|
| 367 |
|
| 368 |
@torch.inference_mode()
|
| 369 |
-
def denoise(
|
|
|
|
|
|
|
| 370 |
return self.ref.denoise(
|
| 371 |
-
frame_hiddens,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
)
|
| 373 |
|
| 374 |
@torch.inference_mode()
|
|
@@ -400,22 +411,53 @@ class Music3Generator:
|
|
| 400 |
sem = self.semantic_generation(text_ids, mf, generator, stats=stats, on_frame=on_frame)
|
| 401 |
out = {**sem, "text_ids": text_ids}
|
| 402 |
if "denoise" in stages and "frame_hiddens" in sem:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
t1 = time.time()
|
| 404 |
-
|
| 405 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
stats.chunks = len(den["latent_chunks"])
|
| 407 |
out.update(den)
|
| 408 |
if "decode" in stages:
|
| 409 |
-
t2 = time.time()
|
| 410 |
-
out["audio"] = self.decode(den["latent_chunks"])
|
| 411 |
stats.decode_s = time.time() - t2
|
|
|
|
| 412 |
stats.audio_s = out["audio"].shape[-1] / self.cfg.vocoder.sampling_rate
|
| 413 |
out["sample_rate"] = self.cfg.vocoder.sampling_rate
|
| 414 |
stats.total_s = time.time() - t0
|
| 415 |
out["stats"] = stats
|
| 416 |
self.log(
|
| 417 |
f"generate: {stats.frames} frames, {stats.audio_s:.1f}s audio in {stats.total_s:.1f}s (RTF {stats.rtf:.2f}; prefill {stats.prefill_s:.1f}s, "
|
| 418 |
-
f"llm {stats.ms_per_frame_llm:.1f} ms/f, depth {stats.ms_per_frame_depth:.1f} ms/f, denoise {stats.denoise_s:.1f}s,
|
|
|
|
| 419 |
)
|
| 420 |
return out
|
| 421 |
|
|
|
|
| 9 |
|
| 10 |
import os
|
| 11 |
import time
|
| 12 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 13 |
from dataclasses import dataclass
|
| 14 |
from pathlib import Path
|
| 15 |
from typing import Callable, Dict, List, Optional
|
|
|
|
| 50 |
depth_s: float = 0.0
|
| 51 |
denoise_s: float = 0.0
|
| 52 |
decode_s: float = 0.0
|
| 53 |
+
vocoder_s: float = 0.0 # summed per-window vocoder compute (overlaps denoise_s when pipelined)
|
| 54 |
total_s: float = 0.0
|
| 55 |
audio_s: float = 0.0
|
| 56 |
chunks: int = 0
|
|
|
|
| 185 |
]
|
| 186 |
if load_vocoder and self.vocoder_dtype != torch.float32:
|
| 187 |
self.ref.vocoder = self.ref.vocoder.to(self.vocoder_dtype)
|
| 188 |
+
# vocode window k on a worker thread while the DiT denoises window k+1 (MUSIC3_PIPELINE_VOCODER=0 disables)
|
| 189 |
+
self.pipeline_vocoder = os.environ.get("MUSIC3_PIPELINE_VOCODER", "1") not in ("0", "false", "no")
|
| 190 |
self.dit = None
|
| 191 |
if load_dit and dit_device == "tt":
|
| 192 |
from models.autoports.minimaxai_minimax_music3.tt.dit import TTDiT
|
|
|
|
| 370 |
return self.dit(latents, timestep, condition)
|
| 371 |
|
| 372 |
@torch.inference_mode()
|
| 373 |
+
def denoise(
|
| 374 |
+
self, frame_hiddens: torch.Tensor, generator, num_steps: int = DIT_NUM_STEPS, record_steps=(), on_chunk=None
|
| 375 |
+
):
|
| 376 |
return self.ref.denoise(
|
| 377 |
+
frame_hiddens,
|
| 378 |
+
generator,
|
| 379 |
+
num_steps=num_steps,
|
| 380 |
+
record_steps=record_steps,
|
| 381 |
+
dit_forward=self.dit_forward,
|
| 382 |
+
on_chunk=on_chunk,
|
| 383 |
)
|
| 384 |
|
| 385 |
@torch.inference_mode()
|
|
|
|
| 411 |
sem = self.semantic_generation(text_ids, mf, generator, stats=stats, on_frame=on_frame)
|
| 412 |
out = {**sem, "text_ids": text_ids}
|
| 413 |
if "denoise" in stages and "frame_hiddens" in sem:
|
| 414 |
+
pipelined = "decode" in stages and self.pipeline_vocoder
|
| 415 |
+
# Pipelined: the (host, torch) vocoder runs window k on one worker thread while the DiT denoises window
|
| 416 |
+
# k+1 on the chip. Each window is vocoded by the identical call in the identical order, and the crop /
|
| 417 |
+
# stitch happens once at the end exactly as in the reference decode(), so the audio bytes are unchanged
|
| 418 |
+
# (the torch.Generator is only consumed on the denoise side).
|
| 419 |
+
wav_futures: List = []
|
| 420 |
+
vocoder_s = [0.0]
|
| 421 |
+
|
| 422 |
+
def vocode_window(lat):
|
| 423 |
+
t = time.time()
|
| 424 |
+
with torch.inference_mode(): # inference_mode is thread-local
|
| 425 |
+
wav = self.ref.vocode(lat)
|
| 426 |
+
vocoder_s[0] += time.time() - t
|
| 427 |
+
return wav
|
| 428 |
+
|
| 429 |
t1 = time.time()
|
| 430 |
+
if pipelined:
|
| 431 |
+
with ThreadPoolExecutor(max_workers=1, thread_name_prefix="music3-vocoder") as pool:
|
| 432 |
+
den = self.denoise(
|
| 433 |
+
sem["frame_hiddens"],
|
| 434 |
+
generator,
|
| 435 |
+
num_steps=num_steps,
|
| 436 |
+
on_chunk=lambda k, lat: wav_futures.append(pool.submit(vocode_window, lat)),
|
| 437 |
+
)
|
| 438 |
+
stats.denoise_s = time.time() - t1
|
| 439 |
+
t2 = time.time()
|
| 440 |
+
wavs = [f.result() for f in wav_futures]
|
| 441 |
+
out["audio"] = self.ref.stitch(wavs)
|
| 442 |
+
else:
|
| 443 |
+
den = self.denoise(sem["frame_hiddens"], generator, num_steps=num_steps)
|
| 444 |
+
stats.denoise_s = time.time() - t1
|
| 445 |
+
t2 = time.time()
|
| 446 |
+
if "decode" in stages:
|
| 447 |
+
out["audio"] = self.ref.stitch([vocode_window(lat) for lat in den["latent_chunks"]])
|
| 448 |
stats.chunks = len(den["latent_chunks"])
|
| 449 |
out.update(den)
|
| 450 |
if "decode" in stages:
|
|
|
|
|
|
|
| 451 |
stats.decode_s = time.time() - t2
|
| 452 |
+
stats.vocoder_s = vocoder_s[0]
|
| 453 |
stats.audio_s = out["audio"].shape[-1] / self.cfg.vocoder.sampling_rate
|
| 454 |
out["sample_rate"] = self.cfg.vocoder.sampling_rate
|
| 455 |
stats.total_s = time.time() - t0
|
| 456 |
out["stats"] = stats
|
| 457 |
self.log(
|
| 458 |
f"generate: {stats.frames} frames, {stats.audio_s:.1f}s audio in {stats.total_s:.1f}s (RTF {stats.rtf:.2f}; prefill {stats.prefill_s:.1f}s, "
|
| 459 |
+
f"llm {stats.ms_per_frame_llm:.1f} ms/f, depth {stats.ms_per_frame_depth:.1f} ms/f, denoise {stats.denoise_s:.1f}s, "
|
| 460 |
+
f"vocoder {stats.vocoder_s:.1f}s{' pipelined' if self.pipeline_vocoder else ''}, decode tail {stats.decode_s:.1f}s)"
|
| 461 |
)
|
| 462 |
return out
|
| 463 |
|