@@ -3858,6 +3858,232 @@ def reshape_vision_attn_out(input_tensor, target_shape):
38583858
38593859
38603860# {maxtext model name: {maxtext weight name: hf weight name}}
3861+
3862+ def DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING (config , maxtext_config , scan_layers = False ):
3863+ n_layers = config ["num_hidden_layers" ]
3864+ num_experts = config .get ("n_routed_experts" , 8 )
3865+
3866+ mapping = {
3867+ "params-token_embedder-embedding" : "model.embed_tokens.weight" ,
3868+ "params-decoder-decoder_norm-scale" : "model.norm.weight" ,
3869+ "params-decoder-logits_dense-kernel" : "head.weight" ,
3870+ "params-decoder-hc_head-hc_fn" : "model.hc_head.hc_fn" ,
3871+ "params-decoder-hc_head-hc_base" : "model.hc_head.hc_base" ,
3872+ "params-decoder-hc_head-hc_scale" : "model.hc_head.hc_scale" ,
3873+ }
3874+
3875+ def add_layer_mapping (mt_layer_path , hf_layer_indices ):
3876+ is_list = isinstance (hf_layer_indices , list )
3877+
3878+ def get_hf_key (subpath ):
3879+ if subpath is None :
3880+ return None
3881+ if is_list :
3882+ return [f"model.layers.{ idx } .{ subpath } " for idx in hf_layer_indices ]
3883+ else :
3884+ return f"model.layers.{ hf_layer_indices } .{ subpath } "
3885+
3886+ def get_hf_expert_keys (expert_subpath_template ):
3887+ if is_list :
3888+ return [
3889+ [f"model.layers.{ idx } .mlp.experts.{ e } .{ expert_subpath_template } " for idx in hf_layer_indices ]
3890+ for e in range (num_experts )
3891+ ]
3892+ else :
3893+ return [f"model.layers.{ hf_layer_indices } .mlp.experts.{ e } .{ expert_subpath_template } " for e in range (num_experts )]
3894+
3895+ layer_map = {
3896+ f"{ mt_layer_path } -pre_self_attention_layer_norm-scale" : get_hf_key ("input_layernorm.weight" ),
3897+ f"{ mt_layer_path } -post_self_attention_layer_norm-scale" : get_hf_key ("post_attention_layernorm.weight" ),
3898+
3899+ # Attention
3900+ f"{ mt_layer_path } -self_attention-wq_a-kernel" : get_hf_key ("self_attn.q_a_proj.weight" ),
3901+ f"{ mt_layer_path } -self_attention-q_norm-scale" : get_hf_key ("self_attn.q_a_norm.weight" ),
3902+ f"{ mt_layer_path } -self_attention-wq_b-kernel" : get_hf_key ("self_attn.q_b_proj.weight" ),
3903+ f"{ mt_layer_path } -self_attention-wkv-kernel" : get_hf_key ("self_attn.kv_proj.weight" ),
3904+ f"{ mt_layer_path } -self_attention-kv_norm-scale" : get_hf_key ("self_attn.kv_norm.weight" ),
3905+ f"{ mt_layer_path } -self_attention-sinks" : get_hf_key ("self_attn.sinks" ),
3906+ f"{ mt_layer_path } -self_attention-o_a_proj-kernel" : get_hf_key ("self_attn.o_a_proj.weight" ),
3907+ f"{ mt_layer_path } -self_attention-o_b_proj-kernel" : get_hf_key ("self_attn.o_b_proj.weight" ),
3908+
3909+ # mHC Attention
3910+ f"{ mt_layer_path } -mhc_attention-mhc_norm-scale" : None ,
3911+ f"{ mt_layer_path } -mhc_attention-pre_alpha" : get_hf_key ("attn_hc.fn" ),
3912+ f"{ mt_layer_path } -mhc_attention-post_alpha" : get_hf_key ("attn_hc.fn" ),
3913+ f"{ mt_layer_path } -mhc_attention-res_alpha" : get_hf_key ("attn_hc.fn" ),
3914+ f"{ mt_layer_path } -mhc_attention-pre_beta" : get_hf_key ("attn_hc.base" ),
3915+ f"{ mt_layer_path } -mhc_attention-post_beta" : get_hf_key ("attn_hc.base" ),
3916+ f"{ mt_layer_path } -mhc_attention-res_beta" : get_hf_key ("attn_hc.base" ),
3917+ f"{ mt_layer_path } -mhc_attention-pre_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3918+ f"{ mt_layer_path } -mhc_attention-post_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3919+ f"{ mt_layer_path } -mhc_attention-res_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3920+
3921+ # mHC MLP
3922+ f"{ mt_layer_path } -mhc_mlp-mhc_norm-scale" : None ,
3923+ f"{ mt_layer_path } -mhc_mlp-pre_alpha" : get_hf_key ("ffn_hc.fn" ),
3924+ f"{ mt_layer_path } -mhc_mlp-post_alpha" : get_hf_key ("ffn_hc.fn" ),
3925+ f"{ mt_layer_path } -mhc_mlp-res_alpha" : get_hf_key ("ffn_hc.fn" ),
3926+ f"{ mt_layer_path } -mhc_mlp-pre_beta" : get_hf_key ("ffn_hc.base" ),
3927+ f"{ mt_layer_path } -mhc_mlp-post_beta" : get_hf_key ("ffn_hc.base" ),
3928+ f"{ mt_layer_path } -mhc_mlp-res_beta" : get_hf_key ("ffn_hc.base" ),
3929+ f"{ mt_layer_path } -mhc_mlp-pre_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3930+ f"{ mt_layer_path } -mhc_mlp-post_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3931+ f"{ mt_layer_path } -mhc_mlp-res_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3932+
3933+ # MoE Block
3934+ f"{ mt_layer_path } -mlp-MoeBlock_0-gate-kernel" : get_hf_key ("mlp.gate.weight" ),
3935+
3936+ # Shared Experts
3937+ f"{ mt_layer_path } -mlp-shared_experts-wi_0-kernel" : get_hf_key ("mlp.shared_experts.gate_proj.weight" ),
3938+ f"{ mt_layer_path } -mlp-shared_experts-wi_1-kernel" : get_hf_key ("mlp.shared_experts.up_proj.weight" ),
3939+ f"{ mt_layer_path } -mlp-shared_experts-wo-kernel" : get_hf_key ("mlp.shared_experts.down_proj.weight" ),
3940+
3941+ # Stacked Experts
3942+ f"{ mt_layer_path } -mlp-MoeBlock_0-wi_0" : get_hf_expert_keys ("w1.weight" ),
3943+ f"{ mt_layer_path } -mlp-MoeBlock_0-wi_1" : get_hf_expert_keys ("w3.weight" ),
3944+ f"{ mt_layer_path } -mlp-MoeBlock_0-wo" : get_hf_expert_keys ("w2.weight" ),
3945+ }
3946+
3947+ if (is_list and hf_layer_indices [0 ] >= 3 ) or (not is_list and hf_layer_indices >= 3 ):
3948+ layer_map [f"{ mt_layer_path } -mlp-MoeBlock_0-gate-bias" ] = get_hf_key ("mlp.gate.e_score_correction_bias" )
3949+
3950+ first_idx = hf_layer_indices [0 ] if is_list else hf_layer_indices
3951+ if first_idx >= 2 :
3952+ if first_idx % 2 == 0 or first_idx == 2 :
3953+ layer_map .update ({
3954+ f"{ mt_layer_path } -self_attention-csa_compressor-kv_proj-kernel" : get_hf_key ("self_attn.compressor.kv_proj.weight" ),
3955+ f"{ mt_layer_path } -self_attention-csa_compressor-gate_proj-kernel" : get_hf_key ("self_attn.compressor.gate_proj.weight" ),
3956+ f"{ mt_layer_path } -self_attention-csa_compressor-position_bias" : get_hf_key ("self_attn.compressor.position_bias" ),
3957+ f"{ mt_layer_path } -self_attention-csa_compressor-kv_norm-scale" : get_hf_key ("self_attn.compressor.kv_norm.weight" ),
3958+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-gate_proj-kernel" : get_hf_key ("self_attn.compressor.indexer.gate_proj.weight" ),
3959+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-kv_proj-kernel" : get_hf_key ("self_attn.compressor.indexer.kv_proj.weight" ),
3960+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-q_proj-kernel" : get_hf_key ("self_attn.compressor.indexer.q_b_proj.weight" ),
3961+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-weights_proj-kernel" : get_hf_key ("self_attn.compressor.indexer.scorer.weights_proj.weight" ),
3962+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-position_bias" : get_hf_key ("self_attn.compressor.indexer.position_bias" ),
3963+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-kv_norm-scale" : get_hf_key ("self_attn.compressor.indexer.kv_norm.weight" ),
3964+ })
3965+ else :
3966+ layer_map .update ({
3967+ f"{ mt_layer_path } -self_attention-hca_compressor-kv_proj-kernel" : get_hf_key ("self_attn.compressor.kv_proj.weight" ),
3968+ f"{ mt_layer_path } -self_attention-hca_compressor-gate_proj-kernel" : get_hf_key ("self_attn.compressor.gate_proj.weight" ),
3969+ f"{ mt_layer_path } -self_attention-hca_compressor-position_bias" : get_hf_key ("self_attn.compressor.position_bias" ),
3970+ f"{ mt_layer_path } -self_attention-hca_compressor-kv_norm-scale" : get_hf_key ("self_attn.compressor.kv_norm.weight" ),
3971+ })
3972+
3973+ mapping .update (layer_map )
3974+
3975+ if not scan_layers :
3976+ for i in range (n_layers ):
3977+ add_layer_mapping (f"params-decoder-layers_{ i } " , i )
3978+ else :
3979+ for i in range (3 ):
3980+ add_layer_mapping (f"params-decoder-layers_{ i } " , i )
3981+ add_layer_mapping ("params-decoder-scanned_blocks-layers_0" , list (range (3 , n_layers , 2 )))
3982+ add_layer_mapping ("params-decoder-scanned_blocks-layers_1" , list (range (4 , n_layers , 2 )))
3983+
3984+ for i in range (3 ):
3985+ mapping [f"Tid2EidVar-decoder-layers_{ i } -mlp-MoeBlock_0-tid2eid" ] = f"model.layers.{ i } .mlp.gate.tid2eid"
3986+
3987+ return mapping
3988+
3989+ def DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN (config , maxtext_config , scan_layers = False , saving_to_hf = False ):
3990+ def transpose (input_tensor , target_shape = None ):
3991+ return np .transpose (input_tensor )
3992+
3993+ def transpose_stack (input_tensor , target_shape = None ):
3994+ # input_tensor is a list of tensors
3995+ stacked = np .stack (input_tensor , axis = 0 ) # [E, out, in]
3996+ return np .transpose (stacked , (0 , 2 , 1 )) # [E, in, out]
3997+
3998+ def ones_norm (input_tensor , target_shape = None ):
3999+ return np .ones (target_shape , dtype = np .float32 )
4000+
4001+ def identity (input_tensor , target_shape = None ):
4002+ return input_tensor
4003+
4004+ # Reshaping functions for wq_b, wkv, o_a_proj
4005+ def reshape_transpose_wq_b (input_tensor , target_shape = None ):
4006+ # HF: [n_heads * q_head_dim, kv_lora_rank]
4007+ # MaxText: [kv_lora_rank, n_heads, q_head_dim]
4008+ tensor = np .transpose (input_tensor ) # [kv_lora_rank, n_heads * q_head_dim]
4009+ n_heads = config ["num_attention_heads" ]
4010+ return tensor .reshape (target_shape )
4011+
4012+ def reshape_transpose_wkv (input_tensor , target_shape = None ):
4013+ # HF: [n_kv_heads * (q_head_dim + v_head_dim), kv_lora_rank]
4014+ # MaxText: [kv_lora_rank, n_kv_heads, q_head_dim + v_head_dim]
4015+ tensor = np .transpose (input_tensor )
4016+ return tensor .reshape (target_shape )
4017+
4018+ def reshape_transpose_o_a (input_tensor , target_shape = None ):
4019+ # HF: [n_heads * v_head_dim, kv_lora_rank] (e.g. [8192, 4096])
4020+ # MaxText: [n_heads, v_head_dim, kv_lora_rank] (e.g. [8, 4096, 1024])
4021+ # We must reshape first and then permute (transpose) to get correct ordering.
4022+ num_heads = target_shape [0 ]
4023+ embed_dim = target_shape [1 ]
4024+ kv_lora_rank = target_shape [2 ]
4025+ tensor = input_tensor .reshape ((num_heads , kv_lora_rank , embed_dim ))
4026+ return np .transpose (tensor , (0 , 2 , 1 ))
4027+
4028+ # Functions for mHC split
4029+ def mhc_split_fn_pre (input_tensor , target_shape = None ):
4030+ return np .transpose (input_tensor [0 :4 , :])
4031+ def mhc_split_fn_post (input_tensor , target_shape = None ):
4032+ return np .transpose (input_tensor [4 :8 , :])
4033+ def mhc_split_fn_res (input_tensor , target_shape = None ):
4034+ return np .transpose (input_tensor [8 :24 , :])
4035+
4036+ def mhc_split_base_pre (input_tensor , target_shape = None ):
4037+ return input_tensor [0 :4 ]
4038+ def mhc_split_base_post (input_tensor , target_shape = None ):
4039+ return input_tensor [4 :8 ]
4040+ def mhc_split_base_res (input_tensor , target_shape = None ):
4041+ return input_tensor [8 :24 ].reshape (target_shape )
4042+
4043+ def mhc_split_scale_pre (input_tensor , target_shape = None ):
4044+ return np .array ([input_tensor [0 ]]).reshape (target_shape )
4045+ def mhc_split_scale_post (input_tensor , target_shape = None ):
4046+ return np .array ([input_tensor [1 ]]).reshape (target_shape )
4047+ def mhc_split_scale_res (input_tensor , target_shape = None ):
4048+ return np .array ([input_tensor [2 ]]).reshape (target_shape )
4049+
4050+ mapping = {}
4051+
4052+ # Base mapping logic from original file
4053+ for key , hf_key in DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING (config , maxtext_config , scan_layers ).items ():
4054+ if hf_key is None :
4055+ mapping [key ] = ones_norm
4056+ elif "token_embedder-embedding" in key :
4057+ mapping [key ] = identity
4058+ elif "-wkv-kernel" in key :
4059+ mapping [key ] = reshape_transpose_wkv
4060+ elif "-wq_b-kernel" in key :
4061+ mapping [key ] = reshape_transpose_wq_b
4062+ elif "-o_a_proj-kernel" in key :
4063+ mapping [key ] = reshape_transpose_o_a
4064+ elif "mhc" in key :
4065+ if "pre_alpha" in key and "scale" not in key : mapping [key ] = mhc_split_fn_pre
4066+ elif "post_alpha" in key and "scale" not in key : mapping [key ] = mhc_split_fn_post
4067+ elif "res_alpha" in key and "scale" not in key : mapping [key ] = mhc_split_fn_res
4068+ elif "pre_beta" in key : mapping [key ] = mhc_split_base_pre
4069+ elif "post_beta" in key : mapping [key ] = mhc_split_base_post
4070+ elif "res_beta" in key : mapping [key ] = mhc_split_base_res
4071+ elif "pre_alpha_scale" in key : mapping [key ] = mhc_split_scale_pre
4072+ elif "post_alpha_scale" in key : mapping [key ] = mhc_split_scale_post
4073+ elif "res_alpha_scale" in key : mapping [key ] = mhc_split_scale_res
4074+ elif "position_bias" in key :
4075+ mapping [key ] = identity
4076+ elif "hc_head-hc_fn" in key :
4077+ mapping [key ] = transpose
4078+ elif "hc_head-hc_base" in key or "hc_head-hc_scale" in key :
4079+ mapping [key ] = identity
4080+ elif type (hf_key ) == list :
4081+ mapping [key ] = transpose if not saving_to_hf else transpose_stack
4082+ elif "-kernel" in key or "-embedding" in key or "-sinks" in key :
4083+ mapping [key ] = transpose
4084+
4085+ return mapping
4086+
38614087PARAM_MAPPING = {
38624088 "gemma2-2b" : GEMMA2_MAXTEXT_TO_HF_PARAM_MAPPING ,
38634089 "gemma2-9b" : GEMMA2_MAXTEXT_TO_HF_PARAM_MAPPING ,
@@ -3896,6 +4122,7 @@ def reshape_vision_attn_out(input_tensor, target_shape):
38964122 "deepseek2-16b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
38974123 "deepseek3-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
38984124 "deepseek3.2-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
4125+ "deepseek4-284b" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING ,
38994126 "gpt-oss-20b" : GPT_OSS_MAXTEXT_TO_HF_PARAM_MAPPING ,
39004127 "gpt-oss-120b" : GPT_OSS_MAXTEXT_TO_HF_PARAM_MAPPING ,
39014128 "qwen3-omni-30b-a3b" : QWEN3_OMNI_MOE_MAXTEXT_TO_HF_PARAM_MAPPING ,
@@ -3948,6 +4175,8 @@ def reshape_vision_attn_out(input_tensor, target_shape):
39484175 "deepseek2-16b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39494176 "deepseek3-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39504177 "deepseek3.2-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
4178+ "deepseek4-tiny" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
4179+ "deepseek4-284b" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39514180 "gpt-oss-20b" : GPT_OSS_TO_HF_PARAM_HOOK_FN ,
39524181 "gpt-oss-120b" : GPT_OSS_TO_HF_PARAM_HOOK_FN ,
39534182 "qwen3-omni-30b-a3b" : QWEN3_OMNI_MOE_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
0 commit comments