Aluode/PerceptionLabPortable
0
1# Copyright 2020 The HuggingFace Inc. team.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15 16import copy17import json18import os19import warnings20from typing import Any, Optional, TypeVar, Union21 22import numpy as np23 24from .dynamic_module_utils import custom_object_save25from .feature_extraction_utils import BatchFeature as BaseBatchFeature26from .image_utils import is_valid_image, load_image27from .utils import (28 IMAGE_PROCESSOR_NAME,29 PROCESSOR_NAME,30 PushToHubMixin,31 copy_func,32 download_url,33 is_offline_mode,34 is_remote_url,35 logging,36)37from .utils.hub import cached_file38 39 40ImageProcessorType = TypeVar("ImageProcessorType", bound="ImageProcessingMixin")41 42 43logger = logging.get_logger(__name__)44 45 46# TODO: Move BatchFeature to be imported by both image_processing_utils and image_processing_utils_fast47# We override the class string here, but logic is the same.48class BatchFeature(BaseBatchFeature):49 r"""50 Holds the output of the image processor specific `__call__` methods.51 52 This class is derived from a python dictionary and can be used as a dictionary.53 54 Args:55 data (`dict`):56 Dictionary of lists/arrays/tensors returned by the __call__ method ('pixel_values', etc.).57 tensor_type (`Union[None, str, TensorType]`, *optional*):58 You can give a tensor_type here to convert the lists of integers in PyTorch/TensorFlow/Numpy Tensors at59 initialization.60 """61 62 63# TODO: (Amy) - factor out the common parts of this and the feature extractor64class ImageProcessingMixin(PushToHubMixin):65 """66 This is an image processor mixin used to provide saving/loading functionality for sequential and image feature67 extractors.68 """69 70 _auto_class = None71 72 def __init__(self, **kwargs):73 """Set elements of `kwargs` as attributes."""74 # This key was saved while we still used `XXXFeatureExtractor` for image processing. Now we use75 # `XXXImageProcessor`, this attribute and its value are misleading.76 kwargs.pop("feature_extractor_type", None)77 # Pop "processor_class" as it should be saved as private attribute78 self._processor_class = kwargs.pop("processor_class", None)79 # Additional attributes without default values80 for key, value in kwargs.items():81 try:82 setattr(self, key, value)83 except AttributeError as err:84 logger.error(f"Can't set {key} with value {value} for {self}")85 raise err86 87 def _set_processor_class(self, processor_class: str):88 """Sets processor class as an attribute."""89 self._processor_class = processor_class90 91 @classmethod92 def from_pretrained(93 cls: type[ImageProcessorType],94 pretrained_model_name_or_path: Union[str, os.PathLike],95 cache_dir: Optional[Union[str, os.PathLike]] = None,96 force_download: bool = False,97 local_files_only: bool = False,98 token: Optional[Union[str, bool]] = None,99 revision: str = "main",100 **kwargs,101 ) -> ImageProcessorType:102 r"""103 Instantiate a type of [`~image_processing_utils.ImageProcessingMixin`] from an image processor.104 105 Args:106 pretrained_model_name_or_path (`str` or `os.PathLike`):107 This can be either:108 109 - a string, the *model id* of a pretrained image_processor hosted inside a model repo on110 huggingface.co.111 - a path to a *directory* containing a image processor file saved using the112 [`~image_processing_utils.ImageProcessingMixin.save_pretrained`] method, e.g.,113 `./my_model_directory/`.114 - a path or url to a saved image processor JSON *file*, e.g.,115 `./my_model_directory/preprocessor_config.json`.116 cache_dir (`str` or `os.PathLike`, *optional*):117 Path to a directory in which a downloaded pretrained model image processor should be cached if the118 standard cache should not be used.119 force_download (`bool`, *optional*, defaults to `False`):120 Whether or not to force to (re-)download the image processor files and override the cached versions if121 they exist.122 resume_download:123 Deprecated and ignored. All downloads are now resumed by default when possible.124 Will be removed in v5 of Transformers.125 proxies (`dict[str, str]`, *optional*):126 A dictionary of proxy servers to use by protocol or endpoint, e.g., `{'http': 'foo.bar:3128',127 'http://hostname': 'foo.bar:4012'}.` The proxies are used on each request.128 token (`str` or `bool`, *optional*):129 The token to use as HTTP bearer authorization for remote files. If `True`, or not specified, will use130 the token generated when running `hf auth login` (stored in `~/.huggingface`).131 revision (`str`, *optional*, defaults to `"main"`):132 The specific model version to use. It can be a branch name, a tag name, or a commit id, since we use a133 git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any134 identifier allowed by git.135 136 137 <Tip>138 139 To test a pull request you made on the Hub, you can pass `revision="refs/pr/<pr_number>"`.140 141 </Tip>142 143 return_unused_kwargs (`bool`, *optional*, defaults to `False`):144 If `False`, then this function returns just the final image processor object. If `True`, then this145 functions returns a `Tuple(image_processor, unused_kwargs)` where *unused_kwargs* is a dictionary146 consisting of the key/value pairs whose keys are not image processor attributes: i.e., the part of147 `kwargs` which has not been used to update `image_processor` and is otherwise ignored.148 subfolder (`str`, *optional*, defaults to `""`):149 In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can150 specify the folder name here.151 kwargs (`dict[str, Any]`, *optional*):152 The values in kwargs of any keys which are image processor attributes will be used to override the153 loaded values. Behavior concerning key/value pairs whose keys are *not* image processor attributes is154 controlled by the `return_unused_kwargs` keyword parameter.155 156 Returns:157 A image processor of type [`~image_processing_utils.ImageProcessingMixin`].158 159 Examples:160 161 ```python162 # We can't instantiate directly the base class *ImageProcessingMixin* so let's show the examples on a163 # derived class: *CLIPImageProcessor*164 image_processor = CLIPImageProcessor.from_pretrained(165 "openai/clip-vit-base-patch32"166 ) # Download image_processing_config from huggingface.co and cache.167 image_processor = CLIPImageProcessor.from_pretrained(168 "./test/saved_model/"169 ) # E.g. image processor (or model) was saved using *save_pretrained('./test/saved_model/')*170 image_processor = CLIPImageProcessor.from_pretrained("./test/saved_model/preprocessor_config.json")171 image_processor = CLIPImageProcessor.from_pretrained(172 "openai/clip-vit-base-patch32", do_normalize=False, foo=False173 )174 assert image_processor.do_normalize is False175 image_processor, unused_kwargs = CLIPImageProcessor.from_pretrained(176 "openai/clip-vit-base-patch32", do_normalize=False, foo=False, return_unused_kwargs=True177 )178 assert image_processor.do_normalize is False179 assert unused_kwargs == {"foo": False}180 ```"""181 kwargs["cache_dir"] = cache_dir182 kwargs["force_download"] = force_download183 kwargs["local_files_only"] = local_files_only184 kwargs["revision"] = revision185 186 use_auth_token = kwargs.pop("use_auth_token", None)187 if use_auth_token is not None:188 warnings.warn(189 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers. Please use `token` instead.",190 FutureWarning,191 )192 if token is not None:193 raise ValueError(194 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."195 )196 token = use_auth_token197 198 if token is not None:199 kwargs["token"] = token200 201 image_processor_dict, kwargs = cls.get_image_processor_dict(pretrained_model_name_or_path, **kwargs)202 203 return cls.from_dict(image_processor_dict, **kwargs)204 205 def save_pretrained(self, save_directory: Union[str, os.PathLike], push_to_hub: bool = False, **kwargs):206 """207 Save an image processor object to the directory `save_directory`, so that it can be re-loaded using the208 [`~image_processing_utils.ImageProcessingMixin.from_pretrained`] class method.209 210 Args:211 save_directory (`str` or `os.PathLike`):212 Directory where the image processor JSON file will be saved (will be created if it does not exist).213 push_to_hub (`bool`, *optional*, defaults to `False`):214 Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the215 repository you want to push to with `repo_id` (will default to the name of `save_directory` in your216 namespace).217 kwargs (`dict[str, Any]`, *optional*):218 Additional key word arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.219 """220 use_auth_token = kwargs.pop("use_auth_token", None)221 222 if use_auth_token is not None:223 warnings.warn(224 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers. Please use `token` instead.",225 FutureWarning,226 )227 if kwargs.get("token") is not None:228 raise ValueError(229 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."230 )231 kwargs["token"] = use_auth_token232 233 if os.path.isfile(save_directory):234 raise AssertionError(f"Provided path ({save_directory}) should be a directory, not a file")235 236 os.makedirs(save_directory, exist_ok=True)237 238 if push_to_hub:239 commit_message = kwargs.pop("commit_message", None)240 repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1])241 repo_id = self._create_repo(repo_id, **kwargs)242 files_timestamps = self._get_files_timestamps(save_directory)243 244 # If we have a custom config, we copy the file defining it in the folder and set the attributes so it can be245 # loaded from the Hub.246 if self._auto_class is not None:247 custom_object_save(self, save_directory, config=self)248 249 # If we save using the predefined names, we can load using `from_pretrained`250 output_image_processor_file = os.path.join(save_directory, IMAGE_PROCESSOR_NAME)251 252 self.to_json_file(output_image_processor_file)253 logger.info(f"Image processor saved in {output_image_processor_file}")254 255 if push_to_hub:256 self._upload_modified_files(257 save_directory,258 repo_id,259 files_timestamps,260 commit_message=commit_message,261 token=kwargs.get("token"),262 )263 264 return [output_image_processor_file]265 266 @classmethod267 def get_image_processor_dict(268 cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs269 ) -> tuple[dict[str, Any], dict[str, Any]]:270 """271 From a `pretrained_model_name_or_path`, resolve to a dictionary of parameters, to be used for instantiating a272 image processor of type [`~image_processor_utils.ImageProcessingMixin`] using `from_dict`.273 274 Parameters:275 pretrained_model_name_or_path (`str` or `os.PathLike`):276 The identifier of the pre-trained checkpoint from which we want the dictionary of parameters.277 subfolder (`str`, *optional*, defaults to `""`):278 In case the relevant files are located inside a subfolder of the model repo on huggingface.co, you can279 specify the folder name here.280 image_processor_filename (`str`, *optional*, defaults to `"config.json"`):281 The name of the file in the model directory to use for the image processor config.282 283 Returns:284 `tuple[Dict, Dict]`: The dictionary(ies) that will be used to instantiate the image processor object.285 """286 cache_dir = kwargs.pop("cache_dir", None)287 force_download = kwargs.pop("force_download", False)288 resume_download = kwargs.pop("resume_download", None)289 proxies = kwargs.pop("proxies", None)290 token = kwargs.pop("token", None)291 use_auth_token = kwargs.pop("use_auth_token", None)292 local_files_only = kwargs.pop("local_files_only", False)293 revision = kwargs.pop("revision", None)294 subfolder = kwargs.pop("subfolder", "")295 image_processor_filename = kwargs.pop("image_processor_filename", IMAGE_PROCESSOR_NAME)296 297 from_pipeline = kwargs.pop("_from_pipeline", None)298 from_auto_class = kwargs.pop("_from_auto", False)299 300 if use_auth_token is not None:301 warnings.warn(302 "The `use_auth_token` argument is deprecated and will be removed in v5 of Transformers. Please use `token` instead.",303 FutureWarning,304 )305 if token is not None:306 raise ValueError(307 "`token` and `use_auth_token` are both specified. Please set only the argument `token`."308 )309 token = use_auth_token310 311 user_agent = {"file_type": "image processor", "from_auto_class": from_auto_class}312 if from_pipeline is not None:313 user_agent["using_pipeline"] = from_pipeline314 315 if is_offline_mode() and not local_files_only:316 logger.info("Offline mode: forcing local_files_only=True")317 local_files_only = True318 319 pretrained_model_name_or_path = str(pretrained_model_name_or_path)320 is_local = os.path.isdir(pretrained_model_name_or_path)321 if os.path.isdir(pretrained_model_name_or_path):322 image_processor_file = os.path.join(pretrained_model_name_or_path, image_processor_filename)323 if os.path.isfile(pretrained_model_name_or_path):324 resolved_image_processor_file = pretrained_model_name_or_path325 is_local = True326 elif is_remote_url(pretrained_model_name_or_path):327 image_processor_file = pretrained_model_name_or_path328 resolved_image_processor_file = download_url(pretrained_model_name_or_path)329 else:330 image_processor_file = image_processor_filename331 try:332 # Load from local folder or from cache or download from model Hub and cache333 resolved_image_processor_files = [334 resolved_file335 for filename in [image_processor_file, PROCESSOR_NAME]336 if (337 resolved_file := cached_file(338 pretrained_model_name_or_path,339 filename=filename,340 cache_dir=cache_dir,341 force_download=force_download,342 proxies=proxies,343 resume_download=resume_download,344 local_files_only=local_files_only,345 token=token,346 user_agent=user_agent,347 revision=revision,348 subfolder=subfolder,349 _raise_exceptions_for_missing_entries=False,350 )351 )352 is not None353 ]354 resolved_image_processor_file = resolved_image_processor_files[0]355 except OSError:356 # Raise any environment error raise by `cached_file`. It will have a helpful error message adapted to357 # the original exception.358 raise359 except Exception:360 # For any other exception, we throw a generic error.361 raise OSError(362 f"Can't load image processor for '{pretrained_model_name_or_path}'. If you were trying to load"363 " it from 'https://huggingface.co/models', make sure you don't have a local directory with the"364 f" same name. Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a"365 f" directory containing a {image_processor_filename} file"366 )367 368 try:369 # Load image_processor dict370 with open(resolved_image_processor_file, encoding="utf-8") as reader:371 text = reader.read()372 image_processor_dict = json.loads(text)373 image_processor_dict = image_processor_dict.get("image_processor", image_processor_dict)374 375 except json.JSONDecodeError:376 raise OSError(377 f"It looks like the config file at '{resolved_image_processor_file}' is not a valid JSON file."378 )379 380 if is_local:381 logger.info(f"loading configuration file {resolved_image_processor_file}")382 else:383 logger.info(384 f"loading configuration file {image_processor_file} from cache at {resolved_image_processor_file}"385 )386 387 return image_processor_dict, kwargs388 389 @classmethod390 def from_dict(cls, image_processor_dict: dict[str, Any], **kwargs):391 """392 Instantiates a type of [`~image_processing_utils.ImageProcessingMixin`] from a Python dictionary of parameters.393 394 Args:395 image_processor_dict (`dict[str, Any]`):396 Dictionary that will be used to instantiate the image processor object. Such a dictionary can be397 retrieved from a pretrained checkpoint by leveraging the398 [`~image_processing_utils.ImageProcessingMixin.to_dict`] method.399 kwargs (`dict[str, Any]`):400 Additional parameters from which to initialize the image processor object.401 402 Returns:403 [`~image_processing_utils.ImageProcessingMixin`]: The image processor object instantiated from those404 parameters.405 """406 image_processor_dict = image_processor_dict.copy()407 return_unused_kwargs = kwargs.pop("return_unused_kwargs", False)408 409 # The `size` parameter is a dict and was previously an int or tuple in feature extractors.410 # We set `size` here directly to the `image_processor_dict` so that it is converted to the appropriate411 # dict within the image processor and isn't overwritten if `size` is passed in as a kwarg.412 if "size" in kwargs and "size" in image_processor_dict:413 image_processor_dict["size"] = kwargs.pop("size")414 if "crop_size" in kwargs and "crop_size" in image_processor_dict:415 image_processor_dict["crop_size"] = kwargs.pop("crop_size")416 417 image_processor = cls(**image_processor_dict)418 419 # Update image_processor with kwargs if needed420 to_remove = []421 for key, value in kwargs.items():422 if hasattr(image_processor, key):423 setattr(image_processor, key, value)424 to_remove.append(key)425 for key in to_remove:426 kwargs.pop(key, None)427 428 logger.info(f"Image processor {image_processor}")429 if return_unused_kwargs:430 return image_processor, kwargs431 else:432 return image_processor433 434 def to_dict(self) -> dict[str, Any]:435 """436 Serializes this instance to a Python dictionary.437 438 Returns:439 `dict[str, Any]`: Dictionary of all the attributes that make up this image processor instance.440 """441 output = copy.deepcopy(self.__dict__)442 output["image_processor_type"] = self.__class__.__name__443 444 return output445 446 @classmethod447 def from_json_file(cls, json_file: Union[str, os.PathLike]):448 """449 Instantiates a image processor of type [`~image_processing_utils.ImageProcessingMixin`] from the path to a JSON450 file of parameters.451 452 Args:453 json_file (`str` or `os.PathLike`):454 Path to the JSON file containing the parameters.455 456 Returns:457 A image processor of type [`~image_processing_utils.ImageProcessingMixin`]: The image_processor object458 instantiated from that JSON file.459 """460 with open(json_file, encoding="utf-8") as reader:461 text = reader.read()462 image_processor_dict = json.loads(text)463 return cls(**image_processor_dict)464 465 def to_json_string(self) -> str:466 """467 Serializes this instance to a JSON string.468 469 Returns:470 `str`: String containing all the attributes that make up this feature_extractor instance in JSON format.471 """472 dictionary = self.to_dict()473 474 for key, value in dictionary.items():475 if isinstance(value, np.ndarray):476 dictionary[key] = value.tolist()477 478 # make sure private name "_processor_class" is correctly479 # saved as "processor_class"480 _processor_class = dictionary.pop("_processor_class", None)481 if _processor_class is not None:482 dictionary["processor_class"] = _processor_class483 484 return json.dumps(dictionary, indent=2, sort_keys=True) + "\n"485 486 def to_json_file(self, json_file_path: Union[str, os.PathLike]):487 """488 Save this instance to a JSON file.489 490 Args:491 json_file_path (`str` or `os.PathLike`):492 Path to the JSON file in which this image_processor instance's parameters will be saved.493 """494 with open(json_file_path, "w", encoding="utf-8") as writer:495 writer.write(self.to_json_string())496 497 def __repr__(self):498 return f"{self.__class__.__name__} {self.to_json_string()}"499 500 @classmethod501 def register_for_auto_class(cls, auto_class="AutoImageProcessor"):502 """503 Register this class with a given auto class. This should only be used for custom image processors as the ones504 in the library are already mapped with `AutoImageProcessor `.505 506 507 508 Args:509 auto_class (`str` or `type`, *optional*, defaults to `"AutoImageProcessor "`):510 The auto class to register this new image processor with.511 """512 if not isinstance(auto_class, str):513 auto_class = auto_class.__name__514 515 import transformers.models.auto as auto_module516 517 if not hasattr(auto_module, auto_class):518 raise ValueError(f"{auto_class} is not a valid auto class.")519 520 cls._auto_class = auto_class521 522 def fetch_images(self, image_url_or_urls: Union[str, list[str], list[list[str]]]):523 """524 Convert a single or a list of urls into the corresponding `PIL.Image` objects.525 526 If a single url is passed, the return value will be a single object. If a list is passed a list of objects is527 returned.528 """529 if isinstance(image_url_or_urls, list):530 return [self.fetch_images(x) for x in image_url_or_urls]531 elif isinstance(image_url_or_urls, str):532 return load_image(image_url_or_urls)533 elif is_valid_image(image_url_or_urls):534 return image_url_or_urls535 else:536 raise TypeError(f"only a single or a list of entries is supported but got type={type(image_url_or_urls)}")537 538 539ImageProcessingMixin.push_to_hub = copy_func(ImageProcessingMixin.push_to_hub)540if ImageProcessingMixin.push_to_hub.__doc__ is not None:541 ImageProcessingMixin.push_to_hub.__doc__ = ImageProcessingMixin.push_to_hub.__doc__.format(542 object="image processor", object_class="AutoImageProcessor", object_files="image processor file"543 )544 