multimodalart HF Staff commited on
Commit
8d850e9
·
verified ·
1 Parent(s): 1a1f010

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +29 -131
app.py CHANGED
@@ -14,7 +14,6 @@ from omegaconf import OmegaConf
14
  from einops import rearrange
15
 
16
  from pipeline import CausalInferencePipeline
17
- from utils.wan_wrapper import WanDiffusionWrapper, WanTextEncoder, WanVAEWrapper
18
  from wan.modules.sparse_attention import calculate_chunk_sparsities
19
 
20
  MODEL_ID = "Wan-AI/Wan2.1-T2V-1.3B"
@@ -22,7 +21,6 @@ LF_CKPT_ID = "mack-williams/Light-Forcing"
22
 
23
  # --- Model loading (module scope, eagerly on cuda) ---
24
 
25
- # Download base model if not present locally
26
  from huggingface_hub import snapshot_download
27
 
28
  if not os.path.exists("wan_models/Wan2.1-T2V-1.3B"):
@@ -30,10 +28,8 @@ if not os.path.exists("wan_models/Wan2.1-T2V-1.3B"):
30
  snapshot_download(
31
  repo_id=MODEL_ID,
32
  local_dir="wan_models/Wan2.1-T2V-1.3B",
33
- local_dir_use_symlinks=False,
34
  )
35
 
36
- # Download Light Forcing checkpoint
37
  lf_ckpt_dir = "checkpoints"
38
  os.makedirs(lf_ckpt_dir, exist_ok=True)
39
  lf_ckpt_path = os.path.join(lf_ckpt_dir, "short_video_gen.pt")
@@ -51,17 +47,9 @@ config = OmegaConf.load("configs/light_forcing_short.yaml")
51
  default_config = OmegaConf.load("configs/default_config.yaml")
52
  config = OmegaConf.merge(default_config, config)
53
 
54
- # Disable efficient_deployment kernels that need sgl_kernel / TRT
55
- # (we use pure PyTorch fallbacks for ZeroGPU compatibility)
56
- model_kwargs = dict(getattr(config, "model_kwargs", {}) or {})
57
- efficient_deployment = model_kwargs.pop("efficient_deployment", None) or {}
58
- # Disable FP8 quantization, lightvae, and custom kernels
59
- efficient_deployment = {}
60
- # Remove efficient_deployment from model_kwargs to avoid duplicate kwarg
61
- model_kwargs.pop("efficient_deployment", None)
62
-
63
  # Calculate sparse attention sparsity schedule
64
  num_frame_per_block = getattr(config, "num_frame_per_block", 1)
 
65
  local_attn_size = model_kwargs.get("local_attn_size", 21)
66
  sparse_config = model_kwargs.get("sparse_config", {}) or {}
67
  NUM_OUTPUT_FRAMES = 21
@@ -70,61 +58,40 @@ sparsity_list = calculate_chunk_sparsities(
70
  )
71
  if sparsity_list:
72
  sparse_config["sparsity_list"] = sparsity_list
73
- model_kwargs["sparse_config"] = sparse_config
74
 
75
- print(f"Model kwargs: {model_kwargs}")
76
  print(f"Sparsity list: {sparsity_list}")
77
 
78
- # Initialize components
79
- text_encoder = WanTextEncoder()
80
- vae = WanVAEWrapper()
81
- transformer = WanDiffusionWrapper(
82
- **model_kwargs, is_causal=True, efficient_deployment=efficient_deployment
83
- )
84
 
85
  # Load Light Forcing checkpoint
86
  state_dict = torch.load(lf_ckpt_path, map_location="cpu", weights_only=False)
87
- transformer.load_state_dict(state_dict["generator_ema"])
88
-
89
- text_encoder.eval()
90
- transformer.eval()
91
- vae.eval()
92
-
93
- text_encoder.requires_grad_(False)
94
- transformer.requires_grad_(False)
95
- vae.requires_grad_(False)
96
-
97
- # Move to cuda
98
- pipeline = CausalInferencePipeline(
99
- config,
100
- device="cuda",
101
- generator=transformer,
102
- text_encoder=text_encoder,
103
- vae=vae,
104
- )
105
 
106
  pipeline = pipeline.to(dtype=torch.bfloat16)
107
- text_encoder.to("cuda")
108
- transformer.to("cuda")
109
- vae.to("cuda")
 
 
 
 
 
 
 
 
110
 
111
  print("Model loaded successfully!")
112
 
113
 
114
- @spaces.GPU(duration=120)
115
  def generate(
116
  prompt: str,
117
  seed: int = 42,
118
  num_output_frames: int = 21,
119
  progress=gr.Progress(track_tqdm=True),
120
  ):
