add repaint

This commit is contained in:
chuxij
2025-04-29 06:39:57 +00:00
parent 09560dd878
commit 3eb0c178a9
2 changed files with 176 additions and 6 deletions
+65 -5
View File
@@ -27,6 +27,12 @@ from apg_guidance import apg_forward, MomentumBuffer, cfg_forward, cfg_zero_star
import torchaudio import torchaudio
torch.backends.cudnn.benchmark = False
torch.set_float32_matmul_precision('high')
torch.backends.cudnn.deterministic = True
torch.backends.cuda.matmul.allow_tf32 = True
SUPPORT_LANGUAGES = { SUPPORT_LANGUAGES = {
"en": 259, "de": 260, "fr": 262, "es": 284, "it": 285, "en": 259, "de": 260, "fr": 262, "es": 284, "it": 285,
"pt": 286, "pl": 294, "tr": 295, "ru": 267, "cs": 293, "pt": 286, "pl": 294, "tr": 295, "ru": 267, "cs": 293,
@@ -63,7 +69,7 @@ class ACEStepPipeline:
self.checkpoint_dir = checkpoint_dir self.checkpoint_dir = checkpoint_dir
device = torch.device(f"cuda:{device_id}") if torch.cuda.is_available() else torch.device("cpu") device = torch.device(f"cuda:{device_id}") if torch.cuda.is_available() else torch.device("cpu")
self.dtype = torch.bfloat16 if dtype == "bfloat16" else torch.float32 self.dtype = torch.float16 if dtype == "bfloat16" else torch.float32
self.device = device self.device = device
self.loaded = False self.loaded = False
@@ -239,6 +245,9 @@ class ACEStepPipeline:
add_retake_noise=False, add_retake_noise=False,
guidance_scale_text=0.0, guidance_scale_text=0.0,
guidance_scale_lyric=0.0, guidance_scale_lyric=0.0,
repaint_start=0,
repaint_end=0,
src_latents=None,
): ):
logger.info("cfg_type: {}, guidance_scale: {}, omega_scale: {}".format(cfg_type, guidance_scale, omega_scale)) logger.info("cfg_type: {}, guidance_scale: {}, omega_scale: {}".format(cfg_type, guidance_scale, omega_scale))
@@ -265,7 +274,10 @@ class ACEStepPipeline:
num_train_timesteps=1000, num_train_timesteps=1000,
shift=3.0, shift=3.0,
) )
frame_length = int(duration * 44100 / 512 / 8) frame_length = int(duration * 44100 / 512 / 8)
if src_latents is not None:
frame_length = src_latents.shape[-1]
if len(oss_steps) > 0: if len(oss_steps) > 0:
infer_steps = max(oss_steps) infer_steps = max(oss_steps)
@@ -282,15 +294,29 @@ class ACEStepPipeline:
timesteps, num_inference_steps = retrieve_timesteps(scheduler, num_inference_steps=infer_steps, device=device, timesteps=None) timesteps, num_inference_steps = retrieve_timesteps(scheduler, num_inference_steps=infer_steps, device=device, timesteps=None)
target_latents = randn_tensor(shape=(bsz, 8, 16, frame_length), generator=random_generators, device=device, dtype=dtype) target_latents = randn_tensor(shape=(bsz, 8, 16, frame_length), generator=random_generators, device=device, dtype=dtype)
is_repaint = False
if add_retake_noise: if add_retake_noise:
retake_variance = torch.tensor(retake_variance * math.pi/2).to(device).to(dtype) retake_variance = torch.tensor(retake_variance * math.pi/2).to(device).to(dtype)
retake_latents = randn_tensor(shape=(bsz, 8, 16, frame_length), generator=retake_random_generators, device=device, dtype=dtype) retake_latents = randn_tensor(shape=(bsz, 8, 16, frame_length), generator=retake_random_generators, device=device, dtype=dtype)
repaint_start_frame = int(repaint_start * 44100 / 512 / 8)
repaint_end_frame = int(repaint_end * 44100 / 512 / 8)
# retake
is_repaint = repaint_end_frame - repaint_start_frame != frame_length
# to make sure mean = 0, std = 1 # to make sure mean = 0, std = 1
target_latents = torch.cos(retake_variance) * target_latents + torch.sin(retake_variance) * retake_latents if not is_repaint:
target_latents = torch.cos(retake_variance) * target_latents + torch.sin(retake_variance) * retake_latents
else:
repaint_mask = torch.zeros((bsz, 8, 16, frame_length), device=device, dtype=dtype)
repaint_mask[:, :, :, repaint_start_frame:repaint_end_frame] = 1.0
repaint_noise = torch.cos(retake_variance) * target_latents + torch.sin(retake_variance) * retake_latents
repaint_noise = torch.where(repaint_mask == 1.0, repaint_noise, target_latents)
z0 = repaint_noise
attention_mask = torch.ones(bsz, frame_length, device=device, dtype=dtype) attention_mask = torch.ones(bsz, frame_length, device=device, dtype=dtype)
# guidance interval逻辑 # guidance interval
start_idx = int(num_inference_steps * ((1 - guidance_interval) / 2)) start_idx = int(num_inference_steps * ((1 - guidance_interval) / 2))
end_idx = int(num_inference_steps * (guidance_interval / 2 + 0.5)) end_idx = int(num_inference_steps * (guidance_interval / 2 + 0.5))
logger.info(f"start_idx: {start_idx}, end_idx: {end_idx}, num_inference_steps: {num_inference_steps}") logger.info(f"start_idx: {start_idx}, end_idx: {end_idx}, num_inference_steps: {num_inference_steps}")
@@ -495,6 +521,12 @@ class ACEStepPipeline:
).sample ).sample
target_latents = scheduler.step(model_output=noise_pred, timestep=t, sample=target_latents, return_dict=False, omega=omega_scale)[0] target_latents = scheduler.step(model_output=noise_pred, timestep=t, sample=target_latents, return_dict=False, omega=omega_scale)[0]
if is_repaint:
t_i = t / 1000
x0 = src_latents
xt = (1 - t_i) * x0 + t_i * z0
target_latents = torch.where(repaint_mask == 1.0, target_latents, xt)
return target_latents return target_latents
@@ -525,6 +557,16 @@ class ACEStepPipeline:
torchaudio.save(output_path_flac, target_wav, sample_rate=sample_rate, format=format, backend="ffmpeg", compression=torchaudio.io.CodecConfig(bit_rate=320000)) torchaudio.save(output_path_flac, target_wav, sample_rate=sample_rate, format=format, backend="ffmpeg", compression=torchaudio.io.CodecConfig(bit_rate=320000))
return output_path_flac return output_path_flac
def infer_latents(self, input_audio_path):
if input_audio_path is None:
return None
input_audio, sr = self.music_dcae.load_audio(input_audio_path)
input_audio = input_audio.unsqueeze(0)
device, dtype = self.device, self.dtype
input_audio = input_audio.to(device=device, dtype=dtype)
latents, _ = self.music_dcae.encode(input_audio, sr=sr)
return latents
def __call__( def __call__(
self, self,
audio_duration: float = 60.0, audio_duration: float = 60.0,
@@ -548,6 +590,9 @@ class ACEStepPipeline:
retake_seeds: list = None, retake_seeds: list = None,
retake_variance: float = 0.5, retake_variance: float = 0.5,
task: str = "text2music", task: str = "text2music",
repaint_start: int = 0,
repaint_end: int = 0,
src_audio_path: str = None,
save_path: str = None, save_path: str = None,
format: str = "flac", format: str = "flac",
batch_size: int = 1, batch_size: int = 1,
@@ -601,6 +646,18 @@ class ACEStepPipeline:
preprocess_time_cost = end_time - start_time preprocess_time_cost = end_time - start_time
start_time = end_time start_time = end_time
add_retake_noise = task in ("retake", "repaint")
# retake equal to repaint
if task == "retake":
repaint_start = 0
repaint_end = audio_duration
src_latents = None
if task == "repaint":
assert src_audio_path is not None, "src_audio_path is required for repaint task"
assert os.path.exists(src_audio_path), f"src_audio_path {src_audio_path} does not exist"
src_latents = self.infer_latents(src_audio_path)
target_latents = self.text2music_diffusion_process( target_latents = self.text2music_diffusion_process(
duration=audio_duration, duration=audio_duration,
encoder_text_hidden_states=encoder_text_hidden_states, encoder_text_hidden_states=encoder_text_hidden_states,
@@ -623,9 +680,12 @@ class ACEStepPipeline:
use_erg_diffusion=use_erg_diffusion, use_erg_diffusion=use_erg_diffusion,
retake_random_generators=retake_random_generators, retake_random_generators=retake_random_generators,
retake_variance=retake_variance, retake_variance=retake_variance,
add_retake_noise=task == "retake", add_retake_noise=add_retake_noise,
guidance_scale_text=guidance_scale_text, guidance_scale_text=guidance_scale_text,
guidance_scale_lyric=guidance_scale_lyric, guidance_scale_lyric=guidance_scale_lyric,
repaint_start=repaint_start,
repaint_end=repaint_end,
src_latents=src_latents,
) )
end_time = time.time() end_time = time.time()
+111 -1
View File
@@ -138,7 +138,117 @@ def create_text2music_ui(
outputs=retake_outputs + [retake_input_params_json], outputs=retake_outputs + [retake_input_params_json],
) )
with gr.Tab("repainting"): with gr.Tab("repainting"):
pass retake_variance = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=0.2, label="variance", info="Variance for the retake. 0.0 means no variance. 1.0 means full variance.")
retake_seeds = gr.Textbox(label="retake seeds (default None)", placeholder="", value=None, info="Seed for the retake.")
repaint_start = gr.Slider(minimum=0.0, maximum=240.0, step=0.01, value=0.0, label="Repaint Start Time", interactive=True)
repaint_end = gr.Slider(minimum=0.0, maximum=240.0, step=0.01, value=30.0, label="Repaint End Time", interactive=True)
repaint_source = gr.Radio(["text2music", "last_repaint", "upload"], value="text2music", label="Repaint Source", elem_id="repaint_source")
repaint_source_audio_upload = gr.Audio(label="Upload Audio", type="filepath", visible=False, elem_id="repaint_source_audio_upload")
repaint_source.change(
fn=lambda x: gr.update(visible=x == "upload", elem_id="repaint_source_audio_upload"),
inputs=[repaint_source],
outputs=[repaint_source_audio_upload],
)
repaint_bnt = gr.Button("Repaint", variant="primary")
repaint_outputs, repaint_input_params_json = create_output_ui("Repaint")
def repaint_process_func(
text2music_json_data,
repaint_json_data,
retake_variance,
retake_seeds,
repaint_start,
repaint_end,
repaint_source,
repaint_source_audio_upload,
prompt,
lyrics,
infer_step,
guidance_scale,
scheduler_type,
cfg_type,
omega_scale,
manual_seeds,
guidance_interval,
guidance_interval_decay,
min_guidance_scale,
use_erg_tag,
use_erg_lyric,
use_erg_diffusion,
oss_steps,
guidance_scale_text,
guidance_scale_lyric,
):
if repaint_source == "upload":
src_audio_path = repaint_source_audio_upload
json_data = text2music_json_data
elif repaint_source == "text2music":
json_data = text2music_json_data
src_audio_path = json_data["audio_path"]
elif repaint_source == "last_repaint":
json_data = repaint_json_data
src_audio_path = json_data["audio_path"]
return text2music_process_func(
json_data["audio_duration"],
prompt,
lyrics,
infer_step,
guidance_scale,
scheduler_type,
cfg_type,
omega_scale,
manual_seeds,
guidance_interval,
guidance_interval_decay,
min_guidance_scale,
use_erg_tag,
use_erg_lyric,
use_erg_diffusion,
oss_steps,
guidance_scale_text,
guidance_scale_lyric,
retake_seeds=retake_seeds,
retake_variance=retake_variance,
task="repaint",
repaint_start=repaint_start,
repaint_end=repaint_end,
src_audio_path=src_audio_path,
)
repaint_bnt.click(
fn=repaint_process_func,
inputs=[
input_params_json,
repaint_input_params_json,
retake_variance,
retake_seeds,
repaint_start,
repaint_end,
repaint_source,
repaint_source_audio_upload,
prompt,
lyrics,
infer_step,
guidance_scale,
scheduler_type,
cfg_type,
omega_scale,
manual_seeds,
guidance_interval,
guidance_interval_decay,
min_guidance_scale,
use_erg_tag,
use_erg_lyric,
use_erg_diffusion,
oss_steps,
guidance_scale_text,
guidance_scale_lyric,
],
outputs=repaint_outputs + [repaint_input_params_json],
)
with gr.Tab("edit"): with gr.Tab("edit"):
pass pass