jashansinghTT commited on
Commit
5dca4f9
·
verified ·
1 Parent(s): cbea20e

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 decode(self, latent_chunks: List[torch.Tensor], vocoder=None) -> torch.Tensor:
298
- """decoders.py: vocode each window, crop overlaps, stitch -> [1, 2, samples] float32 in [-1, 1] at 44.1 kHz."""
 
 
 
 
 
 
299
  vocoder = vocoder or self.vocoder
300
  hop = vocoder.hop_length
301
- n = len(latent_chunks)
302
  chunks = []
303
- for i, lat in enumerate(latent_chunks):
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(self, frame_hiddens: torch.Tensor, generator, num_steps: int = DIT_NUM_STEPS, record_steps=()):
 
 
370
  return self.ref.denoise(
371
- frame_hiddens, generator, num_steps=num_steps, record_steps=record_steps, dit_forward=self.dit_forward
 
 
 
 
 
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
- den = self.denoise(sem["frame_hiddens"], generator, num_steps=num_steps)
405
- stats.denoise_s = time.time() - t1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, vocoder {stats.decode_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