@@ -4566,6 +4566,14 @@ def set_gguf_parameters(self):
4566
4566
class MambaModel (TextModel ):
4567
4567
model_arch = gguf .MODEL_ARCH .MAMBA
4568
4568
4569
+ def __init__ (self , dir_model : Path , * args , ** kwargs ):
4570
+ # Avoid using AutoConfig for hparams
4571
+ hparams = kwargs .pop ("hparams" , None )
4572
+ if hparams is None :
4573
+ with open (dir_model / "config.json" , "r" , encoding = "utf-8" ) as f :
4574
+ hparams = json .load (f )
4575
+ super ().__init__ (dir_model , * args , hparams = hparams , ** kwargs )
4576
+
4569
4577
def set_vocab (self ):
4570
4578
vocab_size = self .hparams ["vocab_size" ]
4571
4579
# Round vocab size to next multiple of 8
@@ -4640,6 +4648,100 @@ def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iter
4640
4648
return [(new_name , data_torch )]
4641
4649
4642
4650
4651
+ @ModelBase .register ("Mamba2ForCausalLM" )
4652
+ class Mamba2Model (TextModel ):
4653
+ model_arch = gguf .MODEL_ARCH .MAMBA2
4654
+
4655
+ def __init__ (self , dir_model : Path , * args , ** kwargs ):
4656
+ # Avoid using AutoConfig for hparams
4657
+ # It wrongly assumes all Mamba2 models are Mamba-Codestral-7B-v0.1
4658
+ hparams = kwargs .pop ("hparams" , None )
4659
+ if hparams is None :
4660
+ with open (dir_model / "config.json" , "r" , encoding = "utf-8" ) as f :
4661
+ hparams = json .load (f )
4662
+ super ().__init__ (dir_model , * args , hparams = hparams , ** kwargs )
4663
+
4664
+ def set_vocab (self ):
4665
+ vocab_size = self .hparams ["vocab_size" ]
4666
+ # Round vocab size to next multiple of 16
4667
+ pad_vocab = self .hparams .get ("pad_vocab_size_multiple" , 16 )
4668
+ # pad using ceiling division
4669
+ # ref: https://stackoverflow.com/a/17511341/22827863
4670
+ vocab_size = - (vocab_size // - pad_vocab ) * pad_vocab
4671
+ self .hparams ["vocab_size" ] = vocab_size
4672
+
4673
+ if (self .dir_model / "tokenizer.model" ).is_file ():
4674
+ self ._set_vocab_sentencepiece ()
4675
+ elif (self .dir_model / "tokenizer.model.v3" ).is_file ():
4676
+ # mamba-codestral
4677
+ raise NotImplementedError (f"Please rename { self .dir_model / 'tokenizer.model.v3' } to { self .dir_model / 'tokenizer.model' } " )
4678
+ elif (self .dir_model / "tokenizer.json" ).is_file ():
4679
+ self ._set_vocab_gpt2 ()
4680
+ else :
4681
+ # Use the GPT-NeoX tokenizer when no tokenizer files are present
4682
+ self ._set_vocab_builtin ("gpt-neox" , vocab_size )
4683
+
4684
+ def set_gguf_parameters (self ):
4685
+ d_model = self .find_hparam (["hidden_size" , "d_model" , "dim" ])
4686
+ d_conv = self .find_hparam (["conv_kernel" , "d_conv" ], optional = True ) or 4
4687
+ d_inner = self .find_hparam (["intermediate_size" , "d_inner" ], optional = True ) or 2 * d_model
4688
+ d_state = self .find_hparam (["state_size" , "d_state" ], optional = True ) or 128
4689
+ head_dim = self .find_hparam (["head_dim" ], optional = True ) or 64
4690
+ n_group = self .find_hparam (["n_groups" ], optional = True ) or 1
4691
+
4692
+ rms_norm_eps = self .find_hparam (["layer_norm_epsilon" , "rms_norm_eps" ], optional = True ) or 1e-5
4693
+
4694
+ # Fail early for models which don't have a block expansion factor of 2
4695
+ # TODO: does this really matter?
4696
+ assert d_inner == 2 * d_model
4697
+ assert d_inner % head_dim == 0
4698
+
4699
+ self .gguf_writer .add_context_length (2 ** 20 ) # arbitrary value; for those who use the default
4700
+ self .gguf_writer .add_embedding_length (d_model )
4701
+ self .gguf_writer .add_feed_forward_length (0 ) # unused, but seemingly required when loading
4702
+ self .gguf_writer .add_head_count (0 ) # unused, but seemingly required when loading
4703
+ self .gguf_writer .add_block_count (self .block_count )
4704
+ self .gguf_writer .add_ssm_conv_kernel (d_conv )
4705
+ self .gguf_writer .add_ssm_inner_size (d_inner )
4706
+ self .gguf_writer .add_ssm_state_size (d_state )
4707
+ self .gguf_writer .add_ssm_time_step_rank (d_inner // head_dim )
4708
+ self .gguf_writer .add_ssm_group_count (n_group )
4709
+ self .gguf_writer .add_layer_norm_rms_eps (rms_norm_eps )
4710
+ self .gguf_writer .add_file_type (self .ftype )
4711
+
4712
+ def modify_tensors (self , data_torch : Tensor , name : str , bid : int | None ) -> Iterable [tuple [str , Tensor ]]:
4713
+
4714
+ if name .startswith ("model.backbone" ) or name .startswith ("model.lm_head" ):
4715
+ # map Mamba-Codestral-7B-v0.1 tensor names to the names used by Mamba-2
4716
+ name = name .removeprefix ("model." )
4717
+
4718
+ if name .endswith (".dt_bias" ):
4719
+ name = name .rpartition (".dt_bias" )[0 ] + ".dt_proj.bias"
4720
+
4721
+ new_name = self .map_tensor_name (name )
4722
+
4723
+ if self .match_model_tensor_name (new_name , gguf .MODEL_TENSOR .SSM_CONV1D , bid ):
4724
+ data_torch = data_torch .squeeze ()
4725
+ elif any (self .match_model_tensor_name (new_name , t , bid , suffix = "" ) for t in [
4726
+ gguf .MODEL_TENSOR .SSM_A ,
4727
+ gguf .MODEL_TENSOR .SSM_D ,
4728
+ ]):
4729
+ # unsqueeze A to use similar shape semantics as Mamba-1
4730
+ # (D is also unsqueezed, but for more straightforward broadcast internally)
4731
+ data_torch = data_torch .reshape ((* data_torch .shape , 1 ))
4732
+ elif self .match_model_tensor_name (new_name , gguf .MODEL_TENSOR .SSM_NORM , bid ):
4733
+ d_model = self .find_hparam (["hidden_size" , "d_model" , "dim" ])
4734
+ d_inner = self .find_hparam (["intermediate_size" , "d_inner" ], optional = True ) or 2 * d_model
4735
+ n_group = self .hparams .get ("n_groups" , 1 )
4736
+ data_torch = data_torch .reshape ((n_group , d_inner // n_group ))
4737
+
4738
+ if name .endswith (".A_log" ):
4739
+ logger .debug ("A_log --> A ==> " + new_name )
4740
+ data_torch = - torch .exp (data_torch )
4741
+
4742
+ yield (new_name , data_torch )
4743
+
4744
+
4643
4745
@ModelBase .register ("CohereForCausalLM" )
4644
4746
class CommandR2Model (TextModel ):
4645
4747
model_arch = gguf .MODEL_ARCH .COMMAND_R
@@ -6406,12 +6508,20 @@ def get_model_architecture(hparams: dict[str, Any], model_type: ModelType) -> st
6406
6508
# maybe we should fallback to text model's arch in that case, since not many models have both
6407
6509
text_config = hparams .get ("text_config" , {})
6408
6510
vision_config = hparams .get ("vision_config" , {})
6409
- arch = hparams ["architectures" ][0 ]
6511
+ arch = None
6512
+ if (arches := hparams .get ("architectures" )) is not None and len (arches ) > 0 :
6513
+ arch = arches [0 ]
6514
+ elif "ssm_cfg" in hparams :
6515
+ # For non-hf Mamba and Mamba2 models
6516
+ arch = hparams ["ssm_cfg" ].get ("layer" , "Mamba" ) + "ForCausalLM"
6517
+
6410
6518
# if "architectures" is found in the sub-config, use that instead
6411
6519
if model_type == ModelType .TEXT and text_config .get ("architectures" ) is not None :
6412
6520
arch = text_config ["architectures" ][0 ]
6413
6521
elif model_type == ModelType .MMPROJ and vision_config .get ("architectures" ) is not None :
6414
6522
arch = vision_config ["architectures" ][0 ]
6523
+ if arch is None :
6524
+ raise ValueError ("Failed to detect model architecture" )
6415
6525
return arch
6416
6526
6417
6527
0 commit comments