121
- """Generate a short video from a text prompt using Light Forcing sparse attention.
122
-
123
- Args:
124
- prompt: Text description of the video to generate.
125
- seed: Random seed for reproducibility.
126
- num_output_frames: Number of latent frames to generate (21 ≈ 5s video at 16fps).
127
- """
128
  if not prompt.strip():
129
  return None, "Please enter a prompt."
130
 
@@ -133,91 +100,23 @@ def generate(
133
 
134
  start_time = time.time()
135
 
136
- # Initialize KV cache
137
- pipeline._initialize_kv_cache(batch_size=1, dtype=torch.float16, device="cuda")
138
- pipeline._initialize_crossattn_cache(batch_size=1, dtype=torch.float16, device="cuda")
139
-
140
- # Generate noise
141
  noise = torch.randn(
142
  [1, num_output_frames, 16, 64, 96],
143
  device="cuda",
144
- dtype=torch.float16,
145
  )
146
 
147
- # Text encoding
148
- conditional_dict = text_encoder(text_prompts=[prompt])
149
- for key, value in conditional_dict.items():
150
- conditional_dict[key] = value.to(dtype=torch.float16)
151
-
152
- # Autoregressive block-by-block generation
153
- num_blocks = num_output_frames // num_frame_per_block
154
- all_num_frames = [pipeline.num_frame_per_block] * num_blocks
155
- current_start_frame = 0
156
- all_latents = []
157
-
158
- for idx, current_num_frames in enumerate(all_num_frames):
159
- progress((idx + 1) / len(all_num_frames), desc=f"Generating block {idx+1}/{len(all_num_frames)}")
160
-
161
- noisy_input = noise[
162
- :, current_start_frame:current_start_frame + current_num_frames
163
- ]
164
-
165
- # Denoising loop (few-step: 4 steps from denoising_step_list)
166
- for index, current_timestep in enumerate(pipeline.denoising_step_list):
167
- timestep = torch.ones(
168
- [1, current_num_frames], device="cuda", dtype=torch.int64
169
- ) * current_timestep
170
-
171
- if index < len(pipeline.denoising_step_list) - 1:
172
- _, denoised_pred = transformer(
173
- noisy_image_or_video=noisy_input,
174
- conditional_dict=conditional_dict,
175
- timestep=timestep,
176
- kv_cache=pipeline.kv_cache1,
177
- crossattn_cache=pipeline.crossattn_cache,
178
- current_start=current_start_frame * pipeline.frame_seq_length,
179
- )
180
- next_timestep = pipeline.denoising_step_list[index + 1]
181
- noisy_input = pipeline.scheduler.add_noise(
182
- denoised_pred.flatten(0, 1),
183
- torch.randn_like(denoised_pred.flatten(0, 1)),
184
- next_timestep * torch.ones(
185
- [current_num_frames], device="cuda", dtype=torch.long
186
- ),
187
- ).unflatten(0, denoised_pred.shape[:2])
188
- else:
189
- _, denoised_pred = transformer(
190
- noisy_image_or_video=noisy_input,
191
- conditional_dict=conditional_dict,
192
- timestep=timestep,
193
- kv_cache=pipeline.kv_cache1,
194
- crossattn_cache=pipeline.crossattn_cache,
195
- current_start=current_start_frame * pipeline.frame_seq_length,
196
- )
197
-
198
- all_latents.append(denoised_pred)
199
-
200
- # Update KV cache with clean context
201
- if idx != len(all_num_frames) - 1:
202
- transformer(
203
- noisy_image_or_video=denoised_pred,
204
- conditional_dict=conditional_dict,
205
- timestep=torch.zeros_like(timestep),
206
- kv_cache=pipeline.kv_cache1,
207
- crossattn_cache=pipeline.crossattn_cache,
208
- current_start=current_start_frame * pipeline.frame_seq_length,
209
- )
210
-
211
- current_start_frame += current_num_frames
212
-
213
- # Stack all latents
214
- output = torch.cat(all_latents, dim=1)
215
-
216
- # Decode to video
217
- video = vae.decode_to_pixel(output, use_cache=False)
218
- video = (video * 0.5 + 0.5).clamp(0, 1)
219
 
220
- # Convert to video format
221
  video = rearrange(video, 'b t c h w -> b t h w c').cpu()
222
 
223
  # Save as MP4
@@ -229,12 +128,11 @@ def generate(
229
  elapsed = time.time() - start_time
230
  print(f"Generation completed in {elapsed:.2f}s")
231
 
232
- return output_path, f"Generated in {elapsed:.1f}s"
233
 
234
 
235
  CSS = """
236
  #col-container { max-width: 900px; margin: 0 auto; }
237
- .dark .gradio-container { color: var(--body-text-color); }
238
  """
239
 
240
  with gr.Blocks() as demo:
 
14
  from einops import rearrange
15
 
16
  from pipeline import CausalInferencePipeline
 
17
  from wan.modules.sparse_attention import calculate_chunk_sparsities
18
 
19
  MODEL_ID = "Wan-AI/Wan2.1-T2V-1.3B"
 
21
 
22
  # --- Model loading (module scope, eagerly on cuda) ---
23
 
 
24
  from huggingface_hub import snapshot_download
25
 
26
  if not os.path.exists("wan_models/Wan2.1-T2V-1.3B"):
 
28
  snapshot_download(
29
  repo_id=MODEL_ID,
30
  local_dir="wan_models/Wan2.1-T2V-1.3B",
 
31
  )
32
 
 
33
  lf_ckpt_dir = "checkpoints"
34
  os.makedirs(lf_ckpt_dir, exist_ok=True)
35
  lf_ckpt_path = os.path.join(lf_ckpt_dir, "short_video_gen.pt")
 
47
  default_config = OmegaConf.load("configs/default_config.yaml")
48
  config = OmegaConf.merge(default_config, config)
49
 
 
 
 
 
 
 
 
 
 
50
  # Calculate sparse attention sparsity schedule
51
  num_frame_per_block = getattr(config, "num_frame_per_block", 1)
52
+ model_kwargs = dict(getattr(config, "model_kwargs", {}) or {})
53
  local_attn_size = model_kwargs.get("local_attn_size", 21)
54
  sparse_config = model_kwargs.get("sparse_config", {}) or {}
55
  NUM_OUTPUT_FRAMES = 21
 
58
  )
59
  if sparsity_list:
60
  sparse_config["sparsity_list"] = sparsity_list
 
61
 
 
62
  print(f"Sparsity list: {sparsity_list}")
63
 
64
+ # Initialize pipeline (CausalInferencePipeline handles all model init internally)
65
+ pipeline = CausalInferencePipeline(config, device="cuda")
 
 
 
 
66
 
67
  # Load Light Forcing checkpoint
68
  state_dict = torch.load(lf_ckpt_path, map_location="cpu", weights_only=False)
69
+ pipeline.generator.load_state_dict(state_dict["generator_ema"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  pipeline = pipeline.to(dtype=torch.bfloat16)
72
+ pipeline.text_encoder.to("cuda")
73
+ pipeline.generator.to("cuda")
74
+ pipeline.vae.to("cuda")
75
+
76
+ pipeline.text_encoder.eval()
77
+ pipeline.generator.eval()
78
+ pipeline.vae.eval()
79
+
80
+ pipeline.text_encoder.requires_grad_(False)
81
+ pipeline.generator.requires_grad_(False)
82
+ pipeline.vae.requires_grad_(False)
83
 
84
  print("Model loaded successfully!")
85
 
86
 
87
+ @spaces.GPU(duration=180)
88
  def generate(
89
  prompt: str,
90
  seed: int = 42,
91
  num_output_frames: int = 21,
92
  progress=gr.Progress(track_tqdm=True),
93
  ):
94
+ """Generate a short video from a text prompt using Light Forcing sparse attention."""
 
 
 
 
 
 
95
  if not prompt.strip():
96
  return None, "Please enter a prompt."
97
 
 
100
 
101
  start_time = time.time()
102
 
103
+ # Generate noise (bfloat16 to match model)
 
 
 
 
104
  noise = torch.randn(
105
  [1, num_output_frames, 16, 64, 96],
106
  device="cuda",
107
+ dtype=torch.bfloat16,
108
  )
109
 
110
+ # Run inference using the pipeline's built-in method
111
+ video = pipeline.inference(
112
+ noise=noise,
113
+ text_prompts=[prompt],
114
+ return_latents=False,
115
+ profile=False,
116
+ low_memory=False,
117
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ # video: [b, t, c, h, w] in [0, 1]
120
  video = rearrange(video, 'b t c h w -> b t h w c').cpu()
121
 
122
  # Save as MP4
 
128
  elapsed = time.time() - start_time
129
  print(f"Generation completed in {elapsed:.2f}s")
130
 
131
+ return output_path, f"Generated {num_output_frames} frames in {elapsed:.1f}s"
132
 
133
 
134
  CSS = """
135
  #col-container { max-width: 900px; margin: 0 auto; }
 
136
  """
137
 
138
  with gr.Blocks() as demo: