CoolFace
Apppublic

SubstanceSHIFT/wan-2-2-first-last-frame

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
optimization.py133 linesDownload Raw Back to root
1"""2"""3 4from typing import Any5from typing import Callable6from typing import ParamSpec7 8import spaces9import torch10from torch.utils._pytree import tree_map_only11from torchao.quantization import quantize_12from torchao.quantization import Float8DynamicActivationFloat8WeightConfig13from torchao.quantization import Int8WeightOnlyConfig14 15from optimization_utils import capture_component_call16from optimization_utils import aoti_compile17from optimization_utils import drain_module_parameters18 19 20P = ParamSpec('P')21 22# --- CORRECTED DYNAMIC SHAPING ---23 24# VAE temporal scale factor is 1, latent_frames = num_frames. Range is [8, 81].25LATENT_FRAMES_DIM = torch.export.Dim('num_latent_frames', min=8, max=81)26 27# The transformer has a patch_size of (1, 2, 2), which means the input latent height and width28# are effectively divided by 2. This creates constraints that fail if the symbolic tracer29# assumes odd numbers are possible.30#31# To solve this, we define the dynamic dimension for the *patched* (i.e., post-division) size,32# and then express the input shape as 2 * this dimension. This mathematically guarantees33# to the compiler that the input latent dimensions are always even, satisfying the constraints.34 35# App range for pixel dimensions: [480, 832]. VAE scale factor is 8.36# Latent dimension range: [480/8, 832/8] = [60, 104].37# Patched latent dimension range: [60/2, 104/2] = [30, 52].38LATENT_PATCHED_HEIGHT_DIM = torch.export.Dim('latent_patched_height', min=30, max=52)39LATENT_PATCHED_WIDTH_DIM = torch.export.Dim('latent_patched_width', min=30, max=52)40 41# Now, we define the dynamic shapes for the transformer's `hidden_states` input,42# which has the shape (batch_size, channels, num_frames, height, width).43TRANSFORMER_DYNAMIC_SHAPES = {44    'hidden_states': {45        2: LATENT_FRAMES_DIM,46        3: 2 * LATENT_PATCHED_HEIGHT_DIM, # Guarantees even height47        4: 2 * LATENT_PATCHED_WIDTH_DIM,  # Guarantees even width48    },49}50 51# --- END OF CORRECTION ---52 53 54INDUCTOR_CONFIGS = {55    'conv_1x1_as_mm': True,56    'epilogue_fusion': False,57    'coordinate_descent_tuning': True,58    'coordinate_descent_check_all_directions': True,59    'max_autotune': True,60    'triton.cudagraphs': True,61}62 63 64def optimize_pipeline_(pipeline: Callable[P, Any], *args: P.args, **kwargs: P.kwargs):65 66    @spaces.GPU(duration=1500)67    def compile_transformer():68        69        # This LoRA fusion part remains the same70        pipeline.load_lora_weights(71            "Kijai/WanVideo_comfy", 72            weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors", 73            adapter_name="lightx2v"74        )75        kwargs_lora = {}76        kwargs_lora["load_into_transformer_2"] = True77        pipeline.load_lora_weights(78            "Kijai/WanVideo_comfy", 79            weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors", 80            adapter_name="lightx2v_2", **kwargs_lora81        )82        pipeline.set_adapters(["lightx2v", "lightx2v_2"], adapter_weights=[1., 1.])83        pipeline.fuse_lora(adapter_names=["lightx2v"], lora_scale=3., components=["transformer"])84        pipeline.fuse_lora(adapter_names=["lightx2v_2"], lora_scale=1., components=["transformer_2"])85        pipeline.unload_lora_weights()86        87        # Capture a single call to get the args/kwargs structure88        with capture_component_call(pipeline, 'transformer') as call:89            pipeline(*args, **kwargs)90        91        dynamic_shapes = tree_map_only((torch.Tensor, bool), lambda t: None, call.kwargs)92        dynamic_shapes |= TRANSFORMER_DYNAMIC_SHAPES93 94        # Quantization remains the same95        quantize_(pipeline.transformer, Float8DynamicActivationFloat8WeightConfig())96        quantize_(pipeline.transformer_2, Float8DynamicActivationFloat8WeightConfig())97        98        # --- SIMPLIFIED COMPILATION ---99        100        exported_1 = torch.export.export(101            mod=pipeline.transformer,102            args=call.args,103            kwargs=call.kwargs,104            dynamic_shapes=dynamic_shapes,105        )106        107        exported_2 = torch.export.export(108            mod=pipeline.transformer_2,109            args=call.args,110            kwargs=call.kwargs,111            dynamic_shapes=dynamic_shapes,112        )113 114        compiled_1 = aoti_compile(exported_1, INDUCTOR_CONFIGS)115        compiled_2 = aoti_compile(exported_2, INDUCTOR_CONFIGS)116        117        # Return the two compiled models118        return compiled_1, compiled_2119 120 121    # Quantize text encoder (same as before)122    quantize_(pipeline.text_encoder, Int8WeightOnlyConfig())123    124    # Get the two dynamically-shaped compiled models125    compiled_transformer_1, compiled_transformer_2 = compile_transformer()126 127    # --- SIMPLIFIED ASSIGNMENT ---128    129    pipeline.transformer.forward = compiled_transformer_1130    drain_module_parameters(pipeline.transformer)131 132    pipeline.transformer_2.forward = compiled_transformer_2133    drain_module_parameters(pipeline.transformer_2)