alex commited on
Commit ·
7787c31
1
Parent(s): e3cddce
tea_cache
Browse files- app.py +14 -9
- wan/animate.py +60 -1
- wan/modules/animate/model_animate.py +47 -15
app.py
CHANGED
|
@@ -258,23 +258,23 @@ def calculate_time_required(max_duration_s, rc_bool):
|
|
| 258 |
if max_duration_s == -1:
|
| 259 |
return 75
|
| 260 |
if max_duration_s == 2:
|
| 261 |
-
return
|
| 262 |
elif max_duration_s == 3:
|
| 263 |
-
return
|
| 264 |
elif max_duration_s == 4:
|
| 265 |
-
return
|
| 266 |
elif max_duration_s == 5:
|
| 267 |
-
return
|
| 268 |
elif max_duration_s == 6:
|
| 269 |
-
return
|
| 270 |
elif max_duration_s == 7:
|
| 271 |
-
return
|
| 272 |
elif max_duration_s == 8:
|
| 273 |
-
return
|
| 274 |
elif max_duration_s == 9:
|
| 275 |
-
return
|
| 276 |
elif max_duration_s == 10:
|
| 277 |
-
return
|
| 278 |
|
| 279 |
def get_display_time_required(max_duration_s, rc_bool):
|
| 280 |
# the 30 seconds extra is just for saftey in case of a unexpected slow down
|
|
@@ -484,6 +484,8 @@ def get_sam_mask(prompt_state, frames, frame_idx, input_points, input_labels):
|
|
| 484 |
def animate_scene(input_video, max_duration_s, edited_frame, rc_str,
|
| 485 |
prompt_state=None, session_id=None,
|
| 486 |
progress=gr.Progress(track_tqdm=True)):
|
|
|
|
|
|
|
| 487 |
|
| 488 |
# Build dicts keyed by frame index, or empty if none
|
| 489 |
if not prompt_state or "selections" not in prompt_state:
|
|
@@ -546,6 +548,9 @@ def animate_scene(input_video, max_duration_s, edited_frame, rc_str,
|
|
| 546 |
else:
|
| 547 |
final_video_path = output_video_path
|
| 548 |
|
|
|
|
|
|
|
|
|
|
| 549 |
print(f"task for {session_id} finalised")
|
| 550 |
return final_video_path, pose_video, bg_video, mask_video, face_video
|
| 551 |
|
|
|
|
| 258 |
if max_duration_s == -1:
|
| 259 |
return 75
|
| 260 |
if max_duration_s == 2:
|
| 261 |
+
return 90
|
| 262 |
elif max_duration_s == 3:
|
| 263 |
+
return 150
|
| 264 |
elif max_duration_s == 4:
|
| 265 |
+
return 150
|
| 266 |
elif max_duration_s == 5:
|
| 267 |
+
return 150
|
| 268 |
elif max_duration_s == 6:
|
| 269 |
+
return 210
|
| 270 |
elif max_duration_s == 7:
|
| 271 |
+
return 220
|
| 272 |
elif max_duration_s == 8:
|
| 273 |
+
return 260
|
| 274 |
elif max_duration_s == 9:
|
| 275 |
+
return 270
|
| 276 |
elif max_duration_s == 10:
|
| 277 |
+
return 270
|
| 278 |
|
| 279 |
def get_display_time_required(max_duration_s, rc_bool):
|
| 280 |
# the 30 seconds extra is just for saftey in case of a unexpected slow down
|
|
|
|
| 484 |
def animate_scene(input_video, max_duration_s, edited_frame, rc_str,
|
| 485 |
prompt_state=None, session_id=None,
|
| 486 |
progress=gr.Progress(track_tqdm=True)):
|
| 487 |
+
|
| 488 |
+
start_preprocess = time.time()
|
| 489 |
|
| 490 |
# Build dicts keyed by frame index, or empty if none
|
| 491 |
if not prompt_state or "selections" not in prompt_state:
|
|
|
|
| 548 |
else:
|
| 549 |
final_video_path = output_video_path
|
| 550 |
|
| 551 |
+
preprocess_time = time.time() - start_preprocess
|
| 552 |
+
print(f"total time for duration {max_duration_s} took {preprocess_time:.2f} seconds")
|
| 553 |
+
|
| 554 |
print(f"task for {session_id} finalised")
|
| 555 |
return final_video_path, pose_video, bg_video, mask_video, face_video
|
| 556 |
|
wan/animate.py
CHANGED
|
@@ -611,6 +611,15 @@ class WanAnimate:
|
|
| 611 |
"face_pixel_values": face_pixel_values_uncond,
|
| 612 |
}
|
| 613 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 614 |
for i, t in enumerate(timesteps):
|
| 615 |
latent_model_input = latents
|
| 616 |
timestep = [t]
|
|
@@ -618,7 +627,7 @@ class WanAnimate:
|
|
| 618 |
timestep = torch.stack(timestep)
|
| 619 |
|
| 620 |
noise_pred_cond = TensorList(
|
| 621 |
-
self.noise_model(TensorList(latent_model_input), t=timestep, **arg_c)
|
| 622 |
)
|
| 623 |
|
| 624 |
if guide_scale > 1:
|
|
@@ -661,3 +670,53 @@ class WanAnimate:
|
|
| 661 |
|
| 662 |
videos = torch.cat(all_out_frames, dim=2)[:, :, :real_frame_len]
|
| 663 |
return videos[0] if self.rank == 0 else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
"face_pixel_values": face_pixel_values_uncond,
|
| 612 |
}
|
| 613 |
|
| 614 |
+
|
| 615 |
+
tea_cache_posi = {
|
| 616 |
+
"tea_cache": TeaCache(
|
| 617 |
+
num_inference_steps=sampling_steps,
|
| 618 |
+
rel_l1_thresh=0.3,
|
| 619 |
+
timestep_scale=float(self.num_train_timesteps),
|
| 620 |
+
)
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
for i, t in enumerate(timesteps):
|
| 624 |
latent_model_input = latents
|
| 625 |
timestep = [t]
|
|
|
|
| 627 |
timestep = torch.stack(timestep)
|
| 628 |
|
| 629 |
noise_pred_cond = TensorList(
|
| 630 |
+
self.noise_model(TensorList(latent_model_input), t=timestep, **tea_cache_posi, **arg_c)
|
| 631 |
)
|
| 632 |
|
| 633 |
if guide_scale > 1:
|
|
|
|
| 670 |
|
| 671 |
videos = torch.cat(all_out_frames, dim=2)[:, :, :real_frame_len]
|
| 672 |
return videos[0] if self.rank == 0 else None
|
| 673 |
+
|
| 674 |
+
class TeaCache:
|
| 675 |
+
def __init__(self, num_inference_steps, rel_l1_thresh, timestep_scale=1000.0):
|
| 676 |
+
self.num_inference_steps = num_inference_steps
|
| 677 |
+
self.rel_l1_thresh = rel_l1_thresh
|
| 678 |
+
self.timestep_scale = timestep_scale
|
| 679 |
+
|
| 680 |
+
self.step = 0
|
| 681 |
+
self.accumulated_rel_l1_distance = 0.0
|
| 682 |
+
self.previous_modulated_input = None
|
| 683 |
+
self.previous_residual = None
|
| 684 |
+
self.previous_hidden_states = None
|
| 685 |
+
|
| 686 |
+
def check(self, x, t_scalar):
|
| 687 |
+
# scheduler-agnostic timestep-aware weighting
|
| 688 |
+
# works for UniPC / flow schedulers that only expose t
|
| 689 |
+
w = float(t_scalar) / max(self.timestep_scale, 1.0)
|
| 690 |
+
modulated_input = x * w
|
| 691 |
+
|
| 692 |
+
if self.step == 0 or self.step == self.num_inference_steps - 1:
|
| 693 |
+
should_calc = True
|
| 694 |
+
self.accumulated_rel_l1_distance = 0.0
|
| 695 |
+
else:
|
| 696 |
+
diff = torch.abs(modulated_input - self.previous_modulated_input)
|
| 697 |
+
ref = torch.abs(self.previous_modulated_input)
|
| 698 |
+
relative_l1 = diff.sum() / (ref.sum() + 1e-8)
|
| 699 |
+
|
| 700 |
+
self.accumulated_rel_l1_distance += relative_l1.item()
|
| 701 |
+
should_calc = self.accumulated_rel_l1_distance >= self.rel_l1_thresh
|
| 702 |
+
|
| 703 |
+
if should_calc:
|
| 704 |
+
self.accumulated_rel_l1_distance = 0.0
|
| 705 |
+
|
| 706 |
+
self.previous_modulated_input = modulated_input.detach()
|
| 707 |
+
|
| 708 |
+
self.step += 1
|
| 709 |
+
if self.step == self.num_inference_steps:
|
| 710 |
+
self.step = 0
|
| 711 |
+
|
| 712 |
+
if should_calc:
|
| 713 |
+
self.previous_hidden_states = x.clone()
|
| 714 |
+
|
| 715 |
+
return not should_calc
|
| 716 |
+
|
| 717 |
+
def store(self, hidden_states):
|
| 718 |
+
self.previous_residual = hidden_states - self.previous_hidden_states
|
| 719 |
+
self.previous_hidden_states = None
|
| 720 |
+
|
| 721 |
+
def update(self, hidden_states):
|
| 722 |
+
return hidden_states + self.previous_residual
|
wan/modules/animate/model_animate.py
CHANGED
|
@@ -375,6 +375,7 @@ class WanAnimateModel(ModelMixin, ConfigMixin, PeftAdapterMixin):
|
|
| 375 |
x,
|
| 376 |
t,
|
| 377 |
clip_fea,
|
|
|
|
| 378 |
context,
|
| 379 |
seq_len,
|
| 380 |
y=None,
|
|
@@ -391,14 +392,17 @@ class WanAnimateModel(ModelMixin, ConfigMixin, PeftAdapterMixin):
|
|
| 391 |
x = [self.patch_embedding(u.unsqueeze(0)) for u in x]
|
| 392 |
x, motion_vec = self.after_patch_embedding(x, pose_latents, face_pixel_values)
|
| 393 |
|
|
|
|
| 394 |
grid_sizes = torch.stack(
|
| 395 |
-
[torch.tensor(u.shape[2:], dtype=torch.long) for u in x]
|
|
|
|
| 396 |
x = [u.flatten(2).transpose(1, 2) for u in x]
|
| 397 |
-
seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long)
|
| 398 |
assert seq_lens.max() <= seq_len
|
|
|
|
| 399 |
x = torch.cat([
|
| 400 |
-
torch.cat([u, u.new_zeros(1, seq_len - u.size(1), u.size(2))],
|
| 401 |
-
|
| 402 |
])
|
| 403 |
|
| 404 |
# time embeddings
|
|
@@ -413,36 +417,64 @@ class WanAnimateModel(ModelMixin, ConfigMixin, PeftAdapterMixin):
|
|
| 413 |
context_lens = None
|
| 414 |
context = self.text_embedding(
|
| 415 |
torch.stack([
|
| 416 |
-
torch.cat(
|
| 417 |
-
[u, u.new_zeros(self.text_len - u.size(0), u.size(1))])
|
| 418 |
for u in context
|
| 419 |
-
])
|
|
|
|
| 420 |
|
| 421 |
if self.use_img_emb:
|
| 422 |
-
context_clip = self.img_emb(clip_fea)
|
| 423 |
context = torch.concat([context_clip, context], dim=1)
|
| 424 |
|
| 425 |
-
# arguments
|
| 426 |
kwargs = dict(
|
| 427 |
e=e0,
|
| 428 |
seq_lens=seq_lens,
|
| 429 |
grid_sizes=grid_sizes,
|
| 430 |
freqs=freqs,
|
| 431 |
context=context,
|
| 432 |
-
context_lens=context_lens
|
|
|
|
| 433 |
|
| 434 |
-
|
| 435 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
|
|
|
| 440 |
|
| 441 |
# head
|
| 442 |
x = self.head(x, e)
|
| 443 |
|
| 444 |
if self.use_context_parallel:
|
| 445 |
x = gather_forward(x, dim=1)
|
|
|
|
| 446 |
|
| 447 |
# unpatchify
|
| 448 |
x = self.unpatchify(x, grid_sizes)
|
|
|
|
| 375 |
x,
|
| 376 |
t,
|
| 377 |
clip_fea,
|
| 378 |
+
tea_cache,
|
| 379 |
context,
|
| 380 |
seq_len,
|
| 381 |
y=None,
|
|
|
|
| 392 |
x = [self.patch_embedding(u.unsqueeze(0)) for u in x]
|
| 393 |
x, motion_vec = self.after_patch_embedding(x, pose_latents, face_pixel_values)
|
| 394 |
|
| 395 |
+
device = x[0].device
|
| 396 |
grid_sizes = torch.stack(
|
| 397 |
+
[torch.tensor(u.shape[2:], dtype=torch.long, device=device) for u in x]
|
| 398 |
+
)
|
| 399 |
x = [u.flatten(2).transpose(1, 2) for u in x]
|
| 400 |
+
seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long, device=device)
|
| 401 |
assert seq_lens.max() <= seq_len
|
| 402 |
+
|
| 403 |
x = torch.cat([
|
| 404 |
+
torch.cat([u, u.new_zeros(1, seq_len - u.size(1), u.size(2))], dim=1)
|
| 405 |
+
for u in x
|
| 406 |
])
|
| 407 |
|
| 408 |
# time embeddings
|
|
|
|
| 417 |
context_lens = None
|
| 418 |
context = self.text_embedding(
|
| 419 |
torch.stack([
|
| 420 |
+
torch.cat([u, u.new_zeros(self.text_len - u.size(0), u.size(1))])
|
|
|
|
| 421 |
for u in context
|
| 422 |
+
])
|
| 423 |
+
)
|
| 424 |
|
| 425 |
if self.use_img_emb:
|
| 426 |
+
context_clip = self.img_emb(clip_fea)
|
| 427 |
context = torch.concat([context_clip, context], dim=1)
|
| 428 |
|
|
|
|
| 429 |
kwargs = dict(
|
| 430 |
e=e0,
|
| 431 |
seq_lens=seq_lens,
|
| 432 |
grid_sizes=grid_sizes,
|
| 433 |
freqs=freqs,
|
| 434 |
context=context,
|
| 435 |
+
context_lens=context_lens,
|
| 436 |
+
)
|
| 437 |
|
| 438 |
+
# tea cache check must happen after e0 exists
|
| 439 |
+
ori_x_len = x.shape[1]
|
| 440 |
+
if tea_cache is not None:
|
| 441 |
+
t_scalar = int(t.flatten()[0].item())
|
| 442 |
+
tea_cache_update = tea_cache.check(x, t_scalar)
|
| 443 |
+
else:
|
| 444 |
+
tea_cache_update = False
|
| 445 |
+
|
| 446 |
+
if tea_cache_update:
|
| 447 |
+
x = tea_cache.update(x)
|
| 448 |
+
else:
|
| 449 |
+
if self.use_context_parallel:
|
| 450 |
+
world_size = get_world_size()
|
| 451 |
+
rank = get_rank()
|
| 452 |
+
|
| 453 |
+
pad_size = 0
|
| 454 |
+
if x.shape[1] % world_size != 0:
|
| 455 |
+
pad_size = world_size - (x.shape[1] % world_size)
|
| 456 |
+
x = torch.cat(
|
| 457 |
+
[x, x.new_zeros(x.shape[0], pad_size, x.shape[2])],
|
| 458 |
+
dim=1
|
| 459 |
+
)
|
| 460 |
+
|
| 461 |
+
x = torch.chunk(x, world_size, dim=1)[rank]
|
| 462 |
+
|
| 463 |
+
for idx, block in enumerate(self.blocks):
|
| 464 |
+
x = block(x, **kwargs)
|
| 465 |
+
x = self.after_transformer_block(idx, x, motion_vec)
|
| 466 |
|
| 467 |
+
if tea_cache is not None:
|
| 468 |
+
x_cache = gather_forward(x, dim=1) if self.use_context_parallel else x
|
| 469 |
+
x_cache = x_cache[:, :ori_x_len]
|
| 470 |
+
tea_cache.store(x_cache)
|
| 471 |
|
| 472 |
# head
|
| 473 |
x = self.head(x, e)
|
| 474 |
|
| 475 |
if self.use_context_parallel:
|
| 476 |
x = gather_forward(x, dim=1)
|
| 477 |
+
x = x[:, :ori_x_len]
|
| 478 |
|
| 479 |
# unpatchify
|
| 480 |
x = self.unpatchify(x, grid_sizes)
|