@@ -3870,6 +3870,278 @@ def reshape_vision_attn_out(input_tensor, target_shape):
38703870
38713871
38723872# {maxtext model name: {maxtext weight name: hf weight name}}
3873+
3874+
3875+ def DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING (config , maxtext_config , scan_layers = False ):
3876+ """Maps MaxText parameter keys to HuggingFace parameter keys for DeepSeek V4."""
3877+ n_layers = config ["num_hidden_layers" ]
3878+ num_experts = config .get ("n_routed_experts" , 8 )
3879+
3880+ mapping = {
3881+ "params-token_embedder-embedding" : "model.embed_tokens.weight" ,
3882+ "params-decoder-decoder_norm-scale" : "model.norm.weight" ,
3883+ "params-decoder-logits_dense-kernel" : "head.weight" ,
3884+ "params-decoder-hc_head-hc_fn" : "model.hc_head.hc_fn" ,
3885+ "params-decoder-hc_head-hc_base" : "model.hc_head.hc_base" ,
3886+ "params-decoder-hc_head-hc_scale" : "model.hc_head.hc_scale" ,
3887+ }
3888+
3889+ def add_layer_mapping (mt_layer_path , hf_layer_indices ):
3890+ is_list = isinstance (hf_layer_indices , list )
3891+
3892+ def get_hf_key (subpath ):
3893+ if subpath is None :
3894+ return None
3895+ if is_list :
3896+ return [f"model.layers.{ idx } .{ subpath } " for idx in hf_layer_indices ]
3897+ else :
3898+ return f"model.layers.{ hf_layer_indices } .{ subpath } "
3899+
3900+ def get_hf_expert_keys (expert_subpath_template ):
3901+ if is_list :
3902+ return [
3903+ [f"model.layers.{ idx } .mlp.experts.{ e } .{ expert_subpath_template } " for idx in hf_layer_indices ]
3904+ for e in range (num_experts )
3905+ ]
3906+ else :
3907+ return [f"model.layers.{ hf_layer_indices } .mlp.experts.{ e } .{ expert_subpath_template } " for e in range (num_experts )]
3908+
3909+ layer_map = {
3910+ f"{ mt_layer_path } -pre_self_attention_layer_norm-scale" : get_hf_key ("input_layernorm.weight" ),
3911+ f"{ mt_layer_path } -post_self_attention_layer_norm-scale" : get_hf_key ("post_attention_layernorm.weight" ),
3912+ # Attention
3913+ f"{ mt_layer_path } -self_attention-wq_a-kernel" : get_hf_key ("self_attn.q_a_proj.weight" ),
3914+ f"{ mt_layer_path } -self_attention-q_norm-scale" : get_hf_key ("self_attn.q_a_norm.weight" ),
3915+ f"{ mt_layer_path } -self_attention-wq_b-kernel" : get_hf_key ("self_attn.q_b_proj.weight" ),
3916+ f"{ mt_layer_path } -self_attention-wkv-kernel" : get_hf_key ("self_attn.kv_proj.weight" ),
3917+ f"{ mt_layer_path } -self_attention-kv_norm-scale" : get_hf_key ("self_attn.kv_norm.weight" ),
3918+ f"{ mt_layer_path } -self_attention-sinks" : get_hf_key ("self_attn.sinks" ),
3919+ f"{ mt_layer_path } -self_attention-o_a_proj-kernel" : get_hf_key ("self_attn.o_a_proj.weight" ),
3920+ f"{ mt_layer_path } -self_attention-o_b_proj-kernel" : get_hf_key ("self_attn.o_b_proj.weight" ),
3921+ # mHC Attention
3922+ f"{ mt_layer_path } -mhc_attention-mhc_norm-scale" : None ,
3923+ f"{ mt_layer_path } -mhc_attention-pre_alpha" : get_hf_key ("attn_hc.fn" ),
3924+ f"{ mt_layer_path } -mhc_attention-post_alpha" : get_hf_key ("attn_hc.fn" ),
3925+ f"{ mt_layer_path } -mhc_attention-res_alpha" : get_hf_key ("attn_hc.fn" ),
3926+ f"{ mt_layer_path } -mhc_attention-pre_beta" : get_hf_key ("attn_hc.base" ),
3927+ f"{ mt_layer_path } -mhc_attention-post_beta" : get_hf_key ("attn_hc.base" ),
3928+ f"{ mt_layer_path } -mhc_attention-res_beta" : get_hf_key ("attn_hc.base" ),
3929+ f"{ mt_layer_path } -mhc_attention-pre_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3930+ f"{ mt_layer_path } -mhc_attention-post_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3931+ f"{ mt_layer_path } -mhc_attention-res_alpha_scale" : get_hf_key ("attn_hc.scale" ),
3932+ # mHC MLP
3933+ f"{ mt_layer_path } -mhc_mlp-mhc_norm-scale" : None ,
3934+ f"{ mt_layer_path } -mhc_mlp-pre_alpha" : get_hf_key ("ffn_hc.fn" ),
3935+ f"{ mt_layer_path } -mhc_mlp-post_alpha" : get_hf_key ("ffn_hc.fn" ),
3936+ f"{ mt_layer_path } -mhc_mlp-res_alpha" : get_hf_key ("ffn_hc.fn" ),
3937+ f"{ mt_layer_path } -mhc_mlp-pre_beta" : get_hf_key ("ffn_hc.base" ),
3938+ f"{ mt_layer_path } -mhc_mlp-post_beta" : get_hf_key ("ffn_hc.base" ),
3939+ f"{ mt_layer_path } -mhc_mlp-res_beta" : get_hf_key ("ffn_hc.base" ),
3940+ f"{ mt_layer_path } -mhc_mlp-pre_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3941+ f"{ mt_layer_path } -mhc_mlp-post_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3942+ f"{ mt_layer_path } -mhc_mlp-res_alpha_scale" : get_hf_key ("ffn_hc.scale" ),
3943+ # MoE Block
3944+ f"{ mt_layer_path } -mlp-MoeBlock_0-gate-kernel" : get_hf_key ("mlp.gate.weight" ),
3945+ # Shared Experts
3946+ f"{ mt_layer_path } -mlp-shared_experts-wi_0-kernel" : get_hf_key ("mlp.shared_experts.gate_proj.weight" ),
3947+ f"{ mt_layer_path } -mlp-shared_experts-wi_1-kernel" : get_hf_key ("mlp.shared_experts.up_proj.weight" ),
3948+ f"{ mt_layer_path } -mlp-shared_experts-wo-kernel" : get_hf_key ("mlp.shared_experts.down_proj.weight" ),
3949+ # Stacked Experts
3950+ f"{ mt_layer_path } -mlp-MoeBlock_0-wi_0" : get_hf_expert_keys ("w1.weight" ),
3951+ f"{ mt_layer_path } -mlp-MoeBlock_0-wi_1" : get_hf_expert_keys ("w3.weight" ),
3952+ f"{ mt_layer_path } -mlp-MoeBlock_0-wo" : get_hf_expert_keys ("w2.weight" ),
3953+ }
3954+
3955+ if (is_list and hf_layer_indices [0 ] >= 3 ) or (not is_list and hf_layer_indices >= 3 ):
3956+ layer_map [f"{ mt_layer_path } -mlp-MoeBlock_0-gate-bias" ] = get_hf_key ("mlp.gate.e_score_correction_bias" )
3957+
3958+ first_idx = hf_layer_indices [0 ] if is_list else hf_layer_indices
3959+ if first_idx >= 2 :
3960+ if first_idx % 2 == 0 or first_idx == 2 :
3961+ layer_map .update (
3962+ {
3963+ f"{ mt_layer_path } -self_attention-csa_compressor-kv_proj-kernel" : get_hf_key (
3964+ "self_attn.compressor.kv_proj.weight"
3965+ ),
3966+ f"{ mt_layer_path } -self_attention-csa_compressor-gate_proj-kernel" : get_hf_key (
3967+ "self_attn.compressor.gate_proj.weight"
3968+ ),
3969+ f"{ mt_layer_path } -self_attention-csa_compressor-position_bias" : get_hf_key (
3970+ "self_attn.compressor.position_bias"
3971+ ),
3972+ f"{ mt_layer_path } -self_attention-csa_compressor-kv_norm-scale" : get_hf_key (
3973+ "self_attn.compressor.kv_norm.weight"
3974+ ),
3975+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-gate_proj-kernel" : get_hf_key (
3976+ "self_attn.compressor.indexer.gate_proj.weight"
3977+ ),
3978+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-kv_proj-kernel" : get_hf_key (
3979+ "self_attn.compressor.indexer.kv_proj.weight"
3980+ ),
3981+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-q_proj-kernel" : get_hf_key (
3982+ "self_attn.compressor.indexer.q_b_proj.weight"
3983+ ),
3984+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-weights_proj-kernel" : get_hf_key (
3985+ "self_attn.compressor.indexer.scorer.weights_proj.weight"
3986+ ),
3987+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-position_bias" : get_hf_key (
3988+ "self_attn.compressor.indexer.position_bias"
3989+ ),
3990+ f"{ mt_layer_path } -self_attention-csa_compressor-indexer-kv_norm-scale" : get_hf_key (
3991+ "self_attn.compressor.indexer.kv_norm.weight"
3992+ ),
3993+ }
3994+ )
3995+ else :
3996+ layer_map .update (
3997+ {
3998+ f"{ mt_layer_path } -self_attention-hca_compressor-kv_proj-kernel" : get_hf_key (
3999+ "self_attn.compressor.kv_proj.weight"
4000+ ),
4001+ f"{ mt_layer_path } -self_attention-hca_compressor-gate_proj-kernel" : get_hf_key (
4002+ "self_attn.compressor.gate_proj.weight"
4003+ ),
4004+ f"{ mt_layer_path } -self_attention-hca_compressor-position_bias" : get_hf_key (
4005+ "self_attn.compressor.position_bias"
4006+ ),
4007+ f"{ mt_layer_path } -self_attention-hca_compressor-kv_norm-scale" : get_hf_key (
4008+ "self_attn.compressor.kv_norm.weight"
4009+ ),
4010+ }
4011+ )
4012+
4013+ mapping .update (layer_map )
4014+
4015+ if not scan_layers :
4016+ for i in range (n_layers ):
4017+ add_layer_mapping (f"params-decoder-layers_{ i } " , i )
4018+ else :
4019+ for i in range (3 ):
4020+ add_layer_mapping (f"params-decoder-layers_{ i } " , i )
4021+ add_layer_mapping ("params-decoder-scanned_blocks-layers_0" , list (range (3 , n_layers , 2 )))
4022+ add_layer_mapping ("params-decoder-scanned_blocks-layers_1" , list (range (4 , n_layers , 2 )))
4023+
4024+ for i in range (3 ):
4025+ mapping [f"Tid2EidVar-decoder-layers_{ i } -mlp-MoeBlock_0-tid2eid" ] = f"model.layers.{ i } .mlp.gate.tid2eid"
4026+
4027+ return mapping
4028+
4029+
4030+ def DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN (config , maxtext_config , scan_layers = False , saving_to_hf = False ):
4031+ """Returns hook functions for transforming weights between MaxText and HuggingFace for DeepSeek V4."""
4032+
4033+ def transpose (input_tensor , target_shape = None ):
4034+ return np .transpose (input_tensor )
4035+
4036+ def transpose_stack (input_tensor , target_shape = None ):
4037+ # input_tensor is a list of tensors
4038+ stacked = np .stack (input_tensor , axis = 0 ) # [E, out, in]
4039+ return np .transpose (stacked , (0 , 2 , 1 )) # [E, in, out]
4040+
4041+ def ones_norm (input_tensor , target_shape = None ):
4042+ return np .ones (target_shape , dtype = np .float32 )
4043+
4044+ def identity (input_tensor , target_shape = None ):
4045+ return input_tensor
4046+
4047+ # Reshaping functions for wq_b, wkv, o_a_proj
4048+ def reshape_transpose_wq_b (input_tensor , target_shape = None ):
4049+ # HF: [n_heads * q_head_dim, kv_lora_rank]
4050+ # MaxText: [kv_lora_rank, n_heads, q_head_dim]
4051+ tensor = np .transpose (input_tensor ) # [kv_lora_rank, n_heads * q_head_dim]
4052+ return tensor .reshape (target_shape )
4053+
4054+ def reshape_transpose_wkv (input_tensor , target_shape = None ):
4055+ # HF: [n_kv_heads * (q_head_dim + v_head_dim), kv_lora_rank]
4056+ # MaxText: [kv_lora_rank, n_kv_heads, q_head_dim + v_head_dim]
4057+ tensor = np .transpose (input_tensor )
4058+ return tensor .reshape (target_shape )
4059+
4060+ def reshape_transpose_o_a (input_tensor , target_shape = None ):
4061+ # HF: [n_heads * v_head_dim, kv_lora_rank] (e.g. [8192, 4096])
4062+ # MaxText: [n_heads, v_head_dim, kv_lora_rank] (e.g. [8, 4096, 1024])
4063+ # We must reshape first and then permute (transpose) to get correct ordering.
4064+ num_heads = target_shape [0 ]
4065+ embed_dim = target_shape [1 ]
4066+ kv_lora_rank = target_shape [2 ]
4067+ tensor = input_tensor .reshape ((num_heads , kv_lora_rank , embed_dim ))
4068+ return np .transpose (tensor , (0 , 2 , 1 ))
4069+
4070+ # Functions for mHC split
4071+ def mhc_split_fn_pre (input_tensor , target_shape = None ):
4072+ return np .transpose (input_tensor [0 :4 , :])
4073+
4074+ def mhc_split_fn_post (input_tensor , target_shape = None ):
4075+ return np .transpose (input_tensor [4 :8 , :])
4076+
4077+ def mhc_split_fn_res (input_tensor , target_shape = None ):
4078+ return np .transpose (input_tensor [8 :24 , :])
4079+
4080+ def mhc_split_base_pre (input_tensor , target_shape = None ):
4081+ return input_tensor [0 :4 ]
4082+
4083+ def mhc_split_base_post (input_tensor , target_shape = None ):
4084+ return input_tensor [4 :8 ]
4085+
4086+ def mhc_split_base_res (input_tensor , target_shape = None ):
4087+ return input_tensor [8 :24 ].reshape (target_shape )
4088+
4089+ def mhc_split_scale_pre (input_tensor , target_shape = None ):
4090+ return np .array ([input_tensor [0 ]]).reshape (target_shape )
4091+
4092+ def mhc_split_scale_post (input_tensor , target_shape = None ):
4093+ return np .array ([input_tensor [1 ]]).reshape (target_shape )
4094+
4095+ def mhc_split_scale_res (input_tensor , target_shape = None ):
4096+ return np .array ([input_tensor [2 ]]).reshape (target_shape )
4097+
4098+ mapping = {}
4099+
4100+ # Base mapping logic from original file
4101+ for key , hf_key in DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING (config , maxtext_config , scan_layers ).items ():
4102+ if hf_key is None :
4103+ mapping [key ] = ones_norm
4104+ elif "token_embedder-embedding" in key :
4105+ mapping [key ] = identity
4106+ elif "-wkv-kernel" in key :
4107+ mapping [key ] = reshape_transpose_wkv
4108+ elif "-wq_b-kernel" in key :
4109+ mapping [key ] = reshape_transpose_wq_b
4110+ elif "-o_a_proj-kernel" in key :
4111+ mapping [key ] = reshape_transpose_o_a
4112+ elif "mhc" in key :
4113+ if "pre_alpha" in key and "scale" not in key :
4114+ mapping [key ] = mhc_split_fn_pre
4115+ elif "post_alpha" in key and "scale" not in key :
4116+ mapping [key ] = mhc_split_fn_post
4117+ elif "res_alpha" in key and "scale" not in key :
4118+ mapping [key ] = mhc_split_fn_res
4119+ elif "pre_beta" in key :
4120+ mapping [key ] = mhc_split_base_pre
4121+ elif "post_beta" in key :
4122+ mapping [key ] = mhc_split_base_post
4123+ elif "res_beta" in key :
4124+ mapping [key ] = mhc_split_base_res
4125+ elif "pre_alpha_scale" in key :
4126+ mapping [key ] = mhc_split_scale_pre
4127+ elif "post_alpha_scale" in key :
4128+ mapping [key ] = mhc_split_scale_post
4129+ elif "res_alpha_scale" in key :
4130+ mapping [key ] = mhc_split_scale_res
4131+ elif "position_bias" in key :
4132+ mapping [key ] = identity
4133+ elif "hc_head-hc_fn" in key :
4134+ mapping [key ] = transpose
4135+ elif "hc_head-hc_base" in key or "hc_head-hc_scale" in key :
4136+ mapping [key ] = identity
4137+ elif isinstance (hf_key , list ):
4138+ mapping [key ] = transpose if not saving_to_hf else transpose_stack
4139+ elif "-kernel" in key or "-embedding" in key or "-sinks" in key :
4140+ mapping [key ] = transpose
4141+
4142+ return mapping
4143+
4144+
38734145PARAM_MAPPING = {
38744146 "gemma2-2b" : GEMMA2_MAXTEXT_TO_HF_PARAM_MAPPING ,
38754147 "gemma2-9b" : GEMMA2_MAXTEXT_TO_HF_PARAM_MAPPING ,
@@ -3908,6 +4180,7 @@ def reshape_vision_attn_out(input_tensor, target_shape):
39084180 "deepseek2-16b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
39094181 "deepseek3-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
39104182 "deepseek3.2-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_MAPPING ,
4183+ "deepseek4-284b" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_MAPPING ,
39114184 "gpt-oss-20b" : GPT_OSS_MAXTEXT_TO_HF_PARAM_MAPPING ,
39124185 "gpt-oss-120b" : GPT_OSS_MAXTEXT_TO_HF_PARAM_MAPPING ,
39134186 "qwen3-omni-30b-a3b" : QWEN3_OMNI_MOE_MAXTEXT_TO_HF_PARAM_MAPPING ,
@@ -3960,6 +4233,8 @@ def reshape_vision_attn_out(input_tensor, target_shape):
39604233 "deepseek2-16b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39614234 "deepseek3-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39624235 "deepseek3.2-671b" : DEEPSEEK_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
4236+ "deepseek4-tiny" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
4237+ "deepseek4-284b" : DEEPSEEKV4_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
39634238 "gpt-oss-20b" : GPT_OSS_TO_HF_PARAM_HOOK_FN ,
39644239 "gpt-oss-120b" : GPT_OSS_TO_HF_PARAM_HOOK_FN ,
39654240 "qwen3-omni-30b-a3b" : QWEN3_OMNI_MOE_MAXTEXT_TO_HF_PARAM_HOOK_FN ,
0 commit comments