OnyxMunk's picture
Upload folder using huggingface_hub
1e69a1f verified
Raw
History Blame Contribute Delete
4.27 kB
"""Batch preparation helpers for handler decomposition."""
from typing import Dict, List, Optional, Union
import torch
from acestep.constants import DEFAULT_DIT_INSTRUCTION
class BatchPrepMixin:
"""Mixin containing batch and input normalization helpers.
Depends on host members:
- Attributes: ``device``, ``dtype``.
- Methods: ``tiled_encode``, ``extract_caption_from_sft_format``,
``_build_metadata_dict``.
"""
def _normalize_audio_code_hints(
self, audio_code_hints: Optional[Union[str, List[str]]], batch_size: int
) -> List[Optional[str]]:
"""Normalize ``audio_code_hints`` into a batch-length list."""
if audio_code_hints is None:
normalized: List[Optional[str]] = [None] * batch_size
elif isinstance(audio_code_hints, str):
normalized = [audio_code_hints] * batch_size
elif len(audio_code_hints) == 1 and batch_size > 1:
normalized = audio_code_hints * batch_size
elif len(audio_code_hints) != batch_size:
normalized = list(audio_code_hints[:batch_size])
while len(normalized) < batch_size:
normalized.append(None)
else:
normalized = list(audio_code_hints)
return [hint if isinstance(hint, str) and hint.strip() else None for hint in normalized]
def _normalize_instructions(
self,
instructions: Optional[Union[str, List[str]]],
batch_size: int,
default: Optional[str] = None,
) -> List[str]:
"""Normalize instructions into a batch-length list."""
if instructions is None:
default_instruction = default or DEFAULT_DIT_INSTRUCTION
return [default_instruction] * batch_size
if isinstance(instructions, str):
return [instructions] * batch_size
if len(instructions) == 1:
return instructions * batch_size
if len(instructions) != batch_size:
normalized = list(instructions[:batch_size])
default_instruction = default or DEFAULT_DIT_INSTRUCTION
while len(normalized) < batch_size:
normalized.append(default_instruction)
return normalized
return list(instructions)
def _create_fallback_vocal_languages(self, batch_size: int) -> List[str]:
"""Create default vocal-language values for missing inputs."""
return ["en"] * batch_size
def _encode_audio_to_latents(self, audio: torch.Tensor) -> torch.Tensor:
"""Encode audio to latents using tiled VAE encode path."""
input_was_2d = audio.dim() == 2
if input_was_2d:
audio = audio.unsqueeze(0)
with torch.inference_mode():
latents = self.tiled_encode(audio, offload_latent_to_cpu=True)
latents = latents.to(self.device).to(self.dtype)
latents = latents.transpose(1, 2)
if input_was_2d:
latents = latents.squeeze(0)
return latents
def prepare_batch_data(
self,
actual_batch_size,
processed_src_audio,
audio_duration,
captions,
lyrics,
vocal_language,
instruction,
bpm,
key_scale,
time_signature,
):
"""Prepare repeated batch-level caption/instruction/metadata values."""
pure_caption = self.extract_caption_from_sft_format(captions)
captions_batch = [pure_caption] * actual_batch_size
instructions_batch = [instruction] * actual_batch_size
lyrics_batch = [lyrics] * actual_batch_size
vocal_languages_batch = [vocal_language] * actual_batch_size
calculated_duration = None
if processed_src_audio is not None:
calculated_duration = processed_src_audio.shape[-1] / 48000.0
elif audio_duration is not None and float(audio_duration) > 0:
calculated_duration = float(audio_duration)
metadata_dict: Dict[str, Union[str, int]] = self._build_metadata_dict(
bpm, key_scale, time_signature, calculated_duration
)
metas_batch = [metadata_dict.copy() for _ in range(actual_batch_size)]
return captions_batch, instructions_batch, lyrics_batch, vocal_languages_batch, metas_batch