|
22 | 22 | import jax.numpy as jnp |
23 | 23 | from ... import common_types |
24 | 24 | from ..attention_flax import NNXAttentionOp |
| 25 | +from ..wan.transformers import svg_attention |
25 | 26 | from .logical_sharding_ltx2 import get_sharding_specs, LTX2DiTShardingSpecs |
26 | 27 |
|
27 | 28 | Array = common_types.Array |
@@ -352,7 +353,58 @@ def __init__( |
352 | 353 | use_base2_exp: bool = False, |
353 | 354 | use_experimental_scheduler: bool = False, |
354 | 355 | enable_jax_named_scopes: bool = False, |
| 356 | + attention_config: Optional[dict] = None, |
355 | 357 | ): |
| 358 | + attention_config = { |
| 359 | + "use_base2_exp": use_base2_exp, |
| 360 | + "use_experimental_scheduler": use_experimental_scheduler, |
| 361 | + "ulysses_shards": ulysses_shards, |
| 362 | + "ulysses_attention_chunks": ulysses_attention_chunks, |
| 363 | + "use_svg_attention": False, |
| 364 | + "svg_implementation": "official_svg", |
| 365 | + "svg_spatial_density": 0.25, |
| 366 | + "svg_sample_max_row": 10000, |
| 367 | + "svg_profile_query_count": 64, |
| 368 | + "svg_profile_seed": 0, |
| 369 | + "svg_dense_layer_fraction": 0.0, |
| 370 | + "svg_dense_timestep_fraction": 0.0, |
| 371 | + "svg_active_start_step": -1, |
| 372 | + "svg_active_end_step": -1, |
| 373 | + "svg_active_start_layer": -1, |
| 374 | + "svg_active_end_layer": -1, |
| 375 | + "svg_num_train_timesteps": 1000, |
| 376 | + "svg_num_layers": 48, |
| 377 | + "svg_include_first_frame": True, |
| 378 | + "svg_global_stride": 0, |
| 379 | + "svg_global_offset": 0, |
| 380 | + "svg_high_noise_density": -1.0, |
| 381 | + "svg_low_noise_density": -1.0, |
| 382 | + "svg_flash_block_sizes": None, |
| 383 | + **(attention_config or {}), |
| 384 | + } |
| 385 | + |
| 386 | + self.is_self_attention = context_dim is None |
| 387 | + self.use_svg_attention = bool(attention_config["use_svg_attention"]) and self.is_self_attention |
| 388 | + self.svg_implementation = attention_config["svg_implementation"] |
| 389 | + self.svg_spatial_density = attention_config["svg_spatial_density"] |
| 390 | + self.svg_sample_max_row = attention_config["svg_sample_max_row"] |
| 391 | + self.svg_profile_query_count = attention_config["svg_profile_query_count"] |
| 392 | + self.svg_profile_seed = attention_config["svg_profile_seed"] |
| 393 | + self.svg_dense_layer_fraction = attention_config["svg_dense_layer_fraction"] |
| 394 | + self.svg_dense_timestep_fraction = attention_config["svg_dense_timestep_fraction"] |
| 395 | + self.svg_active_start_step = attention_config["svg_active_start_step"] |
| 396 | + self.svg_active_end_step = attention_config["svg_active_end_step"] |
| 397 | + self.svg_active_start_layer = attention_config["svg_active_start_layer"] |
| 398 | + self.svg_active_end_layer = attention_config["svg_active_end_layer"] |
| 399 | + self.svg_num_train_timesteps = attention_config["svg_num_train_timesteps"] |
| 400 | + self.svg_num_layers = attention_config["svg_num_layers"] |
| 401 | + self.svg_include_first_frame = attention_config["svg_include_first_frame"] |
| 402 | + self.svg_global_stride = attention_config["svg_global_stride"] |
| 403 | + self.svg_global_offset = attention_config["svg_global_offset"] |
| 404 | + self.svg_high_noise_density = attention_config["svg_high_noise_density"] |
| 405 | + self.svg_low_noise_density = attention_config["svg_low_noise_density"] |
| 406 | + self.svg_flash_block_sizes = attention_config["svg_flash_block_sizes"] |
| 407 | + |
356 | 408 | self.heads = heads |
357 | 409 | self.rope_type = rope_type |
358 | 410 | self.dim_head = dim_head |
@@ -542,10 +594,22 @@ def __call__( |
542 | 594 | k_rotary_emb: Optional[Tuple[Array, Array]] = None, |
543 | 595 | perturbation_mask: Optional[Array] = None, |
544 | 596 | cached_kv: Optional[Tuple[Array, Array]] = None, |
| 597 | + deterministic: bool = True, |
| 598 | + spatiotemporal_shape: Optional[Tuple[int, int, int]] = None, |
| 599 | + svg_layer_index: Optional[int | jax.Array] = None, |
| 600 | + svg_timestep: Optional[int | float | jax.Array] = None, |
| 601 | + svg_step_index: Optional[int | jax.Array] = None, |
545 | 602 | ) -> Array: |
546 | 603 | # Determine context (Self or Cross) |
| 604 | + is_self_attention = encoder_hidden_states is None |
547 | 605 | context = encoder_hidden_states if encoder_hidden_states is not None else hidden_states |
548 | 606 |
|
| 607 | + if self.use_svg_attention and is_self_attention: |
| 608 | + if not deterministic: |
| 609 | + raise ValueError("SVG attention supports deterministic inference only.") |
| 610 | + if spatiotemporal_shape is None: |
| 611 | + raise ValueError("SVG attention requires spatiotemporal_shape.") |
| 612 | + |
549 | 613 | # 1. Project and Norm |
550 | 614 | with self.named_scope("QKV Projection"): |
551 | 615 | query = self.to_q(hidden_states) |
@@ -586,8 +650,66 @@ def __call__( |
586 | 650 |
|
587 | 651 | with self.named_scope("Attention and Output Project"): |
588 | 652 | # 4. Attention |
589 | | - # NNXAttentionOp expects flattened input [B, S, InnerDim] for flash kernel |
590 | | - attn_output = self.attention_op.apply_attention(query=query, key=key, value=value, attention_mask=attention_mask) |
| 653 | + if self.use_svg_attention and is_self_attention and spatiotemporal_shape is not None: |
| 654 | + is_active = svg_attention.is_svg_active( |
| 655 | + step_index=svg_step_index, |
| 656 | + layer_index=svg_layer_index, |
| 657 | + timestep=svg_timestep, |
| 658 | + start_step=self.svg_active_start_step, |
| 659 | + end_step=self.svg_active_end_step, |
| 660 | + start_layer=self.svg_active_start_layer, |
| 661 | + end_layer=self.svg_active_end_layer, |
| 662 | + dense_layer_fraction=self.svg_dense_layer_fraction, |
| 663 | + dense_timestep_fraction=self.svg_dense_timestep_fraction, |
| 664 | + num_train_timesteps=self.svg_num_train_timesteps, |
| 665 | + num_layers=self.svg_num_layers, |
| 666 | + ) |
| 667 | + |
| 668 | + def run_dense(_): |
| 669 | + return self.attention_op.apply_attention( |
| 670 | + query=query, |
| 671 | + key=key, |
| 672 | + value=value, |
| 673 | + attention_mask=attention_mask, |
| 674 | + ) |
| 675 | + |
| 676 | + def run_sparse_svg(_): |
| 677 | + execution_band_width = svg_attention.svg_execution_band_width( |
| 678 | + spatiotemporal_shape, |
| 679 | + self.svg_spatial_density, |
| 680 | + ) |
| 681 | + sparse_config = { |
| 682 | + "use_svg_attention": True, |
| 683 | + "mask_type": "svg_spatial", |
| 684 | + "band_width": execution_band_width, |
| 685 | + "include_first_frame": self.svg_include_first_frame, |
| 686 | + "global_stride": self.svg_global_stride, |
| 687 | + "global_offset": self.svg_global_offset, |
| 688 | + "profile_query_count": self.svg_profile_query_count, |
| 689 | + "profile_seed": self.svg_profile_seed, |
| 690 | + "sample_max_row": self.svg_sample_max_row, |
| 691 | + "custom_flash_block_sizes": self.svg_flash_block_sizes, |
| 692 | + "svg_step_index": svg_step_index, |
| 693 | + "svg_layer_index": svg_layer_index, |
| 694 | + "svg_timestep": svg_timestep, |
| 695 | + } |
| 696 | + return self.attention_op.apply_attention( |
| 697 | + query=query, |
| 698 | + key=key, |
| 699 | + value=value, |
| 700 | + attention_mask=attention_mask, |
| 701 | + spatiotemporal_shape=spatiotemporal_shape, |
| 702 | + sparse_config_override=sparse_config, |
| 703 | + ) |
| 704 | + |
| 705 | + with self.named_scope("apply_attention"): |
| 706 | + if isinstance(is_active, bool): |
| 707 | + attn_output = run_sparse_svg(None) if is_active else run_dense(None) |
| 708 | + else: |
| 709 | + attn_output = jax.lax.cond(is_active, run_sparse_svg, run_dense, operand=None) |
| 710 | + else: |
| 711 | + with self.named_scope("apply_attention"): |
| 712 | + attn_output = self.attention_op.apply_attention(query=query, key=key, value=value, attention_mask=attention_mask) |
591 | 713 |
|
592 | 714 | if perturbation_mask is not None: |
593 | 715 | # value is [B, S, InnerDim] |
|
0 commit comments