-
Notifications
You must be signed in to change notification settings - Fork 34.1k
add initial design for uniform processors + align model #31197
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
Changes from 7 commits
b85036f
bb8ac70
cd8c601
f00c852
693036f
766da3a
844394d
c19bbc6
3c38119
81ae819
ce4abcd
3acdf28
404239f
603be40
71c9d6c
26383c5
4521f4f
b96eb64
9c5c01c
3ccb505
142acf3
60a5730
be6c141
84135d7
ce967ac
f78ec52
52fd5ad
8f21abe
d510030
fd43bcd
b2cd7c9
bcbd646
39c1587
1f73bdf
b3f98ba
e4d6d12
1e09e4a
d4232f0
162b1a7
0da1dc3
f955510
f6f1dac
c4b7e84
3ce3608
6b83e39
3818b86
31b7a60
4072336
bcce007
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 | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,8 +16,66 @@ | |||||||
| Image/Text processor class for ALIGN | ||||||||
| """ | ||||||||
|
|
||||||||
| from ...processing_utils import ProcessorMixin | ||||||||
| from ...tokenization_utils_base import BatchEncoding | ||||||||
| from typing import List, Union | ||||||||
|
|
||||||||
| from ...image_utils import ImageInput | ||||||||
| from ...processing_utils import ( | ||||||||
| CommonKwargs, | ||||||||
| ImagesKwargs, | ||||||||
| ProcessingKwargs, | ||||||||
| ProcessorMixin, | ||||||||
| TextKwargs, | ||||||||
| ) | ||||||||
| from ...tokenization_utils_base import BatchEncoding, PreTokenizedInput, TextInput | ||||||||
| from ...utils import is_torch_available, is_vision_available | ||||||||
|
|
||||||||
|
|
||||||||
| # TODO (@molbap) This is a bother, forward references from TypedDict are resolved and need this to work | ||||||||
| if is_vision_available(): | ||||||||
| import PIL # noqa: F401 | ||||||||
| if is_torch_available(): | ||||||||
| import torch # noqa: F401 | ||||||||
|
|
||||||||
|
|
||||||||
| class AlignProcessorKwargs(ProcessingKwargs, total=False): | ||||||||
| """ | ||||||||
| Inherits from `ProcessingKwargs` to provide: | ||||||||
| 1) Additional keys that this model requires to process inputs. | ||||||||
| 2) Default values for extra keys. | ||||||||
| New keys have to be defined as follows to ensure type hinting is done correctly. | ||||||||
|
|
||||||||
| ```python | ||||||||
| common_kwargs: CommonKwargs = { | ||||||||
| **CommonKwargs.__annotations__, | ||||||||
| } | ||||||||
| text_kwargs: TextKwargs = { | ||||||||
| **TextKwargs.__annotations__, | ||||||||
| "a_new_text_boolean_key": Optional[bool], | ||||||||
| } | ||||||||
| images_kwargs: ImagesKwargs = { | ||||||||
| **ImagesKwargs.__annotations__, | ||||||||
| "a_new_image_processing_key": Optional[int] | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| """ | ||||||||
|
|
||||||||
| common_kwargs: CommonKwargs = { | ||||||||
| **CommonKwargs.__annotations__, | ||||||||
| } | ||||||||
| text_kwargs: TextKwargs = { | ||||||||
| **TextKwargs.__annotations__, | ||||||||
| } | ||||||||
| images_kwargs: ImagesKwargs = { | ||||||||
| **ImagesKwargs.__annotations__, | ||||||||
| } | ||||||||
|
|
||||||||
| _defaults = { | ||||||||
|
Collaborator
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.
Suggested change
should work no? Or does it not update the default for type-hints?
Collaborator
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. yes it works for sure, this was to have a structured dict for defaults. Can change :)
Collaborator
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. ah, now I remember, it actually can't work like that since Typed Dicts don't support default values, they are made to hold the layout. They can have any attributes however, but it won't pass a value as default -like a
Collaborator
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. ok got it thanks! Let's maybe comment about this!
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. Do we have a comment for future code inspectors? I'm assuming here isn't the best place (we don't want it for all models) but didn't find a corresponding one elsewhere on a quick skim
Collaborator
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. On that: there's doc in |
||||||||
| "text_kwargs": { | ||||||||
| "padding": "max_length", | ||||||||
| "max_length": 64, | ||||||||
| }, | ||||||||
| } | ||||||||
|
|
||||||||
|
|
||||||||
| class AlignProcessor(ProcessorMixin): | ||||||||
|
|
@@ -26,12 +84,39 @@ class AlignProcessor(ProcessorMixin): | |||||||
| [`BertTokenizer`]/[`BertTokenizerFast`] into a single processor that interits both the image processor and | ||||||||
| tokenizer functionalities. See the [`~AlignProcessor.__call__`] and [`~OwlViTProcessor.decode`] for more | ||||||||
| information. | ||||||||
| The preferred way of passing kwargs is as a dictionary per modality, see usage example below. | ||||||||
| ```python | ||||||||
| from transformers import AlignProcessor | ||||||||
| from PIL import Image | ||||||||
| model_id = "kakaobrain/align-base" | ||||||||
| processor = AlignProcessor.from_pretrained(model_id) | ||||||||
|
|
||||||||
| # Define the kwargs for each modality | ||||||||
| common_kwargs = {"return_tensors": "pt"} | ||||||||
| images_kwargs = {"crop_size": {"height": 224, "width": 224}} | ||||||||
| text_kwargs = {"padding": "do_not_pad"} | ||||||||
|
molbap marked this conversation as resolved.
Outdated
|
||||||||
|
|
||||||||
| # Combine them into a single dictionary | ||||||||
|
|
||||||||
| all_kwargs = { | ||||||||
| "images_kwargs": images_kwargs, | ||||||||
| "text_kwargs": text_kwargs, | ||||||||
| "common_kwargs": common_kwargs | ||||||||
|
molbap marked this conversation as resolved.
Outdated
|
||||||||
| } | ||||||||
|
|
||||||||
| processor(images=your_pil_image, text=["What is that?"], **all_kwargs) | ||||||||
|
|
||||||||
| # passing directly any number of kwargs is also supported, but not recommended | ||||||||
|
|
||||||||
| processor(images=your_pil_image, text=["What is that?"], padding="do_not_pad) | ||||||||
| ``` | ||||||||
|
|
||||||||
| Args: | ||||||||
| image_processor ([`EfficientNetImageProcessor`]): | ||||||||
| The image processor is a required input. | ||||||||
| tokenizer ([`BertTokenizer`, `BertTokenizerFast`]): | ||||||||
| The tokenizer is a required input. | ||||||||
|
|
||||||||
| """ | ||||||||
|
|
||||||||
| attributes = ["image_processor", "tokenizer"] | ||||||||
|
|
@@ -41,11 +126,21 @@ class AlignProcessor(ProcessorMixin): | |||||||
| def __init__(self, image_processor, tokenizer): | ||||||||
| super().__init__(image_processor, tokenizer) | ||||||||
|
|
||||||||
| def __call__(self, text=None, images=None, padding="max_length", max_length=64, return_tensors=None, **kwargs): | ||||||||
| def __call__( | ||||||||
| self, | ||||||||
| text: Union[TextInput, PreTokenizedInput, List[TextInput], List[PreTokenizedInput]] = None, | ||||||||
| images: ImageInput = None, | ||||||||
| audio=None, | ||||||||
| videos=None, | ||||||||
| text_kwargs: AlignProcessorKwargs.text_kwargs = None, | ||||||||
| images_kwargs: AlignProcessorKwargs.images_kwargs = None, | ||||||||
| common_kwargs: AlignProcessorKwargs.common_kwargs = None, | ||||||||
| **kwargs: AlignProcessorKwargs, | ||||||||
| ) -> BatchEncoding: | ||||||||
| """ | ||||||||
| Main method to prepare text(s) and image(s) to be fed as input to the model. This method forwards the `text` | ||||||||
| and `kwargs` arguments to BertTokenizerFast's [`~BertTokenizerFast.__call__`] if `text` is not `None` to encode | ||||||||
| the text. To prepare the image(s), this method forwards the `images` and `kwargs` arguments to | ||||||||
| arguments to BertTokenizerFast's [`~BertTokenizerFast.__call__`] if `text` is not `None` to encode | ||||||||
| the text. To prepare the image(s), this method forwards the `images` arguments to | ||||||||
| EfficientNetImageProcessor's [`~EfficientNetImageProcessor.__call__`] if `images` is not `None`. Please refer | ||||||||
| to the doctsring of the above two methods for more information. | ||||||||
|
|
||||||||
|
|
@@ -57,20 +152,12 @@ def __call__(self, text=None, images=None, padding="max_length", max_length=64, | |||||||
| images (`PIL.Image.Image`, `np.ndarray`, `torch.Tensor`, `List[PIL.Image.Image]`, `List[np.ndarray]`, `List[torch.Tensor]`): | ||||||||
| The image or batch of images to be prepared. Each image can be a PIL image, NumPy array or PyTorch | ||||||||
| tensor. Both channels-first and channels-last formats are supported. | ||||||||
| padding (`bool`, `str` or [`~utils.PaddingStrategy`], *optional*, defaults to `max_length`): | ||||||||
| Activates and controls padding for tokenization of input text. Choose between [`True` or `'longest'`, | ||||||||
| `'max_length'`, `False` or `'do_not_pad'`] | ||||||||
| max_length (`int`, *optional*, defaults to `max_length`): | ||||||||
| Maximum padding value to use to pad the input text during tokenization. | ||||||||
|
|
||||||||
| return_tensors (`str` or [`~utils.TensorType`], *optional*): | ||||||||
| If set, will return tensors of a particular framework. Acceptable values are: | ||||||||
|
|
||||||||
| - `'tf'`: Return TensorFlow `tf.constant` objects. | ||||||||
| - `'pt'`: Return PyTorch `torch.Tensor` objects. | ||||||||
| - `'np'`: Return NumPy `np.ndarray` objects. | ||||||||
| - `'jax'`: Return JAX `jnp.ndarray` objects. | ||||||||
|
|
||||||||
| - `'tf'`: Return TensorFlow `tf.constant` objects. | ||||||||
| - `'pt'`: Return PyTorch `torch.Tensor` objects. | ||||||||
| - `'np'`: Return NumPy `np.ndarray` objects. | ||||||||
| - `'jax'`: Return JAX `jnp.ndarray` objects. | ||||||||
| Returns: | ||||||||
| [`BatchEncoding`]: A [`BatchEncoding`] with the following fields: | ||||||||
|
|
||||||||
|
|
@@ -81,15 +168,53 @@ def __call__(self, text=None, images=None, padding="max_length", max_length=64, | |||||||
| - **pixel_values** -- Pixel values to be fed to a model. Returned when `images` is not `None`. | ||||||||
| """ | ||||||||
| if text is None and images is None: | ||||||||
| raise ValueError("You have to specify either text or images. Both cannot be none.") | ||||||||
|
|
||||||||
| raise ValueError("You must specify either text or images.") | ||||||||
| # set kwargs as empty dicts to avoid default mutable | ||||||||
| if text_kwargs is None: | ||||||||
| text_kwargs = {} | ||||||||
| if images_kwargs is None: | ||||||||
| images_kwargs = {} | ||||||||
| if common_kwargs is None: | ||||||||
| common_kwargs = {} | ||||||||
| # Init with default values if they exist | ||||||||
| default_text_kwargs = AlignProcessorKwargs._defaults.get("text_kwargs", {}).copy() | ||||||||
|
|
||||||||
| # then override with tokenizer-level arguments passed | ||||||||
| default_text_kwargs.update( | ||||||||
| {k: v for k, v in self.tokenizer.init_kwargs.items() if k in AlignProcessorKwargs.text_kwargs} | ||||||||
| ) | ||||||||
| # then get passed per-modality dictionaries if they exist | ||||||||
| text_kwargs = {**default_text_kwargs, **text_kwargs, **kwargs.pop("text_kwargs", {})} | ||||||||
| images_kwargs.update(kwargs.pop("images_kwargs", {})) | ||||||||
| common_kwargs.update(kwargs.pop("common_kwargs", {})) | ||||||||
|
|
||||||||
| # then merge kwargs by name | ||||||||
| for text_key in AlignProcessorKwargs.text_kwargs.keys(): | ||||||||
| text_kwarg_value = kwargs.pop(text_key, None) | ||||||||
| if text_kwarg_value is not None: | ||||||||
| text_kwargs[text_key] = text_kwarg_value | ||||||||
|
|
||||||||
| for images_key in AlignProcessorKwargs.images_kwargs.keys(): | ||||||||
| images_kwarg_value = kwargs.pop(images_key, None) | ||||||||
| if images_kwarg_value is not None: | ||||||||
| images_kwargs[images_key] = images_kwarg_value | ||||||||
| # if something remains in kwargs, it belongs to common | ||||||||
| common_kwargs.update(kwargs) | ||||||||
|
|
||||||||
| # all modality-specific kwargs are updated with common kwargs | ||||||||
| text_kwargs.update(common_kwargs) | ||||||||
| images_kwargs.update(common_kwargs) | ||||||||
|
|
||||||||
| # then, we can pass correct kwargs to each processor | ||||||||
| if text is not None: | ||||||||
| encoding = self.tokenizer( | ||||||||
| text, padding=padding, max_length=max_length, return_tensors=return_tensors, **kwargs | ||||||||
| ) | ||||||||
| encoding = self.tokenizer(text, **text_kwargs) | ||||||||
|
|
||||||||
| if images is not None: | ||||||||
| image_features = self.image_processor(images, return_tensors=return_tensors, **kwargs) | ||||||||
| image_features = self.image_processor(images, **images_kwargs) | ||||||||
|
|
||||||||
| # BC for explicit return_tensors | ||||||||
| if "return_tensors" in common_kwargs: | ||||||||
| return_tensors = common_kwargs.pop("return_tensors", None) | ||||||||
|
|
||||||||
| if text is not None and images is not None: | ||||||||
| encoding["pixel_values"] = image_features.pixel_values | ||||||||
|
|
||||||||
Uh oh!
There was an error while loading. Please reload this page.