-
Notifications
You must be signed in to change notification settings - Fork 362
Add missing RoBERTa converter #2960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d52441b
82665f3
88fe711
e1d95da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| import numpy as np | ||
|
|
||
| from keras_hub.src.models.roberta.roberta_backbone import RobertaBackbone | ||
| from keras_hub.src.utils.preset_utils import get_file | ||
|
|
||
| backbone_cls = RobertaBackbone | ||
|
|
||
| # RoBERTa reserves the first `padding_idx + 1` position embedding rows | ||
| # (padding_idx=1 for RoBERTa) and starts real positions at index 2. | ||
| _POSITION_OFFSET = 2 | ||
|
|
||
|
|
||
| def convert_backbone_config(transformers_config): | ||
| return { | ||
| "vocabulary_size": transformers_config["vocab_size"], | ||
| "num_layers": transformers_config["num_hidden_layers"], | ||
| "num_heads": transformers_config["num_attention_heads"], | ||
| "hidden_dim": transformers_config["hidden_size"], | ||
| "intermediate_dim": transformers_config["intermediate_size"], | ||
| "dropout": transformers_config["hidden_dropout_prob"], | ||
| "max_sequence_length": transformers_config["max_position_embeddings"] | ||
| - _POSITION_OFFSET, | ||
| } | ||
|
|
||
|
|
||
| def transpose_and_reshape(x, shape): | ||
| return np.reshape(np.transpose(x), shape) | ||
|
|
||
|
|
||
| def convert_weights(backbone, loader, transformers_config): | ||
| # Embeddings | ||
| loader.port_weight( | ||
| keras_variable=backbone.token_embedding.embeddings, | ||
| hf_weight_key="roberta.embeddings.word_embeddings.weight", | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=backbone.embeddings.position_embedding.position_embeddings, | ||
| hf_weight_key="roberta.embeddings.position_embeddings.weight", | ||
| hook_fn=lambda x, _: x[_POSITION_OFFSET:, :], | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=backbone.embeddings_layer_norm.gamma, | ||
| hf_weight_key="roberta.embeddings.LayerNorm.weight", | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=backbone.embeddings_layer_norm.beta, | ||
| hf_weight_key="roberta.embeddings.LayerNorm.bias", | ||
| ) | ||
|
|
||
| # Attention blocks | ||
| for index in range(backbone.num_layers): | ||
| encoder_layer = backbone.transformer_layers[index] | ||
| hf_prefix = f"roberta.encoder.layer.{index}" | ||
|
|
||
| # Attention layers | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.query_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.query.weight", | ||
| hook_fn=transpose_and_reshape, | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.query_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.query.bias", | ||
| hook_fn=lambda hf_tensor, shape: np.reshape(hf_tensor, shape), | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.key_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.key.weight", | ||
| hook_fn=transpose_and_reshape, | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.key_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.key.bias", | ||
| hook_fn=lambda hf_tensor, shape: np.reshape(hf_tensor, shape), | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.value_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.value.weight", | ||
| hook_fn=transpose_and_reshape, | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.value_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.attention.self.value.bias", | ||
| hook_fn=lambda hf_tensor, shape: np.reshape(hf_tensor, shape), | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.output_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.attention.output.dense.weight", | ||
| hook_fn=transpose_and_reshape, | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer.output_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.attention.output.dense.bias", | ||
| hook_fn=lambda hf_tensor, shape: np.reshape(hf_tensor, shape), | ||
| ) | ||
| # Attention layer norm. | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer_norm.gamma, | ||
| hf_weight_key=f"{hf_prefix}.attention.output.LayerNorm.weight", | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._self_attention_layer_norm.beta, | ||
| hf_weight_key=f"{hf_prefix}.attention.output.LayerNorm.bias", | ||
| ) | ||
| # MLP layers | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_intermediate_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.intermediate.dense.weight", | ||
| hook_fn=lambda hf_tensor, _: np.transpose(hf_tensor, axes=(1, 0)), | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_intermediate_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.intermediate.dense.bias", | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_output_dense.kernel, | ||
| hf_weight_key=f"{hf_prefix}.output.dense.weight", | ||
| hook_fn=lambda hf_tensor, _: np.transpose(hf_tensor, axes=(1, 0)), | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_output_dense.bias, | ||
| hf_weight_key=f"{hf_prefix}.output.dense.bias", | ||
| ) | ||
| # Output layer norm. | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_layer_norm.gamma, | ||
| hf_weight_key=f"{hf_prefix}.output.LayerNorm.weight", | ||
| ) | ||
| loader.port_weight( | ||
| keras_variable=encoder_layer._feedforward_layer_norm.beta, | ||
| hf_weight_key=f"{hf_prefix}.output.LayerNorm.bias", | ||
| ) | ||
|
|
||
|
|
||
| def convert_tokenizer(cls, preset, **kwargs): | ||
| vocab_file = get_file(preset, "vocab.json") | ||
| merges_file = get_file(preset, "merges.txt") | ||
| return cls( | ||
| vocabulary=vocab_file, | ||
| merges=merges_file, | ||
| **kwargs, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||||||||||||||
| import pytest | ||||||||||||||||||
|
|
||||||||||||||||||
| from keras_hub.src.models.backbone import Backbone | ||||||||||||||||||
| from keras_hub.src.models.roberta.roberta_backbone import RobertaBackbone | ||||||||||||||||||
| from keras_hub.src.models.roberta.roberta_text_classifier import ( | ||||||||||||||||||
| RobertaTextClassifier, | ||||||||||||||||||
| ) | ||||||||||||||||||
| from keras_hub.src.models.text_classifier import TextClassifier | ||||||||||||||||||
| from keras_hub.src.tests.test_case import TestCase | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| class TestRobertaConverter(TestCase): | ||||||||||||||||||
| @pytest.mark.extra_large | ||||||||||||||||||
| def test_convert_tiny_preset(self): | ||||||||||||||||||
| model = RobertaTextClassifier.from_preset( | ||||||||||||||||||
| "hf://FacebookAI/roberta-base", num_classes=2 | ||||||||||||||||||
| ) | ||||||||||||||||||
|
Comment on lines
+14
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test
Suggested change
References
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the model size is under 500 mb, it should be fine. also tried the suggested preset anyways, there was an error. |
||||||||||||||||||
| prompt = "That movies was terrible." | ||||||||||||||||||
| model.predict([prompt]) | ||||||||||||||||||
|
|
||||||||||||||||||
| @pytest.mark.large | ||||||||||||||||||
| def test_class_detection(self): | ||||||||||||||||||
| model = TextClassifier.from_preset( | ||||||||||||||||||
| "hf://FacebookAI/roberta-base", | ||||||||||||||||||
| num_classes=2, | ||||||||||||||||||
| load_weights=False, | ||||||||||||||||||
| ) | ||||||||||||||||||
| self.assertIsInstance(model, RobertaTextClassifier) | ||||||||||||||||||
| model = Backbone.from_preset( | ||||||||||||||||||
| "hf://FacebookAI/roberta-base", | ||||||||||||||||||
| load_weights=False, | ||||||||||||||||||
| ) | ||||||||||||||||||
| self.assertIsInstance(model, RobertaBackbone) | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The attention dense layers in Keras's
MultiHeadAttention(used byTransformerEncoder) are private attributes prefixed with an underscore (e.g.,_query_dense,_key_dense,_value_dense,_output_dense). Accessing them as public attributes (e.g.,query_dense) will raise anAttributeErrorat runtime when loading weights. Please restore the leading underscores to match the Keras implementation and the original checkpoint conversion script.References
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query_dense/key_dense/value_dense/output_dense are public property aliases for the private attrs in Keras's MultiHeadAttention, so the current code is correct.The tests already pass without an AttributeError.