Skip to content

Commit 751223d

Browse files
committed
[Flux] TPU Optimizations & Speedups for Flux.1-dev, Flux.1-schnell, and Flux.2-klein
- Implemented performance profiling, kernel fusion, instruction scheduling, and latency optimizations for the Flux model family (Flux.1-dev, Flux.1-schnell, Flux.2-klein-4B/9B) on Cloud TPU v6e (Trillium). - Enabled ulysses_custom_fixed_m attention kernel with base-2 exponential scaling (use_base2_exp: True). - Tuned Flash Block Sizes and Pallas multi-head tile batching (heads_per_tile: 3/4). - Enabled LP LLO instruction scheduler in Pallas (use_experimental_scheduler: True). - Fused Rotary Position Embeddings (RoPE) directly on (B, L, H, D) layout, eliminating 228 redundant transpose/swapaxes ops. - Fused LayerNorm scale and shift calculations into single multiply-add ops. - Maintained latents in native bfloat16 for VAE decoding, cutting VAE decode time by 54.2%. - Fixed null check for image_rotary_emb in FlaxFluxAttention to prevent AttributeError.
1 parent 5acfa5b commit 751223d

19 files changed

Lines changed: 233 additions & 155 deletions

src/maxdiffusion/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@
367367
_import_structure["models.controlnet_flax"] = ["FlaxControlNetModel"]
368368
_import_structure["models.modeling_flax_utils"] = ["FlaxModelMixin"]
369369
_import_structure["models.unet_2d_condition_flax"] = ["FlaxUNet2DConditionModel"]
370-
_import_structure["models.flux.transformers.transformer_flux_flax"] = ["FluxTransformer2DModel"]
370+
_import_structure["models.flux.transformers.transformer_flux"] = ["FluxTransformer2DModel"]
371371
_import_structure["models.vae_flax"] = ["FlaxAutoencoderKL"]
372372
_import_structure["models.ltx_video.transformers.transformer3d"] = ["Transformer3DModel"]
373373
_import_structure["pipelines"].extend(["FlaxDiffusionPipeline"])
@@ -444,7 +444,7 @@
444444
from .models.controlnet_flax import FlaxControlNetModel
445445
from .models.modeling_flax_utils import FlaxModelMixin
446446
from .models.unet_2d_condition_flax import FlaxUNet2DConditionModel
447-
from .models.flux.transformers.transformer_flux_flax import FluxTransformer2DModel
447+
from .models.flux.transformers.transformer_flux import FluxTransformer2DModel
448448
from .models.ltx_video.transformers.transformer3d import Transformer3DModel
449449
from .models.vae_flax import FlaxAutoencoderKL
450450
from .pipelines import FlaxDiffusionPipeline

src/maxdiffusion/checkpointing/flux_checkpointer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
FlaxAutoencoderKL,
2828
max_logging,
2929
)
30-
from maxdiffusion.models.flux.transformers.transformer_flux_flax import FluxTransformer2DModel
30+
from maxdiffusion.models.flux.transformers.transformer_flux import FluxTransformer2DModel
3131
from ..pipelines.flux.flux_pipeline import FluxPipeline
3232

3333
from transformers import (CLIPTokenizer, FlaxCLIPTextModel, FlaxT5EncoderModel, AutoTokenizer)

src/maxdiffusion/configs/base_flux2klein.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ flux_name: "flux2klein"
3636
scale_shift_order: "scale_shift"
3737
use_latents: False
3838
latents_path: ""
39-
max_sequence_length: 512
39+
max_sequence_length: 256
4040
time_shift: True
4141
base_shift: 0.5
4242
max_shift: 1.15
@@ -63,18 +63,31 @@ jit_initializers: True
6363
# Set true to load weights from pytorch
6464
from_pt: True
6565
split_head_dim: True
66-
attention: 'flash' # Supported attention: dot_product, flash, cudnn_flash_te
66+
attention: 'ulysses_custom_fixed_m' # Supported attention: dot_product, flash, cudnn_flash_te
67+
use_base2_exp: True
68+
use_experimental_scheduler: True
6769
# If mask_padding_tokens is True, we pass in segment ids to splash attention to avoid attending to padding tokens.
6870
# Else we do not pass in segment ids and on vpu bound hardware like trillium this is faster.
6971
# However, when padding tokens are significant, this will lead to worse quality and should be set to True.
70-
mask_padding_tokens: True
72+
mask_padding_tokens: False
7173
# Maxdiffusion has 2 types of attention sharding strategies:
7274
# 1. attention_sharding_uniform = True : same sequence sharding rules applied for q in both (self and cross attention)
7375
# 2. attention_sharding_uniform = False : Heads are sharded uniformly across devices for self attention while sequence is sharded
7476
# in cross attention q.
7577
attention_sharding_uniform: True
7678

