1717import json
1818from typing import Optional
1919import torch
20+ import numpy as np
2021import jax
2122import jax .numpy as jnp
2223from maxdiffusion import max_logging
@@ -184,6 +185,14 @@ def load_sharded_checkpoint(pretrained_model_name_or_path, subfolder, device, fi
184185 return tensors
185186
186187
188+ def _torch_tensor_to_numpy (tensor : torch .Tensor ) -> np .ndarray :
189+ import ml_dtypes
190+
191+ if tensor .dtype == torch .bfloat16 :
192+ return tensor .view (torch .uint16 ).numpy ().view (ml_dtypes .bfloat16 )
193+ return tensor .numpy ()
194+
195+
187196def load_transformer_weights (
188197 pretrained_model_name_or_path : str ,
189198 eval_shapes : dict ,
@@ -193,38 +202,110 @@ def load_transformer_weights(
193202 scan_layers : bool = True ,
194203 subfolder : str = "transformer" ,
195204):
205+ import threading
206+ import concurrent .futures
207+ import time
208+
196209 device = jax .local_devices (backend = device )[0 ]
197210 max_logging .log (f"Load and port { pretrained_model_name_or_path } { subfolder } on { device } " )
198211
199- with jax .default_device (device ):
200- # Support sharded loading
201- tensors = load_sharded_checkpoint (pretrained_model_name_or_path , subfolder , device )
212+ index_file = "diffusion_pytorch_model.safetensors.index.json"
213+ try :
214+ index_path = hf_hub_download (pretrained_model_name_or_path , subfolder = subfolder , filename = index_file )
215+ with open (index_path , "r" ) as f :
216+ index_data = json .load (f )
217+ weight_map = index_data ["weight_map" ]
218+ shards = sorted (set (weight_map .values ()))
202219
203- flax_state_dict = {}
204- cpu = jax .local_devices (backend = "cpu" )[0 ]
205- flattened_dict = flatten_dict (eval_shapes )
220+ def resolve_shard_path (model_file ):
221+ return hf_hub_download (pretrained_model_name_or_path , subfolder = subfolder , filename = model_file )
206222
207- random_flax_state_dict = {}
208- for key in flattened_dict :
209- random_flax_state_dict [tuple (str (item ) for item in key )] = flattened_dict [key ]
223+ except EntryNotFoundError :
224+ shards = ["diffusion_pytorch_model.safetensors" ]
210225
211- for pt_key , tensor in tensors .items ():
212- renamed_pt_key = rename_key (pt_key )
213- renamed_pt_key = rename_for_ltx2_transformer (renamed_pt_key )
226+ def resolve_shard_path (model_file ):
227+ try :
228+ return hf_hub_download (pretrained_model_name_or_path , subfolder = subfolder , filename = model_file )
229+ except EntryNotFoundError :
230+ return hf_hub_download (pretrained_model_name_or_path , subfolder = subfolder , filename = "diffusion_pytorch_model.bin" )
214231
215- pt_tuple_key = tuple ( renamed_pt_key . split ( "." ) )
232+ t_start = time . perf_counter ( )
216233
217- flax_key , flax_tensor = get_key_and_value (
218- pt_tuple_key , tensor , flax_state_dict , random_flax_state_dict , scan_layers , num_layers
219- )
234+ flattened_dict = flatten_dict (eval_shapes )
235+ random_flax_state_dict = {}
236+ for key in flattened_dict :
237+ random_flax_state_dict [tuple (str (item ) for item in key )] = flattened_dict [key ]
220238
221- flax_state_dict [flax_key ] = jax .device_put (jnp .asarray (flax_tensor ), device = cpu )
239+ flax_state_dict = {}
240+ dict_lock = threading .Lock ()
241+
242+ def convert_chunk (ckpt_shard_path , chunk_keys ):
243+ if ckpt_shard_path .endswith (".safetensors" ):
244+ with safe_open (ckpt_shard_path , framework = "pt" ) as f :
245+ for pt_key in chunk_keys :
246+ tensor = _torch_tensor_to_numpy (f .get_tensor (pt_key ))
247+ process_tensor (pt_key , tensor )
248+ else :
249+ loaded_state_dict = torch .load (ckpt_shard_path , map_location = "cpu" )
250+ for pt_key in chunk_keys :
251+ tensor = _torch_tensor_to_numpy (loaded_state_dict [pt_key ])
252+ process_tensor (pt_key , tensor )
253+
254+ def process_tensor (pt_key , tensor ):
255+ renamed_pt_key = rename_key (pt_key )
256+ renamed_pt_key = rename_for_ltx2_transformer (renamed_pt_key )
257+ pt_tuple_key = tuple (renamed_pt_key .split ("." ))
258+
259+ block_index = None
260+ if scan_layers and len (pt_tuple_key ) > 0 and "transformer_blocks_" in pt_tuple_key [0 ]:
261+ import re
262+
263+ m = re .match (r"transformer_blocks_(\d+)" , pt_tuple_key [0 ])
264+ if m :
265+ block_index = int (m .group (1 ))
266+ pt_tuple_key = ("transformer_blocks" ,) + pt_tuple_key [1 :]
222267
223- validate_flax_state_dict (eval_shapes , flax_state_dict )
224- flax_state_dict = unflatten_dict (flax_state_dict )
225- del tensors
226- jax .clear_caches ()
227- return flax_state_dict
268+ flax_key , flax_tensor = rename_key_and_reshape_tensor (pt_tuple_key , tensor , random_flax_state_dict , scan_layers )
269+ flax_key_str = [str (k ) for k in flax_key ]
270+ if "scale_shift_table" in flax_key_str and flax_key_str [- 1 ] in ["kernel" , "weight" ]:
271+ flax_key_str .pop ()
272+ flax_key = tuple (flax_key_str )
273+ flax_key = _tuple_str_to_int (flax_key )
274+
275+ if block_index is not None :
276+ with dict_lock :
277+ stacked = flax_state_dict .get (flax_key )
278+ if stacked is None :
279+ stacked = np .empty ((num_layers ,) + flax_tensor .shape , dtype = flax_tensor .dtype )
280+ flax_state_dict [flax_key ] = stacked
281+ stacked [block_index ] = flax_tensor
282+ else :
283+ value = np .array (flax_tensor , dtype = flax_tensor .dtype , copy = True , order = "C" )
284+ with dict_lock :
285+ flax_state_dict [flax_key ] = value
286+
287+ chunk_size = 32
288+ tasks = []
289+ for model_file in shards :
290+ ckpt_shard_path = resolve_shard_path (model_file )
291+ if ckpt_shard_path .endswith (".safetensors" ):
292+ with safe_open (ckpt_shard_path , framework = "pt" ) as f :
293+ shard_keys = list (f .keys ())
294+ else :
295+ loaded_state_dict = torch .load (ckpt_shard_path , map_location = "cpu" )
296+ shard_keys = list (loaded_state_dict .keys ())
297+ for i in range (0 , len (shard_keys ), chunk_size ):
298+ tasks .append ((ckpt_shard_path , shard_keys [i : i + chunk_size ]))
299+
300+ with concurrent .futures .ThreadPoolExecutor (max_workers = 32 ) as executor :
301+ futures = [executor .submit (convert_chunk , path , keys ) for path , keys in tasks ]
302+ for future in concurrent .futures .as_completed (futures ):
303+ future .result ()
304+
305+ validate_flax_state_dict (eval_shapes , flax_state_dict )
306+ flax_state_dict = unflatten_dict (flax_state_dict )
307+ max_logging .log (f"Converted weights in { time .perf_counter () - t_start :.1f} s" )
308+ return flax_state_dict
228309
229310
230311def load_vae_weights (
0 commit comments