rahul7star commited on
Commit
6685bf2
·
verified ·
1 Parent(s): 41f72ce

Update app_lora.py

Browse files
Files changed (1) hide show
  1. app_lora.py +233 -0
app_lora.py CHANGED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import types
2
+ import random
3
+ import spaces
4
+
5
+ import torch
6
+ import numpy as np
7
+ from diffusers import AutoencoderKLWan, UniPCMultistepScheduler
8
+ from diffusers.utils import export_to_video
9
+ from diffusers import AutoModel
10
+ import gradio as gr
11
+ import tempfile
12
+ from huggingface_hub import hf_hub_download
13
+
14
+ from src.pipeline_wan_nag import NAGWanPipeline
15
+ from src.transformer_wan_nag import NagWanTransformer3DModel
16
+
17
+
18
+ MOD_VALUE = 32
19
+ DEFAULT_DURATION_SECONDS = 4
20
+ DEFAULT_STEPS = 4
21
+ DEFAULT_SEED = 2025
22
+ DEFAULT_H_SLIDER_VALUE = 480
23
+ DEFAULT_W_SLIDER_VALUE = 832
24
+ NEW_FORMULA_MAX_AREA = 480.0 * 832.0
25
+
26
+ SLIDER_MIN_H, SLIDER_MAX_H = 128, 896
27
+ SLIDER_MIN_W, SLIDER_MAX_W = 128, 896
28
+ MAX_SEED = np.iinfo(np.int32).max
29
+
30
+ FIXED_FPS = 16
31
+ MIN_FRAMES_MODEL = 8
32
+ MAX_FRAMES_MODEL = 81
33
+
34
+ DEFAULT_NAG_NEGATIVE_PROMPT = "Static, motionless, still, ugly, bad quality, worst quality, poorly drawn, low resolution, blurry, lack of details"
35
+
36
+ MODEL_ID = "Wan-AI/Wan2.1-T2V-14B-Diffusers"
37
+ SUB_MODEL_ID = "vrgamedevgirl84/Wan14BT2VFusioniX"
38
+ SUB_MODEL_FILENAME = "Wan14BT2VFusioniX_fp16_.safetensors"
39
+
40
+
41
+
42
+ #LORA_REPO_ID = "Kijai/WanVideo_comfy"
43
+ #LORA_FILENAME = "Wan21_CausVid_14B_T2V_lora_rank32.safetensors"
44
+
45
+
46
+ # new experiment for future work
47
+
48
+ LORA_REPO_ID = "vrgamedevgirl84/Wan14BT2VFusioniX"
49
+ LORA_FILENAME = "FusionX_LoRa/Wan2.1_T2V_14B_FusionX_LoRA.safetensors"
50
+
51
+ vae = AutoencoderKLWan.from_pretrained(MODEL_ID, subfolder="vae", torch_dtype=torch.float32)
52
+ wan_path = hf_hub_download(repo_id=SUB_MODEL_ID, filename=SUB_MODEL_FILENAME)
53
+ transformer = NagWanTransformer3DModel.from_single_file(wan_path, torch_dtype=torch.bfloat16)
54
+ pipe = NAGWanPipeline.from_pretrained(
55
+ MODEL_ID, vae=vae, transformer=transformer, torch_dtype=torch.bfloat16
56
+ )
57
+ pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=5.0)
58
+ pipe.to("cuda")
59
+
60
+
61
+
62
+
63
+
64
+ pipe.transformer.__class__.attn_processors = NagWanTransformer3DModel.attn_processors
65
+ pipe.transformer.__class__.set_attn_processor = NagWanTransformer3DModel.set_attn_processor
66
+ pipe.transformer.__class__.forward = NagWanTransformer3DModel.forward
67
+
68
+ examples = [
69
+ ["A ginger cat passionately plays eletric guitar with intensity and emotion on a stage. The background is shrouded in deep darkness. Spotlights casts dramatic shadows.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
70
+ ["A red vintage Porsche convertible flying over a rugged coastal cliff. Monstrous waves violently crashing against the rocks below. A lighthouse stands tall atop the cliff.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
71
+ ["Enormous glowing jellyfish float slowly across a sky filled with soft clouds. Their tentacles shimmer with iridescent light as they drift above a peaceful mountain landscape. Magical and dreamlike, captured in a wide shot. Surreal realism style with detailed textures.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
72
+ ]
73
+
74
+
75
+ def get_duration(
76
+ prompt,
77
+ nag_negative_prompt, nag_scale,
78
+ height, width, duration_seconds,
79
+ steps,
80
+ seed, randomize_seed,
81
+ compare,
82
+ ):
83
+ duration = int(duration_seconds) * int(steps) * 2.25 + 5
84
+ if compare:
85
+ duration *= 2
86
+ return duration
87
+
88
+ @spaces.GPU(duration=get_duration)
89
+ def generate_video(
90
+ prompt,
91
+ nag_negative_prompt, nag_scale,
92
+ height=DEFAULT_H_SLIDER_VALUE, width=DEFAULT_W_SLIDER_VALUE, duration_seconds=DEFAULT_DURATION_SECONDS,
93
+ steps=DEFAULT_STEPS,
94
+ seed=DEFAULT_SEED, randomize_seed=False,
95
+ compare=True,
96
+ ):
97
+ target_h = max(MOD_VALUE, (int(height) // MOD_VALUE) * MOD_VALUE)
98
+ target_w = max(MOD_VALUE, (int(width) // MOD_VALUE) * MOD_VALUE)
99
+
100
+ num_frames = np.clip(int(round(int(duration_seconds) * FIXED_FPS) + 1), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
101
+
102
+ current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
103
+
104
+ with torch.inference_mode():
105
+ nag_output_frames_list = pipe(
106
+ prompt=prompt,
107
+ nag_negative_prompt=nag_negative_prompt,
108
+ nag_scale=nag_scale,
109
+ nag_tau=3.5,
110
+ nag_alpha=0.5,
111
+ height=target_h, width=target_w, num_frames=num_frames,
112
+ guidance_scale=0.,
113
+ num_inference_steps=int(steps),
114
+ generator=torch.Generator(device="cuda").manual_seed(current_seed)
115
+ ).frames[0]
116
+
117
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
118
+ nag_video_path = tmpfile.name
119
+ export_to_video(nag_output_frames_list, nag_video_path, fps=FIXED_FPS)
120
+
121
+ if compare:
122
+ baseline_output_frames_list = pipe(
123
+ prompt=prompt,
124
+ nag_negative_prompt=nag_negative_prompt,
125
+ height=target_h, width=target_w, num_frames=num_frames,
126
+ guidance_scale=0.,
127
+ num_inference_steps=int(steps),
128
+ generator=torch.Generator(device="cuda").manual_seed(current_seed)
129
+ ).frames[0]
130
+
131
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
132
+ baseline_video_path = tmpfile.name
133
+ export_to_video(baseline_output_frames_list, baseline_video_path, fps=FIXED_FPS)
134
+ else:
135
+ baseline_video_path = None
136
+
137
+ return nag_video_path, baseline_video_path, current_seed
138
+
139
+
140
+ def generate_video_with_example(
141
+ prompt,
142
+ nag_negative_prompt,
143
+ nag_scale,
144
+ ):
145
+ nag_video_path, baseline_video_path, seed = generate_video(
146
+ prompt=prompt,
147
+ nag_negative_prompt=nag_negative_prompt, nag_scale=nag_scale,
148
+ height=DEFAULT_H_SLIDER_VALUE, width=DEFAULT_W_SLIDER_VALUE, duration_seconds=DEFAULT_DURATION_SECONDS,
149
+ steps=DEFAULT_STEPS,
150
+ seed=DEFAULT_SEED, randomize_seed=False,
151
+ compare=True,
152
+ )
153
+ return nag_video_path, baseline_video_path, \
154
+ DEFAULT_H_SLIDER_VALUE, DEFAULT_W_SLIDER_VALUE, \
155
+ DEFAULT_DURATION_SECONDS, DEFAULT_STEPS, seed, True
156
+
157
+
158
+ with gr.Blocks() as demo:
159
+ gr.Markdown('''# Normalized Attention Guidance (NAG) for fast 4 steps Wan2.1-T2V-14B with CausVid LoRA
160
+ Implementation of [Normalized Attention Guidance](https://chendaryen.github.io/NAG.github.io/).
161
+
162
+ [CausVid](https://github.com/tianweiy/CausVid) is a distilled version of Wan2.1 to run faster in just 4-8 steps, [extracted as LoRA by Kijai](https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Wan21_CausVid_14B_T2V_lora_rank32.safetensors).
163
+ ''')
164
+
165
+ with gr.Row():
166
+ with gr.Column():
167
+ prompt = gr.Textbox(
168
+ label="Prompt",
169
+ max_lines=3,
170
+ placeholder="Enter your prompt",
171
+ )
172
+ nag_negative_prompt = gr.Textbox(
173
+ label="Negative Prompt for NAG",
174
+ value=DEFAULT_NAG_NEGATIVE_PROMPT,
175
+ max_lines=3,
176
+ )
177
+ nag_scale = gr.Slider(label="NAG Scale", minimum=1., maximum=20., step=0.25, value=11.)
178
+ compare = gr.Checkbox(
179
+ label="Compare with baseline",
180
+ info="If unchecked, only sample with NAG will be generated.", value=True,
181
+ )
182
+
183
+ with gr.Accordion("Advanced Settings", open=False):
184
+ steps_slider = gr.Slider(minimum=1, maximum=8, step=1, value=DEFAULT_STEPS, label="Inference Steps")
185
+ duration_seconds_input = gr.Slider(
186
+ minimum=1, maximum=5, step=1, value=DEFAULT_DURATION_SECONDS,
187
+ label="Duration (seconds)",
188
+ )
189
+ seed_input = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=DEFAULT_SEED, interactive=True)
190
+ randomize_seed_checkbox = gr.Checkbox(label="Randomize seed", value=True, interactive=True)
191
+ with gr.Row():
192
+ height_input = gr.Slider(minimum=SLIDER_MIN_H, maximum=SLIDER_MAX_H, step=MOD_VALUE,
193
+ value=DEFAULT_H_SLIDER_VALUE,
194
+ label=f"Output Height (multiple of {MOD_VALUE})")
195
+ width_input = gr.Slider(minimum=SLIDER_MIN_W, maximum=SLIDER_MAX_W, step=MOD_VALUE,
196
+ value=DEFAULT_W_SLIDER_VALUE,
197
+ label=f"Output Width (multiple of {MOD_VALUE})")
198
+
199
+ generate_button = gr.Button("Generate Video", variant="primary")
200
+ with gr.Column():
201
+ nag_video_output = gr.Video(label="Video with NAG", autoplay=True, interactive=False)
202
+ baseline_video_output = gr.Video(label="Baseline Video without NAG", autoplay=True, interactive=False)
203
+
204
+ gr.Examples(
205
+ examples=examples,
206
+ fn=generate_video_with_example,
207
+ inputs=[prompt, nag_negative_prompt, nag_scale],
208
+ outputs=[
209
+ nag_video_output, baseline_video_output,
210
+ height_input, width_input, duration_seconds_input,
211
+ steps_slider,
212
+ seed_input,
213
+ compare,
214
+ ],
215
+ cache_examples="lazy"
216
+ )
217
+
218
+ ui_inputs = [
219
+ prompt,
220
+ nag_negative_prompt, nag_scale,
221
+ height_input, width_input, duration_seconds_input,
222
+ steps_slider,
223
+ seed_input, randomize_seed_checkbox,
224
+ compare,
225
+ ]
226
+ generate_button.click(
227
+ fn=generate_video,
228
+ inputs=ui_inputs,
229
+ outputs=[nag_video_output, baseline_video_output, seed_input],
230
+ )
231
+
232
+ if __name__ == "__main__":
233
+ demo.queue().launch()