77-
flash_block_sizes: {}
79+
flash_block_sizes: {
80+
"block_q" : 4352,
81+
"block_kv_compute" : 1024,
82+
"block_kv" : 1024,
83+
"block_kv_compute_in" : 1024,
84+
"heads_per_tile" : 3,
85+
"block_q_dkv" : 4352,
86+
"block_kv_dkv" : 1024,
87+
"block_kv_dkv_compute" : 1024,
88+
"block_q_dq" : 4352,
89+
"block_kv_dq" : 1024
90+
}
7891
# GroupNorm groups
7992
norm_num_groups: 32
8093

@@ -148,7 +161,7 @@ logical_axis_rules: [
148161
['out_channels', 'tensor'],
149162
['conv_out', 'fsdp'],
150163
]
151-
data_sharding: [['data', 'fsdp', 'context', 'tensor']]
164+
data_sharding: [['data', 'fsdp']]
152165

153166
# One axis for each parallelism type may hold a placeholder (-1)
154167
# value to auto-shard based on available slices and devices.
@@ -203,7 +216,7 @@ num_train_epochs: 1
203216
seed: 0
204217
output_dir: 'output/'
205218
output_name: "flux2klein_generated_image.png"
206-
per_device_batch_size: 1
219+
per_device_batch_size: 1.0
207220

208221
warmup_steps_fraction: 0.1
209222
learning_rate_schedule_steps: -1 # By default the length of the schedule is set to the number of steps.

src/maxdiffusion/configs/base_flux2klein_9B.yml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,31 @@ jit_initializers: True
6363
# Set true to load weights from pytorch
6464
from_pt: True
6565
split_head_dim: True
66-
attention: 'flash' # Supported attention: dot_product, flash, cudnn_flash_te
66+
attention: 'ulysses_custom_fixed_m' # Supported attention: dot_product, flash, cudnn_flash_te
67+
use_base2_exp: True
68+
use_experimental_scheduler: True
6769
# If mask_padding_tokens is True, we pass in segment ids to splash attention to avoid attending to padding tokens.
6870
# Else we do not pass in segment ids and on vpu bound hardware like trillium this is faster.
6971
# However, when padding tokens are significant, this will lead to worse quality and should be set to True.
70-
mask_padding_tokens: True
72+
mask_padding_tokens: False
7173
# Maxdiffusion has 2 types of attention sharding strategies:
7274
# 1. attention_sharding_uniform = True : same sequence sharding rules applied for q in both (self and cross attention)
7375
# 2. attention_sharding_uniform = False : Heads are sharded uniformly across devices for self attention while sequence is sharded
7476
# in cross attention q.
7577
attention_sharding_uniform: True
7678

77-
flash_block_sizes: {}
79+
flash_block_sizes: {
80+
"block_q" : 4864,
81+
"block_kv_compute" : 1024,
82+
"block_kv" : 1024,
83+
"block_kv_compute_in" : 1024,
84+
"heads_per_tile" : 3,
85+
"block_q_dkv" : 4864,
86+
"block_kv_dkv" : 1024,
87+
"block_kv_dkv_compute" : 1024,
88+
"block_q_dq" : 4864,
89+
"block_kv_dq" : 1024
90+
}
7891
# GroupNorm groups
7992
norm_num_groups: 32
8093

@@ -148,7 +161,7 @@ logical_axis_rules: [
148161
['out_channels', 'tensor'],
149162
['conv_out', 'fsdp'],
150163
]
151-
data_sharding: [['data', 'fsdp', 'context', 'tensor']]
164+
data_sharding: [['data', 'fsdp']]
152165

153166
# One axis for each parallelism type may hold a placeholder (-1)
154167
# value to auto-shard based on available slices and devices.
@@ -203,7 +216,7 @@ num_train_epochs: 1
203216
seed: 0
204217
output_dir: 'output/'
205218
output_name: "flux2klein_generated_image.png"
206-
per_device_batch_size: 1
219+
per_device_batch_size: 1.0
207220

208221
warmup_steps_fraction: 0.1
209222
learning_rate_schedule_steps: -1 # By default the length of the schedule is set to the number of steps.

