From 37f33e1fe01e6d282ba405b4788b41fa847688a3 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sat, 26 Jul 2025 09:51:41 +0530 Subject: [PATCH 01/14] export_to_transformers --- keras_hub/src/models/backbone.py | 18 ++++ keras_hub/src/models/causal_lm.py | 22 +++++ keras_hub/src/tokenizers/tokenizer.py | 16 ++++ .../src/utils/transformers/export/gemma.py | 4 +- .../utils/transformers/export/gemma_test.py | 36 ++++--- .../utils/transformers/export/hf_exporter.py | 96 ++++++++++++++++++- 6 files changed, 175 insertions(+), 17 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index cd4c7ecaf9..e000a42393 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -277,3 +277,21 @@ def load_lora_weights(self, filepath): layer.lora_kernel_a.assign(lora_kernel_a) layer.lora_kernel_b.assign(lora_kernel_b) store.close() + + def export_to_transformers(self, path, verbose=True): + """Export the backbone model to HuggingFace Transformers format. + + This saves the backbone's configuration and weights in a format + compatible with HuggingFace Transformers. For unsupported model + architectures, a ValueError is raised. + + Args: + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + + """ + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_backbone, + ) + + export_backbone(self, path, verbose=verbose) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 0e31d2c5a2..97399de838 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -392,3 +392,25 @@ def postprocess(x): outputs = [postprocess(x) for x in outputs] return self._normalize_generate_outputs(outputs, input_is_scalar) + + def export_to_transformers(self, path, verbose=True): + """Export the full CausalLM model to HuggingFace Transformers format. + + This exports the backbone, tokenizer, and configurations in a format + compatible with HuggingFace Transformers. For unsupported + model architectures, a ValueError is raised. + + Args: + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + + """ + if self.preprocessor is None or self.preprocessor.tokenizer is None: + raise ValueError( + "CausalLM must have a preprocessor with a tokenizer for export" + ) + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_to_safetensors, + ) + + export_to_safetensors(self, path, verbose=verbose) diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index 5e8986a89e..6880531606 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -261,3 +261,19 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from if cls.backbone_cls != backbone_cls: cls = find_subclass(preset, cls, backbone_cls) return loader.load_tokenizer(cls, config_file, **kwargs) + + def export_to_transformers(self, path, verbose=True): + """Export the tokenizer to HuggingFace Transformers format. + + This saves tokenizer assets in a format compatible with HuggingFace + Transformers. + + Args: + path: str. Path to save the exported tokenizer. + verbose: bool. If True, print success messages (default: True). + """ + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, + ) + + export_tokenizer(self, path, verbose=verbose) diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index d401b7675f..d5e2e2b51a 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -11,6 +11,7 @@ def get_gemma_config(backbone): "intermediate_size": backbone.intermediate_dim // 2, "head_dim": backbone.head_dim, "max_position_embeddings": 8192, + "tie_word_embeddings": True, } return hf_config @@ -83,7 +84,4 @@ def get_gemma_weights_map(backbone): "final_normalization" ).weights[0] - # Tie weights, but clone to avoid sharing memory issues - weights_dict["lm_head.weight"] = ops.copy(token_embedding_layer.weights[0]) - return weights_dict diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index ef588b7414..1c8633ce10 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -3,7 +3,8 @@ import numpy as np import torch from sentencepiece import SentencePieceTrainer -from transformers import GemmaForCausalLM +from transformers import GemmaForCausalLM as HFGemmaForCausalLM +from transformers import GemmaModel as HFGemmaModel from transformers import GemmaTokenizer as HFGemmaTokenizer from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone @@ -13,9 +14,6 @@ ) from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.tests.test_case import TestCase -from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_to_safetensors, -) class TestGemmaExport(TestCase): @@ -72,15 +70,27 @@ def test_export_to_hf(self): weights[i] = rng.random(weights[i].shape).astype(weights[i].dtype) keras_model.set_weights(weights) - # Export to Hugging Face format - export_path = os.path.join(self.get_temp_dir(), "export_small_model") - export_to_safetensors(keras_model, export_path) - # Load Hugging Face model and tokenizer - hf_model = GemmaForCausalLM.from_pretrained(export_path) - hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path) + # Export to Hugging Face format using the new methods + export_path_backbone = os.path.join( + self.get_temp_dir(), "export_backbone" + ) + backbone.export_to_transformers(export_path_backbone) + + export_path_tokenizer = os.path.join( + self.get_temp_dir(), "export_tokenizer" + ) + preprocessor.tokenizer.export_to_transformers(export_path_tokenizer) + + export_path_task = os.path.join(self.get_temp_dir(), "export_task") + keras_model.export_to_transformers(export_path_task) + + # Load Hugging Face models and tokenizer + hf_backbone = HFGemmaModel.from_pretrained(export_path_backbone) + hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path_tokenizer) + hf_full_model = HFGemmaForCausalLM.from_pretrained(export_path_task) # Verify configuration - hf_config = hf_model.config + hf_config = hf_backbone.config self.assertEqual( hf_config.vocab_size, backbone.vocabulary_size, @@ -129,12 +139,12 @@ def test_export_to_hf(self): "Tokenizer vocabulary sizes do not match", ) - # Compare generated outputs + # Compare generated outputs using full model prompt = "the quick" keras_output = keras_model.generate(prompt, max_length=20) input_ids = hf_tokenizer.encode(prompt, return_tensors="pt") with torch.no_grad(): - output_ids = hf_model.generate( + output_ids = hf_full_model.generate( input_ids, max_length=20, do_sample=False ) hf_output = hf_tokenizer.decode(output_ids[0], skip_special_tokens=True) diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 9247ba67a6..dc7f12a79d 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -19,7 +19,7 @@ } -def export_to_safetensors(keras_model, path): +def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. It does the following: @@ -32,6 +32,7 @@ def export_to_safetensors(keras_model, path): keras_model: The Keras model to convert. path: str. Path of the directory to which the safetensors file, config and tokenizer will be saved. + verbose: bool. If True, print success messages (default: True). """ backend = keras.config.backend() backbone = keras_model.backbone @@ -96,3 +97,96 @@ def export_to_safetensors(keras_model, path): "is correct and that the vocabulary file is present " "in the original model." ) + + if verbose: + print(f"Model exported successfully to {path}") + + +def export_backbone(backbone, path, verbose=True): + """Export only the backbone model to HuggingFace format. + + Args: + backbone: The Keras backbone model to convert. + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + """ + backend = keras.config.backend() + model_type = backbone.__class__.__name__ + + if model_type not in MODEL_CONFIGS: + raise ValueError(f"Config not implemented for {model_type}") + if model_type not in MODEL_EXPORTERS: + raise ValueError(f"Exporter not implemented for {model_type}") + + # Get config + get_config_fn = MODEL_CONFIGS[model_type] + hf_config = get_config_fn(backbone) + + # Get weights + get_weights_fn = MODEL_EXPORTERS[model_type] + weights_dict = get_weights_fn(backbone) + + if not weights_dict: + raise ValueError("No weights to save.") + + # Save config + os.makedirs(path, exist_ok=True) + config_path = os.path.join(path, "config.json") + with open(config_path, "w") as f: + json.dump(hf_config, f) + + # Save weights based on backend + weights_path = os.path.join(path, "model.safetensors") + if backend == "torch": + from safetensors.torch import save_file + + weights_dict_contiguous = { + k: v.value.contiguous() if hasattr(v, "value") else v.contiguous() + for k, v in weights_dict.items() + } + save_file( + weights_dict_contiguous, weights_path, metadata={"format": "pt"} + ) + elif backend == "tensorflow": + from safetensors.tensorflow import save_file + + save_file(weights_dict, weights_path, metadata={"format": "pt"}) + elif backend == "jax": + from safetensors.flax import save_file + + save_file(weights_dict, weights_path, metadata={"format": "pt"}) + else: + raise ValueError(f"Unsupported backend: {backend}") + + if verbose: + print(f"Backbone exported successfully to {path}") + + +def export_tokenizer(tokenizer, path, verbose=True): + """Export only the tokenizer to HuggingFace format. + + Args: + tokenizer: The Keras tokenizer to convert. + path: str. Path to save the exported tokenizer. + verbose: bool. If True, print success messages (default: True). + """ + os.makedirs(path, exist_ok=True) + + # Save tokenizer assets + tokenizer.save_assets(path) + + # Rename vocabulary file + vocab_spm_path = os.path.join(path, "vocabulary.spm") + tokenizer_model_path = os.path.join(path, "tokenizer.model") + if os.path.exists(vocab_spm_path): + shutil.move(vocab_spm_path, tokenizer_model_path) + else: + warnings.warn( + f"{vocab_spm_path} not found. Tokenizer may not load " + "correctly. Ensure that the tokenizer configuration " + "is correct and that the vocabulary file is present " + "in the original model." + ) + + if verbose: + print(f"Tokenizer exported successfully to {path}") From 9a17cde688d96d905e0f7b64b3285a01c8530c81 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sun, 3 Aug 2025 01:26:38 +0530 Subject: [PATCH 02/14] Address comments --- keras_hub/src/models/causal_lm.py | 10 ++- .../utils/transformers/export/hf_exporter.py | 86 ++----------------- 2 files changed, 13 insertions(+), 83 deletions(-) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 97399de838..b9e560f66c 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -405,9 +405,15 @@ def export_to_transformers(self, path, verbose=True): verbose: bool. If True, print success messages (default: True). """ - if self.preprocessor is None or self.preprocessor.tokenizer is None: + missing = [] + if self.preprocessor is None: + missing.append("preprocessor") + elif self.preprocessor.tokenizer is None: + missing.append("tokenizer") + if missing: raise ValueError( - "CausalLM must have a preprocessor with a tokenizer for export" + "CausalLM must have a preprocessor and a tokenizer for export. " + "Missing: " + " ".join(missing) ) from keras_hub.src.utils.transformers.export.hf_exporter import ( export_to_safetensors, diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index dc7f12a79d..1a6c644008 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -21,90 +21,25 @@ def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. - It does the following: - - Extracts and maps weights from the Keras backbone to safetensors. - - Saves the configuration as 'config.json'. - - Saves weights in 'model.safetensors'. - - Saves tokenizer assets. - + - Exports the backbone (config and weights). + - Exports the tokenizer assets. Args: keras_model: The Keras model to convert. path: str. Path of the directory to which the safetensors file, config and tokenizer will be saved. verbose: bool. If True, print success messages (default: True). """ - backend = keras.config.backend() backbone = keras_model.backbone - model_type = backbone.__class__.__name__ - - if model_type not in MODEL_CONFIGS: - raise ValueError(f"Config not implemented for {model_type}") - - if model_type not in MODEL_EXPORTERS: - raise ValueError(f"Exporter not implemented for {model_type}") - - get_config_fn = MODEL_CONFIGS[model_type] - hf_config = get_config_fn(backbone) - - get_weights_fn = MODEL_EXPORTERS[model_type] - weights_dict = get_weights_fn(backbone) - - if not weights_dict: - raise ValueError("No weights to save.") - - # Save config - os.makedirs(path, exist_ok=True) - config_path = os.path.join(path, "config.json") - with open(config_path, "w") as f: - json.dump(hf_config, f) - - # Save weights based on backend - weights_path = os.path.join(path, "model.safetensors") - if backend == "torch": - from safetensors.torch import save_file - - weights_dict_contiguous = { - k: v.value.contiguous() if hasattr(v, "value") else v.contiguous() - for k, v in weights_dict.items() - } - save_file( - weights_dict_contiguous, weights_path, metadata={"format": "pt"} - ) - elif backend == "tensorflow": - from safetensors.tensorflow import save_file - - save_file(weights_dict, weights_path, metadata={"format": "pt"}) - elif backend == "jax": - from safetensors.flax import save_file - - save_file(weights_dict, weights_path, metadata={"format": "pt"}) - else: - raise ValueError(f"Unsupported backend: {backend}") - - # Save tokenizer assets - keras_model.preprocessor.tokenizer.save_assets(path) - - # Rename vocabulary file - vocab_spm_path = os.path.join(path, "vocabulary.spm") - tokenizer_model_path = os.path.join(path, "tokenizer.model") - if os.path.exists(vocab_spm_path): - shutil.move(vocab_spm_path, tokenizer_model_path) - else: - warnings.warn( - f"{vocab_spm_path} not found. Tokenizer may not load " - "correctly. Ensure that the tokenizer configuration " - "is correct and that the vocabulary file is present " - "in the original model." - ) - + export_backbone(backbone, path, verbose=verbose) + tokenizer = keras_model.preprocessor.tokenizer + export_tokenizer(tokenizer, path, verbose=verbose) if verbose: print(f"Model exported successfully to {path}") def export_backbone(backbone, path, verbose=True): """Export only the backbone model to HuggingFace format. - Args: backbone: The Keras backbone model to convert. path: str. Path to save the exported model. @@ -112,29 +47,23 @@ def export_backbone(backbone, path, verbose=True): """ backend = keras.config.backend() model_type = backbone.__class__.__name__ - if model_type not in MODEL_CONFIGS: raise ValueError(f"Config not implemented for {model_type}") if model_type not in MODEL_EXPORTERS: raise ValueError(f"Exporter not implemented for {model_type}") - # Get config get_config_fn = MODEL_CONFIGS[model_type] hf_config = get_config_fn(backbone) - # Get weights get_weights_fn = MODEL_EXPORTERS[model_type] weights_dict = get_weights_fn(backbone) - if not weights_dict: raise ValueError("No weights to save.") - # Save config os.makedirs(path, exist_ok=True) config_path = os.path.join(path, "config.json") with open(config_path, "w") as f: json.dump(hf_config, f) - # Save weights based on backend weights_path = os.path.join(path, "model.safetensors") if backend == "torch": @@ -157,24 +86,20 @@ def export_backbone(backbone, path, verbose=True): save_file(weights_dict, weights_path, metadata={"format": "pt"}) else: raise ValueError(f"Unsupported backend: {backend}") - if verbose: print(f"Backbone exported successfully to {path}") def export_tokenizer(tokenizer, path, verbose=True): """Export only the tokenizer to HuggingFace format. - Args: tokenizer: The Keras tokenizer to convert. path: str. Path to save the exported tokenizer. verbose: bool. If True, print success messages (default: True). """ os.makedirs(path, exist_ok=True) - # Save tokenizer assets tokenizer.save_assets(path) - # Rename vocabulary file vocab_spm_path = os.path.join(path, "vocabulary.spm") tokenizer_model_path = os.path.join(path, "tokenizer.model") @@ -187,6 +112,5 @@ def export_tokenizer(tokenizer, path, verbose=True): "is correct and that the vocabulary file is present " "in the original model." ) - if verbose: print(f"Tokenizer exported successfully to {path}") From f12c9988a07658b2d2830cb20c73f063ac0891ab Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sun, 3 Aug 2025 23:25:55 +0530 Subject: [PATCH 03/14] Fixes AutoTokenizer and AutoModel compatibility --- .../src/utils/transformers/export/gemma.py | 55 +++++++++++++++++ .../utils/transformers/export/gemma_test.py | 59 ++++++++++++++----- .../utils/transformers/export/hf_exporter.py | 19 ++++++ 3 files changed, 119 insertions(+), 14 deletions(-) diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index d5e2e2b51a..8e7b86b953 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -12,6 +12,10 @@ def get_gemma_config(backbone): "head_dim": backbone.head_dim, "max_position_embeddings": 8192, "tie_word_embeddings": True, + "pad_token_id": 0, + "bos_token_id": 2, + "eos_token_id": 1, + "model_type": "gemma", } return hf_config @@ -85,3 +89,54 @@ def get_gemma_weights_map(backbone): ).weights[0] return weights_dict + + +def get_gemma_tokenizer_config(tokenizer): + tokenizer_config = { + "tokenizer_class": "GemmaTokenizer", + "clean_up_tokenization_spaces": False, + "bos_token": "", + "eos_token": "", + "pad_token": "", + "unk_token": "", + "add_bos_token": True, + "add_eos_token": False, + "model_max_length": 8192, + } + # Get token IDs if available + if hasattr(tokenizer, "token_to_id"): + tokenizer_config.update( + { + "bos_token_id": tokenizer.token_to_id(""), + "eos_token_id": tokenizer.token_to_id(""), + "pad_token_id": tokenizer.token_to_id(""), + "unk_token_id": tokenizer.token_to_id(""), + } + ) + # Add added_tokens_decoder + added_tokens_decoder = {} + special_tokens = ["", "", "", ""] + for token in special_tokens: + token_id = tokenizer.token_to_id(token) + added_tokens_decoder[str(token_id)] = { + "content": token, + "special": True, + "single_word": False, + "lstrip": False, + "rstrip": False, + "normalized": False, + } + # Add user-defined symbols if present + for extra_token in ["", ""]: + if tokenizer.token_to_id(extra_token) is not None: + token_id = tokenizer.token_to_id(extra_token) + added_tokens_decoder[str(token_id)] = { + "content": extra_token, + "special": True, + "single_word": False, + "lstrip": False, + "rstrip": False, + "normalized": False, + } + tokenizer_config["added_tokens_decoder"] = added_tokens_decoder + return tokenizer_config diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 1c8633ce10..86d9803cf5 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -3,9 +3,9 @@ import numpy as np import torch from sentencepiece import SentencePieceTrainer -from transformers import GemmaForCausalLM as HFGemmaForCausalLM -from transformers import GemmaModel as HFGemmaModel -from transformers import GemmaTokenizer as HFGemmaTokenizer +from transformers import AutoModel +from transformers import AutoModelForCausalLM +from transformers import AutoTokenizer from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone from keras_hub.src.models.gemma.gemma_causal_lm import GemmaCausalLM @@ -33,8 +33,8 @@ def test_export_to_hf(self): vocab_size=290, model_type="unigram", pad_id=0, - bos_id=1, - eos_id=2, + bos_id=2, + eos_id=1, unk_id=3, byte_fallback=True, pad_piece="", @@ -42,6 +42,7 @@ def test_export_to_hf(self): eos_piece="", unk_piece="", user_defined_symbols=["", ""], + add_dummy_prefix=False, ) tokenizer = GemmaTokenizer(proto=f"{proto_prefix}.model") @@ -85,9 +86,12 @@ def test_export_to_hf(self): keras_model.export_to_transformers(export_path_task) # Load Hugging Face models and tokenizer - hf_backbone = HFGemmaModel.from_pretrained(export_path_backbone) - hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path_tokenizer) - hf_full_model = HFGemmaForCausalLM.from_pretrained(export_path_task) + hf_backbone = AutoModel.from_pretrained(export_path_backbone) + hf_tokenizer_fast = AutoTokenizer.from_pretrained(export_path_tokenizer) + hf_tokenizer_slow = AutoTokenizer.from_pretrained( + export_path_tokenizer, use_fast=False + ) + hf_full_model = AutoModelForCausalLM.from_pretrained(export_path_task) # Verify configuration hf_config = hf_backbone.config @@ -134,20 +138,47 @@ def test_export_to_hf(self): # Verify tokenizer compatibility self.assertEqual( - hf_tokenizer.vocab_size, + hf_tokenizer_fast.vocab_size, tokenizer.vocabulary_size(), "Tokenizer vocabulary sizes do not match", ) # Compare generated outputs using full model prompt = "the quick" + # Set seed for reproducibility + torch.manual_seed(42) + np.random.seed(42) + # Generate with Keras model keras_output = keras_model.generate(prompt, max_length=20) - input_ids = hf_tokenizer.encode(prompt, return_tensors="pt") + # Generate with HuggingFace model using fast tokenizer + input_ids_fast = hf_tokenizer_fast.encode(prompt, return_tensors="pt") + with torch.no_grad(): + output_ids_fast = hf_full_model.generate( + input_ids_fast, max_length=20, do_sample=False + ) + hf_fast_output = hf_tokenizer_fast.decode( + output_ids_fast[0], skip_special_tokens=True + ) + # Generate with HuggingFace model using slow tokenizer + input_ids_slow = hf_tokenizer_slow.encode(prompt, return_tensors="pt") with torch.no_grad(): - output_ids = hf_full_model.generate( - input_ids, max_length=20, do_sample=False + output_ids_slow = hf_full_model.generate( + input_ids_slow, max_length=20, do_sample=False ) - hf_output = hf_tokenizer.decode(output_ids[0], skip_special_tokens=True) + hf_slow_output = hf_tokenizer_slow.decode( + output_ids_slow[0], skip_special_tokens=True + ) + # Debug print to see the actual outputs + print(f"Keras output: '{keras_output}'") + print(f"HF fast output: '{hf_fast_output}'") + print(f"HF slow output: '{hf_slow_output}'") + self.assertEqual( + keras_output, + hf_fast_output, + "Generated outputs do not match (fast)", + ) self.assertEqual( - keras_output, hf_output, "Generated outputs do not match" + keras_output, + hf_slow_output, + "Generated outputs do not match (slow)", ) diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 1a6c644008..411d7585f7 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -6,6 +6,9 @@ import keras from keras_hub.src.utils.transformers.export.gemma import get_gemma_config +from keras_hub.src.utils.transformers.export.gemma import ( + get_gemma_tokenizer_config, +) from keras_hub.src.utils.transformers.export.gemma import get_gemma_weights_map MODEL_CONFIGS = { @@ -18,6 +21,11 @@ # Add future models here, e.g., "LlamaBackbone": get_llama_weights_map, } +MODEL_TOKENIZER_CONFIGS = { + "GemmaTokenizer": get_gemma_tokenizer_config, + # Add for future models, e.g., "LlamaTokenizer": get_llama_tokenizer_config, +} + def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. @@ -100,6 +108,17 @@ def export_tokenizer(tokenizer, path, verbose=True): os.makedirs(path, exist_ok=True) # Save tokenizer assets tokenizer.save_assets(path) + # Export tokenizer config + tokenizer_type = tokenizer.__class__.__name__ + if tokenizer_type not in MODEL_TOKENIZER_CONFIGS: + raise ValueError( + f"Tokenizer config not implemented for {tokenizer_type}" + ) + get_tokenizer_config_fn = MODEL_TOKENIZER_CONFIGS[tokenizer_type] + tokenizer_config = get_tokenizer_config_fn(tokenizer) + tokenizer_config_path = os.path.join(path, "tokenizer_config.json") + with open(tokenizer_config_path, "w") as f: + json.dump(tokenizer_config, f, indent=4) # Rename vocabulary file vocab_spm_path = os.path.join(path, "vocabulary.spm") tokenizer_model_path = os.path.join(path, "tokenizer.model") From cd4bdffcc46ad0bfa6e8111cbb107cef91e4257f Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Thu, 7 Aug 2025 04:51:49 +0530 Subject: [PATCH 04/14] Add tests --- keras_hub/src/models/backbone.py | 8 +- keras_hub/src/models/backbone_test.py | 31 ++++++ keras_hub/src/models/causal_lm.py | 31 +++--- .../src/models/causal_lm_preprocessor.py | 13 +++ .../src/models/causal_lm_preprocessor_test.py | 51 ++++++++++ keras_hub/src/models/task_test.py | 94 +++++++++++++++++++ keras_hub/src/tokenizers/tokenizer.py | 7 +- keras_hub/src/tokenizers/tokenizer_test.py | 46 +++++++++ .../utils/transformers/export/hf_exporter.py | 27 +----- 9 files changed, 255 insertions(+), 53 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index e000a42393..1912e9a96e 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -278,20 +278,16 @@ def load_lora_weights(self, filepath): layer.lora_kernel_b.assign(lora_kernel_b) store.close() - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the backbone model to HuggingFace Transformers format. - This saves the backbone's configuration and weights in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. - Args: path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). - """ from keras_hub.src.utils.transformers.export.hf_exporter import ( export_backbone, ) - export_backbone(self, path, verbose=verbose) + export_backbone(self, path) diff --git a/keras_hub/src/models/backbone_test.py b/keras_hub/src/models/backbone_test.py index 217addcb95..b1708b10ca 100644 --- a/keras_hub/src/models/backbone_test.py +++ b/keras_hub/src/models/backbone_test.py @@ -5,6 +5,7 @@ from keras_hub.src.models.backbone import Backbone from keras_hub.src.models.bert.bert_backbone import BertBackbone +from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone from keras_hub.src.models.gpt2.gpt2_backbone import GPT2Backbone from keras_hub.src.tests.test_case import TestCase from keras_hub.src.utils.preset_utils import CONFIG_FILE @@ -15,6 +16,18 @@ class TestBackbone(TestCase): + def setUp(self): + # Common config for backbone instantiation in export tests + self.backbone_config = { + "vocabulary_size": 1000, + "num_layers": 2, + "num_query_heads": 4, + "num_key_value_heads": 1, + "hidden_dim": 512, + "intermediate_dim": 1024, + "head_dim": 128, + } + def test_preset_accessors(self): bert_presets = set(BertBackbone.presets.keys()) gpt2_presets = set(GPT2Backbone.presets.keys()) @@ -105,3 +118,21 @@ def test_save_to_preset(self): ref_out = backbone(data) new_out = restored_backbone(data) self.assertAllClose(ref_out, new_out) + + def test_export_supported_model(self): + backbone = GemmaBackbone(**self.backbone_config) + export_path = os.path.join(self.get_temp_dir(), "export_backbone") + backbone.export_to_transformers(export_path) + # Basic check: config file exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + + def test_export_unsupported_model(self): + class UnsupportedBackbone(GemmaBackbone): + pass + + backbone = UnsupportedBackbone(**self.backbone_config) + export_path = os.path.join(self.get_temp_dir(), "unsupported") + with self.assertRaises(ValueError): + backbone.export_to_transformers(export_path) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index b9e560f66c..9eb568edbb 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -393,30 +393,27 @@ def postprocess(x): return self._normalize_generate_outputs(outputs, input_is_scalar) - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the full CausalLM model to HuggingFace Transformers format. - This exports the backbone, tokenizer, and configurations in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. - + If the preprocessor is None, only the backbone is exported. Args: path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). - """ - missing = [] - if self.preprocessor is None: - missing.append("preprocessor") - elif self.preprocessor.tokenizer is None: - missing.append("tokenizer") - if missing: - raise ValueError( - "CausalLM must have a preprocessor and a tokenizer for export. " - "Missing: " + " ".join(missing) - ) from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_to_safetensors, + export_backbone, + ) + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, ) - export_to_safetensors(self, path, verbose=verbose) + export_backbone(self.backbone, path) + if self.preprocessor is not None: + if self.preprocessor.tokenizer is None: + raise ValueError( + "CausalLM preprocessor must have a tokenizer for" + "export if attached." + ) + export_tokenizer(self.preprocessor.tokenizer, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor.py b/keras_hub/src/models/causal_lm_preprocessor.py index 3284e312cd..3362a10ef8 100644 --- a/keras_hub/src/models/causal_lm_preprocessor.py +++ b/keras_hub/src/models/causal_lm_preprocessor.py @@ -180,3 +180,16 @@ def sequence_length(self, value): self._sequence_length = value if self.packer is not None: self.packer.sequence_length = value + + def export_to_transformers(self, path): + """Export the preprocessor(tokenizer) to HuggingFace format. + Args: + path: str. Path to save the exported preprocessor/tokenizer. + """ + if self.tokenizer is None: + raise ValueError("Preprocessor must have a tokenizer for export.") + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, + ) + + export_tokenizer(self.tokenizer, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor_test.py b/keras_hub/src/models/causal_lm_preprocessor_test.py index 8eb411a181..d203dc45bb 100644 --- a/keras_hub/src/models/causal_lm_preprocessor_test.py +++ b/keras_hub/src/models/causal_lm_preprocessor_test.py @@ -1,7 +1,14 @@ +import os + import pytest +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_tokenizer import BertTokenizer from keras_hub.src.models.causal_lm_preprocessor import CausalLMPreprocessor +from keras_hub.src.models.gemma.gemma_causal_lm_preprocessor import ( + GemmaCausalLMPreprocessor, +) +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_causal_lm_preprocessor import ( GPT2CausalLMPreprocessor, ) @@ -10,6 +17,32 @@ class TestCausalLMPreprocessor(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Preprocessor.presets.keys()) @@ -43,3 +76,21 @@ def test_from_preset_errors(self): with self.assertRaises(ValueError): # No loading on a non-keras model. GPT2CausalLMPreprocessor.from_preset("hf://spacy/en_core_web_sm") + + def test_export_supported_preprocessor(self): + tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + preprocessor = GemmaCausalLMPreprocessor(tokenizer=tokenizer) + export_path = os.path.join(self.get_temp_dir(), "export_preprocessor") + preprocessor.export_to_transformers(export_path) + # Basic check: tokenizer config exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_missing_tokenizer(self): + preprocessor = GemmaCausalLMPreprocessor(tokenizer=None) + export_path = os.path.join( + self.get_temp_dir(), "export_missing_tokenizer" + ) + with self.assertRaises(ValueError): + preprocessor.export_to_transformers(export_path) diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index ac4f8def5b..f558221483 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -4,9 +4,16 @@ import keras import numpy as np import pytest +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_text_classifier import BertTextClassifier from keras_hub.src.models.causal_lm import CausalLM +from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone +from keras_hub.src.models.gemma.gemma_causal_lm import GemmaCausalLM +from keras_hub.src.models.gemma.gemma_causal_lm_preprocessor import ( + GemmaCausalLMPreprocessor, +) +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_causal_lm import GPT2CausalLM from keras_hub.src.models.image_classifier import ImageClassifier from keras_hub.src.models.preprocessor import Preprocessor @@ -44,6 +51,46 @@ def __init__(self, preprocessor=None, activation=None, **kwargs): class TestTask(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + self.tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + self.backbone = GemmaBackbone( + vocabulary_size=self.tokenizer.vocabulary_size(), + num_layers=2, + num_query_heads=4, + num_key_value_heads=1, + hidden_dim=512, + intermediate_dim=1024, + head_dim=128, + ) + self.preprocessor = GemmaCausalLMPreprocessor(tokenizer=self.tokenizer) + self.causal_lm = GemmaCausalLM( + backbone=self.backbone, preprocessor=self.preprocessor + ) + def test_preset_accessors(self): bert_presets = set(BertTextClassifier.presets.keys()) gpt2_presets = set(GPT2CausalLM.presets.keys()) @@ -171,3 +218,50 @@ def test_save_to_preset_custom_backbone_and_preprocessor(self): restored_task = ImageClassifier.from_preset(save_dir) actual = restored_task.predict(batch) self.assertAllClose(expected, actual) + + def test_export_attached(self): + export_path = os.path.join(self.get_temp_dir(), "export_attached") + self.causal_lm.export_to_transformers(export_path) + # Basic check: config and tokenizer files exist + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_detached(self): + export_path_backbone = os.path.join( + self.get_temp_dir(), "export_detached_backbone" + ) + export_path_preprocessor = os.path.join( + self.get_temp_dir(), "export_detached_preprocessor" + ) + original_preprocessor = self.causal_lm.preprocessor + self.causal_lm.preprocessor = None + self.causal_lm.export_to_transformers(export_path_backbone) + self.causal_lm.preprocessor = original_preprocessor + self.preprocessor.export_to_transformers(export_path_preprocessor) + # Basic check: backbone has config, no tokenizer; preprocessor has + # tokenizer config + self.assertTrue( + os.path.exists(os.path.join(export_path_backbone, "config.json")) + ) + self.assertFalse( + os.path.exists( + os.path.join(export_path_backbone, "tokenizer_config.json") + ) + ) + self.assertTrue( + os.path.exists( + os.path.join(export_path_preprocessor, "tokenizer_config.json") + ) + ) + + def test_export_missing_tokenizer(self): + self.preprocessor.tokenizer = None + export_path = os.path.join( + self.get_temp_dir(), "export_missing_tokenizer" + ) + with self.assertRaises(ValueError): + self.causal_lm.export_to_transformers(export_path) diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index 6880531606..e8bc76421b 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -262,18 +262,15 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from cls = find_subclass(preset, cls, backbone_cls) return loader.load_tokenizer(cls, config_file, **kwargs) - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the tokenizer to HuggingFace Transformers format. - This saves tokenizer assets in a format compatible with HuggingFace Transformers. - Args: path: str. Path to save the exported tokenizer. - verbose: bool. If True, print success messages (default: True). """ from keras_hub.src.utils.transformers.export.hf_exporter import ( export_tokenizer, ) - export_tokenizer(self, path, verbose=verbose) + export_tokenizer(self, path) diff --git a/keras_hub/src/tokenizers/tokenizer_test.py b/keras_hub/src/tokenizers/tokenizer_test.py index 5c7d840805..954ce4b941 100644 --- a/keras_hub/src/tokenizers/tokenizer_test.py +++ b/keras_hub/src/tokenizers/tokenizer_test.py @@ -3,9 +3,11 @@ import pytest import tensorflow as tf from absl.testing import parameterized +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.albert.albert_tokenizer import AlbertTokenizer from keras_hub.src.models.bert.bert_tokenizer import BertTokenizer +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_tokenizer import GPT2Tokenizer from keras_hub.src.models.roberta.roberta_tokenizer import RobertaTokenizer from keras_hub.src.tests.test_case import TestCase @@ -27,6 +29,32 @@ def detokenize(self, inputs): class TokenizerTest(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Tokenizer.presets.keys()) @@ -113,3 +141,21 @@ def test_save_to_preset(self, cls, preset_name, tokenizer_type): # Check config class. tokenizer_config = load_json(save_dir, TOKENIZER_CONFIG_FILE) self.assertEqual(cls, check_config_class(tokenizer_config)) + + def test_export_supported_tokenizer(self): + tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + export_path = os.path.join(self.get_temp_dir(), "export_tokenizer") + tokenizer.export_to_transformers(export_path) + # Basic check: tokenizer config exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_unsupported_tokenizer(self): + class UnsupportedTokenizer(GemmaTokenizer): + pass + + tokenizer = UnsupportedTokenizer(proto=f"{self.proto_prefix}.model") + export_path = os.path.join(self.get_temp_dir(), "unsupported_tokenizer") + with self.assertRaises(ValueError): + tokenizer.export_to_transformers(export_path) diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 411d7585f7..5a251e701a 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -27,26 +27,7 @@ } -def export_to_safetensors(keras_model, path, verbose=True): - """Converts a Keras model to Hugging Face safetensor format. - It does the following: - - Exports the backbone (config and weights). - - Exports the tokenizer assets. - Args: - keras_model: The Keras model to convert. - path: str. Path of the directory to which the safetensors file, - config and tokenizer will be saved. - verbose: bool. If True, print success messages (default: True). - """ - backbone = keras_model.backbone - export_backbone(backbone, path, verbose=verbose) - tokenizer = keras_model.preprocessor.tokenizer - export_tokenizer(tokenizer, path, verbose=verbose) - if verbose: - print(f"Model exported successfully to {path}") - - -def export_backbone(backbone, path, verbose=True): +def export_backbone(backbone, path): """Export only the backbone model to HuggingFace format. Args: backbone: The Keras backbone model to convert. @@ -94,11 +75,9 @@ def export_backbone(backbone, path, verbose=True): save_file(weights_dict, weights_path, metadata={"format": "pt"}) else: raise ValueError(f"Unsupported backend: {backend}") - if verbose: - print(f"Backbone exported successfully to {path}") -def export_tokenizer(tokenizer, path, verbose=True): +def export_tokenizer(tokenizer, path): """Export only the tokenizer to HuggingFace format. Args: tokenizer: The Keras tokenizer to convert. @@ -131,5 +110,3 @@ def export_tokenizer(tokenizer, path, verbose=True): "is correct and that the vocabulary file is present " "in the original model." ) - if verbose: - print(f"Tokenizer exported successfully to {path}") From ba30d5e99c467dd4f9e5b470f3bc16388d19884f Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Fri, 8 Aug 2025 18:52:17 +0530 Subject: [PATCH 05/14] Add lm_head --- keras_hub/src/models/backbone.py | 2 + keras_hub/src/models/causal_lm.py | 26 ++++++------- .../src/models/causal_lm_preprocessor.py | 3 +- keras_hub/src/models/task_test.py | 15 ++++++++ keras_hub/src/tokenizers/tokenizer.py | 2 + .../src/utils/transformers/export/gemma.py | 20 ++++------ .../utils/transformers/export/gemma_test.py | 6 ++- .../utils/transformers/export/hf_exporter.py | 37 ++++++++++++++++--- 8 files changed, 77 insertions(+), 34 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index 1912e9a96e..55aaec239d 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -280,9 +280,11 @@ def load_lora_weights(self, filepath): def export_to_transformers(self, path): """Export the backbone model to HuggingFace Transformers format. + This saves the backbone's configuration and weights in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. + Args: path: str. Path to save the exported model. """ diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 9eb568edbb..932111f19a 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -395,25 +395,21 @@ def postprocess(x): def export_to_transformers(self, path): """Export the full CausalLM model to HuggingFace Transformers format. + This exports the backbone, tokenizer, and configurations in a format - compatible with HuggingFace Transformers. For unsupported - model architectures, a ValueError is raised. - If the preprocessor is None, only the backbone is exported. + compatible with HuggingFace Transformers. For unsupported model + architectures, a ValueError is raised. + + If the preprocessor is attached (default), both the backbone and + tokenizer are exported. To export only the backbone, set + `self.preprocessor = None` before calling this method, then export the, + preprocessor separately via `preprocessor.export_to_transformers(path)`. + Args: path: str. Path to save the exported model. """ from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_backbone, - ) - from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_tokenizer, + export_to_safetensors, ) - export_backbone(self.backbone, path) - if self.preprocessor is not None: - if self.preprocessor.tokenizer is None: - raise ValueError( - "CausalLM preprocessor must have a tokenizer for" - "export if attached." - ) - export_tokenizer(self.preprocessor.tokenizer, path) + export_to_safetensors(self, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor.py b/keras_hub/src/models/causal_lm_preprocessor.py index 3362a10ef8..1a9ea4c657 100644 --- a/keras_hub/src/models/causal_lm_preprocessor.py +++ b/keras_hub/src/models/causal_lm_preprocessor.py @@ -182,7 +182,8 @@ def sequence_length(self, value): self.packer.sequence_length = value def export_to_transformers(self, path): - """Export the preprocessor(tokenizer) to HuggingFace format. + """Export the preprocessor (tokenizer) to HuggingFace format. + Args: path: str. Path to save the exported preprocessor/tokenizer. """ diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index f558221483..f2d560c859 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -230,6 +230,21 @@ def test_export_attached(self): os.path.exists(os.path.join(export_path, "tokenizer_config.json")) ) + def test_export_attached_with_lm_head(self): + # Since attached export always includes lm_head=True, this test verifies + # the same but explicitly notes it for coverage. + export_path = os.path.join( + self.get_temp_dir(), "export_attached_lm_head" + ) + self.causal_lm.export_to_transformers(export_path) + # Basic check: config and tokenizer files exist + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + def test_export_detached(self): export_path_backbone = os.path.join( self.get_temp_dir(), "export_detached_backbone" diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index e8bc76421b..3a130a7fb6 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -264,8 +264,10 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from def export_to_transformers(self, path): """Export the tokenizer to HuggingFace Transformers format. + This saves tokenizer assets in a format compatible with HuggingFace Transformers. + Args: path: str. Path to save the exported tokenizer. """ diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index 8e7b86b953..e8d615a16a 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -2,6 +2,7 @@ def get_gemma_config(backbone): + token_embedding_layer = backbone.get_layer("token_embedding") hf_config = { "vocab_size": backbone.vocabulary_size, "num_hidden_layers": backbone.num_layers, @@ -11,7 +12,7 @@ def get_gemma_config(backbone): "intermediate_size": backbone.intermediate_dim // 2, "head_dim": backbone.head_dim, "max_position_embeddings": 8192, - "tie_word_embeddings": True, + "tie_word_embeddings": token_embedding_layer.tie_weights, "pad_token_id": 0, "bos_token_id": 2, "eos_token_id": 1, @@ -20,7 +21,7 @@ def get_gemma_config(backbone): return hf_config -def get_gemma_weights_map(backbone): +def get_gemma_weights_map(backbone, include_lm_head=False): weights_dict = {} # Map token embedding @@ -88,6 +89,11 @@ def get_gemma_weights_map(backbone): "final_normalization" ).weights[0] + # Map lm_head if embeddings are not tied + if include_lm_head and not token_embedding_layer.tie_weights: + weights_dict["lm_head.weight"] = ops.transpose( + token_embedding_layer.reverse_embeddings + ) return weights_dict @@ -103,16 +109,6 @@ def get_gemma_tokenizer_config(tokenizer): "add_eos_token": False, "model_max_length": 8192, } - # Get token IDs if available - if hasattr(tokenizer, "token_to_id"): - tokenizer_config.update( - { - "bos_token_id": tokenizer.token_to_id(""), - "eos_token_id": tokenizer.token_to_id(""), - "pad_token_id": tokenizer.token_to_id(""), - "unk_token_id": tokenizer.token_to_id(""), - } - ) # Add added_tokens_decoder added_tokens_decoder = {} special_tokens = ["", "", "", ""] diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 86d9803cf5..32cf76cdc9 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -135,7 +135,11 @@ def test_export_to_hf(self): 8192, "Max position embeddings do not match", ) - + self.assertEqual( + hf_config.tie_word_embeddings, + backbone.token_embedding.tie_weights, + "Tie word embeddings do not match", + ) # Verify tokenizer compatibility self.assertEqual( hf_tokenizer_fast.vocab_size, diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 5a251e701a..c27369f0e9 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -27,12 +27,13 @@ } -def export_backbone(backbone, path): - """Export only the backbone model to HuggingFace format. +def export_backbone(backbone, path, include_lm_head=False): + """Export the backbone model to HuggingFace format. + Args: backbone: The Keras backbone model to convert. path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). + include_lm_head: bool. If True, include lm_head weights if applicable. """ backend = keras.config.backend() model_type = backbone.__class__.__name__ @@ -45,7 +46,7 @@ def export_backbone(backbone, path): hf_config = get_config_fn(backbone) # Get weights get_weights_fn = MODEL_EXPORTERS[model_type] - weights_dict = get_weights_fn(backbone) + weights_dict = get_weights_fn(backbone, include_lm_head=include_lm_head) if not weights_dict: raise ValueError("No weights to save.") # Save config @@ -79,10 +80,10 @@ def export_backbone(backbone, path): def export_tokenizer(tokenizer, path): """Export only the tokenizer to HuggingFace format. + Args: tokenizer: The Keras tokenizer to convert. path: str. Path to save the exported tokenizer. - verbose: bool. If True, print success messages (default: True). """ os.makedirs(path, exist_ok=True) # Save tokenizer assets @@ -110,3 +111,29 @@ def export_tokenizer(tokenizer, path): "is correct and that the vocabulary file is present " "in the original model." ) + + +def export_to_safetensors(keras_model, path): + """Converts a Keras model to Hugging Face safetensor format. + + It does the following: + - Exports the backbone (config and weights). + - Exports the tokenizer assets. + + Args: + keras_model: The Keras model to convert. + path: str. Path of the directory to which the safetensors file, + config and tokenizer will be saved. + """ + backbone = keras_model.backbone + export_backbone(backbone, path, include_lm_head=True) + if ( + keras_model.preprocessor is not None + and keras_model.preprocessor.tokenizer is None + ): + raise ValueError( + "CausalLM preprocessor must have a tokenizer for export " + "if attached." + ) + if keras_model.preprocessor is not None: + export_tokenizer(keras_model.preprocessor.tokenizer, path) From 21ebaa30868abf7c34f6d30b5105d1a254233b3b Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sat, 26 Jul 2025 09:51:41 +0530 Subject: [PATCH 06/14] export_to_transformers --- keras_hub/src/models/backbone.py | 18 ++++ keras_hub/src/models/causal_lm.py | 22 +++++ keras_hub/src/tokenizers/tokenizer.py | 16 ++++ .../src/utils/transformers/export/gemma.py | 4 +- .../utils/transformers/export/gemma_test.py | 41 +++++--- .../utils/transformers/export/hf_exporter.py | 96 ++++++++++++++++++- 6 files changed, 178 insertions(+), 19 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index cd4c7ecaf9..e000a42393 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -277,3 +277,21 @@ def load_lora_weights(self, filepath): layer.lora_kernel_a.assign(lora_kernel_a) layer.lora_kernel_b.assign(lora_kernel_b) store.close() + + def export_to_transformers(self, path, verbose=True): + """Export the backbone model to HuggingFace Transformers format. + + This saves the backbone's configuration and weights in a format + compatible with HuggingFace Transformers. For unsupported model + architectures, a ValueError is raised. + + Args: + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + + """ + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_backbone, + ) + + export_backbone(self, path, verbose=verbose) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 0e31d2c5a2..97399de838 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -392,3 +392,25 @@ def postprocess(x): outputs = [postprocess(x) for x in outputs] return self._normalize_generate_outputs(outputs, input_is_scalar) + + def export_to_transformers(self, path, verbose=True): + """Export the full CausalLM model to HuggingFace Transformers format. + + This exports the backbone, tokenizer, and configurations in a format + compatible with HuggingFace Transformers. For unsupported + model architectures, a ValueError is raised. + + Args: + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + + """ + if self.preprocessor is None or self.preprocessor.tokenizer is None: + raise ValueError( + "CausalLM must have a preprocessor with a tokenizer for export" + ) + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_to_safetensors, + ) + + export_to_safetensors(self, path, verbose=verbose) diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index 5e8986a89e..6880531606 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -261,3 +261,19 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from if cls.backbone_cls != backbone_cls: cls = find_subclass(preset, cls, backbone_cls) return loader.load_tokenizer(cls, config_file, **kwargs) + + def export_to_transformers(self, path, verbose=True): + """Export the tokenizer to HuggingFace Transformers format. + + This saves tokenizer assets in a format compatible with HuggingFace + Transformers. + + Args: + path: str. Path to save the exported tokenizer. + verbose: bool. If True, print success messages (default: True). + """ + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, + ) + + export_tokenizer(self, path, verbose=verbose) diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index d401b7675f..d5e2e2b51a 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -11,6 +11,7 @@ def get_gemma_config(backbone): "intermediate_size": backbone.intermediate_dim // 2, "head_dim": backbone.head_dim, "max_position_embeddings": 8192, + "tie_word_embeddings": True, } return hf_config @@ -83,7 +84,4 @@ def get_gemma_weights_map(backbone): "final_normalization" ).weights[0] - # Tie weights, but clone to avoid sharing memory issues - weights_dict["lm_head.weight"] = ops.copy(token_embedding_layer.weights[0]) - return weights_dict diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index fef44446a3..21d2a4736e 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -2,7 +2,8 @@ import numpy as np from sentencepiece import SentencePieceTrainer -from transformers import GemmaForCausalLM +from transformers import GemmaForCausalLM as HFGemmaForCausalLM +from transformers import GemmaModel as HFGemmaModel from transformers import GemmaTokenizer as HFGemmaTokenizer from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone @@ -12,9 +13,6 @@ ) from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.tests.test_case import TestCase -from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_to_safetensors, -) class TestGemmaExport(TestCase): @@ -71,15 +69,27 @@ def test_export_to_hf(self): weights[i] = rng.random(weights[i].shape).astype(weights[i].dtype) keras_model.set_weights(weights) - # Export to Hugging Face format - export_path = os.path.join(self.get_temp_dir(), "export_small_model") - export_to_safetensors(keras_model, export_path) - # Load Hugging Face model and tokenizer - hf_model = GemmaForCausalLM.from_pretrained(export_path) - hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path) + # Export to Hugging Face format using the new methods + export_path_backbone = os.path.join( + self.get_temp_dir(), "export_backbone" + ) + backbone.export_to_transformers(export_path_backbone) + + export_path_tokenizer = os.path.join( + self.get_temp_dir(), "export_tokenizer" + ) + preprocessor.tokenizer.export_to_transformers(export_path_tokenizer) + + export_path_task = os.path.join(self.get_temp_dir(), "export_task") + keras_model.export_to_transformers(export_path_task) + + # Load Hugging Face models and tokenizer + hf_backbone = HFGemmaModel.from_pretrained(export_path_backbone) + hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path_tokenizer) + hf_full_model = HFGemmaForCausalLM.from_pretrained(export_path_task) # Verify configuration - hf_config = hf_model.config + hf_config = hf_backbone.config self.assertEqual( hf_config.vocab_size, backbone.vocabulary_size, @@ -128,13 +138,14 @@ def test_export_to_hf(self): "Tokenizer vocabulary sizes do not match", ) - # Compare generated outputs + # Compare generated outputs using full model prompt = "the quick" keras_output = keras_model.generate(prompt, max_length=20) input_ids = hf_tokenizer.encode(prompt, return_tensors="pt") - output_ids = hf_model.generate( - input_ids, max_length=20, do_sample=False - ) + with torch.no_grad(): + output_ids = hf_full_model.generate( + input_ids, max_length=20, do_sample=False + ) hf_output = hf_tokenizer.decode(output_ids[0], skip_special_tokens=True) self.assertEqual( keras_output, hf_output, "Generated outputs do not match" diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 9247ba67a6..dc7f12a79d 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -19,7 +19,7 @@ } -def export_to_safetensors(keras_model, path): +def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. It does the following: @@ -32,6 +32,7 @@ def export_to_safetensors(keras_model, path): keras_model: The Keras model to convert. path: str. Path of the directory to which the safetensors file, config and tokenizer will be saved. + verbose: bool. If True, print success messages (default: True). """ backend = keras.config.backend() backbone = keras_model.backbone @@ -96,3 +97,96 @@ def export_to_safetensors(keras_model, path): "is correct and that the vocabulary file is present " "in the original model." ) + + if verbose: + print(f"Model exported successfully to {path}") + + +def export_backbone(backbone, path, verbose=True): + """Export only the backbone model to HuggingFace format. + + Args: + backbone: The Keras backbone model to convert. + path: str. Path to save the exported model. + verbose: bool. If True, print success messages (default: True). + """ + backend = keras.config.backend() + model_type = backbone.__class__.__name__ + + if model_type not in MODEL_CONFIGS: + raise ValueError(f"Config not implemented for {model_type}") + if model_type not in MODEL_EXPORTERS: + raise ValueError(f"Exporter not implemented for {model_type}") + + # Get config + get_config_fn = MODEL_CONFIGS[model_type] + hf_config = get_config_fn(backbone) + + # Get weights + get_weights_fn = MODEL_EXPORTERS[model_type] + weights_dict = get_weights_fn(backbone) + + if not weights_dict: + raise ValueError("No weights to save.") + + # Save config + os.makedirs(path, exist_ok=True) + config_path = os.path.join(path, "config.json") + with open(config_path, "w") as f: + json.dump(hf_config, f) + + # Save weights based on backend + weights_path = os.path.join(path, "model.safetensors") + if backend == "torch": + from safetensors.torch import save_file + + weights_dict_contiguous = { + k: v.value.contiguous() if hasattr(v, "value") else v.contiguous() + for k, v in weights_dict.items() + } + save_file( + weights_dict_contiguous, weights_path, metadata={"format": "pt"} + ) + elif backend == "tensorflow": + from safetensors.tensorflow import save_file + + save_file(weights_dict, weights_path, metadata={"format": "pt"}) + elif backend == "jax": + from safetensors.flax import save_file + + save_file(weights_dict, weights_path, metadata={"format": "pt"}) + else: + raise ValueError(f"Unsupported backend: {backend}") + + if verbose: + print(f"Backbone exported successfully to {path}") + + +def export_tokenizer(tokenizer, path, verbose=True): + """Export only the tokenizer to HuggingFace format. + + Args: + tokenizer: The Keras tokenizer to convert. + path: str. Path to save the exported tokenizer. + verbose: bool. If True, print success messages (default: True). + """ + os.makedirs(path, exist_ok=True) + + # Save tokenizer assets + tokenizer.save_assets(path) + + # Rename vocabulary file + vocab_spm_path = os.path.join(path, "vocabulary.spm") + tokenizer_model_path = os.path.join(path, "tokenizer.model") + if os.path.exists(vocab_spm_path): + shutil.move(vocab_spm_path, tokenizer_model_path) + else: + warnings.warn( + f"{vocab_spm_path} not found. Tokenizer may not load " + "correctly. Ensure that the tokenizer configuration " + "is correct and that the vocabulary file is present " + "in the original model." + ) + + if verbose: + print(f"Tokenizer exported successfully to {path}") From 6fa66b02cddb37bb7837b146f5239f949243f185 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sun, 3 Aug 2025 01:26:38 +0530 Subject: [PATCH 07/14] Address comments --- keras_hub/src/models/causal_lm.py | 10 ++- .../utils/transformers/export/hf_exporter.py | 86 ++----------------- 2 files changed, 13 insertions(+), 83 deletions(-) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 97399de838..b9e560f66c 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -405,9 +405,15 @@ def export_to_transformers(self, path, verbose=True): verbose: bool. If True, print success messages (default: True). """ - if self.preprocessor is None or self.preprocessor.tokenizer is None: + missing = [] + if self.preprocessor is None: + missing.append("preprocessor") + elif self.preprocessor.tokenizer is None: + missing.append("tokenizer") + if missing: raise ValueError( - "CausalLM must have a preprocessor with a tokenizer for export" + "CausalLM must have a preprocessor and a tokenizer for export. " + "Missing: " + " ".join(missing) ) from keras_hub.src.utils.transformers.export.hf_exporter import ( export_to_safetensors, diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index dc7f12a79d..1a6c644008 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -21,90 +21,25 @@ def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. - It does the following: - - Extracts and maps weights from the Keras backbone to safetensors. - - Saves the configuration as 'config.json'. - - Saves weights in 'model.safetensors'. - - Saves tokenizer assets. - + - Exports the backbone (config and weights). + - Exports the tokenizer assets. Args: keras_model: The Keras model to convert. path: str. Path of the directory to which the safetensors file, config and tokenizer will be saved. verbose: bool. If True, print success messages (default: True). """ - backend = keras.config.backend() backbone = keras_model.backbone - model_type = backbone.__class__.__name__ - - if model_type not in MODEL_CONFIGS: - raise ValueError(f"Config not implemented for {model_type}") - - if model_type not in MODEL_EXPORTERS: - raise ValueError(f"Exporter not implemented for {model_type}") - - get_config_fn = MODEL_CONFIGS[model_type] - hf_config = get_config_fn(backbone) - - get_weights_fn = MODEL_EXPORTERS[model_type] - weights_dict = get_weights_fn(backbone) - - if not weights_dict: - raise ValueError("No weights to save.") - - # Save config - os.makedirs(path, exist_ok=True) - config_path = os.path.join(path, "config.json") - with open(config_path, "w") as f: - json.dump(hf_config, f) - - # Save weights based on backend - weights_path = os.path.join(path, "model.safetensors") - if backend == "torch": - from safetensors.torch import save_file - - weights_dict_contiguous = { - k: v.value.contiguous() if hasattr(v, "value") else v.contiguous() - for k, v in weights_dict.items() - } - save_file( - weights_dict_contiguous, weights_path, metadata={"format": "pt"} - ) - elif backend == "tensorflow": - from safetensors.tensorflow import save_file - - save_file(weights_dict, weights_path, metadata={"format": "pt"}) - elif backend == "jax": - from safetensors.flax import save_file - - save_file(weights_dict, weights_path, metadata={"format": "pt"}) - else: - raise ValueError(f"Unsupported backend: {backend}") - - # Save tokenizer assets - keras_model.preprocessor.tokenizer.save_assets(path) - - # Rename vocabulary file - vocab_spm_path = os.path.join(path, "vocabulary.spm") - tokenizer_model_path = os.path.join(path, "tokenizer.model") - if os.path.exists(vocab_spm_path): - shutil.move(vocab_spm_path, tokenizer_model_path) - else: - warnings.warn( - f"{vocab_spm_path} not found. Tokenizer may not load " - "correctly. Ensure that the tokenizer configuration " - "is correct and that the vocabulary file is present " - "in the original model." - ) - + export_backbone(backbone, path, verbose=verbose) + tokenizer = keras_model.preprocessor.tokenizer + export_tokenizer(tokenizer, path, verbose=verbose) if verbose: print(f"Model exported successfully to {path}") def export_backbone(backbone, path, verbose=True): """Export only the backbone model to HuggingFace format. - Args: backbone: The Keras backbone model to convert. path: str. Path to save the exported model. @@ -112,29 +47,23 @@ def export_backbone(backbone, path, verbose=True): """ backend = keras.config.backend() model_type = backbone.__class__.__name__ - if model_type not in MODEL_CONFIGS: raise ValueError(f"Config not implemented for {model_type}") if model_type not in MODEL_EXPORTERS: raise ValueError(f"Exporter not implemented for {model_type}") - # Get config get_config_fn = MODEL_CONFIGS[model_type] hf_config = get_config_fn(backbone) - # Get weights get_weights_fn = MODEL_EXPORTERS[model_type] weights_dict = get_weights_fn(backbone) - if not weights_dict: raise ValueError("No weights to save.") - # Save config os.makedirs(path, exist_ok=True) config_path = os.path.join(path, "config.json") with open(config_path, "w") as f: json.dump(hf_config, f) - # Save weights based on backend weights_path = os.path.join(path, "model.safetensors") if backend == "torch": @@ -157,24 +86,20 @@ def export_backbone(backbone, path, verbose=True): save_file(weights_dict, weights_path, metadata={"format": "pt"}) else: raise ValueError(f"Unsupported backend: {backend}") - if verbose: print(f"Backbone exported successfully to {path}") def export_tokenizer(tokenizer, path, verbose=True): """Export only the tokenizer to HuggingFace format. - Args: tokenizer: The Keras tokenizer to convert. path: str. Path to save the exported tokenizer. verbose: bool. If True, print success messages (default: True). """ os.makedirs(path, exist_ok=True) - # Save tokenizer assets tokenizer.save_assets(path) - # Rename vocabulary file vocab_spm_path = os.path.join(path, "vocabulary.spm") tokenizer_model_path = os.path.join(path, "tokenizer.model") @@ -187,6 +112,5 @@ def export_tokenizer(tokenizer, path, verbose=True): "is correct and that the vocabulary file is present " "in the original model." ) - if verbose: print(f"Tokenizer exported successfully to {path}") From b9c23d66fb74d4d2c60d0a2497482b556cef9c0c Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Sun, 3 Aug 2025 23:25:55 +0530 Subject: [PATCH 08/14] Fixes AutoTokenizer and AutoModel compatibility --- .../src/utils/transformers/export/gemma.py | 55 +++++++++++++++++ .../utils/transformers/export/gemma_test.py | 59 ++++++++++++++----- .../utils/transformers/export/hf_exporter.py | 19 ++++++ 3 files changed, 119 insertions(+), 14 deletions(-) diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index d5e2e2b51a..8e7b86b953 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -12,6 +12,10 @@ def get_gemma_config(backbone): "head_dim": backbone.head_dim, "max_position_embeddings": 8192, "tie_word_embeddings": True, + "pad_token_id": 0, + "bos_token_id": 2, + "eos_token_id": 1, + "model_type": "gemma", } return hf_config @@ -85,3 +89,54 @@ def get_gemma_weights_map(backbone): ).weights[0] return weights_dict + + +def get_gemma_tokenizer_config(tokenizer): + tokenizer_config = { + "tokenizer_class": "GemmaTokenizer", + "clean_up_tokenization_spaces": False, + "bos_token": "", + "eos_token": "", + "pad_token": "", + "unk_token": "", + "add_bos_token": True, + "add_eos_token": False, + "model_max_length": 8192, + } + # Get token IDs if available + if hasattr(tokenizer, "token_to_id"): + tokenizer_config.update( + { + "bos_token_id": tokenizer.token_to_id(""), + "eos_token_id": tokenizer.token_to_id(""), + "pad_token_id": tokenizer.token_to_id(""), + "unk_token_id": tokenizer.token_to_id(""), + } + ) + # Add added_tokens_decoder + added_tokens_decoder = {} + special_tokens = ["", "", "", ""] + for token in special_tokens: + token_id = tokenizer.token_to_id(token) + added_tokens_decoder[str(token_id)] = { + "content": token, + "special": True, + "single_word": False, + "lstrip": False, + "rstrip": False, + "normalized": False, + } + # Add user-defined symbols if present + for extra_token in ["", ""]: + if tokenizer.token_to_id(extra_token) is not None: + token_id = tokenizer.token_to_id(extra_token) + added_tokens_decoder[str(token_id)] = { + "content": extra_token, + "special": True, + "single_word": False, + "lstrip": False, + "rstrip": False, + "normalized": False, + } + tokenizer_config["added_tokens_decoder"] = added_tokens_decoder + return tokenizer_config diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 21d2a4736e..1bcdd5f08c 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -2,9 +2,9 @@ import numpy as np from sentencepiece import SentencePieceTrainer -from transformers import GemmaForCausalLM as HFGemmaForCausalLM -from transformers import GemmaModel as HFGemmaModel -from transformers import GemmaTokenizer as HFGemmaTokenizer +from transformers import AutoModel +from transformers import AutoModelForCausalLM +from transformers import AutoTokenizer from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone from keras_hub.src.models.gemma.gemma_causal_lm import GemmaCausalLM @@ -32,8 +32,8 @@ def test_export_to_hf(self): vocab_size=290, model_type="unigram", pad_id=0, - bos_id=1, - eos_id=2, + bos_id=2, + eos_id=1, unk_id=3, byte_fallback=True, pad_piece="", @@ -41,6 +41,7 @@ def test_export_to_hf(self): eos_piece="", unk_piece="", user_defined_symbols=["", ""], + add_dummy_prefix=False, ) tokenizer = GemmaTokenizer(proto=f"{proto_prefix}.model") @@ -84,9 +85,12 @@ def test_export_to_hf(self): keras_model.export_to_transformers(export_path_task) # Load Hugging Face models and tokenizer - hf_backbone = HFGemmaModel.from_pretrained(export_path_backbone) - hf_tokenizer = HFGemmaTokenizer.from_pretrained(export_path_tokenizer) - hf_full_model = HFGemmaForCausalLM.from_pretrained(export_path_task) + hf_backbone = AutoModel.from_pretrained(export_path_backbone) + hf_tokenizer_fast = AutoTokenizer.from_pretrained(export_path_tokenizer) + hf_tokenizer_slow = AutoTokenizer.from_pretrained( + export_path_tokenizer, use_fast=False + ) + hf_full_model = AutoModelForCausalLM.from_pretrained(export_path_task) # Verify configuration hf_config = hf_backbone.config @@ -133,20 +137,47 @@ def test_export_to_hf(self): # Verify tokenizer compatibility self.assertEqual( - hf_tokenizer.vocab_size, + hf_tokenizer_fast.vocab_size, tokenizer.vocabulary_size(), "Tokenizer vocabulary sizes do not match", ) # Compare generated outputs using full model prompt = "the quick" + # Set seed for reproducibility + torch.manual_seed(42) + np.random.seed(42) + # Generate with Keras model keras_output = keras_model.generate(prompt, max_length=20) - input_ids = hf_tokenizer.encode(prompt, return_tensors="pt") + # Generate with HuggingFace model using fast tokenizer + input_ids_fast = hf_tokenizer_fast.encode(prompt, return_tensors="pt") + with torch.no_grad(): + output_ids_fast = hf_full_model.generate( + input_ids_fast, max_length=20, do_sample=False + ) + hf_fast_output = hf_tokenizer_fast.decode( + output_ids_fast[0], skip_special_tokens=True + ) + # Generate with HuggingFace model using slow tokenizer + input_ids_slow = hf_tokenizer_slow.encode(prompt, return_tensors="pt") with torch.no_grad(): - output_ids = hf_full_model.generate( - input_ids, max_length=20, do_sample=False + output_ids_slow = hf_full_model.generate( + input_ids_slow, max_length=20, do_sample=False ) - hf_output = hf_tokenizer.decode(output_ids[0], skip_special_tokens=True) + hf_slow_output = hf_tokenizer_slow.decode( + output_ids_slow[0], skip_special_tokens=True + ) + # Debug print to see the actual outputs + print(f"Keras output: '{keras_output}'") + print(f"HF fast output: '{hf_fast_output}'") + print(f"HF slow output: '{hf_slow_output}'") + self.assertEqual( + keras_output, + hf_fast_output, + "Generated outputs do not match (fast)", + ) self.assertEqual( - keras_output, hf_output, "Generated outputs do not match" + keras_output, + hf_slow_output, + "Generated outputs do not match (slow)", ) diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 1a6c644008..411d7585f7 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -6,6 +6,9 @@ import keras from keras_hub.src.utils.transformers.export.gemma import get_gemma_config +from keras_hub.src.utils.transformers.export.gemma import ( + get_gemma_tokenizer_config, +) from keras_hub.src.utils.transformers.export.gemma import get_gemma_weights_map MODEL_CONFIGS = { @@ -18,6 +21,11 @@ # Add future models here, e.g., "LlamaBackbone": get_llama_weights_map, } +MODEL_TOKENIZER_CONFIGS = { + "GemmaTokenizer": get_gemma_tokenizer_config, + # Add for future models, e.g., "LlamaTokenizer": get_llama_tokenizer_config, +} + def export_to_safetensors(keras_model, path, verbose=True): """Converts a Keras model to Hugging Face safetensor format. @@ -100,6 +108,17 @@ def export_tokenizer(tokenizer, path, verbose=True): os.makedirs(path, exist_ok=True) # Save tokenizer assets tokenizer.save_assets(path) + # Export tokenizer config + tokenizer_type = tokenizer.__class__.__name__ + if tokenizer_type not in MODEL_TOKENIZER_CONFIGS: + raise ValueError( + f"Tokenizer config not implemented for {tokenizer_type}" + ) + get_tokenizer_config_fn = MODEL_TOKENIZER_CONFIGS[tokenizer_type] + tokenizer_config = get_tokenizer_config_fn(tokenizer) + tokenizer_config_path = os.path.join(path, "tokenizer_config.json") + with open(tokenizer_config_path, "w") as f: + json.dump(tokenizer_config, f, indent=4) # Rename vocabulary file vocab_spm_path = os.path.join(path, "vocabulary.spm") tokenizer_model_path = os.path.join(path, "tokenizer.model") From fefa0b87998dd32984dcdd6409109959df985da2 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Thu, 7 Aug 2025 04:51:49 +0530 Subject: [PATCH 09/14] Add tests --- keras_hub/src/models/backbone.py | 8 +- keras_hub/src/models/backbone_test.py | 31 ++++++ keras_hub/src/models/causal_lm.py | 31 +++--- .../src/models/causal_lm_preprocessor.py | 13 +++ .../src/models/causal_lm_preprocessor_test.py | 51 ++++++++++ keras_hub/src/models/task_test.py | 94 +++++++++++++++++++ keras_hub/src/tokenizers/tokenizer.py | 7 +- keras_hub/src/tokenizers/tokenizer_test.py | 46 +++++++++ .../utils/transformers/export/hf_exporter.py | 27 +----- 9 files changed, 255 insertions(+), 53 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index e000a42393..1912e9a96e 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -278,20 +278,16 @@ def load_lora_weights(self, filepath): layer.lora_kernel_b.assign(lora_kernel_b) store.close() - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the backbone model to HuggingFace Transformers format. - This saves the backbone's configuration and weights in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. - Args: path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). - """ from keras_hub.src.utils.transformers.export.hf_exporter import ( export_backbone, ) - export_backbone(self, path, verbose=verbose) + export_backbone(self, path) diff --git a/keras_hub/src/models/backbone_test.py b/keras_hub/src/models/backbone_test.py index 217addcb95..b1708b10ca 100644 --- a/keras_hub/src/models/backbone_test.py +++ b/keras_hub/src/models/backbone_test.py @@ -5,6 +5,7 @@ from keras_hub.src.models.backbone import Backbone from keras_hub.src.models.bert.bert_backbone import BertBackbone +from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone from keras_hub.src.models.gpt2.gpt2_backbone import GPT2Backbone from keras_hub.src.tests.test_case import TestCase from keras_hub.src.utils.preset_utils import CONFIG_FILE @@ -15,6 +16,18 @@ class TestBackbone(TestCase): + def setUp(self): + # Common config for backbone instantiation in export tests + self.backbone_config = { + "vocabulary_size": 1000, + "num_layers": 2, + "num_query_heads": 4, + "num_key_value_heads": 1, + "hidden_dim": 512, + "intermediate_dim": 1024, + "head_dim": 128, + } + def test_preset_accessors(self): bert_presets = set(BertBackbone.presets.keys()) gpt2_presets = set(GPT2Backbone.presets.keys()) @@ -105,3 +118,21 @@ def test_save_to_preset(self): ref_out = backbone(data) new_out = restored_backbone(data) self.assertAllClose(ref_out, new_out) + + def test_export_supported_model(self): + backbone = GemmaBackbone(**self.backbone_config) + export_path = os.path.join(self.get_temp_dir(), "export_backbone") + backbone.export_to_transformers(export_path) + # Basic check: config file exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + + def test_export_unsupported_model(self): + class UnsupportedBackbone(GemmaBackbone): + pass + + backbone = UnsupportedBackbone(**self.backbone_config) + export_path = os.path.join(self.get_temp_dir(), "unsupported") + with self.assertRaises(ValueError): + backbone.export_to_transformers(export_path) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index b9e560f66c..9eb568edbb 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -393,30 +393,27 @@ def postprocess(x): return self._normalize_generate_outputs(outputs, input_is_scalar) - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the full CausalLM model to HuggingFace Transformers format. - This exports the backbone, tokenizer, and configurations in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. - + If the preprocessor is None, only the backbone is exported. Args: path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). - """ - missing = [] - if self.preprocessor is None: - missing.append("preprocessor") - elif self.preprocessor.tokenizer is None: - missing.append("tokenizer") - if missing: - raise ValueError( - "CausalLM must have a preprocessor and a tokenizer for export. " - "Missing: " + " ".join(missing) - ) from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_to_safetensors, + export_backbone, + ) + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, ) - export_to_safetensors(self, path, verbose=verbose) + export_backbone(self.backbone, path) + if self.preprocessor is not None: + if self.preprocessor.tokenizer is None: + raise ValueError( + "CausalLM preprocessor must have a tokenizer for" + "export if attached." + ) + export_tokenizer(self.preprocessor.tokenizer, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor.py b/keras_hub/src/models/causal_lm_preprocessor.py index 3284e312cd..3362a10ef8 100644 --- a/keras_hub/src/models/causal_lm_preprocessor.py +++ b/keras_hub/src/models/causal_lm_preprocessor.py @@ -180,3 +180,16 @@ def sequence_length(self, value): self._sequence_length = value if self.packer is not None: self.packer.sequence_length = value + + def export_to_transformers(self, path): + """Export the preprocessor(tokenizer) to HuggingFace format. + Args: + path: str. Path to save the exported preprocessor/tokenizer. + """ + if self.tokenizer is None: + raise ValueError("Preprocessor must have a tokenizer for export.") + from keras_hub.src.utils.transformers.export.hf_exporter import ( + export_tokenizer, + ) + + export_tokenizer(self.tokenizer, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor_test.py b/keras_hub/src/models/causal_lm_preprocessor_test.py index 8eb411a181..d203dc45bb 100644 --- a/keras_hub/src/models/causal_lm_preprocessor_test.py +++ b/keras_hub/src/models/causal_lm_preprocessor_test.py @@ -1,7 +1,14 @@ +import os + import pytest +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_tokenizer import BertTokenizer from keras_hub.src.models.causal_lm_preprocessor import CausalLMPreprocessor +from keras_hub.src.models.gemma.gemma_causal_lm_preprocessor import ( + GemmaCausalLMPreprocessor, +) +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_causal_lm_preprocessor import ( GPT2CausalLMPreprocessor, ) @@ -10,6 +17,32 @@ class TestCausalLMPreprocessor(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Preprocessor.presets.keys()) @@ -43,3 +76,21 @@ def test_from_preset_errors(self): with self.assertRaises(ValueError): # No loading on a non-keras model. GPT2CausalLMPreprocessor.from_preset("hf://spacy/en_core_web_sm") + + def test_export_supported_preprocessor(self): + tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + preprocessor = GemmaCausalLMPreprocessor(tokenizer=tokenizer) + export_path = os.path.join(self.get_temp_dir(), "export_preprocessor") + preprocessor.export_to_transformers(export_path) + # Basic check: tokenizer config exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_missing_tokenizer(self): + preprocessor = GemmaCausalLMPreprocessor(tokenizer=None) + export_path = os.path.join( + self.get_temp_dir(), "export_missing_tokenizer" + ) + with self.assertRaises(ValueError): + preprocessor.export_to_transformers(export_path) diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index ac4f8def5b..f558221483 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -4,9 +4,16 @@ import keras import numpy as np import pytest +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_text_classifier import BertTextClassifier from keras_hub.src.models.causal_lm import CausalLM +from keras_hub.src.models.gemma.gemma_backbone import GemmaBackbone +from keras_hub.src.models.gemma.gemma_causal_lm import GemmaCausalLM +from keras_hub.src.models.gemma.gemma_causal_lm_preprocessor import ( + GemmaCausalLMPreprocessor, +) +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_causal_lm import GPT2CausalLM from keras_hub.src.models.image_classifier import ImageClassifier from keras_hub.src.models.preprocessor import Preprocessor @@ -44,6 +51,46 @@ def __init__(self, preprocessor=None, activation=None, **kwargs): class TestTask(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + self.tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + self.backbone = GemmaBackbone( + vocabulary_size=self.tokenizer.vocabulary_size(), + num_layers=2, + num_query_heads=4, + num_key_value_heads=1, + hidden_dim=512, + intermediate_dim=1024, + head_dim=128, + ) + self.preprocessor = GemmaCausalLMPreprocessor(tokenizer=self.tokenizer) + self.causal_lm = GemmaCausalLM( + backbone=self.backbone, preprocessor=self.preprocessor + ) + def test_preset_accessors(self): bert_presets = set(BertTextClassifier.presets.keys()) gpt2_presets = set(GPT2CausalLM.presets.keys()) @@ -171,3 +218,50 @@ def test_save_to_preset_custom_backbone_and_preprocessor(self): restored_task = ImageClassifier.from_preset(save_dir) actual = restored_task.predict(batch) self.assertAllClose(expected, actual) + + def test_export_attached(self): + export_path = os.path.join(self.get_temp_dir(), "export_attached") + self.causal_lm.export_to_transformers(export_path) + # Basic check: config and tokenizer files exist + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_detached(self): + export_path_backbone = os.path.join( + self.get_temp_dir(), "export_detached_backbone" + ) + export_path_preprocessor = os.path.join( + self.get_temp_dir(), "export_detached_preprocessor" + ) + original_preprocessor = self.causal_lm.preprocessor + self.causal_lm.preprocessor = None + self.causal_lm.export_to_transformers(export_path_backbone) + self.causal_lm.preprocessor = original_preprocessor + self.preprocessor.export_to_transformers(export_path_preprocessor) + # Basic check: backbone has config, no tokenizer; preprocessor has + # tokenizer config + self.assertTrue( + os.path.exists(os.path.join(export_path_backbone, "config.json")) + ) + self.assertFalse( + os.path.exists( + os.path.join(export_path_backbone, "tokenizer_config.json") + ) + ) + self.assertTrue( + os.path.exists( + os.path.join(export_path_preprocessor, "tokenizer_config.json") + ) + ) + + def test_export_missing_tokenizer(self): + self.preprocessor.tokenizer = None + export_path = os.path.join( + self.get_temp_dir(), "export_missing_tokenizer" + ) + with self.assertRaises(ValueError): + self.causal_lm.export_to_transformers(export_path) diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index 6880531606..e8bc76421b 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -262,18 +262,15 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from cls = find_subclass(preset, cls, backbone_cls) return loader.load_tokenizer(cls, config_file, **kwargs) - def export_to_transformers(self, path, verbose=True): + def export_to_transformers(self, path): """Export the tokenizer to HuggingFace Transformers format. - This saves tokenizer assets in a format compatible with HuggingFace Transformers. - Args: path: str. Path to save the exported tokenizer. - verbose: bool. If True, print success messages (default: True). """ from keras_hub.src.utils.transformers.export.hf_exporter import ( export_tokenizer, ) - export_tokenizer(self, path, verbose=verbose) + export_tokenizer(self, path) diff --git a/keras_hub/src/tokenizers/tokenizer_test.py b/keras_hub/src/tokenizers/tokenizer_test.py index 5c7d840805..954ce4b941 100644 --- a/keras_hub/src/tokenizers/tokenizer_test.py +++ b/keras_hub/src/tokenizers/tokenizer_test.py @@ -3,9 +3,11 @@ import pytest import tensorflow as tf from absl.testing import parameterized +from sentencepiece import SentencePieceTrainer from keras_hub.src.models.albert.albert_tokenizer import AlbertTokenizer from keras_hub.src.models.bert.bert_tokenizer import BertTokenizer +from keras_hub.src.models.gemma.gemma_tokenizer import GemmaTokenizer from keras_hub.src.models.gpt2.gpt2_tokenizer import GPT2Tokenizer from keras_hub.src.models.roberta.roberta_tokenizer import RobertaTokenizer from keras_hub.src.tests.test_case import TestCase @@ -27,6 +29,32 @@ def detokenize(self, inputs): class TokenizerTest(TestCase): + def setUp(self): + # Common setup for export tests + train_sentences = [ + "The quick brown fox jumped.", + "I like pizza.", + "This is a test.", + ] + self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") + SentencePieceTrainer.train( + sentence_iterator=iter(train_sentences), + model_prefix=self.proto_prefix, + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Tokenizer.presets.keys()) @@ -113,3 +141,21 @@ def test_save_to_preset(self, cls, preset_name, tokenizer_type): # Check config class. tokenizer_config = load_json(save_dir, TOKENIZER_CONFIG_FILE) self.assertEqual(cls, check_config_class(tokenizer_config)) + + def test_export_supported_tokenizer(self): + tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + export_path = os.path.join(self.get_temp_dir(), "export_tokenizer") + tokenizer.export_to_transformers(export_path) + # Basic check: tokenizer config exists + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + + def test_export_unsupported_tokenizer(self): + class UnsupportedTokenizer(GemmaTokenizer): + pass + + tokenizer = UnsupportedTokenizer(proto=f"{self.proto_prefix}.model") + export_path = os.path.join(self.get_temp_dir(), "unsupported_tokenizer") + with self.assertRaises(ValueError): + tokenizer.export_to_transformers(export_path) diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 411d7585f7..5a251e701a 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -27,26 +27,7 @@ } -def export_to_safetensors(keras_model, path, verbose=True): - """Converts a Keras model to Hugging Face safetensor format. - It does the following: - - Exports the backbone (config and weights). - - Exports the tokenizer assets. - Args: - keras_model: The Keras model to convert. - path: str. Path of the directory to which the safetensors file, - config and tokenizer will be saved. - verbose: bool. If True, print success messages (default: True). - """ - backbone = keras_model.backbone - export_backbone(backbone, path, verbose=verbose) - tokenizer = keras_model.preprocessor.tokenizer - export_tokenizer(tokenizer, path, verbose=verbose) - if verbose: - print(f"Model exported successfully to {path}") - - -def export_backbone(backbone, path, verbose=True): +def export_backbone(backbone, path): """Export only the backbone model to HuggingFace format. Args: backbone: The Keras backbone model to convert. @@ -94,11 +75,9 @@ def export_backbone(backbone, path, verbose=True): save_file(weights_dict, weights_path, metadata={"format": "pt"}) else: raise ValueError(f"Unsupported backend: {backend}") - if verbose: - print(f"Backbone exported successfully to {path}") -def export_tokenizer(tokenizer, path, verbose=True): +def export_tokenizer(tokenizer, path): """Export only the tokenizer to HuggingFace format. Args: tokenizer: The Keras tokenizer to convert. @@ -131,5 +110,3 @@ def export_tokenizer(tokenizer, path, verbose=True): "is correct and that the vocabulary file is present " "in the original model." ) - if verbose: - print(f"Tokenizer exported successfully to {path}") From 98d61fa701f79553c94fd194f21adcaffdc72a3b Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Fri, 8 Aug 2025 18:52:17 +0530 Subject: [PATCH 10/14] Add lm_head --- keras_hub/src/models/backbone.py | 2 + keras_hub/src/models/causal_lm.py | 26 ++++++------- .../src/models/causal_lm_preprocessor.py | 3 +- keras_hub/src/models/task_test.py | 15 ++++++++ keras_hub/src/tokenizers/tokenizer.py | 2 + .../src/utils/transformers/export/gemma.py | 20 ++++------ .../utils/transformers/export/gemma_test.py | 6 ++- .../utils/transformers/export/hf_exporter.py | 37 ++++++++++++++++--- 8 files changed, 77 insertions(+), 34 deletions(-) diff --git a/keras_hub/src/models/backbone.py b/keras_hub/src/models/backbone.py index 1912e9a96e..55aaec239d 100644 --- a/keras_hub/src/models/backbone.py +++ b/keras_hub/src/models/backbone.py @@ -280,9 +280,11 @@ def load_lora_weights(self, filepath): def export_to_transformers(self, path): """Export the backbone model to HuggingFace Transformers format. + This saves the backbone's configuration and weights in a format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. + Args: path: str. Path to save the exported model. """ diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 9eb568edbb..932111f19a 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -395,25 +395,21 @@ def postprocess(x): def export_to_transformers(self, path): """Export the full CausalLM model to HuggingFace Transformers format. + This exports the backbone, tokenizer, and configurations in a format - compatible with HuggingFace Transformers. For unsupported - model architectures, a ValueError is raised. - If the preprocessor is None, only the backbone is exported. + compatible with HuggingFace Transformers. For unsupported model + architectures, a ValueError is raised. + + If the preprocessor is attached (default), both the backbone and + tokenizer are exported. To export only the backbone, set + `self.preprocessor = None` before calling this method, then export the, + preprocessor separately via `preprocessor.export_to_transformers(path)`. + Args: path: str. Path to save the exported model. """ from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_backbone, - ) - from keras_hub.src.utils.transformers.export.hf_exporter import ( - export_tokenizer, + export_to_safetensors, ) - export_backbone(self.backbone, path) - if self.preprocessor is not None: - if self.preprocessor.tokenizer is None: - raise ValueError( - "CausalLM preprocessor must have a tokenizer for" - "export if attached." - ) - export_tokenizer(self.preprocessor.tokenizer, path) + export_to_safetensors(self, path) diff --git a/keras_hub/src/models/causal_lm_preprocessor.py b/keras_hub/src/models/causal_lm_preprocessor.py index 3362a10ef8..1a9ea4c657 100644 --- a/keras_hub/src/models/causal_lm_preprocessor.py +++ b/keras_hub/src/models/causal_lm_preprocessor.py @@ -182,7 +182,8 @@ def sequence_length(self, value): self.packer.sequence_length = value def export_to_transformers(self, path): - """Export the preprocessor(tokenizer) to HuggingFace format. + """Export the preprocessor (tokenizer) to HuggingFace format. + Args: path: str. Path to save the exported preprocessor/tokenizer. """ diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index f558221483..f2d560c859 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -230,6 +230,21 @@ def test_export_attached(self): os.path.exists(os.path.join(export_path, "tokenizer_config.json")) ) + def test_export_attached_with_lm_head(self): + # Since attached export always includes lm_head=True, this test verifies + # the same but explicitly notes it for coverage. + export_path = os.path.join( + self.get_temp_dir(), "export_attached_lm_head" + ) + self.causal_lm.export_to_transformers(export_path) + # Basic check: config and tokenizer files exist + self.assertTrue( + os.path.exists(os.path.join(export_path, "config.json")) + ) + self.assertTrue( + os.path.exists(os.path.join(export_path, "tokenizer_config.json")) + ) + def test_export_detached(self): export_path_backbone = os.path.join( self.get_temp_dir(), "export_detached_backbone" diff --git a/keras_hub/src/tokenizers/tokenizer.py b/keras_hub/src/tokenizers/tokenizer.py index e8bc76421b..3a130a7fb6 100644 --- a/keras_hub/src/tokenizers/tokenizer.py +++ b/keras_hub/src/tokenizers/tokenizer.py @@ -264,8 +264,10 @@ class like `keras_hub.models.Tokenizer.from_preset()`, or from def export_to_transformers(self, path): """Export the tokenizer to HuggingFace Transformers format. + This saves tokenizer assets in a format compatible with HuggingFace Transformers. + Args: path: str. Path to save the exported tokenizer. """ diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index 8e7b86b953..e8d615a16a 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -2,6 +2,7 @@ def get_gemma_config(backbone): + token_embedding_layer = backbone.get_layer("token_embedding") hf_config = { "vocab_size": backbone.vocabulary_size, "num_hidden_layers": backbone.num_layers, @@ -11,7 +12,7 @@ def get_gemma_config(backbone): "intermediate_size": backbone.intermediate_dim // 2, "head_dim": backbone.head_dim, "max_position_embeddings": 8192, - "tie_word_embeddings": True, + "tie_word_embeddings": token_embedding_layer.tie_weights, "pad_token_id": 0, "bos_token_id": 2, "eos_token_id": 1, @@ -20,7 +21,7 @@ def get_gemma_config(backbone): return hf_config -def get_gemma_weights_map(backbone): +def get_gemma_weights_map(backbone, include_lm_head=False): weights_dict = {} # Map token embedding @@ -88,6 +89,11 @@ def get_gemma_weights_map(backbone): "final_normalization" ).weights[0] + # Map lm_head if embeddings are not tied + if include_lm_head and not token_embedding_layer.tie_weights: + weights_dict["lm_head.weight"] = ops.transpose( + token_embedding_layer.reverse_embeddings + ) return weights_dict @@ -103,16 +109,6 @@ def get_gemma_tokenizer_config(tokenizer): "add_eos_token": False, "model_max_length": 8192, } - # Get token IDs if available - if hasattr(tokenizer, "token_to_id"): - tokenizer_config.update( - { - "bos_token_id": tokenizer.token_to_id(""), - "eos_token_id": tokenizer.token_to_id(""), - "pad_token_id": tokenizer.token_to_id(""), - "unk_token_id": tokenizer.token_to_id(""), - } - ) # Add added_tokens_decoder added_tokens_decoder = {} special_tokens = ["", "", "", ""] diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 1bcdd5f08c..e9699956b9 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -134,7 +134,11 @@ def test_export_to_hf(self): 8192, "Max position embeddings do not match", ) - + self.assertEqual( + hf_config.tie_word_embeddings, + backbone.token_embedding.tie_weights, + "Tie word embeddings do not match", + ) # Verify tokenizer compatibility self.assertEqual( hf_tokenizer_fast.vocab_size, diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 5a251e701a..c27369f0e9 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -27,12 +27,13 @@ } -def export_backbone(backbone, path): - """Export only the backbone model to HuggingFace format. +def export_backbone(backbone, path, include_lm_head=False): + """Export the backbone model to HuggingFace format. + Args: backbone: The Keras backbone model to convert. path: str. Path to save the exported model. - verbose: bool. If True, print success messages (default: True). + include_lm_head: bool. If True, include lm_head weights if applicable. """ backend = keras.config.backend() model_type = backbone.__class__.__name__ @@ -45,7 +46,7 @@ def export_backbone(backbone, path): hf_config = get_config_fn(backbone) # Get weights get_weights_fn = MODEL_EXPORTERS[model_type] - weights_dict = get_weights_fn(backbone) + weights_dict = get_weights_fn(backbone, include_lm_head=include_lm_head) if not weights_dict: raise ValueError("No weights to save.") # Save config @@ -79,10 +80,10 @@ def export_backbone(backbone, path): def export_tokenizer(tokenizer, path): """Export only the tokenizer to HuggingFace format. + Args: tokenizer: The Keras tokenizer to convert. path: str. Path to save the exported tokenizer. - verbose: bool. If True, print success messages (default: True). """ os.makedirs(path, exist_ok=True) # Save tokenizer assets @@ -110,3 +111,29 @@ def export_tokenizer(tokenizer, path): "is correct and that the vocabulary file is present " "in the original model." ) + + +def export_to_safetensors(keras_model, path): + """Converts a Keras model to Hugging Face safetensor format. + + It does the following: + - Exports the backbone (config and weights). + - Exports the tokenizer assets. + + Args: + keras_model: The Keras model to convert. + path: str. Path of the directory to which the safetensors file, + config and tokenizer will be saved. + """ + backbone = keras_model.backbone + export_backbone(backbone, path, include_lm_head=True) + if ( + keras_model.preprocessor is not None + and keras_model.preprocessor.tokenizer is None + ): + raise ValueError( + "CausalLM preprocessor must have a tokenizer for export " + "if attached." + ) + if keras_model.preprocessor is not None: + export_tokenizer(keras_model.preprocessor.tokenizer, path) From 132178fd4634eb957eab36f8e0b6069b6d54fca8 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Fri, 8 Aug 2025 22:07:07 +0530 Subject: [PATCH 11/14] resolve gemma_test --- .../src/utils/transformers/export/gemma_test.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index e9699956b9..3123366001 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -149,25 +149,22 @@ def test_export_to_hf(self): # Compare generated outputs using full model prompt = "the quick" # Set seed for reproducibility - torch.manual_seed(42) - np.random.seed(42) + rng = np.random.default_rng(42) # Generate with Keras model keras_output = keras_model.generate(prompt, max_length=20) # Generate with HuggingFace model using fast tokenizer input_ids_fast = hf_tokenizer_fast.encode(prompt, return_tensors="pt") - with torch.no_grad(): - output_ids_fast = hf_full_model.generate( - input_ids_fast, max_length=20, do_sample=False - ) + output_ids_fast = hf_full_model.generate( + input_ids_fast, max_length=20, do_sample=False + ) hf_fast_output = hf_tokenizer_fast.decode( output_ids_fast[0], skip_special_tokens=True ) # Generate with HuggingFace model using slow tokenizer input_ids_slow = hf_tokenizer_slow.encode(prompt, return_tensors="pt") - with torch.no_grad(): - output_ids_slow = hf_full_model.generate( - input_ids_slow, max_length=20, do_sample=False - ) + output_ids_slow = hf_full_model.generate( + input_ids_slow, max_length=20, do_sample=False + ) hf_slow_output = hf_tokenizer_slow.decode( output_ids_slow[0], skip_special_tokens=True ) From 031c847275ebfd3f094f574823554bebb9d1c178 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Thu, 14 Aug 2025 19:30:14 +0530 Subject: [PATCH 12/14] Address comments and add llama model export support --- keras_hub/src/models/backbone_test.py | 35 ++-- keras_hub/src/models/causal_lm.py | 10 +- .../src/models/causal_lm_preprocessor.py | 2 +- .../src/models/causal_lm_preprocessor_test.py | 34 +--- keras_hub/src/models/task_test.py | 83 ++++------ .../tests/test_data/gemma_export_vocab.spm | Bin 0 -> 242436 bytes .../tests/test_data/llama_export_vocab.spm | Bin 0 -> 242397 bytes keras_hub/src/tokenizers/tokenizer_test.py | 42 ++--- .../src/utils/transformers/export/gemma.py | 24 ++- .../utils/transformers/export/gemma_test.py | 34 +--- .../utils/transformers/export/hf_exporter.py | 29 +++- .../src/utils/transformers/export/llama.py | 117 +++++++++++++ .../utils/transformers/export/llama_test.py | 155 ++++++++++++++++++ .../create_gemma_test_proto.py | 18 ++ .../create_llama_test_proto.py | 18 ++ 15 files changed, 424 insertions(+), 177 deletions(-) create mode 100644 keras_hub/src/tests/test_data/gemma_export_vocab.spm create mode 100644 keras_hub/src/tests/test_data/llama_export_vocab.spm create mode 100644 keras_hub/src/utils/transformers/export/llama.py create mode 100644 keras_hub/src/utils/transformers/export/llama_test.py diff --git a/keras_hub/src/models/backbone_test.py b/keras_hub/src/models/backbone_test.py index b1708b10ca..64d4ad3b92 100644 --- a/keras_hub/src/models/backbone_test.py +++ b/keras_hub/src/models/backbone_test.py @@ -16,18 +16,6 @@ class TestBackbone(TestCase): - def setUp(self): - # Common config for backbone instantiation in export tests - self.backbone_config = { - "vocabulary_size": 1000, - "num_layers": 2, - "num_query_heads": 4, - "num_key_value_heads": 1, - "hidden_dim": 512, - "intermediate_dim": 1024, - "head_dim": 128, - } - def test_preset_accessors(self): bert_presets = set(BertBackbone.presets.keys()) gpt2_presets = set(GPT2Backbone.presets.keys()) @@ -120,7 +108,16 @@ def test_save_to_preset(self): self.assertAllClose(ref_out, new_out) def test_export_supported_model(self): - backbone = GemmaBackbone(**self.backbone_config) + backbone_config = { + "vocabulary_size": 1000, + "num_layers": 2, + "num_query_heads": 4, + "num_key_value_heads": 1, + "hidden_dim": 512, + "intermediate_dim": 1024, + "head_dim": 128, + } + backbone = GemmaBackbone(**backbone_config) export_path = os.path.join(self.get_temp_dir(), "export_backbone") backbone.export_to_transformers(export_path) # Basic check: config file exists @@ -129,10 +126,20 @@ def test_export_supported_model(self): ) def test_export_unsupported_model(self): + backbone_config = { + "vocabulary_size": 1000, + "num_layers": 2, + "num_query_heads": 4, + "num_key_value_heads": 1, + "hidden_dim": 512, + "intermediate_dim": 1024, + "head_dim": 128, + } + class UnsupportedBackbone(GemmaBackbone): pass - backbone = UnsupportedBackbone(**self.backbone_config) + backbone = UnsupportedBackbone(**backbone_config) export_path = os.path.join(self.get_temp_dir(), "unsupported") with self.assertRaises(ValueError): backbone.export_to_transformers(export_path) diff --git a/keras_hub/src/models/causal_lm.py b/keras_hub/src/models/causal_lm.py index 932111f19a..25458c6246 100644 --- a/keras_hub/src/models/causal_lm.py +++ b/keras_hub/src/models/causal_lm.py @@ -396,13 +396,13 @@ def postprocess(x): def export_to_transformers(self, path): """Export the full CausalLM model to HuggingFace Transformers format. - This exports the backbone, tokenizer, and configurations in a format - compatible with HuggingFace Transformers. For unsupported model + This exports the trainable model, tokenizer, and configurations in a + format compatible with HuggingFace Transformers. For unsupported model architectures, a ValueError is raised. - If the preprocessor is attached (default), both the backbone and - tokenizer are exported. To export only the backbone, set - `self.preprocessor = None` before calling this method, then export the, + If the preprocessor is attached (default), both the trainable model and + tokenizer are exported. To export only the trainable model, set + `self.preprocessor = None` before calling this method, then export the preprocessor separately via `preprocessor.export_to_transformers(path)`. Args: diff --git a/keras_hub/src/models/causal_lm_preprocessor.py b/keras_hub/src/models/causal_lm_preprocessor.py index 1a9ea4c657..2bc1f7a3ce 100644 --- a/keras_hub/src/models/causal_lm_preprocessor.py +++ b/keras_hub/src/models/causal_lm_preprocessor.py @@ -182,7 +182,7 @@ def sequence_length(self, value): self.packer.sequence_length = value def export_to_transformers(self, path): - """Export the preprocessor (tokenizer) to HuggingFace format. + """Export the preprocessor to HuggingFace Transformers format. Args: path: str. Path to save the exported preprocessor/tokenizer. diff --git a/keras_hub/src/models/causal_lm_preprocessor_test.py b/keras_hub/src/models/causal_lm_preprocessor_test.py index d203dc45bb..eba8d266bd 100644 --- a/keras_hub/src/models/causal_lm_preprocessor_test.py +++ b/keras_hub/src/models/causal_lm_preprocessor_test.py @@ -1,7 +1,6 @@ import os import pytest -from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_tokenizer import BertTokenizer from keras_hub.src.models.causal_lm_preprocessor import CausalLMPreprocessor @@ -17,32 +16,6 @@ class TestCausalLMPreprocessor(TestCase): - def setUp(self): - # Common setup for export tests - train_sentences = [ - "The quick brown fox jumped.", - "I like pizza.", - "This is a test.", - ] - self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") - SentencePieceTrainer.train( - sentence_iterator=iter(train_sentences), - model_prefix=self.proto_prefix, - vocab_size=290, - model_type="unigram", - pad_id=0, - bos_id=2, - eos_id=1, - unk_id=3, - byte_fallback=True, - pad_piece="", - bos_piece="", - eos_piece="", - unk_piece="", - user_defined_symbols=["", ""], - add_dummy_prefix=False, - ) - def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Preprocessor.presets.keys()) @@ -78,7 +51,12 @@ def test_from_preset_errors(self): GPT2CausalLMPreprocessor.from_preset("hf://spacy/en_core_web_sm") def test_export_supported_preprocessor(self): - tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + proto = os.path.join( + os.path.dirname(__file__), + "../tests/test_data", + "gemma_export_vocab.spm", + ) + tokenizer = GemmaTokenizer(proto=proto) preprocessor = GemmaCausalLMPreprocessor(tokenizer=tokenizer) export_path = os.path.join(self.get_temp_dir(), "export_preprocessor") preprocessor.export_to_transformers(export_path) diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index f2d560c859..f560eee971 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -4,7 +4,6 @@ import keras import numpy as np import pytest -from sentencepiece import SentencePieceTrainer from keras_hub.src.models.bert.bert_text_classifier import BertTextClassifier from keras_hub.src.models.causal_lm import CausalLM @@ -51,46 +50,6 @@ def __init__(self, preprocessor=None, activation=None, **kwargs): class TestTask(TestCase): - def setUp(self): - # Common setup for export tests - train_sentences = [ - "The quick brown fox jumped.", - "I like pizza.", - "This is a test.", - ] - self.proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") - SentencePieceTrainer.train( - sentence_iterator=iter(train_sentences), - model_prefix=self.proto_prefix, - vocab_size=290, - model_type="unigram", - pad_id=0, - bos_id=2, - eos_id=1, - unk_id=3, - byte_fallback=True, - pad_piece="", - bos_piece="", - eos_piece="", - unk_piece="", - user_defined_symbols=["", ""], - add_dummy_prefix=False, - ) - self.tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") - self.backbone = GemmaBackbone( - vocabulary_size=self.tokenizer.vocabulary_size(), - num_layers=2, - num_query_heads=4, - num_key_value_heads=1, - hidden_dim=512, - intermediate_dim=1024, - head_dim=128, - ) - self.preprocessor = GemmaCausalLMPreprocessor(tokenizer=self.tokenizer) - self.causal_lm = GemmaCausalLM( - backbone=self.backbone, preprocessor=self.preprocessor - ) - def test_preset_accessors(self): bert_presets = set(BertTextClassifier.presets.keys()) gpt2_presets = set(GPT2CausalLM.presets.keys()) @@ -219,9 +178,30 @@ def test_save_to_preset_custom_backbone_and_preprocessor(self): actual = restored_task.predict(batch) self.assertAllClose(expected, actual) + def _create_gemma_for_export_tests(self): + proto = os.path.join( + os.path.dirname(__file__), + "../tests/test_data", + "gemma_export_vocab.spm", + ) + tokenizer = GemmaTokenizer(proto=proto) + backbone = GemmaBackbone( + vocabulary_size=tokenizer.vocabulary_size(), + num_layers=2, + num_query_heads=4, + num_key_value_heads=1, + hidden_dim=512, + intermediate_dim=1024, + head_dim=128, + ) + preprocessor = GemmaCausalLMPreprocessor(tokenizer=tokenizer) + causal_lm = GemmaCausalLM(backbone=backbone, preprocessor=preprocessor) + return causal_lm, preprocessor + def test_export_attached(self): + causal_lm, _ = self._create_gemma_for_export_tests() export_path = os.path.join(self.get_temp_dir(), "export_attached") - self.causal_lm.export_to_transformers(export_path) + causal_lm.export_to_transformers(export_path) # Basic check: config and tokenizer files exist self.assertTrue( os.path.exists(os.path.join(export_path, "config.json")) @@ -233,10 +213,11 @@ def test_export_attached(self): def test_export_attached_with_lm_head(self): # Since attached export always includes lm_head=True, this test verifies # the same but explicitly notes it for coverage. + causal_lm, _ = self._create_gemma_for_export_tests() export_path = os.path.join( self.get_temp_dir(), "export_attached_lm_head" ) - self.causal_lm.export_to_transformers(export_path) + causal_lm.export_to_transformers(export_path) # Basic check: config and tokenizer files exist self.assertTrue( os.path.exists(os.path.join(export_path, "config.json")) @@ -246,17 +227,18 @@ def test_export_attached_with_lm_head(self): ) def test_export_detached(self): + causal_lm, preprocessor = self._create_gemma_for_export_tests() export_path_backbone = os.path.join( self.get_temp_dir(), "export_detached_backbone" ) export_path_preprocessor = os.path.join( self.get_temp_dir(), "export_detached_preprocessor" ) - original_preprocessor = self.causal_lm.preprocessor - self.causal_lm.preprocessor = None - self.causal_lm.export_to_transformers(export_path_backbone) - self.causal_lm.preprocessor = original_preprocessor - self.preprocessor.export_to_transformers(export_path_preprocessor) + original_preprocessor = causal_lm.preprocessor + causal_lm.preprocessor = None + causal_lm.export_to_transformers(export_path_backbone) + causal_lm.preprocessor = original_preprocessor + preprocessor.export_to_transformers(export_path_preprocessor) # Basic check: backbone has config, no tokenizer; preprocessor has # tokenizer config self.assertTrue( @@ -274,9 +256,10 @@ def test_export_detached(self): ) def test_export_missing_tokenizer(self): - self.preprocessor.tokenizer = None + causal_lm, preprocessor = self._create_gemma_for_export_tests() + preprocessor.tokenizer = None export_path = os.path.join( self.get_temp_dir(), "export_missing_tokenizer" ) with self.assertRaises(ValueError): - self.causal_lm.export_to_transformers(export_path) + causal_lm.export_to_transformers(export_path) diff --git a/keras_hub/src/tests/test_data/gemma_export_vocab.spm b/keras_hub/src/tests/test_data/gemma_export_vocab.spm new file mode 100644 index 0000000000000000000000000000000000000000..4a33b97013581b39f412e264dc17c1edf018321f GIT binary patch literal 242436 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
  • +1P+Y?xNRr~RHG+cw!FWi~$$os0F)ql?~+ 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

    M=))d@evS>mAod{`-pcxK2xE^x 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 z{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@% zAO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk z{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$j zKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8 z{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5 zfB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG z`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A z|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW z@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K z|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<# z;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e z|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe z!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0` z|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+` zhyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=> z{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci> z5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q% z{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@% 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Լ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 zhyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=> z{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci> z5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q% z{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@% zAO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk z{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$j zKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8 z{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5 zfB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG z`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A z|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW z@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K z|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<# z;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e z|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe z!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+`hyM@%AO1i5fB66K|Kb0` z|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=>{}2Bk{y+SG`2X<#;s3+` zhyM@%AO1i5fB66K|Kb0`|A+q%{~!K8{D1iW@c-fe!~ci>5C0$jKm33A|M36e|HJ=> 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", ""], - add_dummy_prefix=False, - ) - def test_preset_accessors(self): bert_presets = set(BertTokenizer.presets.keys()) gpt2_presets = set(GPT2Tokenizer.presets.keys()) @@ -143,7 +116,12 @@ def test_save_to_preset(self, cls, preset_name, tokenizer_type): self.assertEqual(cls, check_config_class(tokenizer_config)) def test_export_supported_tokenizer(self): - tokenizer = GemmaTokenizer(proto=f"{self.proto_prefix}.model") + proto = os.path.join( + os.path.dirname(__file__), + "../tests/test_data", + "gemma_export_vocab.spm", + ) + tokenizer = GemmaTokenizer(proto=proto) export_path = os.path.join(self.get_temp_dir(), "export_tokenizer") tokenizer.export_to_transformers(export_path) # Basic check: tokenizer config exists @@ -152,10 +130,16 @@ def test_export_supported_tokenizer(self): ) def test_export_unsupported_tokenizer(self): + proto = os.path.join( + os.path.dirname(__file__), + "../tests/test_data", + "gemma_export_vocab.spm", + ) + class UnsupportedTokenizer(GemmaTokenizer): pass - tokenizer = UnsupportedTokenizer(proto=f"{self.proto_prefix}.model") + tokenizer = UnsupportedTokenizer(proto=proto) export_path = os.path.join(self.get_temp_dir(), "unsupported_tokenizer") with self.assertRaises(ValueError): tokenizer.export_to_transformers(export_path) diff --git a/keras_hub/src/utils/transformers/export/gemma.py b/keras_hub/src/utils/transformers/export/gemma.py index e8d615a16a..846e391937 100644 --- a/keras_hub/src/utils/transformers/export/gemma.py +++ b/keras_hub/src/utils/transformers/export/gemma.py @@ -111,23 +111,19 @@ def get_gemma_tokenizer_config(tokenizer): } # Add added_tokens_decoder added_tokens_decoder = {} - special_tokens = ["", "", "", ""] + special_tokens = [ + "", + "", + "", + "", + "", + "", + ] for token in special_tokens: token_id = tokenizer.token_to_id(token) - added_tokens_decoder[str(token_id)] = { - "content": token, - "special": True, - "single_word": False, - "lstrip": False, - "rstrip": False, - "normalized": False, - } - # Add user-defined symbols if present - for extra_token in ["", ""]: - if tokenizer.token_to_id(extra_token) is not None: - token_id = tokenizer.token_to_id(extra_token) + if token_id is not None: added_tokens_decoder[str(token_id)] = { - "content": extra_token, + "content": token, "special": True, "single_word": False, "lstrip": False, diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 3123366001..1627627f90 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -1,7 +1,6 @@ import os import numpy as np -from sentencepiece import SentencePieceTrainer from transformers import AutoModel from transformers import AutoModelForCausalLM from transformers import AutoTokenizer @@ -17,33 +16,12 @@ class TestGemmaExport(TestCase): def test_export_to_hf(self): - # Create a dummy tokenizer - train_sentences = [ - "The quick brown fox jumped.", - "I like pizza.", - "This is a test.", - ] - # TODO:Consider using keras_hub/src/tests/test_data/gemma_test_vocab.spm - # instead of retraining a new vocab here. Will be faster. - proto_prefix = os.path.join(self.get_temp_dir(), "dummy_vocab") - SentencePieceTrainer.train( - sentence_iterator=iter(train_sentences), - model_prefix=proto_prefix, - vocab_size=290, - model_type="unigram", - pad_id=0, - bos_id=2, - eos_id=1, - unk_id=3, - byte_fallback=True, - pad_piece="", - bos_piece="", - eos_piece="", - unk_piece="", - user_defined_symbols=["", ""], - add_dummy_prefix=False, - ) - tokenizer = GemmaTokenizer(proto=f"{proto_prefix}.model") + proto = os.path.join( + os.path.dirname(__file__), + "../../../tests/test_data", + "gemma_export_vocab.spm", + ) + tokenizer = GemmaTokenizer(proto=proto) # Create a small backbone backbone = GemmaBackbone( diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index c27369f0e9..4bdb74e475 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -10,20 +10,29 @@ get_gemma_tokenizer_config, ) from keras_hub.src.utils.transformers.export.gemma import get_gemma_weights_map +from keras_hub.src.utils.transformers.export.llama import get_llama_config +from keras_hub.src.utils.transformers.export.llama import ( + get_llama_tokenizer_config, +) +from keras_hub.src.utils.transformers.export.llama import get_llama_weights_map MODEL_CONFIGS = { "GemmaBackbone": get_gemma_config, - # Add future models here, e.g., "LlamaBackbone": get_llama_config, + "LlamaBackbone": get_llama_config, + # Add for future models, e.g., "MistralBackbone": get_mistral_config } MODEL_EXPORTERS = { "GemmaBackbone": get_gemma_weights_map, - # Add future models here, e.g., "LlamaBackbone": get_llama_weights_map, + "LlamaBackbone": get_llama_weights_map, + # Add for future models, e.g., "MistralBackbone": get_mistral_weights_map } MODEL_TOKENIZER_CONFIGS = { "GemmaTokenizer": get_gemma_tokenizer_config, - # Add for future models, e.g., "LlamaTokenizer": get_llama_tokenizer_config, + "LlamaTokenizer": get_llama_tokenizer_config, + # Add for future models, e.g., "MistralTokenizer": + # get_mistral_tokenizer_config } @@ -38,9 +47,13 @@ def export_backbone(backbone, path, include_lm_head=False): backend = keras.config.backend() model_type = backbone.__class__.__name__ if model_type not in MODEL_CONFIGS: - raise ValueError(f"Config not implemented for {model_type}") + raise ValueError( + f"Export to Transformers format not implemented for {model_type}" + ) if model_type not in MODEL_EXPORTERS: - raise ValueError(f"Exporter not implemented for {model_type}") + raise ValueError( + f"Export to Transformers format not implemented for {model_type}" + ) # Get config get_config_fn = MODEL_CONFIGS[model_type] hf_config = get_config_fn(backbone) @@ -79,7 +92,7 @@ def export_backbone(backbone, path, include_lm_head=False): def export_tokenizer(tokenizer, path): - """Export only the tokenizer to HuggingFace format. + """Export only the tokenizer to HuggingFace Transformers format. Args: tokenizer: The Keras tokenizer to convert. @@ -92,7 +105,7 @@ def export_tokenizer(tokenizer, path): tokenizer_type = tokenizer.__class__.__name__ if tokenizer_type not in MODEL_TOKENIZER_CONFIGS: raise ValueError( - f"Tokenizer config not implemented for {tokenizer_type}" + "Export to Transformers format not implemented for {tokenizer_type}" ) get_tokenizer_config_fn = MODEL_TOKENIZER_CONFIGS[tokenizer_type] tokenizer_config = get_tokenizer_config_fn(tokenizer) @@ -114,7 +127,7 @@ def export_tokenizer(tokenizer, path): def export_to_safetensors(keras_model, path): - """Converts a Keras model to Hugging Face safetensor format. + """Converts a Keras model to Hugging Face Transformers format. It does the following: - Exports the backbone (config and weights). diff --git a/keras_hub/src/utils/transformers/export/llama.py b/keras_hub/src/utils/transformers/export/llama.py new file mode 100644 index 0000000000..70e0bf443b --- /dev/null +++ b/keras_hub/src/utils/transformers/export/llama.py @@ -0,0 +1,117 @@ +import keras.ops as ops + + +def get_llama_config(backbone): + token_embedding_layer = backbone.get_layer("token_embedding") + hf_config = { + "vocab_size": backbone.vocabulary_size, + "num_hidden_layers": backbone.num_layers, + "num_attention_heads": backbone.num_query_heads, + "num_key_value_heads": backbone.num_key_value_heads, + "hidden_size": backbone.hidden_dim, + "intermediate_size": backbone.intermediate_dim, + "max_position_embeddings": 4096, + "tie_word_embeddings": token_embedding_layer.tie_weights, + "rms_norm_eps": backbone.layer_norm_epsilon, + "rope_theta": backbone.rope_max_wavelength, + "model_type": "llama", + } + return hf_config + + +def get_llama_weights_map(backbone, include_lm_head=False): + weights_dict = {} + # Map token embedding + token_embedding_layer = backbone.token_embedding + weights_dict["model.embed_tokens.weight"] = token_embedding_layer.embeddings + for i in range(backbone.num_layers): + transformer_layer = backbone.transformer_layers[i] + # Pre-attention normalization + weights_dict[f"model.layers.{i}.input_layernorm.weight"] = ( + transformer_layer._self_attention_layernorm.weights[0] + ) + # Attention query projection + query_kernel = ( + transformer_layer._self_attention_layer._query_dense.weights[0] + ) + query_kernel = ops.reshape(query_kernel, (backbone.hidden_dim, -1)) + query_kernel = ops.transpose(query_kernel) + weights_dict[f"model.layers.{i}.self_attn.q_proj.weight"] = query_kernel + # Attention key projection + key_kernel = transformer_layer._self_attention_layer._key_dense.weights[ + 0 + ] + key_kernel = ops.reshape(key_kernel, (backbone.hidden_dim, -1)) + key_kernel = ops.transpose(key_kernel) + weights_dict[f"model.layers.{i}.self_attn.k_proj.weight"] = key_kernel + # Attention value projection + value_kernel = ( + transformer_layer._self_attention_layer._value_dense.weights[0] + ) + value_kernel = ops.reshape(value_kernel, (backbone.hidden_dim, -1)) + value_kernel = ops.transpose(value_kernel) + weights_dict[f"model.layers.{i}.self_attn.v_proj.weight"] = value_kernel + # Attention output projection + out_kernel = ( + transformer_layer._self_attention_layer._output_dense.weights[0] + ) + out_kernel = ops.reshape(out_kernel, (-1, backbone.hidden_dim)) + out_kernel = ops.transpose(out_kernel) + weights_dict[f"model.layers.{i}.self_attn.o_proj.weight"] = out_kernel + # Post-attention normalization + weights_dict[f"model.layers.{i}.post_attention_layernorm.weight"] = ( + transformer_layer._feedforward_layernorm.weights[0] + ) + # MLP gate projection + gate_kernel = transformer_layer._feedforward_gate_dense.weights[0] + weights_dict[f"model.layers.{i}.mlp.gate_proj.weight"] = ops.transpose( + gate_kernel + ) + # MLP up projection + up_kernel = transformer_layer._feedforward_intermediate_dense.weights[0] + weights_dict[f"model.layers.{i}.mlp.up_proj.weight"] = ops.transpose( + up_kernel + ) + # MLP down projection + down_kernel = transformer_layer._feedforward_output_dense.weights[0] + weights_dict[f"model.layers.{i}.mlp.down_proj.weight"] = ops.transpose( + down_kernel + ) + # Map final normalization + weights_dict["model.norm.weight"] = backbone.layer_norm.weights[0] + # Map lm head + if include_lm_head and not token_embedding_layer.tie_weights: + weights_dict["lm_head.weight"] = ops.transpose( + token_embedding_layer.reverse_embeddings + ) + return weights_dict + + +def get_llama_tokenizer_config(tokenizer): + tokenizer_config = { + "tokenizer_class": "LlamaTokenizer", + "clean_up_tokenization_spaces": False, + "bos_token": "", + "eos_token": "", + "pad_token": "", + "unk_token": "", + "add_bos_token": True, + "add_eos_token": False, + "model_max_length": 4096, + } + # Add added_tokens_decoder + added_tokens_decoder = {} + special_tokens = ["", "", "", "", "", ""] + for token in special_tokens: + token_id = tokenizer.token_to_id(token) + if token_id is not None: + added_tokens_decoder[str(token_id)] = { + "content": token, + "special": True, + "single_word": False, + "lstrip": False, + "rstrip": False, + "normalized": False, + } + tokenizer_config["added_tokens_decoder"] = added_tokens_decoder + return tokenizer_config diff --git a/keras_hub/src/utils/transformers/export/llama_test.py b/keras_hub/src/utils/transformers/export/llama_test.py new file mode 100644 index 0000000000..d5776ec3b7 --- /dev/null +++ b/keras_hub/src/utils/transformers/export/llama_test.py @@ -0,0 +1,155 @@ +import os + +import numpy as np +from transformers import AutoModel +from transformers import AutoModelForCausalLM +from transformers import AutoTokenizer + +from keras_hub.src.models.llama.llama_backbone import LlamaBackbone +from keras_hub.src.models.llama.llama_causal_lm import LlamaCausalLM +from keras_hub.src.models.llama.llama_causal_lm_preprocessor import ( + LlamaCausalLMPreprocessor, +) +from keras_hub.src.models.llama.llama_tokenizer import LlamaTokenizer +from keras_hub.src.tests.test_case import TestCase + + +class TestLlamaExport(TestCase): + def test_export_to_hf(self): + proto = os.path.join( + os.path.dirname(__file__), + "../../../tests/test_data", + "llama_export_vocab.spm", + ) + tokenizer = LlamaTokenizer(proto=proto) + # Create a small backbone + backbone = LlamaBackbone( + vocabulary_size=tokenizer.vocabulary_size(), + num_layers=2, + num_query_heads=4, + num_key_value_heads=1, + hidden_dim=512, + intermediate_dim=1024, + head_dim=128, + layer_norm_epsilon=1e-6, + rope_max_wavelength=10000, + ) + # Create preprocessor + preprocessor = LlamaCausalLMPreprocessor(tokenizer=tokenizer) + # Create the causal LM model + keras_model = LlamaCausalLM( + backbone=backbone, preprocessor=preprocessor + ) + # Set all weights to random values + rng = np.random.default_rng(42) + weights = keras_model.get_weights() + for i in range(len(weights)): + weights[i] = rng.random(weights[i].shape).astype(weights[i].dtype) + keras_model.set_weights(weights) + # Export to Hugging Face format using the new methods + export_path_backbone = os.path.join( + self.get_temp_dir(), "export_backbone" + ) + backbone.export_to_transformers(export_path_backbone) + export_path_tokenizer = os.path.join( + self.get_temp_dir(), "export_tokenizer" + ) + preprocessor.tokenizer.export_to_transformers(export_path_tokenizer) + export_path_task = os.path.join(self.get_temp_dir(), "export_task") + keras_model.export_to_transformers(export_path_task) + # Load Hugging Face models and tokenizer + hf_backbone = AutoModel.from_pretrained(export_path_backbone) + hf_tokenizer_fast = AutoTokenizer.from_pretrained(export_path_tokenizer) + hf_tokenizer_slow = AutoTokenizer.from_pretrained( + export_path_tokenizer, use_fast=False + ) + hf_full_model = AutoModelForCausalLM.from_pretrained(export_path_task) + # Verify configuration + hf_config = hf_backbone.config + self.assertEqual( + hf_config.vocab_size, + backbone.vocabulary_size, + "Vocabulary sizes do not match", + ) + self.assertEqual( + hf_config.num_hidden_layers, + backbone.num_layers, + "Number of layers do not match", + ) + self.assertEqual( + hf_config.num_attention_heads, + backbone.num_query_heads, + "Number of query heads do not match", + ) + self.assertEqual( + hf_config.num_key_value_heads, + backbone.num_key_value_heads, + "Number of key value heads do not match", + ) + self.assertEqual( + hf_config.hidden_size, + backbone.hidden_dim, + "Hidden dimensions do not match", + ) + self.assertEqual( + hf_config.intermediate_size, + backbone.intermediate_dim, + "Intermediate sizes do not match", + ) + self.assertEqual( + hf_config.max_position_embeddings, + 4096, + "Max position embeddings do not match", + ) + self.assertEqual( + hf_config.rms_norm_eps, + backbone.layer_norm_epsilon, + "RMS norm epsilon does not match", + ) + self.assertEqual( + hf_config.rope_theta, + backbone.rope_max_wavelength, + "RoPE theta does not match", + ) + # Verify tokenizer compatibility + self.assertEqual( + hf_tokenizer_fast.vocab_size, + tokenizer.vocabulary_size(), + "Tokenizer vocabulary sizes do not match", + ) + # Compare generated outputs using full model + prompt = "the quick" + # Set seed for reproducibility + rng = np.random.default_rng(42) + # Generate with Keras model + keras_output = keras_model.generate(prompt, max_length=20) + # Generate with HuggingFace model using fast tokenizer + input_ids_fast = hf_tokenizer_fast.encode(prompt, return_tensors="pt") + output_ids_fast = hf_full_model.generate( + input_ids_fast, max_length=20, do_sample=False + ) + hf_fast_output = hf_tokenizer_fast.decode( + output_ids_fast[0], skip_special_tokens=True + ) + # Generate with HuggingFace model using slow tokenizer + input_ids_slow = hf_tokenizer_slow.encode(prompt, return_tensors="pt") + output_ids_slow = hf_full_model.generate( + input_ids_slow, max_length=20, do_sample=False + ) + hf_slow_output = hf_tokenizer_slow.decode( + output_ids_slow[0], skip_special_tokens=True + ) + # Debug print to see the actual outputs + print(f"Keras output: '{keras_output}'") + print(f"HF fast output: '{hf_fast_output}'") + print(f"HF slow output: '{hf_slow_output}'") + self.assertEqual( + keras_output, + hf_fast_output, + "Generated outputs do not match (fast)", + ) + self.assertEqual( + keras_output, + hf_slow_output, + "Generated outputs do not match (slow)", + ) diff --git a/tools/sentencepiece_testing/create_gemma_test_proto.py b/tools/sentencepiece_testing/create_gemma_test_proto.py index 049297ba48..700085e9d3 100644 --- a/tools/sentencepiece_testing/create_gemma_test_proto.py +++ b/tools/sentencepiece_testing/create_gemma_test_proto.py @@ -17,6 +17,24 @@ def main(): unk_piece="", ) + train_sentencepiece( + ["The quick brown fox jumped.", "I like pizza.", "This is a test."], + "gemma_export_vocab.spm", + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=2, + eos_id=1, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=False, + ) + if __name__ == "__main__": main() diff --git a/tools/sentencepiece_testing/create_llama_test_proto.py b/tools/sentencepiece_testing/create_llama_test_proto.py index f081600dab..e5605e2dee 100644 --- a/tools/sentencepiece_testing/create_llama_test_proto.py +++ b/tools/sentencepiece_testing/create_llama_test_proto.py @@ -13,6 +13,24 @@ def main(): eos_id=2, ) + train_sentencepiece( + ["The quick brown fox jumped.", "I like pizza.", "This is a test."], + "llama_export_vocab.spm", + vocab_size=290, + model_type="unigram", + pad_id=0, + bos_id=1, + eos_id=2, + unk_id=3, + byte_fallback=True, + pad_piece="", + bos_piece="", + eos_piece="", + unk_piece="", + user_defined_symbols=["", ""], + add_dummy_prefix=True, + ) + if __name__ == "__main__": main() From 1d51b97a4c02350353f272cbd45c6fdd05abc625 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Thu, 14 Aug 2025 23:33:57 +0530 Subject: [PATCH 13/14] Move llama to a new PR --- .../utils/transformers/export/hf_exporter.py | 8 - .../src/utils/transformers/export/llama.py | 117 ------------- .../utils/transformers/export/llama_test.py | 155 ------------------ 3 files changed, 280 deletions(-) delete mode 100644 keras_hub/src/utils/transformers/export/llama.py delete mode 100644 keras_hub/src/utils/transformers/export/llama_test.py diff --git a/keras_hub/src/utils/transformers/export/hf_exporter.py b/keras_hub/src/utils/transformers/export/hf_exporter.py index 4bdb74e475..1593987ca9 100644 --- a/keras_hub/src/utils/transformers/export/hf_exporter.py +++ b/keras_hub/src/utils/transformers/export/hf_exporter.py @@ -10,27 +10,19 @@ get_gemma_tokenizer_config, ) from keras_hub.src.utils.transformers.export.gemma import get_gemma_weights_map -from keras_hub.src.utils.transformers.export.llama import get_llama_config -from keras_hub.src.utils.transformers.export.llama import ( - get_llama_tokenizer_config, -) -from keras_hub.src.utils.transformers.export.llama import get_llama_weights_map MODEL_CONFIGS = { "GemmaBackbone": get_gemma_config, - "LlamaBackbone": get_llama_config, # Add for future models, e.g., "MistralBackbone": get_mistral_config } MODEL_EXPORTERS = { "GemmaBackbone": get_gemma_weights_map, - "LlamaBackbone": get_llama_weights_map, # Add for future models, e.g., "MistralBackbone": get_mistral_weights_map } MODEL_TOKENIZER_CONFIGS = { "GemmaTokenizer": get_gemma_tokenizer_config, - "LlamaTokenizer": get_llama_tokenizer_config, # Add for future models, e.g., "MistralTokenizer": # get_mistral_tokenizer_config } diff --git a/keras_hub/src/utils/transformers/export/llama.py b/keras_hub/src/utils/transformers/export/llama.py deleted file mode 100644 index 70e0bf443b..0000000000 --- a/keras_hub/src/utils/transformers/export/llama.py +++ /dev/null @@ -1,117 +0,0 @@ -import keras.ops as ops - - -def get_llama_config(backbone): - token_embedding_layer = backbone.get_layer("token_embedding") - hf_config = { - "vocab_size": backbone.vocabulary_size, - "num_hidden_layers": backbone.num_layers, - "num_attention_heads": backbone.num_query_heads, - "num_key_value_heads": backbone.num_key_value_heads, - "hidden_size": backbone.hidden_dim, - "intermediate_size": backbone.intermediate_dim, - "max_position_embeddings": 4096, - "tie_word_embeddings": token_embedding_layer.tie_weights, - "rms_norm_eps": backbone.layer_norm_epsilon, - "rope_theta": backbone.rope_max_wavelength, - "model_type": "llama", - } - return hf_config - - -def get_llama_weights_map(backbone, include_lm_head=False): - weights_dict = {} - # Map token embedding - token_embedding_layer = backbone.token_embedding - weights_dict["model.embed_tokens.weight"] = token_embedding_layer.embeddings - for i in range(backbone.num_layers): - transformer_layer = backbone.transformer_layers[i] - # Pre-attention normalization - weights_dict[f"model.layers.{i}.input_layernorm.weight"] = ( - transformer_layer._self_attention_layernorm.weights[0] - ) - # Attention query projection - query_kernel = ( - transformer_layer._self_attention_layer._query_dense.weights[0] - ) - query_kernel = ops.reshape(query_kernel, (backbone.hidden_dim, -1)) - query_kernel = ops.transpose(query_kernel) - weights_dict[f"model.layers.{i}.self_attn.q_proj.weight"] = query_kernel - # Attention key projection - key_kernel = transformer_layer._self_attention_layer._key_dense.weights[ - 0 - ] - key_kernel = ops.reshape(key_kernel, (backbone.hidden_dim, -1)) - key_kernel = ops.transpose(key_kernel) - weights_dict[f"model.layers.{i}.self_attn.k_proj.weight"] = key_kernel - # Attention value projection - value_kernel = ( - transformer_layer._self_attention_layer._value_dense.weights[0] - ) - value_kernel = ops.reshape(value_kernel, (backbone.hidden_dim, -1)) - value_kernel = ops.transpose(value_kernel) - weights_dict[f"model.layers.{i}.self_attn.v_proj.weight"] = value_kernel - # Attention output projection - out_kernel = ( - transformer_layer._self_attention_layer._output_dense.weights[0] - ) - out_kernel = ops.reshape(out_kernel, (-1, backbone.hidden_dim)) - out_kernel = ops.transpose(out_kernel) - weights_dict[f"model.layers.{i}.self_attn.o_proj.weight"] = out_kernel - # Post-attention normalization - weights_dict[f"model.layers.{i}.post_attention_layernorm.weight"] = ( - transformer_layer._feedforward_layernorm.weights[0] - ) - # MLP gate projection - gate_kernel = transformer_layer._feedforward_gate_dense.weights[0] - weights_dict[f"model.layers.{i}.mlp.gate_proj.weight"] = ops.transpose( - gate_kernel - ) - # MLP up projection - up_kernel = transformer_layer._feedforward_intermediate_dense.weights[0] - weights_dict[f"model.layers.{i}.mlp.up_proj.weight"] = ops.transpose( - up_kernel - ) - # MLP down projection - down_kernel = transformer_layer._feedforward_output_dense.weights[0] - weights_dict[f"model.layers.{i}.mlp.down_proj.weight"] = ops.transpose( - down_kernel - ) - # Map final normalization - weights_dict["model.norm.weight"] = backbone.layer_norm.weights[0] - # Map lm head - if include_lm_head and not token_embedding_layer.tie_weights: - weights_dict["lm_head.weight"] = ops.transpose( - token_embedding_layer.reverse_embeddings - ) - return weights_dict - - -def get_llama_tokenizer_config(tokenizer): - tokenizer_config = { - "tokenizer_class": "LlamaTokenizer", - "clean_up_tokenization_spaces": False, - "bos_token": "", - "eos_token": "", - "pad_token": "", - "unk_token": "", - "add_bos_token": True, - "add_eos_token": False, - "model_max_length": 4096, - } - # Add added_tokens_decoder - added_tokens_decoder = {} - special_tokens = ["", "", "", "", "", ""] - for token in special_tokens: - token_id = tokenizer.token_to_id(token) - if token_id is not None: - added_tokens_decoder[str(token_id)] = { - "content": token, - "special": True, - "single_word": False, - "lstrip": False, - "rstrip": False, - "normalized": False, - } - tokenizer_config["added_tokens_decoder"] = added_tokens_decoder - return tokenizer_config diff --git a/keras_hub/src/utils/transformers/export/llama_test.py b/keras_hub/src/utils/transformers/export/llama_test.py deleted file mode 100644 index d5776ec3b7..0000000000 --- a/keras_hub/src/utils/transformers/export/llama_test.py +++ /dev/null @@ -1,155 +0,0 @@ -import os - -import numpy as np -from transformers import AutoModel -from transformers import AutoModelForCausalLM -from transformers import AutoTokenizer - -from keras_hub.src.models.llama.llama_backbone import LlamaBackbone -from keras_hub.src.models.llama.llama_causal_lm import LlamaCausalLM -from keras_hub.src.models.llama.llama_causal_lm_preprocessor import ( - LlamaCausalLMPreprocessor, -) -from keras_hub.src.models.llama.llama_tokenizer import LlamaTokenizer -from keras_hub.src.tests.test_case import TestCase - - -class TestLlamaExport(TestCase): - def test_export_to_hf(self): - proto = os.path.join( - os.path.dirname(__file__), - "../../../tests/test_data", - "llama_export_vocab.spm", - ) - tokenizer = LlamaTokenizer(proto=proto) - # Create a small backbone - backbone = LlamaBackbone( - vocabulary_size=tokenizer.vocabulary_size(), - num_layers=2, - num_query_heads=4, - num_key_value_heads=1, - hidden_dim=512, - intermediate_dim=1024, - head_dim=128, - layer_norm_epsilon=1e-6, - rope_max_wavelength=10000, - ) - # Create preprocessor - preprocessor = LlamaCausalLMPreprocessor(tokenizer=tokenizer) - # Create the causal LM model - keras_model = LlamaCausalLM( - backbone=backbone, preprocessor=preprocessor - ) - # Set all weights to random values - rng = np.random.default_rng(42) - weights = keras_model.get_weights() - for i in range(len(weights)): - weights[i] = rng.random(weights[i].shape).astype(weights[i].dtype) - keras_model.set_weights(weights) - # Export to Hugging Face format using the new methods - export_path_backbone = os.path.join( - self.get_temp_dir(), "export_backbone" - ) - backbone.export_to_transformers(export_path_backbone) - export_path_tokenizer = os.path.join( - self.get_temp_dir(), "export_tokenizer" - ) - preprocessor.tokenizer.export_to_transformers(export_path_tokenizer) - export_path_task = os.path.join(self.get_temp_dir(), "export_task") - keras_model.export_to_transformers(export_path_task) - # Load Hugging Face models and tokenizer - hf_backbone = AutoModel.from_pretrained(export_path_backbone) - hf_tokenizer_fast = AutoTokenizer.from_pretrained(export_path_tokenizer) - hf_tokenizer_slow = AutoTokenizer.from_pretrained( - export_path_tokenizer, use_fast=False - ) - hf_full_model = AutoModelForCausalLM.from_pretrained(export_path_task) - # Verify configuration - hf_config = hf_backbone.config - self.assertEqual( - hf_config.vocab_size, - backbone.vocabulary_size, - "Vocabulary sizes do not match", - ) - self.assertEqual( - hf_config.num_hidden_layers, - backbone.num_layers, - "Number of layers do not match", - ) - self.assertEqual( - hf_config.num_attention_heads, - backbone.num_query_heads, - "Number of query heads do not match", - ) - self.assertEqual( - hf_config.num_key_value_heads, - backbone.num_key_value_heads, - "Number of key value heads do not match", - ) - self.assertEqual( - hf_config.hidden_size, - backbone.hidden_dim, - "Hidden dimensions do not match", - ) - self.assertEqual( - hf_config.intermediate_size, - backbone.intermediate_dim, - "Intermediate sizes do not match", - ) - self.assertEqual( - hf_config.max_position_embeddings, - 4096, - "Max position embeddings do not match", - ) - self.assertEqual( - hf_config.rms_norm_eps, - backbone.layer_norm_epsilon, - "RMS norm epsilon does not match", - ) - self.assertEqual( - hf_config.rope_theta, - backbone.rope_max_wavelength, - "RoPE theta does not match", - ) - # Verify tokenizer compatibility - self.assertEqual( - hf_tokenizer_fast.vocab_size, - tokenizer.vocabulary_size(), - "Tokenizer vocabulary sizes do not match", - ) - # Compare generated outputs using full model - prompt = "the quick" - # Set seed for reproducibility - rng = np.random.default_rng(42) - # Generate with Keras model - keras_output = keras_model.generate(prompt, max_length=20) - # Generate with HuggingFace model using fast tokenizer - input_ids_fast = hf_tokenizer_fast.encode(prompt, return_tensors="pt") - output_ids_fast = hf_full_model.generate( - input_ids_fast, max_length=20, do_sample=False - ) - hf_fast_output = hf_tokenizer_fast.decode( - output_ids_fast[0], skip_special_tokens=True - ) - # Generate with HuggingFace model using slow tokenizer - input_ids_slow = hf_tokenizer_slow.encode(prompt, return_tensors="pt") - output_ids_slow = hf_full_model.generate( - input_ids_slow, max_length=20, do_sample=False - ) - hf_slow_output = hf_tokenizer_slow.decode( - output_ids_slow[0], skip_special_tokens=True - ) - # Debug print to see the actual outputs - print(f"Keras output: '{keras_output}'") - print(f"HF fast output: '{hf_fast_output}'") - print(f"HF slow output: '{hf_slow_output}'") - self.assertEqual( - keras_output, - hf_fast_output, - "Generated outputs do not match (fast)", - ) - self.assertEqual( - keras_output, - hf_slow_output, - "Generated outputs do not match (slow)", - ) From 1209ba8a44f1f75db05b72f7b7d12f039b099689 Mon Sep 17 00:00:00 2001 From: Dhiraj BM Date: Mon, 18 Aug 2025 20:40:23 +0530 Subject: [PATCH 14/14] address nits --- keras_hub/src/models/causal_lm_preprocessor_test.py | 6 +----- keras_hub/src/models/task_test.py | 6 +----- keras_hub/src/tokenizers/tokenizer_test.py | 12 ++---------- .../src/utils/transformers/export/gemma_test.py | 6 +----- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/keras_hub/src/models/causal_lm_preprocessor_test.py b/keras_hub/src/models/causal_lm_preprocessor_test.py index eba8d266bd..26da542dfd 100644 --- a/keras_hub/src/models/causal_lm_preprocessor_test.py +++ b/keras_hub/src/models/causal_lm_preprocessor_test.py @@ -51,11 +51,7 @@ def test_from_preset_errors(self): GPT2CausalLMPreprocessor.from_preset("hf://spacy/en_core_web_sm") def test_export_supported_preprocessor(self): - proto = os.path.join( - os.path.dirname(__file__), - "../tests/test_data", - "gemma_export_vocab.spm", - ) + proto = os.path.join(self.get_test_data_dir(), "gemma_export_vocab.spm") tokenizer = GemmaTokenizer(proto=proto) preprocessor = GemmaCausalLMPreprocessor(tokenizer=tokenizer) export_path = os.path.join(self.get_temp_dir(), "export_preprocessor") diff --git a/keras_hub/src/models/task_test.py b/keras_hub/src/models/task_test.py index f560eee971..b46e46b361 100644 --- a/keras_hub/src/models/task_test.py +++ b/keras_hub/src/models/task_test.py @@ -179,11 +179,7 @@ def test_save_to_preset_custom_backbone_and_preprocessor(self): self.assertAllClose(expected, actual) def _create_gemma_for_export_tests(self): - proto = os.path.join( - os.path.dirname(__file__), - "../tests/test_data", - "gemma_export_vocab.spm", - ) + proto = os.path.join(self.get_test_data_dir(), "gemma_export_vocab.spm") tokenizer = GemmaTokenizer(proto=proto) backbone = GemmaBackbone( vocabulary_size=tokenizer.vocabulary_size(), diff --git a/keras_hub/src/tokenizers/tokenizer_test.py b/keras_hub/src/tokenizers/tokenizer_test.py index 7585e23a32..b2a2458257 100644 --- a/keras_hub/src/tokenizers/tokenizer_test.py +++ b/keras_hub/src/tokenizers/tokenizer_test.py @@ -116,11 +116,7 @@ def test_save_to_preset(self, cls, preset_name, tokenizer_type): self.assertEqual(cls, check_config_class(tokenizer_config)) def test_export_supported_tokenizer(self): - proto = os.path.join( - os.path.dirname(__file__), - "../tests/test_data", - "gemma_export_vocab.spm", - ) + proto = os.path.join(self.get_test_data_dir(), "gemma_export_vocab.spm") tokenizer = GemmaTokenizer(proto=proto) export_path = os.path.join(self.get_temp_dir(), "export_tokenizer") tokenizer.export_to_transformers(export_path) @@ -130,11 +126,7 @@ def test_export_supported_tokenizer(self): ) def test_export_unsupported_tokenizer(self): - proto = os.path.join( - os.path.dirname(__file__), - "../tests/test_data", - "gemma_export_vocab.spm", - ) + proto = os.path.join(self.get_test_data_dir(), "gemma_export_vocab.spm") class UnsupportedTokenizer(GemmaTokenizer): pass diff --git a/keras_hub/src/utils/transformers/export/gemma_test.py b/keras_hub/src/utils/transformers/export/gemma_test.py index 1627627f90..e1bffa0645 100644 --- a/keras_hub/src/utils/transformers/export/gemma_test.py +++ b/keras_hub/src/utils/transformers/export/gemma_test.py @@ -16,11 +16,7 @@ class TestGemmaExport(TestCase): def test_export_to_hf(self): - proto = os.path.join( - os.path.dirname(__file__), - "../../../tests/test_data", - "gemma_export_vocab.spm", - ) + proto = os.path.join(self.get_test_data_dir(), "gemma_export_vocab.spm") tokenizer = GemmaTokenizer(proto=proto) # Create a small backbone