@@ -93,13 +93,15 @@ class ModelBase:
9393 # Mistral format specifics
9494 is_mistral_format : bool = False
9595 disable_mistral_community_chat_template : bool = False
96+ sentence_transformers_dense_modules : bool = False
9697
9798 def __init__ (self , dir_model : Path , ftype : gguf .LlamaFileType , fname_out : Path , * , is_big_endian : bool = False ,
9899 use_temp_file : bool = False , eager : bool = False ,
99100 metadata_override : Path | None = None , model_name : str | None = None ,
100101 split_max_tensors : int = 0 , split_max_size : int = 0 , dry_run : bool = False ,
101102 small_first_shard : bool = False , hparams : dict [str , Any ] | None = None , remote_hf_model_id : str | None = None ,
102- disable_mistral_community_chat_template : bool = False ):
103+ disable_mistral_community_chat_template : bool = False ,
104+ sentence_transformers_dense_modules : bool = False ):
103105 if type (self ) is ModelBase or \
104106 type (self ) is TextModel or \
105107 type (self ) is MmprojModel :
@@ -114,6 +116,7 @@ def __init__(self, dir_model: Path, ftype: gguf.LlamaFileType, fname_out: Path,
114116 self .lazy = not eager or (remote_hf_model_id is not None )
115117 self .dry_run = dry_run
116118 self .remote_hf_model_id = remote_hf_model_id
119+ self .sentence_transformers_dense_modules = sentence_transformers_dense_modules
117120 if remote_hf_model_id is not None :
118121 self .is_safetensors = True
119122
@@ -5256,37 +5259,53 @@ def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iter
52565259class EmbeddingGemma (Gemma3Model ):
52575260 model_arch = gguf .MODEL_ARCH .GEMMA_EMBEDDING
52585261 module_paths = []
5259- dense_tensors = []
5262+ dense_features_dims = {}
52605263
52615264 def __init__ (self , * args , ** kwargs ):
52625265 super ().__init__ (* args , ** kwargs )
5263- # read molues.json to determine if model has Dense layers
5264- module_path = self .dir_model / "modules.json"
5265- if module_path .is_file ():
5266- with open (module_path , encoding = "utf-8" ) as f :
5267- modules = json .load (f )
5268- for mod in modules :
5269- if mod ["type" ] == "sentence_transformers.models.Dense" :
5270- module_path = mod ["path" ]
5271- tensors_file = self .dir_model / module_path / "model.safetensors"
5272- if tensors_file .is_file ():
5273- self .module_paths .append (module_path )
5274-
5266+ if self .sentence_transformers_dense_modules :
5267+ # read molues.json to determine if model has Dense layers
5268+ modules_file = self .dir_model / "modules.json"
5269+ if modules_file .is_file ():
5270+ with open (modules_file , encoding = "utf-8" ) as modules_json_file :
5271+ mods = json .load (modules_json_file )
5272+ for mod in mods :
5273+ if mod ["type" ] == "sentence_transformers.models.Dense" :
5274+ mod_path = mod ["path" ]
5275+ # check if model.safetensors file for Dense layer exists
5276+ model_tensors_file = self .dir_model / mod_path / "model.safetensors"
5277+ if model_tensors_file .is_file ():
5278+ self .module_paths .append (mod_path )
5279+ # read config.json of the Dense layer to get in/out features
5280+ mod_conf_file = self .dir_model / mod_path / "config.json"
5281+ if mod_conf_file .is_file ():
5282+ with open (mod_conf_file , encoding = "utf-8" ) as mod_conf_json_file :
5283+ mod_conf = json .load (mod_conf_json_file )
5284+ # hparams dense_2_feat_out and dense_3_feat_in are required when loading model's dense weights
5285+ prefix = self ._get_dense_prefix (mod_path )
5286+ if (mod_conf ["in_features" ] is not None
5287+ and mod_conf ["out_features" ] is not None ):
5288+ self .dense_features_dims [prefix ] = (mod_conf ["in_features" ], mod_conf ["out_features" ])
52755289
52765290 def generate_extra_tensors (self ) -> Iterable [tuple [str , Tensor ]]:
52775291 from safetensors .torch import load_file
52785292 module_paths = list (self .module_paths )
52795293 for i , module_path in enumerate (module_paths ):
52805294 tensors_file = self .dir_model / module_path / "model.safetensors"
52815295 local_tensors = load_file (tensors_file )
5282- tensor_name = "dense_2" if module_path == "2_Dense" else "dense_3"
5296+ tensor_name = self . _get_dense_prefix ( module_path )
52835297 for name , local_tensor in local_tensors .items ():
52845298 if not name .endswith (".weight" ):
52855299 continue
52865300 orig_name = name .replace ("linear" , tensor_name )
52875301 name = self .map_tensor_name (orig_name )
52885302 yield name , local_tensor .clone ()
52895303
5304+ @staticmethod
5305+ def _get_dense_prefix (module_path ) -> str :
5306+ """Get the tensor name prefix for the Dense layer from module path."""
5307+ tensor_name = "dense_2" if module_path == "2_Dense" else "dense_3"
5308+ return tensor_name
52905309
52915310 def set_gguf_parameters (self ):
52925311 super ().set_gguf_parameters ()
@@ -5303,6 +5322,11 @@ def set_gguf_parameters(self):
53035322 logger .info (f"Using original sliding_window from config: { orig_sliding_window } "
53045323 f"instead of { self .hparams ['sliding_window' ]} " )
53055324 self .gguf_writer .add_sliding_window (orig_sliding_window )
5325+ if self .sentence_transformers_dense_modules :
5326+ for dense , dims in self .dense_features_dims .items ():
5327+ logger .info (f"Setting dense layer { dense } in/out features to { dims } " )
5328+ self .gguf_writer .add_dense_features_dims (dense , dims [0 ], dims [1 ])
5329+ self .gguf_writer .add_pooling_type_opt (False )
53065330
53075331 self ._try_set_pooling_type ()
53085332
@@ -9247,6 +9271,13 @@ def parse_args() -> argparse.Namespace:
92479271 )
92489272 )
92499273
9274+ parser .add_argument (
9275+ "--sentence-transformers-dense-modules" , action = "store_true" ,
9276+ help = ("Whether to include sentence-transformers dense modules."
9277+ "It can be used for sentence-transformers models, like google/embeddinggemma-300m"
9278+ "Default these modules are not included." )
9279+ )
9280+
92509281 args = parser .parse_args ()
92519282 if not args .print_supported_models and args .model is None :
92529283 parser .error ("the following arguments are required: model" )
@@ -9309,9 +9340,13 @@ def main() -> None:
93099340 if args .remote :
93109341 hf_repo_id = args .model
93119342 from huggingface_hub import snapshot_download
9343+ allowed_patterns = ["LICENSE" , "*.json" , "*.md" , "*.txt" , "tokenizer.model" ]
9344+ if args .sentence_transformers_dense_modules :
9345+ # include sentence-transformers dense modules safetensors files
9346+ allowed_patterns .append ("*.safetensors" )
93129347 local_dir = snapshot_download (
93139348 repo_id = hf_repo_id ,
9314- allow_patterns = [ "LICENSE" , "*.json" , "*.md" , "*.txt" , "tokenizer.model" ] )
9349+ allow_patterns = allowed_patterns )
93159350 dir_model = Path (local_dir )
93169351 logger .info (f"Downloaded config and tokenizer to { local_dir } " )
93179352 else :
@@ -9379,7 +9414,8 @@ def main() -> None:
93799414 split_max_tensors = args .split_max_tensors ,
93809415 split_max_size = split_str_to_n_bytes (args .split_max_size ), dry_run = args .dry_run ,
93819416 small_first_shard = args .no_tensor_first_split ,
9382- remote_hf_model_id = hf_repo_id , disable_mistral_community_chat_template = disable_mistral_community_chat_template
9417+ remote_hf_model_id = hf_repo_id , disable_mistral_community_chat_template = disable_mistral_community_chat_template ,
9418+ sentence_transformers_dense_modules = args .sentence_transformers_dense_modules
93839419 )
93849420
93859421 if args .vocab_only :
0 commit comments