src/maxdiffusion/configs/base_flux_dev.yml

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ t5xxl_model_name_or_path: 'ariG23498/t5-v1-1-xxl-flax'
3333

3434
# Flux params
3535
flux_name: "flux-dev"
36-
max_sequence_length: 512
36+
max_sequence_length: 256
3737
time_shift: True
3838
base_shift: 0.5
3939
max_shift: 1.15
@@ -62,30 +62,31 @@ jit_initializers: True
6262
# Set true to load weights from pytorch
6363
from_pt: True
6464
split_head_dim: True
65-
attention: 'flash' # Supported attention: dot_product, flash, cudnn_flash_te
66-
use_base2_exp: False
67-
use_experimental_scheduler: False
65+
attention: 'ulysses_custom_fixed_m' # Supported attention: dot_product, flash, cudnn_flash_te, ulysses_custom_fixed_m
66+
use_base2_exp: True
67+
use_experimental_scheduler: True
6868
# If mask_padding_tokens is True, we pass in segment ids to splash attention to avoid attending to padding tokens.
6969
# Else we do not pass in segment ids and on vpu bound hardware like trillium this is faster.
7070
# However, when padding tokens are significant, this will lead to worse quality and should be set to True.
71-
mask_padding_tokens: True
71+
mask_padding_tokens: False
7272
# Maxdiffusion has 2 types of attention sharding strategies:
7373
# 1. attention_sharding_uniform = True : same sequence sharding rules applied for q in both (self and cross attention)
7474
# 2. attention_sharding_uniform = False : Heads are sharded uniformly across devices for self attention while sequence is sharded
7575
# in cross attention q.
7676
attention_sharding_uniform: True
7777

78-
#flash_block_sizes: {}
7978
# Use the following flash_block_sizes on v6e (Trillium) due to larger vmem.
8079
flash_block_sizes: {
81-
"block_q" : 1536,
82-
"block_kv_compute" : 1536,
83-
"block_kv" : 1536,
84-
"block_q_dkv" : 1536,
85-
"block_kv_dkv" : 1536,
86-
"block_kv_dkv_compute" : 1536,
87-
"block_q_dq" : 1536,
88-
"block_kv_dq" : 1536
80+
"block_q" : 4864,
81+
"block_kv_compute" : 1024,
82+
"block_kv" : 1024,
83+
"block_kv_compute_in" : 1024,
84+
"heads_per_tile" : 3,
85+
"block_q_dkv" : 4864,
86+
"block_kv_dkv" : 1024,
87+
"block_kv_dkv_compute" : 1024,
88+
"block_q_dq" : 4864,
89+
"block_kv_dq" : 1024
8990
}
9091
# GroupNorm groups
9192
norm_num_groups: 32
@@ -162,7 +163,7 @@ logical_axis_rules: [
162163
['out_channels', 'tensor'],
163164
['conv_out', 'fsdp'],
164165
]
165-
data_sharding: [['data', 'fsdp', 'context', 'tensor']]
166+
data_sharding: [['data', 'fsdp']]
166167

167168
# One axis for each parallelism type may hold a placeholder (-1)
168169
# value to auto-shard based on available slices and devices.
@@ -251,7 +252,7 @@ max_train_steps: 1500
251252
num_train_epochs: 1
252253
seed: 0
253254
output_dir: 'sdxl-model-finetuned'
254-
per_device_batch_size: 1
255+
per_device_batch_size: 1.0
255256

256257
warmup_steps_fraction: 0.1
257258
learning_rate_schedule_steps: -1 # By default the length of the schedule is set to the number of steps.

