Add Beit3 model#39534
Conversation
|
@NielsRogge Would you be willing to support me in this second attempt (#22289) to finally bring BEIT3 support to HF? |
|
|
||
|
|
||
| def get_tokenizer(): | ||
| return XLMRobertaTokenizer.from_pretrained("https://github.com/addf400/files/releases/download/beit3/beit3.spm") |
There was a problem hiding this comment.
Is there any way how I can convert this directly in a XMLRobertaTokenizerFast? I know I can use the old one here and then when loading the tokenizer from the hf checkpoint it can be converted on the fly.
But I think it would be preferable to convert it directly here.
There was a problem hiding this comment.
Also it seems that model_max_length of the tokenizer / preprocessor is not set automatically as typically with hf models. Why is that the case? Should that not be stored in the beit3.spm or do I need to set that somewhere explicitly? For instance, I couldn't find where the VILT model sets this explicitly, thus I was assuming that huggingface can get it automatically from somewhere
| parser.add_argument( | ||
| "--beit3_model_type", | ||
| default=None, | ||
| type=str, | ||
| help="Beit3 model type, it has to be one of image_classification, vqa, visual_reasoning," | ||
| "image_captioning,image_text_retrieval", | ||
| ) |
There was a problem hiding this comment.
One thing I am overall wondering is: What is with the "base pretrained" BEiT3 image? I think with BEiT3 it is common to finetune the whole model for downstream tasks like vqa or image captioning. Thus, I think it makes sense to provide the base model too and not only the finetuned versions.
But technically the base model of course also has a head. It would probably be something like Beit3ForMaskedImageModelling. Even though it is not advertised like this. So what would be best practice here? Load the standard Beit3Model without any head and ignore certain parameters? This is what I tried locally:
Modify lines 277ff:
model_state_dict = ulilm_state_dict["model"]
model_state_dict = rename_keys(model_state_dict, beit3_model_type)
if isinstance(model, Beit3Model):
# For Beit3Model, we need filter beit3 keys and remove them
model_state_dict = {k.replace("beit3.", ""): v for k, v in model_state_dict.items() if k.startswith("beit3.")}
model.load_state_dict(model_state_dict)
Is this okay? What would be best practise?
| class Beit3MultiwayFeedForwardNetwork(nn.Module): | ||
| def __init__(self, config): | ||
| super().__init__() | ||
| self.text = Beit3FeedForwardNetwork(config) | ||
| self.image = Beit3FeedForwardNetwork(config) | ||
|
|
||
| def forward(self, hidden_states: torch.Tensor, split_position: int = -1): | ||
| if split_position == -1: | ||
| return self.image(hidden_states) | ||
| if split_position == 0: | ||
| return self.text(hidden_states) | ||
| image_hidden, text_hidden = torch.split( | ||
| hidden_states, | ||
| [split_position, hidden_states.size(1) - split_position], | ||
| dim=1, | ||
| ) | ||
| image_out, text_out = self.image(image_hidden), self.text(text_hidden) | ||
| return torch.cat([image_out, text_out], dim=1) |
There was a problem hiding this comment.
Would it make sense to create a parent class MultiwayLayer that takes two networks for text and image?
I think this logic is 2 or 3 three times duplicated here.
There was a problem hiding this comment.
I think that would be great, yeah!
Adding a level of abstraction here would make the code shorter while maintaining readability.
class Beit3ForQuestionAnswering(Beit3PreTrainedModel):
def __init__(self, config):
super().__init__(config)
embed_dim = config.hidden_size
self.num_labels = config.num_labels
self.beit3 = Beit3Model(config, add_pooling_layer=True)
self.classifier = nn.Sequential(
nn.Linear(embed_dim, embed_dim * 2),
nn.LayerNorm(embed_dim * 2, eps=config.layer_norm_eps),
nn.GELU(),
nn.Linear(embed_dim * 2, config.num_labels),
)
self.post_init()
def load_state_dict(self, state_dict, *args, **kwargs):
pos_embed_checkpoint = state_dict["beit3.encoder.embed_positions.image.weight"]
embedding_size = pos_embed_checkpoint.shape[-1]
num_patches = self.beit3.vision_embedding.num_patches
num_extra_tokens = self.beit3.vision_embedding.num_position_embeddings() + 2 - num_patches
orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5)
new_size = int(num_patches**0.5)
if orig_size != new_size:
extra_tokens = pos_embed_checkpoint[:num_extra_tokens].unsqueeze(0)
pos_tokens = pos_embed_checkpoint[num_extra_tokens:]
pos_tokens = pos_tokens.reshape(1, orig_size, orig_size, embedding_size).permute(0, 3, 1, 2)
pos_tokens = torch.nn.functional.interpolate(
pos_tokens, size=(new_size, new_size), mode="bicubic", align_corners=False
)
pos_tokens = pos_tokens.permute(0, 2, 3, 1).reshape(1, new_size * new_size, embedding_size)
new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1).squeeze(0)
state_dict["beit3.encoder.embed_positions.image.weight"] = new_pos_embed
return super().load_state_dict(state_dict, *args, **kwargs)@NielsRogge Could you help me here. I need something along the lines of this in the code. If someone wants to process larger or smaller images, instead of reinitializing the weights, this will interpolate the new embedding weights. It is done here https://github.com/microsoft/unilm/blob/master/beit3/utils.py#L521. |
|
Hello @Leon0402, Thank you for working on this! This implementation could also be really useful for me at work. I’d love to help, but I’m not quite sure how to contribute effectively. I could take care of the small subclassing tasks for Regarding interpolation, I noticed that it's done during the forward pass in the DeiT implementation. |
|
Hi @CharlesAttend, yes, feel free to implement the abstraction for the muliway logic. Maybe the best option would be to create a PR against my branch that I can merge it, once it looks good? Regarding interpolation logic: I think doing it in the forward pass does not work too well, because huggingface will default initialise the parameters during from_pretrained and we then do not have access anymore to the old embeddings, right? |
77e4516 to
d822a1d
Compare
d822a1d to
18efe70
Compare
|
cc @yonigozlan @molbap maybe? |
molbap
left a comment
There was a problem hiding this comment.
I'm down to review this, left a couple guiding comments to modernize the API!
| BEIT3_START_DOCSTRING = r""" | ||
| This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass. Use it | ||
| as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and | ||
| behavior. | ||
|
|
||
| Parameters: | ||
| config ([`Beit3Config`]): Model configuration class with all the parameters of the model. | ||
| Initializing with a config file does not load the weights associated with the model, only the | ||
| configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_MODEL = r""" | ||
| Args: | ||
| input_ids (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Indices of input sequence tokens in the vocabulary. | ||
|
|
||
| Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and | ||
| [`PreTrainedTokenizer.__call__`] for details. | ||
|
|
||
| [What are input IDs?](../glossary#input-ids) | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`, *optional*): | ||
| Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See | ||
| [`BeitImageProcessor.__call__`] for details. | ||
| attention_mask (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: | ||
|
|
||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
|
|
||
| [What are attention masks?](../glossary#attention-mask) | ||
| image_text_mask (`torch.FloatTensor` of shape `({0})`, *optional*): | ||
| Mask to avoid performing attention on image-text tokens. Mask values selected in `[0, 1]`: | ||
|
|
||
| - 1 for tokens that are **not masked**, | ||
| - 0 for tokens that are **masked**. | ||
|
|
||
| vision_masked_position (`torch.LongTensor` of shape pixel_values, *optional*): | ||
| Padding mask for input tokens , of same shape as `pixel_values` | ||
|
|
||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
| past_key_values (`Tuple`, *optional*): | ||
| A Tuple containing the incremental states layerwise.This can be used to when generating next token in | ||
| case of image captioning. | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_FOR_VISUAL_REASONING_INPUTS_DOCSTRING = r""" | ||
| Args: | ||
| input_ids (`torch.LongTensor` of shape `({0})`): | ||
| Indices of input sequence tokens in the vocabulary. | ||
|
|
||
| Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and | ||
| [`PreTrainedTokenizer.__call__`] for details. | ||
|
|
||
| [What are input IDs?](../glossary#input-ids) | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, 2, num_channels, height, width)`): | ||
| Pixel values. Pixel values can be obtained by combining two images after preprocessing using | ||
| [`AutoImageProcessor`]. See [`BeitImageProcessor.__call__`] for details. Use torch.cat with two images, | ||
| with dim=1. | ||
| attention_mask (`torch.LongTensor` of shape `({0})`,*optional*): | ||
| Padding mask for input tokens , of same shape as `input_ids` | ||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*): | ||
| Labels for computing the sequence classification/regression loss. Indices should be in `[0, ..., | ||
| config.num_labels - 1]`. A classification loss is computed (Cross-Entropy) against these labels. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_FOR_IMAGE_CLASSIFICATION_INPUTS_DOCSTRING = r""" | ||
| Args: | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): | ||
| Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See | ||
| [`BeitImageProcessor.__call__`] for details. | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*): | ||
| Labels for computing the classification loss. Indices should be in `[0, ..., config.num_labels - 1]`. A | ||
| classification loss is computed (Cross-Entropy) against these labels. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_FOR_CAPTIONING_INPUTS_DOCSTRING = r""" | ||
| Args: | ||
| input_ids (`torch.LongTensor` of shape `({0})`): | ||
| Indices of input sequence tokens in the vocabulary. | ||
|
|
||
| Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and | ||
| [`PreTrainedTokenizer.__call__`] for details. | ||
|
|
||
| [What are input IDs?](../glossary#input-ids) | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): | ||
| Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See | ||
| [`BeitImageProcessor.__call__`] for details. | ||
| attention_mask (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Padding mask for input tokens , of same shape as `input_ids` | ||
|
|
||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
| language_masked_pos (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| language_masked_pos for denoting tokens for captioning | ||
|
|
||
| - 1 indicates the token is **present**, | ||
| - 0 indicates the token is **absent**. | ||
| text_len (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Length of text for captioning, this is the length of the final caption to be generated, includes the | ||
| input_ids and tokens marked as 64001 (token id marked as to be filled). | ||
| past_key_values (`Tuple`, *optional*): | ||
| A Tuple containing the incremental states layerwise | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*): | ||
| Labels for computing the classification loss. Indices should be in `[0, ..., config.num_labels - 1]`. A | ||
| classification loss is computed (Cross-Entropy) against these labels. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_FOR_VQA_INPUTS_DOCSTRING = r""" | ||
| Args: | ||
| input_ids (`torch.LongTensor` of shape `({0})`): | ||
| Indices of input sequence tokens in the vocabulary. | ||
|
|
||
| Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and | ||
| [`PreTrainedTokenizer.__call__`] for details. [What are input IDs?](../glossary#input-ids) | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): | ||
| Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See | ||
| [`BeitImageProcessor.__call__`] for details. | ||
| attention_mask (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Padding mask for input tokens , of same shape as `input_ids` | ||
|
|
||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*): | ||
| Labels for computing the classification loss. Indices should be in `[0, ..., config.num_labels - 1]`. A | ||
| classification loss is computed (Cross-Entropy) against these labels. | ||
| """ | ||
|
|
||
|
|
||
| BEIT3_FOR_TEXT_RETRIEVAL_INPUTS_DOCSTRING = r""" | ||
| Args: | ||
| input_ids (`torch.LongTensor` of shape `({0})`): | ||
| Indices of input sequence tokens in the vocabulary. | ||
|
|
||
| Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and | ||
| [`PreTrainedTokenizer.__call__`] for details. | ||
|
|
||
| [What are input IDs?](../glossary#input-ids) | ||
| pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): | ||
| Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See | ||
| [`BeitImageProcessor.__call__`] for details. | ||
| attention_mask (`torch.LongTensor` of shape `({0})`, *optional*): | ||
| Padding mask for input tokens , of same shape as `input_ids` | ||
|
|
||
| - 1 indicates the token is **not masked**, | ||
| - 0 indicates the token is **masked**. | ||
| return_loss (`bool`, *optional*): | ||
| Whether or not to return the contrastive loss. | ||
| output_hidden_states (`bool`, *optional*): | ||
| Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for | ||
| more detail. | ||
| output_attentions (`bool`, *optional*): | ||
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned | ||
| tensors for more detail. | ||
| return_dict (`bool`, *optional*): | ||
| Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. | ||
| """ |
There was a problem hiding this comment.
We now have an auto_docstring decorator that should alleviate a portion of these
There was a problem hiding this comment.
In terms of API changes, one big change is the addition of modular transformers: https://huggingface.co/docs/transformers/v4.45.1/en/modular_transformers
Here I'm seeing a lot of components that are very similar to existing ones, or identical (contrastive_loss for instance). What's # Copied from should be removed, and a modular_beit3.py file should be created, with the modeling_beit3.py file being automatically generated from it. Feel free to look at examples across the lib!
|
Thanks @molbap. Do you happen to have any advice on my previous comment:
|
|
[For maintainers] Suggested jobs to run (before merge) run-slow: auto, beit3 |
|
Hey @Leon0402, for your question: right now we don't add hooks to Feel free to ping me again for another review! |
Fixes #22178
This a rebase based on the original PR: #22289
Potentially Missing: