@@ -75,6 +75,7 @@ def __init__(
7575 mesh = None ,
7676 logical_axis_rules = (),
7777 vae_shift_factor : Optional [float ] = None ,
78+ offload_encoders : bool = False ,
7879 ):
7980 self .transformer = transformer
8081 self .vae = vae
@@ -96,6 +97,12 @@ def __init__(
9697 self ._text_encoder_split = nnx .split (self .text_encoder , nnx .Param , ...)
9798 self ._transformer_split = nnx .split (self .transformer , nnx .Param , ...)
9899
100+ self .offload_encoders = offload_encoders
101+ if self .offload_encoders :
102+ # Save the original shardings of the text encoder parameters
103+ graphdef , state , rest = self ._text_encoder_split
104+ self ._text_encoder_shardings = jax .tree_util .tree_map (lambda x : x .sharding , state )
105+
99106 def _decode_fn (self ):
100107 """Jitted VAE decode, including the latent denormalization."""
101108 if self ._jitted_decoder is None :
@@ -127,6 +134,15 @@ def encode_prompt(self, prompt: Union[str, list[str]], max_sequence_length: int
127134 chats , padding = "max_length" , max_length = max_sequence_length , truncation = True , return_tensors = "np"
128135 )
129136 graphdef , state , rest = self ._text_encoder_split
137+
138+ if self .offload_encoders :
139+ # Restore parameters from CPU back to original device shardings
140+ state = jax .tree_util .tree_map (
141+ lambda x , sharding : jax .device_put (x , sharding ),
142+ state ,
143+ self ._text_encoder_shardings
144+ )
145+
130146 with self .mesh if self .mesh is not None else nullcontext ():
131147 embeddings = encode_step (
132148 graphdef ,
@@ -136,6 +152,15 @@ def encode_prompt(self, prompt: Union[str, list[str]], max_sequence_length: int
136152 jnp .asarray (inputs ["attention_mask" ], jnp .int32 ),
137153 )
138154 lengths = np .asarray (inputs ["attention_mask" ]).sum (axis = - 1 )
155+
156+ if self .offload_encoders :
157+ from maxdiffusion import max_logging
158+ s_offload = time .perf_counter ()
159+ cpus = jax .devices ("cpu" )
160+ offloaded_state = jax .tree_util .tree_map (lambda x : jax .device_put (x , device = cpus [0 ]), state )
161+ self ._text_encoder_split = (graphdef , offloaded_state , rest )
162+ max_logging .log (f"Offloaded Qwen3 text encoder parameters to CPU in { (time .perf_counter () - s_offload ):.4f} s." )
163+
139164 return [jnp .asarray (embeddings [index , : lengths [index ]], dtype = self .dtype ) for index in range (len (lengths ))]
140165
141166 @staticmethod
0 commit comments