src/maxdiffusion/configs/base_flux_schnell.yml

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,38 +61,31 @@ jit_initializers: True
6161
# Set true to load weights from pytorch
6262
from_pt: True
6363
split_head_dim: True
64-
attention: 'flash' # Supported attention: dot_product, flash, cudnn_flash_te
64+
attention: 'ulysses_custom_fixed_m' # Supported attention: dot_product, flash, cudnn_flash_te
65+
use_base2_exp: True
66+
use_experimental_scheduler: True
6567
# If mask_padding_tokens is True, we pass in segment ids to splash attention to avoid attending to padding tokens.
6668
# Else we do not pass in segment ids and on vpu bound hardware like trillium this is faster.
6769
# However, when padding tokens are significant, this will lead to worse quality and should be set to True.
68-
mask_padding_tokens: True
70+
mask_padding_tokens: False
6971
# Maxdiffusion has 2 types of attention sharding strategies:
7072
# 1. attention_sharding_uniform = True : same sequence sharding rules applied for q in both (self and cross attention)
7173
# 2. attention_sharding_uniform = False : Heads are sharded uniformly across devices for self attention while sequence is sharded
7274
# in cross attention q.
7375
attention_sharding_uniform: True
76+
# Use the following flash_block_sizes on v6e (Trillium) due to larger vmem.
7477
flash_block_sizes: {
75-
"block_q" : 256,
76-
"block_kv_compute" : 256,
77-
"block_kv" : 256,
78-
"block_q_dkv" : 256,
79-
"block_kv_dkv" : 256,
80-
"block_kv_dkv_compute" : 256,
81-
"block_q_dq" : 256,
82-
"block_kv_dq" : 256
78+
"block_q" : 4864,
79+
"block_kv_compute" : 1024,
80+
"block_kv" : 1024,
81+
"block_kv_compute_in" : 1024,
82+
"heads_per_tile" : 3,
83+
"block_q_dkv" : 4864,
84+
"block_kv_dkv" : 1024,
85+
"block_kv_dkv_compute" : 1024,
86+
"block_q_dq" : 4864,
87+
"block_kv_dq" : 1024
8388
}
84-
85-
# Use the following flash_block_sizes on v6e (Trillium).
86-
# flash_block_sizes: {
87-
# "block_q" : 2176,
88-
# "block_kv_compute" : 2176,
89-
# "block_kv" : 2176,
90-
# "block_q_dkv" : 2176,
91-
# "block_kv_dkv" : 2176,
92-
# "block_kv_dkv_compute" : 2176,
93-
# "block_q_dq" : 2176,
94-
# "block_kv_dq" : 2176
95-
# }
9689
# GroupNorm groups
9790
norm_num_groups: 32
9891

@@ -166,7 +159,7 @@ logical_axis_rules: [
166159
['out_channels', 'tensor'],
167160
['conv_out', 'fsdp'],
168161
]
169-
data_sharding: [['data', 'fsdp', 'context', 'tensor']]
162+
data_sharding: [['data', 'fsdp']]
170163

171164
# One axis for each parallelism type may hold a placeholder (-1)
172165
# value to auto-shard based on available slices and devices.
@@ -227,7 +220,7 @@ max_train_steps: 200
227220
num_train_epochs: 1
228221
seed: 0
229222
output_dir: 'sdxl-model-finetuned'
230-
per_device_batch_size: 1
223+
per_device_batch_size: 1.0
231224

232225
warmup_steps_fraction: 0.0
233226
learning_rate_schedule_steps: -1 # By default the length of the schedule is set to the number of steps.

src/maxdiffusion/generate_flux.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from transformers import (CLIPTokenizer, FlaxCLIPTextModel, T5EncoderModel, FlaxT5EncoderModel, AutoTokenizer)
3333

3434
from maxdiffusion import FlaxAutoencoderKL, pyconfig, max_logging, max_utils
35-
from maxdiffusion.models.flux.transformers.transformer_flux_flax import FluxTransformer2DModel
35+
from maxdiffusion.models.flux.transformers.transformer_flux import FluxTransformer2DModel
3636
from maxdiffusion.train_utils import transformer_engine_context
3737
from maxdiffusion.max_utils import (
3838
device_put_replicated,
@@ -78,7 +78,7 @@ def unpack(x: Array, height: int, width: int) -> Array:
7878

7979

8080
def vae_decode(latents, vae, state, config):
81-
img = unpack(x=latents.astype(jnp.float32), height=config.resolution, width=config.resolution)
81+
img = unpack(x=latents.astype(jnp.bfloat16), height=config.resolution, width=config.resolution)
8282
img = img / vae.config.scaling_factor + vae.config.shift_factor
8383
img = vae.apply({"params": state.params}, img, deterministic=True, method=vae.decode).sample
8484
return img
@@ -281,7 +281,7 @@ def run(config):
281281
devices_array = create_device_mesh(config)
282282
mesh = Mesh(devices_array, config.mesh_axes)
283283

284-
global_batch_size = config.per_device_batch_size * jax.local_device_count()
284+
global_batch_size = int(round(config.per_device_batch_size * jax.local_device_count()))
285285

286286
# LOAD VAE
287287
with mesh:

0 commit comments

Comments
 (0)